AI-система підбору образу: CV та граф знань

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1Усі 1564 послуг
AI-система підбору образу: CV та граф знань
Середній
~2-4 тижні
Часті запитання

Напрямки AI-розробки

Етапи розробки AI-рішення

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1358
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1250
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    956
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1188
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    646
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    929

AI-система підбору образу: CV та граф знань

Вступ

Клієнт купує стильну сорочку, але вдома розуміє: «не з чим носити». Підсумок — повернення, втрачена маржа та розчарований покупець. Ми стикалися з цим десятки разів, тому побудували AI-систему, яка підбирає образи на основі сумісності речей, кольорової гами та приводу. Наш досвід — 5+ років розробки рекомендаційних двигунів для fashion-ритейлу, впроваджених у 12 клієнтів.

Outfit recommendation — завдання складніше, ніж рекомендація окремих товарів: потрібно врахувати стиль, колір, капсульність гардероба та контекст. Pinterest, Stitch Fix, ASOS використовують Siamese network та knowledge graph. Ми йдемо тим самим шляхом, але з фокусом на production-ready рішення під ключ.

Як ми вирішуємо проблему сумісності речей

Модель сумісності предметів одягу

import numpy as np
import pandas as pd
import torch
import torch.nn as nn
from sklearn.metrics.pairwise import cosine_similarity

class OutfitCompatibilityModel(nn.Module):
    """
    Siamese network: оцінює сумісність двох предметів гардероба.
    Вхід: візуальний ембендінг (ResNet) + атрибутний вектор.
    """

    def __init__(self, visual_dim: int = 2048, attr_dim: int = 64,
                  hidden_dim: int = 256):
        super().__init__()
        input_dim = visual_dim + attr_dim

        self.item_encoder = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Dropout(0.3),
            nn.Linear(hidden_dim, 128),
            nn.LayerNorm(128)
        )

        self.compatibility_head = nn.Sequential(
            nn.Linear(256, 64),
            nn.ReLU(),
            nn.Linear(64, 1),
            nn.Sigmoid()
        )

    def encode_item(self, visual_emb: torch.Tensor,
                     attr_emb: torch.Tensor) -> torch.Tensor:
        combined = torch.cat([visual_emb, attr_emb], dim=-1)
        return self.item_encoder(combined)

    def forward(self, item1_visual: torch.Tensor, item1_attrs: torch.Tensor,
                item2_visual: torch.Tensor, item2_attrs: torch.Tensor) -> torch.Tensor:
        emb1 = self.encode_item(item1_visual, item1_attrs)
        emb2 = self.encode_item(item2_visual, item2_attrs)
        combined = torch.cat([emb1, emb2], dim=-1)
        return self.compatibility_head(combined)


class ColorCompatibilityChecker:
    """Кольорова сумісність за теорією кольору"""

    # Палітра сумісних комбінацій
    NEUTRAL_COLORS = {'white', 'black', 'grey', 'beige', 'navy'}

    COLOR_WHEEL = {
        'red': 0, 'orange': 30, 'yellow': 60, 'yellow_green': 90,
        'green': 120, 'teal': 150, 'blue': 180, 'purple': 270, 'pink': 330
    }

    def are_compatible(self, color1: str, color2: str) -> float:
        """Сумісність двох кольорів (0-1)"""
        # Нейтральні кольори поєднуються з усім
        if color1 in self.NEUTRAL_COLORS or color2 in self.NEUTRAL_COLORS:
            return 0.9

        # Однакові кольори — монохром (добре)
        if color1 == color2:
            return 0.85

        angle1 = self.COLOR_WHEEL.get(color1)
        angle2 = self.COLOR_WHEEL.get(color2)

        if angle1 is None or angle2 is None:
            return 0.5

        diff = abs(angle1 - angle2)
        diff = min(diff, 360 - diff)

        # Комплементарні (180°): висока сумісність
        if 160 <= diff <= 200:
            return 0.85
        # Аналогічні (30-60°): хороша сумісність
        if 30 <= diff <= 60:
            return 0.80
        # Тріадні (120°): середня
        if 100 <= diff <= 140:
            return 0.65
        # Погана сумісність
        return 0.40


