Треугольник смерти e-commerce: выбери любые две стороны
Забудьте про магический квадрат. В мире Virtual Try-On есть только три угла: качество, скорость, стоимость. И вы можете выбрать максимум два. Хотите фотографическую точность и 2 секунды на обработку? Готовьте $0.50 за запрос. Нужно дешево и быстро? Получите на выходе кошмар из 2018 года, где джинсы натягиваются на голову.
Мы столкнулись с этим в проекте для крупного ритейлера. Запрос простой: "Сделайте как у Shein, но чтобы не разориться". Проблема в том, что Shein тратит на инфраструктуру Try-On больше, чем некоторые страны на образование. Их пайплайн - это десятки A100, кастомные модели, команда из 50 ML-инженеров. У нас был бюджет на три RTX 4090 и обещание "сделаем за два месяца".
Если кто-то предлагает вам Virtual Try-On "как у Shein" за $10к в месяц - бегите. Либо он врет, либо результат будет таким, что пользователи побегут от вас.
Почему чистые диффузионные модели съедают бизнес
В прошлой статье про Virtual Try-On на диффузионных моделях я уже объяснял, почему Nano Banana и другие SOTA-решения - это красивые игрушки для исследовательских бумаг. Но давайте посмотрим на цифры:
| Модель | Время (сек) | VRAM (GB) | Стоимость/запрос | Качество |
|---|---|---|---|---|
| Nano Banana (чистый) | 12-15 | 24 | ~$0.45 | 9/10 |
| IDM-VTON (чистый) | 8-10 | 18 | ~$0.35 | 8.5/10 |
| Традиционный GAN | 1-2 | 4 | ~$0.05 | 5/10 |
| Наш гибрид | 1.5-2.5 | 6-8 | ~$0.07 | 7.5/10 |
Видите разницу? Чистые диффузионные модели в 5-7 раз дороже. При масштабе 100к запросов в день это $15к против $100к в месяц. Бизнес-логика простая: если Try-On увеличивает конверсию на 15%, но съедает всю маржу - зачем он нужен?
Хирургия диффузионной модели: что можно отрезать без потери качества
Секрет в том, что диффузионные модели для Try-On делают две разные работы:
- Сегментация и позиционирование одежды на теле
- Генерация реалистичных текстур и складок
Первая задача - детерминированная. Вторая - стохастическая. И вот ключевое наблющение: 80% вычислительной мощности уходит на вторую задачу, но именно она дает лишь 20% воспринимаемого качества. Пользователь замечает, если рубашка "плывет" где-то в стороне от тела. Но мелкие складки на локте? Их почти не видно на мобильном экране.
1 Архитектура гибридного пайплайна: IDM-VTON + Leffa
Вот как выглядит наш пайплайн после оптимизации:
# core_pipeline.py
import torch
from idm_vton import IDMWarpingModule
from leffa import LightweightEnhancementModule
from segmentation import FastHumanParser
class HybridTryOnPipeline:
def __init__(self, device='cuda'):
# Тяжелый компонент - но только для warping
self.warper = IDMWarpingModule().to(device).half()
# Легкий компонент - для enhancement
self.enhancer = LightweightEnhancementModule().to(device)
# Супер-легкий - для сегментации
self.parser = FastHumanParser() # CPU-only!
# Кэш для warm-up
self.warmup_cache = {}
def process(self, human_img, garment_img):
"""Основной пайплайн обработки"""
# Шаг 1: Быстрая сегментация на CPU (5-10ms)
human_mask = self.parser.segment(human_img)
# Шаг 2: Warping с IDM-VTON (тяжелая часть)
# Но только 25 шагов вместо 50!
warped_garment = self.warper.warp(
garment_img,
human_img,
human_mask,
num_inference_steps=25 # Быстрее в 2 раза
)
# Шаг 3: Легкое улучшение с Leffa
# Вместо полной диффузии - lightweight CNN
enhanced = self.enhancer.enhance(
human_img,
warped_garment,
human_mask
)
return enhanced
Магия в распределении нагрузки. IDM-VTON делает только warping (деформацию одежды под позу человека). Leffa - легкая CNN-архитектура - добавляет реалистичные текстуры. Сегментация вообще работает на CPU.
2 Leffa: что это и почему это работает
Leffa (Lightweight Enhancement For Fashion Applications) - наша кастомная архитектура. Не SOTA, не революционная. Просто эффективная.
# leffa.py
import torch.nn as nn
class LeffaBlock(nn.Module):
"""Базовый блок Leffa - depthwise separable conv + channel attention"""
def __init__(self, channels):
super().__init__()
# Depthwise convolution - в 8 раз меньше параметров
self.depthwise = nn.Conv2d(
channels, channels,
kernel_size=3, padding=1, groups=channels
)
# Pointwise convolution
self.pointwise = nn.Conv2d(channels, channels, 1)
# Lightweight attention
self.attention = nn.Sequential(
nn.AdaptiveAvgPool2d(1),
nn.Conv2d(channels, channels//8, 1),
nn.ReLU(),
nn.Conv2d(channels//8, channels, 1),
nn.Sigmoid()
)
def forward(self, x):
residual = x
x = self.depthwise(x)
x = self.pointwise(x)
attn = self.attention(x)
return x * attn + residual
class LightweightEnhancementModule(nn.Module):
"""Полная архитектура Leffa - всего 1.2M параметров"""
def __init__(self):
super().__init__()
self.encoder = nn.Sequential(
nn.Conv2d(6, 64, 3, padding=1), # 6 каналов: RGB human + RGB garment
LeffaBlock(64),
LeffaBlock(64),
)
self.decoder = nn.Sequential(
LeffaBlock(64),
nn.Conv2d(64, 32, 3, padding=1),
nn.Conv2d(32, 3, 3, padding=1), # RGB output
nn.Tanh()
)
def forward(self, human, garment):
x = torch.cat([human, garment], dim=1)
x = self.encoder(x)
x = self.decoder(x)
return torch.clamp(x, -1, 1)
1.2 миллиона параметров. Для сравнения: U-Net в Stable Diffusion - около 860 миллионов. Разница в 700 раз. Leffa обучается за день на одной RTX 4090, весит 5MB, инференс занимает 10-15ms.
Не пытайтесь использовать Leffa как standalone решение. Без качественного warping от IDM-VTON она выдаст мусор. Это именно enhancement-модуль, а не полноценная Try-On модель.
Инфраструктура: как обслуживать 1000 RPS на трех видеокартах
Архитектура модели - это полдела. Вторая половина - инфраструктура. Вот наша конфигурация для продакшена:
# docker-compose.prod.yml
version: '3.8'
services:
segmentation-worker:
image: tryon-segmentation:v1.2
deploy:
replicas: 10 # Много реплик, CPU дешевый
cpus: '0.5'
mem_limit: '512M'
command: ["python", "segmentation_worker.py"]
warping-worker:
image: tryon-warping:v1.2
deploy:
replicas: 3 # Мало реплик, но каждая на GPU
runtime: nvidia
environment:
- CUDA_VISIBLE_DEVICES=0
command: ["python", "warping_worker.py"]
enhancement-worker:
image: tryon-enhancement:v1.2
deploy:
replicas: 6 # Среднее количество, легкая модель
runtime: nvidia
environment:
- CUDA_VISIBLE_DEVICES=1
command: ["python", "enhancement_worker.py"]
orchestrator:
image: tryon-orchestrator:v1.2
ports:
- "8080:8080"
depends_on:
- segmentation-worker
- warping-worker
- enhancement-worker
command: ["python", "orchestrator.py"]
Ключевые моменты:
- Сегментация работает на CPU - можно масштабировать горизонтально почти бесплатно
- Warping (IDM-VTON) требует много VRAM - только 3 реплики на тяжелой карте
- Enhancement (Leffa) легкий - 6 реплик на средней карте
- Оркестратор распределяет нагрузку и кэширует промежуточные результаты
3 Кэширование warping: самый важный трюк
В e-commerce 80% запросов приходится на 20% самых популярных товаров. И позы людей тоже повторяются. Мы кэшируем результаты warping:
# warping_cache.py
import hashlib
import redis
from PIL import Image
import numpy as np
class WarpingCache:
def __init__(self, redis_host='localhost'):
self.redis = redis.Redis(redis_host, decode_responses=False)
self.hit_rate = 0
self.total_requests = 0
def get_cache_key(self, garment_img, pose_keypoints):
"""Генерируем ключ из хэша одежды + позы"""
# Хэш изображения одежды
img_hash = hashlib.md5(garment_img.tobytes()).hexdigest()
# Хэш ключевых точек позы (17 точек * 3 координаты)
pose_hash = hashlib.md5(pose_keypoints.tobytes()).hexdigest()
return f"warp:{img_hash}:{pose_hash}"
def get(self, garment_img, pose_keypoints):
"""Пытаемся получить warped garment из кэша"""
self.total_requests += 1
key = self.get_cache_key(garment_img, pose_keypoints)
cached = self.redis.get(key)
if cached:
self.hit_rate = (self.hit_rate * 0.9) + 0.1 # скользящее среднее
return np.frombuffer(cached, dtype=np.float32).reshape(...)
self.hit_rate = self.hit_rate * 0.9 # промах
return None
def set(self, garment_img, pose_keypoints, warped_result):
"""Сохраняем результат warping в кэш"""
key = self.get_cache_key(garment_img, pose_keypoints)
# Сохраняем на 24 часа
self.redis.setex(key, 86400, warped_result.tobytes())
Наш hit-rate в продакшене: 65%. Это значит, что в 65% случаев мы вообще не запускаем тяжелый IDM-VTON warping, а берем результат из кэша. Стоимость обработки падает еще в 2-3 раза.
Ошибки, которые мы совершили (чтобы вы их не повторили)
Ошибка 1: Кэширование полных изображений вместо warped features
Сначала мы кэшировали финальные изображения. Потом поняли, что enhancement (Leffa) все равно нужно запускать - разные люди, разный цвет кожи, освещение. Правильно: кэшировать только выход warping модуля - деформированную одежду без интеграции в человека.
Ошибка 2: Один GPU на все модули
Пытались запустить и warping, и enhancement на одной карте. Результат: memory thrashing, 10% простоя из-за OOM. Решение: выделить отдельные GPU для тяжелых и легких модулей. Как в статье про GB10 vs RTX - правильное распределение железа критично.
Ошибка 3: Игнорирование setup tax
Каждый запуск модели имеет "налог на запуск" - загрузка весов в VRAM, компиляция графа. Если обрабатывать по одному изображению за раз, 30% времени уходит на setup. Решение: батчинг. Даже если пришел один запрос, ждем 50ms для сбора батча. Как в статье про Setup Tax vs Latency Penalty.
Метрики в продакшене: что получилось
После 6 месяцев работы системы:
| Метрика | До оптимизации | После гибридного пайплайна | Изменение |
|---|---|---|---|
| Среднее время обработки | 8.2 сек | 1.8 сек | -78% |
| Стоимость/запрос | $0.32 | $0.047 | -85% |
| Пиковая RPS | 12 | 210 | +1650% |
| Конверсия в корзину | +8% (база) | +14% | +6% |
| Возвраты (по размеру) | 23% | 18% | -22% |
Самое интересное: снижение возвратов на 22%. Пользователи лучше понимают, как сидит одежда. Это экономит ритейлеру больше, чем вся инфраструктура Try-On.
Что дальше? Diffusion-модели умрут для Try-On
Сейчас модно говорить, что диффузионные модели - будущее всего. Для Try-On - нет. Будущее за гибридными архитектурами, где тяжелые компоненты используются точечно, а 80% пайплайна - это оптимизированные lightweight модели.
Через год появятся специализированные архитектуры, которые из коробки будут делать то, что мы собрали из кусков. Они будут обучаться быстрее, требовать меньше памяти, но принцип останется: разделение задачи на детерминированные и стохастические компоненты.
Пока же наш рецепт прост: возьмите IDM-VTON для warping, напишите свой Leffa для enhancement, кэшируйте агрессивно, масштабируйте горизонтально. И не верьте тем, кто говорит, что можно сделать качественный Try-On дешево на чистых диффузионных моделях. Нельзя. Мы проверили.