AI-система прогнозування модних трендів

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

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

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

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

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

Разработка AI для прогнозирования трендов в моде

Fashion trend forecasting — анализ визуального контента (подиумные показы, социальные сети, e-commerce) для прогнозирования актуальных трендов. Традиционно: аналитики-трендсеттеры тратят месяцы на ручной анализ. AI обрабатывает миллионы изображений за часы: выявляет доминирующие цвета, силуэты, принты, паттерны, строит временные ряды популярности каждого атрибута.

Экстрактор модных атрибутов

import numpy as np
import cv2
import torch
from transformers import CLIPProcessor, CLIPModel
from torchvision import transforms
from PIL import Image
from dataclasses import dataclass, field
from collections import Counter, defaultdict
from datetime import datetime
from typing import Optional

@dataclass
class FashionAttributes:
    image_path: str
    timestamp: str
    categories: list[str]      # dress / top / pants / jacket / etc.
    colors: list[str]          # red / navy / beige / etc.
    patterns: list[str]        # solid / stripes / floral / plaid / etc.
    silhouette: str            # slim / oversized / fitted / flared
    style: str                 # casual / formal / streetwear / sport / etc.
    season: Optional[str]      # spring / summer / fall / winter

class FashionAttributeExtractor:
    """
    CLIP-based извлечение модных атрибутов из изображений одежды.
    FashionCLIP (fine-tuned на Farfetch) лучше vanilla CLIP для fashion domain.
    """
    # Атрибуты для CLIP zero-shot classification
    CATEGORIES = ['dress', 'top', 'blouse', 't-shirt', 'pants', 'jeans',
                  'skirt', 'jacket', 'coat', 'blazer', 'sweater', 'hoodie',
                  'shorts', 'suit', 'jumpsuit', 'cardigan']

    COLORS = ['red', 'dark red', 'orange', 'yellow', 'lime green', 'green',
              'teal', 'light blue', 'navy blue', 'purple', 'pink', 'white',
              'off-white', 'beige', 'light gray', 'gray', 'dark gray', 'black',
              'brown', 'camel', 'olive green', 'multicolor']

    PATTERNS = ['solid color', 'vertical stripes', 'horizontal stripes',
                'plaid check', 'floral print', 'animal print', 'geometric pattern',
                'abstract print', 'polka dots', 'camouflage', 'paisley']

    SILHOUETTES = ['slim fit', 'oversized loose fit', 'fitted tailored',
                   'flared wide leg', 'cropped short', 'longline maxi']

    STYLES = ['casual everyday', 'business formal', 'business casual',
              'streetwear urban', 'sport athletic', 'evening cocktail',
              'bohemian romantic', 'minimalist', 'vintage retro']

    def __init__(self, model_name: str = 'patrickjohncyh/fashion-clip',
                  device: str = 'cuda'):
        self.device = device
        try:
            # Fashion-CLIP если доступен
            self.model = CLIPModel.from_pretrained(model_name).to(device)
            self.processor = CLIPProcessor.from_pretrained(model_name)
        except Exception:
            # Fallback на vanilla CLIP
            self.model = CLIPModel.from_pretrained('openai/clip-vit-base-patch32').to(device)
            self.processor = CLIPProcessor.from_pretrained('openai/clip-vit-base-patch32')
        self.model.eval()

        # Pre-compute text features для всех категорий
        self._features_cache = {}
        for attr_name, attr_list in [
            ('categories', self.CATEGORIES), ('colors', self.COLORS),
            ('patterns', self.PATTERNS), ('silhouettes', self.SILHOUETTES),
            ('styles', self.STYLES)
        ]:
            self._features_cache[attr_name] = self._encode_texts(
                [f'a fashion photo of {a}' for a in attr_list]
            )

    @torch.no_grad()
    def _encode_texts(self, texts: list) -> torch.Tensor:
        inputs = self.processor(text=texts, return_tensors='pt',
                                 padding=True, truncation=True).to(self.device)
        features = self.model.get_text_features(**inputs)
        return features / features.norm(dim=-1, keepdim=True)

    @torch.no_grad()
    def extract(self, image: np.ndarray,
                 image_path: str = '') -> FashionAttributes:
        pil = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
        inputs = self.processor(images=pil, return_tensors='pt').to(self.device)
        img_features = self.model.get_image_features(**inputs)
        img_features = img_features / img_features.norm(dim=-1, keepdim=True)

        def top_k_matches(feature_key, attr_list, top_k=2, threshold=0.18):
            features = self._features_cache[feature_key]
            sims = (img_features @ features.T).squeeze().cpu().numpy()
            top_idx = sims.argsort()[-top_k:][::-1]
            return [attr_list[i] for i in top_idx if sims[i] > threshold]

        categories = top_k_matches('categories', self.CATEGORIES, top_k=2)
        colors = top_k_matches('colors', self.COLORS, top_k=3, threshold=0.15)
        patterns = top_k_matches('patterns', self.PATTERNS, top_k=1)
        sils = top_k_matches('silhouettes', self.SILHOUETTES, top_k=1)
        styles = top_k_matches('styles', self.STYLES, top_k=1)

        # Сезонность по цветам
        season = self._infer_season(colors, patterns)

        return FashionAttributes(
            image_path=image_path,
            timestamp=datetime.now().isoformat(),
            categories=categories,
            colors=colors,
            patterns=patterns,
            silhouette=sils[0] if sils else 'unknown',
            style=styles[0] if styles else 'unknown',
            season=season
        )

    def _infer_season(self, colors: list, patterns: list) -> str:
        summer_colors = {'lime green', 'yellow', 'orange', 'light blue', 'white'}
        winter_colors = {'dark gray', 'black', 'navy blue', 'dark red'}
        spring_colors = {'pink', 'light blue', 'off-white', 'beige'}

        if any(c in summer_colors for c in colors):
            return 'summer'
        elif any(c in winter_colors for c in colors):
            return 'winter'
        elif any(c in spring_colors for c in colors):
            return 'spring'
        return 'fall'