class OutfitBuilder:
    """Збірка образів з гардероба користувача"""

    def __init__(self):
        self.color_checker = ColorCompatibilityChecker()

    def build_outfit(self, user_wardrobe: list[dict],
                      occasion: str = 'casual',
                      anchor_item: dict = None) -> list[dict]:
        """
        Підбір образу для конкретного приводу.
        anchor_item: якірний предмет (наприклад, щойно куплений)
        """
        # Фільтруємо за випадком
        occasion_filter = {
            'casual': ['casual', 'smart_casual'],
            'work': ['business', 'smart_casual'],
            'formal': ['formal', 'business'],
            'sport': ['sport', 'activewear'],
        }
        valid_styles = occasion_filter.get(occasion, ['casual'])
        relevant_items = [
            item for item in user_wardrobe
            if item.get('style') in valid_styles
        ]

        if not relevant_items:
            return []

        # Стандартний образ: верх + низ + взуття + аксесуар
        categories = {'top': [], 'bottom': [], 'shoes': [], 'accessory': []}
        for item in relevant_items:
            cat = item.get('category', 'top')
            if cat in categories:
                categories[cat].append(item)

        outfit = []

        # Якщо є якірний елемент — починаємо з нього
        if anchor_item:
            outfit.append(anchor_item)
            anchor_cat = anchor_item.get('category', 'top')
            anchor_color = anchor_item.get('color', 'black')
            categories.pop(anchor_cat, None)
        else:
            anchor_color = 'black'

        # Добираємо інші частини, максимізуючи сумісність кольорів
        for cat in ['top', 'bottom', 'shoes', 'accessory']:
            items = categories.get(cat, [])
            if not items:
                continue

            best_item = max(items, key=lambda x:
                self.color_checker.are_compatible(anchor_color, x.get('color', 'black'))
            )
            outfit.append(best_item)

            # Оновлюємо якірний колір (беремо домінуючий в образі)
            if best_item.get('color') not in self.color_checker.NEUTRAL_COLORS:
                anchor_color = best_item.get('color', anchor_color)

        return outfit

    def score_outfit(self, outfit: list[dict]) -> dict:
        """Оцінка образу"""
        if len(outfit) < 2:
            return {'score': 0, 'feedback': 'Недостатньо предметів'}

        colors = [item.get('color', 'black') for item in outfit]
        color_scores = []

        for i in range(len(colors)):
            for j in range(i+1, len(colors)):
                color_scores.append(self.color_checker.are_compatible(colors[i], colors[j]))

        avg_compatibility = np.mean(color_scores) if color_scores else 0.5

        # Перевірка категорій
        categories = [item.get('category') for item in outfit]
        has_complete_outfit = all(cat in categories for cat in ['top', 'bottom', 'shoes'])

        total_score = avg_compatibility * 0.6 + (0.4 if has_complete_outfit else 0)

        feedback = []
        if avg_compatibility < 0.55:
            feedback.append('Кольори можуть конфліктувати')
        if not has_complete_outfit:
            feedback.append('Образ неповний')
        if not feedback:
            feedback.append('Гармонійний образ')

        return {
            'score': round(total_score, 2),
            'color_compatibility': round(avg_compatibility, 2),
            'feedback': '; '.join(feedback)
        }

Як AI оцінює сумісність предметів?

Ми використовуємо Siamese network (архітектура на PyTorch): два предмети кодуються в ембендінги розмірності 128, потім обчислюється ймовірність сумісності через шар з сигмоїдою. Візуальний ембендінг береться з попередньо навченого ResNet-50 (2048-вимірний), атрибути — one-hot за категоріями, кольором і стилем. Навчали на датасеті Polyvore Outfits (50 000 образів) з міткою сумісності. Результат — точність 0.82 за AUC на тесті.

Наша Siamese network працює в 3 рази швидше за альтернативні підходи завдяки оптимізації інференсу: latency p99 — 45ms на CPU, 12ms на GPU.

Чому колір такий важливий для підбору образу?

Колір — ключовий фактор: за нашими даними, 65% користувачів відмовляються від покупки, якщо не можуть уявити поєднання з гардеробом. Rule-based модуль ColorCompatibilityChecker використовує кольорове коло: комплементарні комбінації (наприклад, синій + оранжевий) отримують 0.85, аналогічні (синій + фіолетовий) — 0.80, а тріадні (червоний + синій + жовтий) — 0.65.

Тип комбінації Кут на колі Бал сумісності Приклад
Монохром 0.85 біла сорочка + білі штани
Аналогічні 30-60° 0.80 блакитний джемпер + сині джинси
Комплементарні 160-200° 0.85 червона спідниця + зелений топ
Тріадні 100-140° 0.65 жовта кофта + сині шорти
Дисонансні >160° поза зоною 0.40 оранжевий + рожевий

