Military-Vehicle Detection: от Python до мобильного продакшена на SSD MobileNetV4

Комплексный курс по детекции военной техники с нуля до продакшена. Охватывает Python и OpenCV, Deep Learning с PyTorch и SSD на MobileNetV4, MLOps-оптимизацию (ONNX, OpenVINO, квантизацию), специфику military-vehicle датасетов и мобильное развёртывание на Android через KotlinDL.

1. Основы Python для Data Science, Computer Vision и обработка изображений с OpenCV

Основы Python для Data Science, Computer Vision и обработка изображений с OpenCV

Когда инженер NASA в 1997 году отправил марсоход Pathfinder на Марс, камера аппарата снимала изображения размером 256×256 пикселей — меньше, чем аватарка в соцсети. Сегодня алгоритмы детекции военной техники обрабатывают снимки с дронов в 4K-разрешении, находя танк на расстоянии нескольких километров. Но прежде чем нейросеть научится «видеть», ей нужно дать данные в правильном формате. Именно поэтому путь к military-vehicle detection начинается с Python, числовых вычислений и работы с изображениями — фундамента, на котором стоит всё остальное.

Почему Python и почему именно для Computer Vision

Python стал стандартом в Data Science не из-за скорости — C++ выполняет вычисления быстрее в 10–100 раз. Причина в экосистеме: библиотеки NumPy, OpenCV, PyTorch и Albumentations образуют единый стек, где данные перетекают между инструментами без потерь. Представьте, что вы переводите текст с английского на русский через три разных словаря — если каждый словарь использует свою систему транскрипции, вы потеряете смысл. В Python-стеке для Computer Vision все библиотеки «говорят на одном языке» — массивах NumPy.

NumPy — это библиотека для быстрых числовых вычислений с многомерными массивами. Когда вы загружаете фотографию танка, OpenCV представляет её как массив NumPy размером (высота × ширина × 3), где три канала — это красный, зелёный и синий (RGB). Каждый пиксель — число от 0 до 255.

Микропример: если вы представляете шахматную доску как матрицу 8×8, где 1 — белая клетка, 0 — чёрная, то это и есть двумерный массив NumPy. Изображение — это просто такая матрица, но с тремя слоями (каналами цвета) вместо одного.

ООП в Python: зачем это нужно в CV-проектах

Объектно-ориентированное программирование в Data Science — это не дань моде, а способ управлять сложностью. Когда вы строите пайплайн детекции военной техники, у вас есть загрузчик данных, аугментатор, модель, постпроцессор результатов. Каждый из них — это класс с чёткими обязанностями.

Класс — это шаблон для создания объектов. Он описывает, какие данные (атрибуты) и какие действия (методы) связаны вместе.

Зачем так, а не просто функция? Представьте, что у вас 50 скриптов для обработки данных. Если размер изображения меняется, при использовании функций вам нужно править каждую. С классом — меняете одно значение в __init__, и все скрипты работают с новым размером. В проектах military-vehicle detection это критично: изображения с дронов, спутников и наземных камер имеют разное разрешение, и параметры предобработки должны быть централизованы.

OpenCV: библиотека, которая научила компьютеры видеть

OpenCV (Open Source Computer Vision Library) — это библиотека с более чем 2500 алгоритмами обработки изображений. Она написана на C++, но имеет полноценные Python-биндинги. Именно OpenCV стоит между «сырым» изображением и нейросетью.

Чтение, конвертация и базовые операции

Первая ловушка, в которую попадают новички: OpenCV загружает изображения в формате BGR (Blue-Green-Red), а не в привычном RGB. Если не конвертировать — цвета будут инвертированы.

Микропример: представьте, что вы перепутали местами провода в наушниках — левый канал играет справа, правый слева. Звук есть, но восприятие искажено. BGR вместо RGB — та же проблема, только с цветами.

Изменение размера и нормализация

Нейросети принимают входы фиксированного размера. Для SSD MobileNetV4 стандартный вход — 300×300 или 320×320 пикселей. Но cv2.resize делает больше, чем просто масштабирование: при уменьшении изображения алгоритм интерполяции решает, какой цвет присвоить каждому новому пикселю.

| Метод интерполяции | Скорость | Качество | Когда использовать | |---|---|---|---| | cv2.INTER_NEAREST | Быстрый | Низкое | Маски сегментации | | cv2.INTER_LINEAR | Средний | Хорошее | Стандарт для обучения | | cv2.INTER_CUBIC | Медленный | Отличное | Визуализация результатов | | cv2.INTER_AREA | Средний | Лучшее при уменьшении | Даунсэмплинг больших снимков |

Нормализация — это масштабирование значений пикселей в диапазон, который нейросеть обрабатывает стабильнее. Без нормализации градиенты при обучении могут «взрываться» (становиться слишком большими) или «затухать» (стремиться к нулю), и модель не обучится.

Рисование на изображениях: разметка и визуализация