Анализ трендов по временным рядам

class TrendAnalyzer:
    """
    Накопление атрибутов из изображений → построение трендовых временных рядов.
    Выявление восходящих и нисходящих трендов через скользящее среднее.
    """
    def __init__(self):
        self.data: list[FashionAttributes] = []

    def add_batch(self, attributes: list[FashionAttributes]) -> None:
        self.data.extend(attributes)

    def analyze_color_trends(self, period_days: int = 30) -> dict:
        """Топ цветов + динамика за период"""
        from datetime import datetime, timedelta

        recent_cutoff = datetime.now() - timedelta(days=period_days)
        recent = [a for a in self.data
                  if datetime.fromisoformat(a.timestamp) > recent_cutoff]

        all_colors = [c for a in recent for c in a.colors]
        prev_all_colors = [c for a in self.data if a not in recent
                          for c in a.colors]

        current_counts = Counter(all_colors)
        prev_counts = Counter(prev_all_colors)

        total_current = max(sum(current_counts.values()), 1)
        total_prev = max(sum(prev_counts.values()), 1)

        trends = {}
        all_keys = set(list(current_counts.keys()) + list(prev_counts.keys()))
        for color in all_keys:
            curr_pct = current_counts.get(color, 0) / total_current * 100
            prev_pct = prev_counts.get(color, 0) / total_prev * 100
            change = curr_pct - prev_pct
            trends[color] = {
                'current_share_pct': round(curr_pct, 2),
                'change_pct': round(change, 2),
                'trend': 'rising' if change > 1 else ('falling' if change < -1 else 'stable')
            }

        # Топ-10 по текущей доле
        top10 = sorted(trends.items(), key=lambda x: x[1]['current_share_pct'], reverse=True)[:10]
        return {k: v for k, v in top10}

    def get_emerging_trends(self, min_growth_pct: float = 2.0) -> list[dict]:
        """Выявление быстро растущих трендов"""
        color_trends = self.analyze_color_trends()
        emerging = [
            {'attribute': color, **data}
            for color, data in color_trends.items()
            if data['change_pct'] >= min_growth_pct
        ]
        return sorted(emerging, key=lambda x: x['change_pct'], reverse=True)
Метрика FashionCLIP Vanilla CLIP
Category Top-1 82–87% 68–75%
Color Detection 78–84% 65–72%
Pattern Detection 72–80% 58–68%
Trend Correlation (vs sales) r=0.73 r=0.58
Задача Срок
Атрибут-экстрактор + базовый анализ 4–6 недель
Трендовый мониторинг + temporal analysis 8–14 недель
Fashion Intelligence платформа + API 14–22 недели