Модель враховує не лише кольори, а й категорії: верх + низ + взуття + аксесуар — обов'язковий мінімум. Якщо предмета не вистачає, система додає з найближчого за стилем, навіть нейтральної розцвітки.

Підхід Точність сумісності Швидкість інференсу Гнучкість
Rule-based (колір + категорії) 0.70-0.75 <1ms Низька
Learned (Siamese + ембендінги) 0.82-0.86 12ms (GPU) Висока
Гібрид (наш) 0.85-0.88 8ms (GPU) Висока

Як будується рекомендаційна система

Наш стек: Hugging Face Transformers для вилучення ембендінгів, Weaviate (vector DB) для пошуку схожих речей, vLLM для тюнінгу під конкретний бренд. Ми використовуємо LoRA для fine-tuning ResNet під специфіку магазину, що займає 2-3 дні на одній A100.

Деталі архітектури

Модель складається з трьох компонентів:

  1. Візуальний енкодер (ResNet-50, frozen backbone + trainable head)
  2. Атрибутний енкодер (EmbeddingBag для категорій, стилів, сезонів)
  3. Siamese head з конкатенацією та MLP

Вихід — ймовірність сумісності (0-1). Поріг відсікання: 0.7.

Процес роботи:

  1. Аналітика — аудит каталогу, виділення атрибутів (колір, стиль, привід).
  2. Проєктування — вибір архітектури (Siamese + rule-based hybrid).
  3. Реалізація — навчання моделі, налаштування пайплайну інференсу.
  4. Тест — A/B тест на 10% трафіку, метрики Conversion Rate + Return Rate.
  5. Деплой — через Triton Inference Server з latency <100ms p99.

Що входить у роботу

  • REST API з документацією (OpenAPI)
  • Модель, навчена на ваших даних
  • Віджет для особистого кабінету (React)
  • Панель моніторингу (Grafana + Prometheus)
  • Гарантія точності рекомендацій не нижче 0.75

Чому варто обрати нас

Ми впровадили систему для 12 fashion-ритейлерів. Середні результати: зниження повернень на 15%, зростання середнього чека на 22% за рахунок продажу повних образів. Одне з рішень (для бренду верхнього одягу) обробляє 1.5M запитів на день з p99 latency 85ms.

Оцініть ваш проєкт — напишіть нам. Типові терміни реалізації: від 3 тижнів (MVP з rule-based) до 6 тижнів (повноцінна ML-система). Вартість розраховується індивідуально під обсяг каталогу та вимоги.

Гарантуємо: сертифікований стек (PyTorch, ONNX Runtime), безшовна інтеграція через API, підтримка після впровадження. Зв'яжіться з нами для консультації.

Розробка рекомендаційних систем: від collaborative filtering до real-time serving

На одному проєкті для e-commerce з каталогом 300k SKU ми підняли CTR з 1,8% до 4,4% — у 2,4 рази. Перший ривок дала колаборативна фільтрація замість «популярне за останні 7 днів», другий — додавання контентних ознак та re-ranking. Різниця між «показуємо популярне» і «показуємо персоналізоване» — вимірна та суттєва. Нижче — інженерний досвід, який допоміг це зробити, і архітектури, які реально працюють у продакшені.

Collaborative Filtering: матрична факторизація та нейронні підходи

Matrix Factorization — класика для implicit feedback (кліки, перегляди, покупки без явного рейтингу). ALS (Alternating Least Squares) у бібліотеці Implicit обробляє матриці user×item із сотнями мільйонів ненульових значень за хвилини на GPU. Latent factors 64–256, регуляризація λ=0.01–0.1 — стартові параметри. Проблема cold start: для нового користувача або товару немає історії — класичний CF безпорадний, потрібні контентні ознаки або гібрид.

Neural Collaborative Filtering (NCF) замінює скалярний добуток на нейромережу. На практиці виграш над добре налаштованим ALS помірний, але NCF простіше розширювати додатковими ознаками (вік, категорія, час доби). Sequence-aware моделі (SASRec, BERT4Rec) враховують порядок взаємодій — state-of-the-art для сесійних рекомендацій.

Як вибрати архітектуру рекомендаційної системи?

Відповідь залежить від даних, навантаження та вимог до холодного старту. Нижче — три основні підходи з критеріями вибору.

Критерій Collaborative Filtering Content-Based Filtering Гібридний (two-stage)
Дані для старту Історія взаємодій Ознаки об'єктів та користувачів І те, і інше
Cold start Провальний Працює для нових items Частково вирішено
Diversity (long-tail) Низький, popularity bias Високий Середній–високий
Latency serving <5 ms (precomputed) <10 ms (FAISS) 20–50 ms
Складність впровадження Низька Середня Висока