Когда модель детекции нашла танк на снимке, результат нужно визуализировать — нарисовать рамку и подписать класс. OpenCV делает это за одну строку:

Микропример: это как рисовать рамку вокруг объекта на фотографии в Paint — только вместо мыши вы указываете координаты числом, и процесс повторяется автоматически для тысяч изображений.

Работа с цветовыми пространствами

Для military-vehicle detection полезно знать не только RGB. HSV (Hue-Saturation-Value) отделяет цвет от яркости, что помогает фильтровать объекты по камуфляжу. Например, оливково-зелёный камуфляж танка имеет определённый диапазон оттенков (Hue), который можно выделить, даже если освещение меняется.

Это не заменяет нейросеть, но полезно для предварительного анализа: если вы знаете, что ищете технику в зелёном камуфляже на фоне пустыни, HSV-фильтр может сузить область поиска.

Работа с путями и пакетная обработка

Реальный датасет military-vehicle detection — это тысячи изображений в структурированных папках. Python-модуль pathlib делает навигацию по файловой системе элегантной:

Микропример: pathlib — это как GPS-навигатор для файлов. Вместо того чтобы вручную прописывать путь C:\data\train\tanks\img001.jpg, вы говорите «найди все JPG в папке data» и получаете список.

Связка NumPy + OpenCV: как данные текут через пайплайн

Вот как выглядит минимальный пайплайн предобработки одного изображения для SSD-детектора:

Обратите внимание на шаг 5: PyTorch ожидает формат (batch, channels, height, width), а OpenCV и NumPy работают с (height, width, channels). Эта перестановка осей — одна из самых частых ошибок новичков. Запомните: OpenCV = «картинка снаружи», PyTorch = «каналы снаружи».

