# Выбор архитектуры под качество, данные, latency и память > Лучшая модель — не самая глубокая, а самая дешёвая модель, которая устойчиво выполняет требования на целевом оборудовании. ## Мотивация Accuracy на исследовательском GPU не описывает production-систему. Мобильное приложение ограничено размером пакета, RAM, энергией и p95 latency; сервер — throughput и стоимостью; маленький датасет — переобучением. Выбор архитектуры является многокритериальной задачей. ## Формализация требований Пусть \(Q(\mathcal{M})\) — качество модели, \(T_{95}\) — p95 latency, \(M_{\mathrm{peak}}\) — пиковая память, \(S\) — размер весов, \(C\) — стоимость. Практическая задача: \[ \max_{\mathcal{M}} Q(\mathcal{M}) \quad\text{при}\quad T_{95}\le T_{\max},\ M_{\mathrm{peak}}\le M_{\max},\ S\le S_{\max},\ C\le C_{\max}. \] Если единого порога нет, ищут **Pareto frontier**: модель доминируется, если другая не хуже по всем критериям и лучше хотя бы по одному. ## Метрики качества Accuracy подходит только при примерно равной цене ошибок и сбалансированных классах. Иначе используют macro-F1, ROC-AUC/PR-AUC, sensitivity при заданной specificity, calibration. Для detection — mAP, для segmentation — IoU/Dice. Сначала фиксируют бизнес-ограничение, затем метрику и порог. Иначе архитектуру оптимизируют под удобное, но нецелевое число. ## Данные определяют режим - **Мало данных, близкий домен:** небольшой предобученный backbone, frozen/partial fine-tuning. - **Много разнообразных данных:** более ёмкая модель и full fine-tuning либо обучение с нуля могут окупиться. - **Сильный domain shift:** профильное предобучение, self-supervised learning или более глубокая адаптация. - **Шумные labels:** аудит данных часто ценнее увеличения модели. - **Высокое разрешение/мелкие объекты:** стоимость растёт квадратично по линейному размеру, но ранний resize может уничтожить сигнал. Learning curves отделяют ограничение данными от ограниченной ёмкости. Если train и validation плохи — возможен underfitting или ошибка pipeline; если train хорош, validation заметно хуже — overfitting/domain mismatch. Глубину нельзя оценивать отдельно от масштаба сигнала. Для ReLU-слоёв He-инициализация выбирает дисперсию весов порядка \(2/\mathrm{fan\_in}\), чтобы дисперсии активаций и градиентов не систематически затухали по слоям. Это переносит принцип из [модуля 09](../../09_neural_networks/notes/03_activations_initialization_regularization.md) на свёртки, где \(\mathrm{fan\_in}=C_{\mathrm{in}}K_hK_w\). Хорошая инициализация облегчает обучение с нуля, но не компенсирует недостаток данных и не заменяет предобучение. ## Стоимость: параметры, операции и активации Для Conv2d приблизительное число multiply-accumulate: \[ \mathrm{MACs}= H_{\mathrm{out}}W_{\mathrm{out}} C_{\mathrm{out}}C_{\mathrm{in}}K_hK_w. \] Параметров: \[ P=C_{\mathrm{out}}(C_{\mathrm{in}}K_hK_w+1). \] Но MACs не равны latency. Depthwise convolution имеет мало операций, но на конкретном устройстве может быть ограничена memory bandwidth или плохо оптимизирована. Latency измеряют после warm-up, нужным batch size, на целевом runtime и устройстве. Память inference включает веса, активации и workspace kernels. При обучении добавляются градиенты, optimizer states и сохранённые активации. Adam часто хранит два дополнительных момента на параметр. ## Разобранный пример **Требование.** Android CPU, batch 1, p95 не более 50 мс, пакет до 20 МБ, macro-F1 не ниже 0.90. **Кандидаты после одинакового fine-tuning:** - A: F1 0.913, p95 82 мс, 18 МБ; - B: F1 0.905, p95 41 мс, 14 МБ; - C: F1 0.898, p95 25 мс, 8 МБ. **Решение.** A нарушает latency, C — качество. B — единственная допустимая. Более высокая accuracy A не делает её лучшей для задачи. **Проверка.** Измерение повторяют на слабейшем поддерживаемом устройстве, с реальным preprocessing и thermal throttling. ## Семейства и inductive bias - ResNet-18/34 — понятные сильные baseline, часто удобны на сервере. - MobileNet/EfficientNet-lite — depthwise/inverted bottlenecks для мобильных ограничений. - EfficientNet — согласованное масштабирование глубины, ширины и разрешения. - Vision Transformer — слабее локальный CNN bias, часто требует сильного предобучения; эффективность зависит от реализации. Название семейства не гарантирует скорость. Поддержка операторов runtime важнее теоретических FLOPs. ## Практический протокол 1. Зафиксировать split, метрику, допустимую деградацию и оборудование. 2. Создать дешёвый baseline, например предобученную ResNet-18 или MobileNet. 3. Проверить данные, leakage, дисбаланс и ошибки по подгруппам. 4. Сравнить 2–3 кандидата при одинаковом training budget. 5. Экспортировать в целевой runtime и измерить end-to-end, включая decode/resize. 6. При необходимости применить mixed precision/quantization, pruning или distillation. 7. Выбрать простейшую модель на допустимой части Pareto frontier. ## Оптимизации после выбора baseline - **FP16/BF16** уменьшают память и могут ускорить GPU. - **INT8 quantization** уменьшает размер и ускоряет поддерживаемое железо, но требует calibration или quantization-aware training и проверки качества. - **Pruning** полезен только если runtime эффективно использует полученную разреженность. - **Knowledge distillation** обучает компактного student имитировать soft targets teacher. - **Batching** повышает throughput, но часто ухудшает latency одного запроса. Оптимизировать модель до корректного baseline рискованно: ошибка preprocessing не лечится quantization. ## Runnable PyTorch: параметры и latency ```python import time import torch from torchvision.models import resnet18 model = resnet18(weights=None).eval() x = torch.randn(1, 3, 224, 224) parameters = sum(p.numel() for p in model.parameters()) with torch.inference_mode(): for _ in range(10): # warm-up model(x) samples = [] for _ in range(30): start = time.perf_counter() model(x) samples.append((time.perf_counter() - start) * 1000) samples.sort() p95 = samples[int(0.95 * (len(samples) - 1))] print("parameters:", parameters) print("p95 milliseconds:", round(p95, 2)) ``` На CUDA перед и после замера нужна `torch.cuda.synchronize()`, иначе измеряется постановка асинхронной операции в очередь. Этот микротест не включает чтение изображения и preprocessing. ## Типичные ошибки и ограничения - Сравнивают модели на разных split или с разным tuning budget. - Выбирают по среднему latency вместо p95/p99. - Приравнивают FLOPs к реальному времени. - Считают только размер файла, игнорируя RAM активаций. - Измеряют batch 32, хотя production использует batch 1. - Увеличивают глубину при проблеме качества данных. ## Краткое резюме - Выбор архитектуры — constrained multi-objective optimization. - Данные, метрика и целевое устройство должны быть известны до сравнения. - Параметры и MACs полезны, но не заменяют end-to-end benchmark. - Выбирают простейшую допустимую модель, а не абсолютный максимум качества. ## Связанные материалы - Предыдущая глава: [`03_pretraining_and_transfer.md`](03_pretraining_and_transfer.md). - Следующая глава: [`05_detection_and_segmentation.md`](05_detection_and_segmentation.md). - База: [активации и He-инициализация](../../09_neural_networks/notes/03_activations_initialization_regularization.md). - Термины: [`../glossary.md`](../glossary.md).