AI Fashion Trend Forecasting System

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1 servicesAll 1566 services
AI Fashion Trend Forecasting System
Medium
~2-4 weeks
FAQ
AI Development Areas
AI Solution Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1212
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822

Разработка 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 недели