Что запомнить из этой главы

  • Изображение в Python — это трёхмерный массив NumPy размером (высота × ширина × 3 канала), где каждый элемент — число от 0 до 255
  • OpenCV загружает в BGR, а не RGB — всегда конвертируйте через cv2.cvtColor, иначе цвета будут инвертированы при визуализации
  • Перед подачей в PyTorch необходимо выполнить три операции: ресайз до фиксированного размера, нормализацию в диапазон [0, 1] и перестановку осей из (H, W, C) в (C, H, W)
  • 2. Deep Learning, CNN и детекция объектов: PyTorch, SSD и MobileNet

    Deep Learning, CNN и детекция объектов: PyTorch, SSD и MobileNet

    В 2012 году нейросеть AlexNet снизила ошибку на конкурсе ImageNet с 26% до 15% — скачок, который за год изменил всю индустрию компьютерного зрения. Ключевым ингредиентом оказались свёрточные нейронные сети (Convolutional Neural Networks, CNN) — архитектура, которая учится извлекать визуальные паттерны прямо из пикселей. Сегодня эта же идея лежит в основе SSD-детекторов на MobileNet, которые обнаруживают военную технику на мобильных устройствах за миллисекунды. Разберёмся, как устроена эта магия от первого слоя до последнего.

    Нейронная сеть: от одного нейрона к глубокой архитектуре

    Нейрон — это математическая функция, которая принимает несколько входов, умножает каждый на вес (weight), суммирует, добавляет смещение (bias) и пропускает результат через функцию активации. Если вы представляете термостат: датчик температуры (вход) → коэффициент чувствительности (вес) → решение «включить или нет» (активация).

    Микропример: представьте, что вы решаете, брать ли зонт. Входы: прогноз дождя (0.8), облачность (0.6), температура (нормализованная, 0.3). Веса: вы больше доверяете прогнозу дождя (0.9), меньше — температуре (0.1). Сумма: 0.8×0.9 + 0.6×0.5 + 0.3×0.1 = 1.05. Если порог (bias) — 0.7, то 1.05 > 0.7, и вы берёте зонт. Нейросеть делает то же самое, но с миллионами входов и весов.

    Функция активации нужна, чтобы сеть могла учить нелинейные зависимости. Без неё любая глубокая сеть сводится к одному линейному преобразованию — сколько бы слоёв ни было. Самая простая — ReLU (Rectified Linear Unit): . Она зануляет отрицательные значения и оставляет положительные без изменений.

    Свёрточный слой: как нейросеть учится «видеть»

    Полносвязный слой (каждый нейрон связан со всеми входами) для изображения 300×300×3 потребовал бы 270 000 входов на каждый нейрон — непрактично много параметров. Свёрточный слой решает эту проблему элегантно: он применяет маленький фильтр (ядро, kernel) размером, например, 3×3 ко всему изображению, «скользя» по нему.

    | Компонент CNN | Что делает | Аналогия | |---|---|---| | Свёрточный слой | Извлекает локальные паттерны (ребра, текстуры) | Лупа, которая исследует маленькие участки | | Пулинг (pooling) | Уменьшает пространственные размеры | Уменьшение фото до миниатюры | | Полносвязный слой | Классифицирует на основе извлечённых признаков | Судья, принимающий финальное решение |

    Микропример: если вы ищете камуфляжный паттерн на снимке, свёрточный фильтр — это как трафарет. Вы прикладываете трафарет к каждому участку изображения и проверяете, насколько паттерн совпадает. Там, где совпадение высокое, активация сильная — сеть «увидела» камуфляж.

    PyTorch: фреймворк для обучения нейросетей

    PyTorch — это библиотека от Meta (Facebook) для построения и обучения нейросетей. Её главное преимущество — динамический граф вычислений: вы пишете код как обычный Python, и PyTorch строит граф на лету. Это упрощает отладку — вы можете поставить breakpoint внутри модели и посмотреть промежуточные тензоры.

    BatchNorm (Batch Normalization) — это слой, который нормализует activations внутри батча. Он стабилизирует обучение и позволяет использовать бо́льшие скорости обучения (learning rate). Представьте, что вы бежите по дорожке, которая постоянно меняет наклон — это мешает набрать скорость. BatchNorm выравнивает дорожку.

    MobileNet: эффективная backbone для мобильных устройств

    Backbone — это «тело» нейросети, которое извлекает признаки из изображения. В SSD-детекторе backbone заменяет «глаза», а голова детекции (detection head) — «мозг», принимающий решение «что и где».

    MobileNet — это семейство архитектур, оптимизированных для мобильных устройств. Ключевая идея — depthwise separable convolution (разделимая свёртка). Обычная свёртка 3×3 с 64 входными и 64 выходными каналами использует 3×3×64×64 = 36 864 параметра. Разделимая свёртка разбивает это на два шага:

  • Depthwise: применяет один фильтр 3×3 к каждому каналу отдельно — 3×3×64 = 576 параметров
  • Pointwise: комбинирует каналы свёрткой 1×1 — 1×1×64×64 = 4 096 параметров
  • Итого: 4 672 параметра вместо 36 864 — почти в 8 раз меньше при сопоставимом качестве.

    Микропример: представьте, что вы моете окно. Обычная свёртка — это протереть всё одним большим движением. Разделимая — сначала протереть каждое стекло отдельно (depthwise), затем проверить общий результат (pointwise). Результат тот же, но усилий меньше.

    MobileNetV4 — последняя версия, которая добавила Universal Inverted Bottleneck (UIB) блоки. UIB адаптивно выбирает оптимальную комбинацию свёрточных операций внутри каждого блока, что даёт лучший баланс между точностью и скоростью на разных устройствах.

    SSD: Single Shot Detector

    SSD (Single Shot MultiBox Detector) — это архитектура детекции объектов, которая предсказывает bounding boxes и классы за один проход изображения через сеть. В отличие от двухэтапных детекторов (например, Faster R-CNN), SSD не использует отдельный этап генерации регионов-кандидатов.

    Как работает SSD

    SSD берёт feature maps (карты признаков) из нескольких слоёв backbone на разных уровнях абстракции. На каждом уровне ставятся якоря (anchors) — заранее определённые прямоугольники разных размеров и пропорций.

    | Уровень feature map | Размер карты | Размер якорей | Что ловит | |---|---|---|---| | 38×38 (ранний слой) | Крупная карта | Мелкие якоря (30×30 px) | Дальние, мелкие объекты | | 19×19 | Средняя | Средние (90×90 px) | Средняя дистанция | | 10×10 | Мелкая | Крупные (150×150 px) | Близкие, крупные объекты | | 3×3 (глубокий слой) | Очень мелкая | Очень крупные (270×270 px) | Заполняющие кадр |

    Для каждого якоря SSD предсказывает:

  • Смещения (dx, dy, dw, dh) — насколько скорректировать якорь, чтобы он точно обхватил объект
  • Вероятности классов — tank, APC, helicopter и т.д.
  • Микропример: представьте рыбака, забрасывающего сети разных размеров в разных местах озера. Мелкая сеть у берега поймает мелкую рыбу, крупная в центре — крупную. SSD делает то же самое: расставляет «сети» (якоря) по всей карте признаков и предсказывает, что в каждой поймалось.

    Функция потерь SSD

    SSD обучается минимизировать сумму двух потерь:

    Где — количество совпавших якорей, — потери классификации (кросс-энтропия), — потери локализации (Smooth L1), — вес локализационной потери (обычно 1).

    Smooth L1 loss — это функция, которая ведёт себя как L2 (квадратичная) для малых ошибок и как L1 (линейная) для больших. Это делает обучение устойчивее к выбросам — если модель ошиблась на 100 пикселей в одном изображении, это не «взорвёт» градиенты.

    Сборка SSD MobileNetV4 с помощью timm

    Библиотека timm (PyTorch Image Models) предоставляет предобученные backbone, включая MobileNetV4. Это экономит дни обучения — backbone уже «знает» общие визуальные паттерны после обучения на ImageNet (14 миллионов изображений, 20 000 классов).

    Ключевой момент: features_only=True отключает финальный классификационный слой и возвращает промежуточные feature maps — именно то, что нужно SSD. Затем на каждый feature map ставится detection head — маленькая свёрточная сеть, предсказывающая смещения якорей и вероятности классов.

    Обучение: цикл, оптимизатор и learning rate

    Обучение нейросети — это итеративный процесс минимизации функции потерь. На каждом шаге (эпохе) модель проходит по всему датасету, считает потери и обновляет веса с помощью обратного распространения ошибки (backpropagation).

    Cosine Annealing — это расписание learning rate, которое плавно уменьшает скорость обучения по косинусоиде. В начале обучения большой learning rate позволяет модели быстро двигаться к оптимуму, ближе к концу маленький — точно настраивает веса. Микропример: как если бы вы ехали на машине к цели — сначала на высокой скорости по шоссе, затем замедлялись на парковке, чтобы точно встать на место.

    Что запомнить из этой главы

  • CNN извлекает визуальные паттерны через свёрточные фильтры: ранние слои ловят рёбра и текстуры, глубокие — сложные объекты вроде танков и вертолётов
  • MobileNetV4 использует разделимые свёртки, которые сокращают число параметров в ~8 раз при сопоставимом качестве — критично для мобильных устройств с ограниченной памятью и процессором
  • SSD предсказывает объекты за один проход, расставляя якоря на нескольких уровнях feature maps: мелкие якоря на крупных картах ловят дальние объекты, крупные якоря на мелких картах — близкие
  • 3. MLOps: экспорт в ONNX, оптимизация с ONNX Runtime и OpenVINO, квантизация моделей

    MLOps: экспорт в ONNX, оптимизация с ONNX Runtime и OpenVINO, квантизация моделей

    Представьте, что вы выиграли тендер на систему детекции военной техники для беспилотника. Модель обучена, точность на тесте — 91% mAP. Но когда вы загружаете её на бортовой компьютер дрона с ARM-процессором, инференс занимает 800 миллисекунд на кадр. При 30 FPS у вас есть 33 миллисекунды на обработку. Модель работает в 24 раза медленнее, чем нужно. Именно здесь начинается MLOps — дисциплина, которая превращает исследовательский ноутбук в работающий продакшен.

    Зачем нужен экспорт: от PyTorch к универсальному формату

    PyTorch сохраняет модели в формате .pt или .pth — это сериализованный Python-объект с архитектурой и весами. Проблема: для загрузки .pt нужен Python и PyTorch. На Android-устройстве ни того, ни другого нет. Решение — ONNX (Open Neural Network Exchange), открытый формат для представления нейросетей независимо от фреймворка.

    Микропример: .pt — это как документ в формате Pages на Mac. ONNX — это PDF, который открывается везде. Вы не теряете содержание, но получаете совместимость с любой платформой.

    Экспорт SSD MobileNetV4 в ONNX

    Opset version — это версия спецификации ONNX. Каждая версия добавляет новые операторы. Opset 13 — стабильный выбор для большинства моделей 2024 года. Старые версии могут не поддерживать某些 операции, новые — не поддерживаться всеми рантаймами.

    Dynamic axes указывают, какие размерности тензоров могут меняться. Без этого ONNX зафиксирует batch size = 1, и при инференсе с batch size = 4 вы получите ошибку.

    Валидация экспорта

    После экспорта нужно убедиться, что ONNX-модель даёт те же результаты, что и PyTorch:

    Допустимое расхождение — до из-за различий в порядке операций с плавающей точкой. Если расхождение больше — что-то пошло не так при экспорте.

    ONNX Runtime: быстрый инференс без перекомпиляции

    ONNX Runtime (ORT) — это движок инференса от Microsoft, оптимизированный для ONNX-моделей. Он автоматически применяет оптимизации графа: удаляет бесполезные операции, объединяет слои, выбирает оптимальные реализации ядер для конкретного CPU или GPU.

    Базовое использование

    Graph optimization levels в ONNX Runtime:

    | Уровень | Что делает | Риск | |---|---|---| | ORT_DISABLE_ALL | Никаких оптимизаций | Нет | | ORT_ENABLE_BASIC | Константфолдинг, удаление identity | Минимальный | | ORT_ENABLE_EXTENDED | Basic + слияние слоёв (layer fusion) | Низкий | | ORT_ENABLE_ALL | Все оптимизации включая layout оптимизации | Средний |

    Layer fusion — это объединение нескольких операций в одну. Например, Conv2D + BatchNorm + ReLU могут быть слиты в одну операцию, что убирает промежуточные записи в память. Микропример: как если бы вы вместо трёх походов в магазин за хлебом, молоком и маслом сходили один раз — путь тот же, но накладных расходов меньше.

    OpenVINO: оптимизация под Intel-железо

    OpenVINO (Open Visual Inference and Neural Network Optimization) — это toolkit от Intel для оптимизации нейросетей на процессорах, интегрированных GPU и Neural Compute Stick. Если ONNX Runtime — универсальный оптимизатор, то OpenVINO — специалист по Intel-архитектуре.

    Конвертация и инференс

    OpenVINO применяет специфичные для Intel оптимизации: MKL-DNN (Math Kernel Library for Deep Neural Networks) для векторизации операций, планирование памяти без лишних аллокаций и использование AVX-512 инструкций процессора. На практике это даёт прирост 1.5–3× по сравнению с базовым ONNX Runtime на CPU Intel.

    OpenVINO vs ONNX Runtime: когда что использовать

    | Критерий | ONNX Runtime | OpenVINO | |---|---|---| | Поддержка платформ | CPU, GPU (CUDA, DirectML, CoreML) | CPU, iGPU Intel, VPU, GNA | | Автооптимизация | Да, хорошая | Да, глубокая для Intel | | Квантизация | Да (через onnxruntime.quantization) | Да (через NNCF — Neural Network Compression Framework) | | Мобильные устройства | Ограниченно | Не поддерживает | | Простота интеграции | Очень простая | Сложнее, больше зависимостей |

    Для military-vehicle detection на наземных станциях с Intel-процессорами OpenVINO — оптимальный выбор. Для кроссплатформенного инференса (сервер + мобильное) — ONNX Runtime.

    Квантизация: сжимаем модель без потери точности

    Квантизация (quantization) — это преобразование весов модели из 32-битных чисел с плавающей точкой (float32) в 8-битные целые (int8). Это даёт ~4× уменьшение размера модели и ~2–4× ускорение инференса на процессорах с поддержкой int8-операций.

    Типы квантизации

    | Тип | Когда применяется | Потеря точности | Скорость | |---|---|---|---| | Post-training (PTQ) | После обучения, без дообучения | 1–3% mAP | Быстро | | Quantization-Aware Training (QAT) | Во время обучения | 0.5–1% mAP | Медленно (нужно дообучение) | | Dynamic quantization | Только веса, activations остаются float32 | Минимальная | Средний прирост |

    Для мобильного развёртывания SSD MobileNetV4 оптимальна PTQ — она не требует доступа к обучающему датасету и занимает минуты вместо часов.

    Посттренировочная квантизация через ONNX Runtime

    Калибровка — это ключевой этап: алгоритм проходит квантизуемую модель на небольшом наборе данных, чтобы определить оптимальные диапазоны значений для каждого тензора. Без калибровки int8-представление может «отрезать» часть значений, что резко снижает точность.

    Микропример: представьте, что вы переводите фотографию из 16-миллионной палитры цветов в 256-цветную. Если выбрать 256 цветов случайно — результат будет ужасным. Если проанализировать фотографию и выбрать 256 самых частых цветов — разница будет минимальной. Калибровка делает именно это, только с числами весов нейросети.

    Квантизация через OpenVINO (NNCF)

    Полный пайплайн: от обученной модели до оптимизированного артефакта

    | Шаг | Инструмент | Вход | Выход | |---|---|---|---| | 1. Экспорт | torch.onnx.export | .pt модель | .onnx файл | | 2. Валидация | onnxruntime | .onnx + тестовые данные | Расхождение < | | 3. Оптимизация графа | ONNX Runtime | .onnx | Оптимизированный .onnx | | 4. Квантизация | ONNX Runtime / NNCF | .onnx + калибровочные данные | .onnx int8 | | 5. Проверка точности | Метрики mAP | int8 модель + тестовый датасет | Потеря < 2% mAP |

    Каждый шаг валидируется отдельно. Если после квантизации mAP упал больше чем на 3% — переходите на QAT или используйте смешанную точность (некоторые слои остаются в float32).

    Что запомнить из этой главы

  • ONNX — это универсальный формат нейросетей, который отделяет модель от фреймворка: обучили в PyTorch, инференсируете в ONNX Runtime, OpenVINO или на Android
  • Квантизация float32 → int8 даёт ~4× уменьшение размера и ~2–4× ускорение с потерей точности 1–3% mAP при правильной калибровке — приемлемый компромисс для мобильных устройств
  • ONNX Runtime и OpenVINO — не взаимозаменяемы, а дополняют друг друга: ORT для кроссплатформенности, OpenVINO для максимальной производительности на Intel-железе
  • 4. Специфика военной детекции техники: датасеты, аугментации Albumentations и сложные условия

    Специфика военной детекции техники: датасеты, аугментации Albumentations и сложные условия

    В 2020 году исследователи из Стэнфорда обнаружили, что модель детекции, обученная на чётких снимках танков днём, теряла 40% точности на ночных ИК-изображениях. Не потому что архитектура была плохой — а потому что датасет не содержал вариативности, с которой сталкивается реальная система. Military-vehicle detection — это не просто «найти машину на фотографии». Это найти замаскированный танк в тумане на расстоянии двух километров, когда половина объекта скрыта за деревьями. Разберёмся, как готовить данные и модели к этим вызовам.

    Почему детекция военной техники — отдельная задача

    Общие датасеты детекции (COCO, Pascal VOC) содержат класс «car» или «truck», но military-vehicle detection принципиально отличается по нескольким параметрам:

    Масштаб объектов. На спутниковом снимке танк занимает 15×8 пикселей — меньше, чем почтовая марка на экране. На снимке с наземной камеры вблизи тот же танк — 400×300 пикселей. Диапазон масштабов варьируется в 30+ раз, тогда как в COCO — обычно в 5–10 раз.

    Камуфляж и слияние с фоном. Оливковый танк на зелёном поле — это задача, где контраст между объектом и фоном минимален. Модель должна учить не цвет, а форму, тень, контуры гусениц, геометрию башни.

    Деградация изображения. Туман, дождь, пыль, дым — всё это стандартные условия battlefield. Камера дрона на скорости 60 км/ч даёт motion blur. ИК-камера ночью — шум и низкое разрешение.

    Датасеты для military-vehicle detection

    Публичные датасететы

    | Датасет | Количество изображений | Классы | Особенности | |---|---|---|---| | DOTA | 2 806 | 15 (включая ship, plane, vehicle) | Спутниковые снимки, крупномасштабные | | xView | 1 127 | 60 (много военных классов) | Снимки WorldView-3, 0.3 м/пикс | | MAR20 | ~5 000 | 5 (tank, APC, truck, helicopter, aircraft) | Аэрофотоснимки, разные условия | | VEDAI | 1 210 | 9 (включая car, pickup, tractor) | Снимки с высоты, мелкие объекты | | Military Vehicles Detection (Roboflow) | ~3 000 | 5–8 | Смешанные источники, аннотации YOLO |

    xView — один из наиболее полезных для military-vehicle detection: он содержит спутниковые снимки высокого разрешения (0.3 метра на пиксель) с аннотациями 60 классов, включая конкретные типы военной техники. Недостаток — только вид сверху, без перспективных снимков.

    Микропример: если автомобиль на парковке — это «лёгкая задача» (контрастный, крупный, на ровном фоне), то танк в лесу в тумане — это «экстремальная задача». Датасет должен содержать оба типа сцен, иначе модель провалится на втором.

    Формат аннотаций

    Для SSD и большинства детекторов bounding boxes задаются в формате (x_min, y_min, x_max, y_max) — координаты левого верхнего и правого нижнего углов. Но разные датасеты используют разные форматы:

  • COCO: (x_min, y_min, width, height)
  • YOLO: (x_center, y_center, width, height) — все значения нормализованы к [0, 1]
  • Pascal VOC: (x_min, y_min, x_max, y_max) в абсолютных пикселях
  • Конвертация между форматами — рутинная, но критичная задача. Ошибка в конвертации приводит к тому, что bounding box смещается, и модель учится на неправильных данных.

    Albumentations: аугментации, которые спасают проект

    Аугментация (augmentation) — это искусственное расширение датасета путём трансформации обучающих изображений. Зачем? Потому что собрать 100 000 размеченных снимков военной техники в реальных условиях практически невозможно. Аугментация позволяет из 5 000 изображений создать эффект 50 000+.

    Albumentations — это библиотека, оптимизированная для задач детекции. В отличие от torchvision.transforms, она корректно трансформирует не только изображения, но и bounding boxes — автоматически пересчитывая координаты при повороте, отзеркаливании и кропе.

    Базовый пайплайн аугментаций

    Специфические аугментации для военной детекции

    Стандартные аугментации — это база. Но military-vehicle detection требуют специфических трансформаций, имитирующих реальные условия battlefield:

    CoarseDropout (Cutout) — случайно затемняет прямоугольные области изображения. Это имитирует частичное перекрытие объекта деревьями, зданиями или дымом. Модель учится определять танк даже по видимой части.

    Downscale — уменьшает разрешение и снова увеличивает. Это имитирует съёмку с большой высоты или через дешёвую оптику, когда детали теряются.

    RandomGamma — изменяет гамму, имитируя разные условия освещения: рассвет, сумерки, ночная съёмка без ИК-фильтра.

    Микропример: представьте, что вы тренируете снайпера. Если он стреляет только в ясный день на полигоне — в бою в тумане он промахнётся. Аугментация — это «искусственный туман» на полигоне, чтобы снайпер учился в условиях, приближенных к боевым.

    Аугментация с сохранением bounding boxes

    Главная ловушка аугментаций для детекции: если вы повернёте изображение на 30°, bounding box тоже должен повернуться. Albumentations делает это автоматически, но важно правильно указать формат координат:

    Если после трансформации bounding box выходит за границы изображения, Albumentations может либо обрезать его, либо отбросить объект — в зависимости от параметра min_area и min_visibility.

    Сложные условия: адаптация модели к реальности

    Камуфляж

    Камуфляж — это не просто «зелёный цвет». Современный военный камуфляж использует паттерны (digital, woodland, desert), которые нарушают контуры объекта. Модель, обученная на чётких силуэтах, провалится на камуфлированной технике.

    Решение: включать в датасет изображения с камуфляжем разных типов и использовать аугментацию ColorJitter с широким диапазоном, чтобы модель не привязывалась к конкретной цветовой гамме.

    Разные дистанции

    Объект на расстоянии 500 метров и на расстоянии 3 километра выглядят совершенно по-разному. Для борьбы с этим SSD использует feature maps на разных уровнях (как мы разбирали в главе про архитектуру), но датасет тоже должен содержать объекты всех масштабов.

    Практический совет: при сборе данных размечайте не только ближнюю технику. Если 80% bounding boxes — крупные объекты, а 20% — мелкие, модель будет хорошо работать только на ближней дистанции. Используйте oversampling мелких объектов или аугментацию RandomScale с отрицательным scale, чтобы искусственно уменьшить объекты.

    Метрики для оценки

    Для military-vehicle detection стандартная метрика — mAP@0.5 (mean Average Precision при IoU-пороге 0.5) и mAP@0.5:0.95 (среднее по порогам от 0.5 до 0.95 с шагом 0.05).

    IoU (Intersection over Union) — это отношение площади пересечения двух bounding boxes к площади их объединения. Если модель предсказала рамку, которая на 80% совпадает с истинной, IoU = 0.8.

    Где — предсказанная область, — истинная область. IoU = 1 означает идеальное совпадение, IoU = 0 — полное отсутствие пересечения.

    Для military-vehicle detection рекомендуется отслеживать mAP отдельно по классам (tank может детектироваться лучше, чем helicopter из-за разной формы и фона) и отдельно по масштабам (small, medium, large objects).

    Что запомнить из этой главы

  • Military-vehicle detection требует специфических датасетов (xView, MAR20, DOTA) с вариативностью условий съёмки — стандартные автомобильные датасеты не покрывают камуфляж, ИК-диапазон и мелкомасштабные объекты
  • Albumentations — ключевой инструмент для аугментаций в задачах детекции, потому что корректно трансформирует bounding boxes вместе с изображением; для военных задач критически важны MotionBlur, RandomFog, CoarseDropout и Downscale
  • mAP@0.5 и mAP@0.5:0.95 — основные метрики, но для продакшена важно отслеживать их отдельно по классам и масштабам объектов, потому что модель может быть сильной на танках и слабой на вертолётах
  • 5. Мобильное развёртывание модели на Android с использованием KotlinDL

    Мобильное развёртывание модели на Android с использованием KotlinDL

    Когда солдат на передовой поднимает планшет и наводит камеру на горизонт, у системы детекции есть 2 секунды, чтобы определить, танк это или грузовик. Нет сервера, нет облака, нет стабильного интернета — только процессор планшета и квантизованная ONNX-модель размером 8 мегабайт. Именно для таких сценариев существует мобильное развёртывание. И именно KotlinDL — библиотека, которая делает это возможным на Android без необходимости писать код на C++ или работать с NDK.

    Зачем мобильное развёртывание, а не облачный инференс

    Облачный инференс (отправить кадр на сервер → получить результат) в условиях military-vehicle detection неприемлем по трём причинам:

    Латентность. Передача изображения 300×300 через мобильную сеть занимает 200–800 мс. Инференс на сервере — ещё 50–100 мс. Итого: 250–900 мс. На планшете с квантизованной моделью — 30–80 мс.

    Доступность сети. В зоне боевых действий связь может отсутствовать часами. Система должна работать автономно.

    Безопасность. Передача разведывательных данных (снимков местности с геолокацией) через общедоступные сети — критический риск утечки. Локальный инференс исключает этот вектор.

    Микропример: облачный инференс — это как звонить переводчику по телефону, когда вы на переговорах. Если связь пропала — вы не понимаете собеседника. Локальный инференс — это как носить с собой карманный словарь: работает всегда, но словарь должен быть компактным и быстрым.

    KotlinDL: Kotlin для Deep Learning на Android

    KotlinDL (Kotlin Deep Learning) — это библиотека от JetBrains, которая позволяет загружать и запускать ONNX-модели на Android-устройствах, используя Kotlin — основной язык разработки под Android. Она обёртывает ONNX Runtime для Android, предоставляя идиоматичный Kotlin API.

    Архитектура мобильного пайплайна

    Каждый этап должен укладываться в общий бюджет 33 мс для 30 FPS или 100 мс для 10 FPS (приемлемо для тактического интерфейса).

    Подключение KotlinDL в проект

    В build.gradle (Module: app) добавляются зависимости:

    Загрузка модели и инференс

    ExecutionProvider — это провайдер вычислений. На Android доступен CPU(). На некоторых устройствах с поддержкой — NNAPI(), который делегирует вычисления аппаратному ускорителю Neural Processing Unit (NPU) чипсета.

    Микропример: ExecutionProvider — это как выбор маршрута в навигаторе. CPU — это «ехать через центр города» (работает везде, но медленно). NNAPI — это «ехать по автомагистрали» (быстрее, но доступна не на всех устройствах).

    Предобработка изображения с камеры

    Камера Android выдаёт кадр в формате YUV (Y — яркость, U и V — цветность), а не RGB. Нужно конвертировать, изменить размер и нормализовать:

    Важный нюанс: mean и std должны точно совпадать с теми, что использовались при обучении модели. Обычно это ImageNet-статистика: mean = [0.485, 0.456, 0.406], std = [0.229, 0.224, 0.225]. Если при обучении вы использовали другие значения — скопируйте их точно. Несовпадение приведёт к падению точности на 10–30% без каких-либо ошибок в коде.

    Постпроцессинг: Non-Maximum Suppression

    SSD выдаёт сотни предсказаний для каждого якоря, многие из которых перекрываются. NMS (Non-Maximum Suppression) — это алгоритм, который оставляет только лучшее предсказание для каждого объекта:

    Микропример: NMS работает как конкурс. Все кандидаты (bounding boxes) выходят на сцену. Сначала выбирается лучший (highest score). Все, кто слишком похож на него (высокий IoU), дисквалифицируются. Затем выбирается следующий лучший из оставшихся. И так, пока кандидаты не закончатся.

    Отрисовка результатов на экране

    Оптимизация производительности на Android

    Бенчмаркинг на реальном устройстве

    Прежде чем оптимизировать — измерьте. Вот типичные результаты для SSD MobileNetV4 (int8) на разных устройствах:

    | Устройство | Чипсет | Инференс (мс) | FPS (только модель) | |---|---|---|---| | Samsung Galaxy S23 | Snapdragon 8 Gen 2 | 12–18 | 55–83 | | Google Pixel 7 | Tensor G2 | 15–22 | 45–67 | | Samsung Galaxy A54 | Exynos 1380 | 35–50 | 20–28 | | Старый планшет (2020) | Snapdragon 665 | 80–120 | 8–12 |

    Полный пайплайн (камера + предобработка + инференс + постпроцессинг + отрисовка) обычно в 1.5–2 раза медленнее чистого инференса.

    Практические оптимизации

    Кэширование модели в памяти. Загружайте модель один раз при старте Activity, а не при каждом кадре. Файл .onnx размером 8 МБ (int8) загружается за 50–100 мс, но инициализация ONNX Runtime сессии — 200–500 мс.

    Пул буферов. Не аллоцируйте FloatArray размером 270 000 (3×300×300) на каждый кадр. Создайте пул из 2–3 буферов и переиспользуйте их. Аллокация на каждый кадр вызывает GC-паузы (Garbage Collection), которые добавляют 10–50 мс латентности.

    Уменьшение разрешения входа. Если 300×300 даёт приемлемую точность, не используйте 512×512. Каждое удвоение разрешения увеличивает время инференса в ~4 раза.

    Асинхронный инференс. Запускайте инференс в отдельном потоке (корутине), а не в UI-потоке. Камера продолжает захватывать кадры, пока предыдущий обрабатывается:

    Полный цикл: от обученной модели до работающего приложения

    | Шаг | Инструмент | Результат | |---|---|---| | 1. Обучение SSD MobileNetV4 | PyTorch + timm | .pt файл | | 2. Экспорт в ONNX | torch.onnx.export | .onnx файл (~32 МБ float32) | | 3. Квантизация int8 | ONNX Runtime / NNCF | .onnx int8 (~8 МБ) | | 4. Интеграция в Android | KotlinDL + ONNX Runtime | Рабочее приложение | | 5. Оптимизация | Бенчмаркинг, пул буферов, NNAPI | 30–80 мс на кадр |

    Микропример: весь этот процесс — как перевод книги. PyTorch-модель — это оригинал на английском. ONNX — перевод на эсперанто (универсальный). Квантизация — сокращённое издание. KotlinDL — местный издатель, который печатает книгу для конкретной аудитории (Android-пользователей).

    Что запомнить из этой главы

  • KotlinDL оборачивает ONNX Runtime для Android, позволяя запускать квантизованные модели на устройстве без C++ и NDK — инференс SSD MobileNetV4 int8 занимает 12–80 мс в зависимости от чипсета
  • Предобработка на Android требует конвертации YUV → RGB и точного совпадения mean/std с обучением — несовпадение нормализации молча снижает точность на десятки процентов без ошибок в коде
  • Асинхронный инференс и пул буферов — обязательные оптимизации: без них GC-паузы и блокировка UI-потока превращают приложение в слайдшоу даже на флагманских устройствах