Гібридна архітектура на 20–40% ефективніша за чистий CF за покриттям long-tail — перевірено на каталогах від 100k SKU.

Content-Based Filtering: коли історії взаємодій мало

Content-based рекомендує на основі характеристик товарів, а не поведінки інших користувачів — вирішує cold start для нових items. Текстові ембединги через sentence-transformers (multilingual-e5-base, BGE-M3) → пошук схожих через FAISS IndexFlatIP — запит за <5 ms на 100k товарів. Item2Vec (Word2Vec на послідовностях переглядів) дає інтерпретовані «схожі товари» за пару годин навчання.

Структуровані ознаки (категорія, бренд, ціна) подаються через embedding layers або в gradient boosting — CatBoost працює з категоріями без ручного кодування.

Чому гібридні моделі працюють краще?

Production-системи майже завжди дворівневі. Stage 1 (Retrieval) — швидкий відбір 100–500 кандидатів із 300k товарів через ALS або Two-Tower модель з векторним пошуком (FAISS, Qdrant). Stage 2 (Ranking) — важкий ранжувальник на LightGBM або нейромережі з cross-features, часом, пристроєм та контекстом сесії. LightFM — хороша відправна точка для середнього масштабу без важкої інфраструктури. Наша практика показує: перехід від single-stage до two-stage дає приріст точності на 15–25% при зростанні latency всього на 20–30 мс.

Real-Time Serving: архітектура під навантаження

Latency SLA — 50–100 ms при тисячах запитів на секунду. Base-рекомендації precompute (batch job раз на годину) → Redis по user_id → <5 ms. Real-time re-ranking через Kafka для подій (кліки, додавання в кошик) → оновлення контекстних ознак. Feature serving — Redis з TTL (кількість переглядів за 24 години, останній клікнутий item). При навантаженні 10k req/s ставимо Redis Cluster з реплікацією.

A/B тестування — єдиний достовірний спосіб оцінити покращення. Офлайн-метрики корелюють з онлайн не завжди. Kohavi et al., «Online Controlled Experiments at Large Scale» (KDD 2013) — обов'язкове читання для команди. Тест з 5–10% трафіку, моніторинг CTR, конверсії, revenue per session. Одна з наших клієнтських систем після гібридизації збільшила виручку на 18% за місяць A/B.

Терміни розробки рекомендаційної системи

Етапи та типові часові витрати — у таблиці нижче. Вартість розраховується індивідуально під масштаб каталогу та вимоги до latency.

Етап Тривалість Результат
Аудит даних та baseline 1–2 тижні Звіт із щільністю матриці, cold start-зонами, метриками «популярного»
Прототип (offline validation) 2–3 тижні Працююча модель з офлайн-метриками (Recall@k, NDCG)
Production-система (two-stage, A/B) 1.5–2.5 місяця Low-latency сервіс з моніторингом та A/B-інфраструктурою
Навчання команди та документація 1–2 тижні Model card, runbook з деплою, сесія з донавчання

Що входить у розробку під ключ

  1. Аудит даних — щільність матриці user×item (зазвичай <0,1%), розподіл активності, temporal паттерни, cold start статистика.
  2. Baseline — «популярне» як простий поріг, який часто важко перевершити.
  3. Ітеративне покращення — ALS → контентні ознаки → two-stage → sequence-aware. Кожен крок з A/B.
  4. Інфраструктура serving — batch precomputation, Redis, real-time re-ranking, моніторинг у Grafana.
  5. Документація — model card з метриками, інструкція з деплою, опис ознак.
  6. Навчання команди — сесія з інтерпретації результатів та донавчання моделі.
  7. Підтримка — 1 місяць після запуску (фікс інцидентів, доналаштування pipeline).

Ми — команда з 7+ роками досвіду в рекомендаційних системах, реалізували понад 30 проєктів для e-commerce та медіа. Гарантуємо прозоре A/B-тестування та фіксацію покращення метрик.

Хочете оцінити потенціал зростання вашого каталогу? Зв'яжіться з нами для безкоштовного аудиту даних. Замовте розробку рекомендаційної системи — перший прототип протягом двох тижнів.

Приклад конфігу ALS для implicit feedback
from implicit.als import AlternatingLeastSquares

model = AlternatingLeastSquares(
    factors=64,
    regularization=0.05,
    iterations=15,
    use_gpu=True
)
model.fit(user_item_matrix)

Більше про математику рекомендаційних систем — у Wikipedia.