Подготовка к собеседованию по компьютерному зрению
Вопросы для собеседования инженера по компьютерному зрению
15 отобранных вопросов для собеседования по компьютерному зрению, сгруппированных по уровням подготовки. Используйте их для повторения основ, понимания практических компромиссов и рассуждений на уровне Senior-специалиста в производственной среде.
1Что такое дискретная двумерная свёртка на изображении, и как она связана с ядрами, фильтрами и кросс-корреляцией?
Дискретная двумерная свёртка на изображении — это линейная операция пространственной фильтрации, при которой матрица весов (ядро) скользит по входному изображению. В каждой пространственной позиции она вычисляет поэлементное произведение между весами ядра и перекрывающимся локальным фрагментом изображения (рецептивным полем), суммирует результаты (часто добавляя член смещения) для получения одного значения пикселя в выходной карте признаков. В классической математике и обработке сигналов истинная свёртка включает переворот (поворот на 180 градусов) ядра по горизонтали и вертикали перед вычислением скользящего скалярного произведения: $(I * K)(i, j) = \sum_m \sum_n I(i - m, j - n) K(m, n)$. В отличие от этого, кросс-корреляция вычисляет скользящее скалярное произведение напрямую без переворота ядра: $(I \star K)(i, j) = \sum_m \sum_n I(i + m, j + n) K(m, n)$. Во фреймворках глубокого обучения, таких как PyTorch и TensorFlow, операция, реализованная под названием «свёртка», на самом деле является кросс-корреляцией. Поскольку веса ядра являются обучаемыми параметрами, оптимизируемыми напрямую с помощью обратного распространения ошибки, сеть просто изучает соответствующим образом ориентированные веса, что делает математический переворот ядра избыточным с вычислительной точки зрения как во время обучения, так и во время инференса.
2Когда вы бы использовали представления RGB, HSV, Lab, YCbCr или оттенки серого (grayscale) в конвейере компьютерного зрения?
Различные цветовые пространства разделяют специфические физические, перцепционные и статистические свойства визуальных данных, что делает их подходящими для конкретных задач компьютерного зрения:
1. **RGB / BGR**: Стандартный формат для сенсоров камер и дисплейного оборудования, представляющий аддитивные основные цвета (Red, Green, Blue). Цветовые каналы сильно коррелированы с яркостью (изменения освещения влияют на все три канала одновременно). Это стандартный вход для свёрточных нейронных сетей (CNN) и Vision Transformers. Основная производственная проблема — это перестановка каналов RGB и BGR (например, OpenCV загружает BGR, в то время как PIL (Python Imaging Library) / PyTorch ожидают RGB), что незаметно снижает точность модели.
2. **HSV / HSL**: Явно отделяет цветность (Hue = цветовой оттенок, Saturation = чистота цвета) от интенсивности (Value/Lightness). Идеально подходит для классической пороговой обработки цвета, отслеживания объектов по цвету и сегментации цвета при изменяющемся освещении, поскольку оттенок (Hue) относительно инвариантен к теням и изменениям яркости.
3. **CIE Lab**: Перцепционно равномерное цветовое пространство, где евклидово расстояние между двумя точками ($\Delta E$) напрямую отражает человеческое перцепционное различие. Оно отделяет яркость ($L^*$) от компонентных осей противоположных цветов ($a^*$ зелено-красный, $b^*$ сине-желтый). Используется для проверки различий в цвете, цветокоррекции, оценки качества изображений и задач колоризации.
4. **YCbCr**: Разделяет яркость ($Y$) от синей цветоразностной ($Cb$) и красной цветоразностной ($Cr$) компонент цветности. Это основа стандартов сжатия видео и изображений (JPEG, MPEG, H.264/H.265), поскольку зрительная система человека менее чувствительна к деталям цветности, что позволяет использовать субдискретизацию цветности (например, 4:2:0) для уменьшения пропускной способности и вычислительных затрат.
5. **Оттенки серого (Grayscale)**: Одноканальное представление интенсивности ($Y \approx 0.299R + 0.587G + 0.114B$). Идеально подходит для задач, основанных на геометрии и текстуре, где цвет не имеет значения (например, оптический поток, SLAM (Simultaneous Localization and Mapping), классическое выделение признаков, таких как SIFT/ORB, обнаружение границ), для экономии 66% памяти и вычислений. Однако его не следует использовать, когда цвет является ключевым различительным признаком (например, классификация состояний светофора).
import cv2
import numpy as np
# Sample image: saturated red under normal and shaded lighting
img_bgr = np.zeros((100, 100, 3), dtype=np.uint8)
img_bgr[:, :50] = [0, 0, 255] # Bright Red in BGR
img_bgr[:, 50:] = [0, 0, 120] # Shaded/Dark Red in BGR
# Convert to HSV (OpenCV H: 0-179, S: 0-255, V: 0-255)
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
# Red Hue wraps around 0/180; track red with single Hue range [0, 10] & high saturation
lower_red = np.array([0, 100, 50])
upper_red = np.array([10, 255, 255])
mask_hsv = cv2.inRange(img_hsv, lower_red, upper_red)
print("HSV segmented pixels:", np.count_nonzero(mask_hsv), "out of", mask_hsv.size)
3Почему поканальная нормализация изображений, нормализация для каждого изображения и последовательное масштабирование пикселей важны в системах компьютерного зрения?
Нормализация изображений жизненно важна в конвейерах компьютерного зрения для поддержания численной стабильности, ускорения сходимости градиентного спуска и предотвращения смещения распределения между обучением и обслуживанием: 1. **Масштабирование пикселей ([0, 1] или [-1, 1])**: Исходные пиксели изображения хранятся как беззнаковые 8-битные целые числа (`uint8` $\in [0, 255]$). Подача сырых значений $[0, 255]$ в нейронные сети вызывает чрезвычайно большие ранние активации и взрыв градиента или его насыщение. Масштабирование до $[0.0, 1.0]$ (делением на 255.0) или $[-1.0, 1.0]$ центрирует входные данные около нуля, что согласуется со стандартными методами инициализации весов (He, Xavier). 2. **Поканальная нормализация на уровне датасета (стандартизация по среднему и стандартному отклонению)**: Стандартизирует входные данные с помощью $x_{norm} = \frac{x - \mu_c}{\sigma_c}$, используя предварительно рассчитанные глобальные поканальные статистики (например, среднее ImageNet `[0.485, 0.456, 0.406]` и стандартное отклонение `[0.229, 0.224, 0.225]`). Это центрирует каждый канал вокруг нулевого среднего со стандартным отклонением, равным единице, по всему набору данных, обеспечивая сбалансированный поток градиента по каналам. Критический операционный сбой — это **перекос распределения между обучением и обслуживанием (train-serving skew)**: если инференс пропускает деление на 255, использует несогласованные константы среднего/стандартного отклонения или применяет их в неправильном порядке каналов (RGB против BGR), производительность модели значительно снижается. 3. **Нормализация для каждого изображения (Instance Normalization / Min-Max / Z-score)**: Вычисляет среднее значение и стандартное отклонение для каждого отдельного изображения: $x_{norm} = \frac{x - \mu_{img}}{\sigma_{img}}$. Это устраняет глобальные вариации контраста и освещенности в различных условиях захвата. Хотя это эффективно при переносе стиля, медицинской визуализации (МРТ/КТ) или спутниковых снимках, это может быть пагубным, когда абсолютная интенсивность пикселей имеет физический смысл (например, классификация дня и ночи, отражательная способность материала или обнаружение дефектов при калиброванном освещении).
import torch
import torchvision.transforms as T
from PIL import Image
import numpy as np
# Create a mock uint8 RGB image
raw_img = Image.fromarray(np.random.randint(0, 256, (224, 224, 3), dtype=np.uint8))
# Standard transform pipeline:
# 1. ToTensor scales uint8 [0, 255] -> float32 [0.0, 1.0] and permutes HWC -> CHW
# 2. Normalize standardizes per-channel using dataset mean and std
preprocess = T.Compose([
T.ToTensor(),
T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
tensor_img = preprocess(raw_img)
print("Tensor shape:", tensor_img.shape)
print("Tensor dtype:", tensor_img.dtype)
print("Channel 0 min/max:", round(tensor_img[0].min().item(), 2), round(tensor_img[0].max().item(), 2))
4Как геометрические и фотометрические аугментации способствуют инвариантности, и как определить, сохраняет ли аугментация метки?
Геометрические аугментации (такие как поворот, перенос, масштабирование и отражение) изменяют отображение пространственных координат пикселей, тогда как фотометрические аугментации (такие как яркость, контрастность, изменение оттенка и размытие) изменяют интенсивность пикселей и цветовые каналы без изменения пространственных координат. В классификации обе категории подвергают модель реалистичным вариациям, побуждая ее изучать инвариантные представления, где предсказания остаются стабильными, несмотря на изменения позы, точки обзора или условий освещения. В задачах пространственного предсказания (детектирование и сегментация) геометрические преобразования требуют соответствующих преобразований для эталонных ограничивающих рамок (ground-truth boxes) или масок для сохранения эквивариантности. Решение о том, сохраняет ли аугментация метки, требует оценки семантики предметной области и физических априорных знаний. Преобразование сохраняет метки, если полученное изображение остается правдоподобным экземпляром исходного целевого класса без изменения его семантической идентичности. Например, горизонтальное отражение сохраняет идентичность для общих объектов (таких как автомобили или животные), но изменяет идентичность или делает недействительными символы в оптическом распознавании символов (OCR) и классификации цифр. Аналогично, полный поворот на 360 градусов допустим в гистологии или спутниковых снимках, где не существует канонической ориентации, но неестественен в автономном вождении, где перевернутые объекты нарушают реальные физические ограничения.
5Что такое интерполяция ближайшего соседа, билинейная, бикубическая интерполяция и интерполяция по площади, и как изменение размера может привести к эффекту наложения частот (aliasing) или размытию?
Методы интерполяции оценивают интенсивность пикселей в непрерывных координатах при повторной дискретизации на новую дискретную сетку:
- **Интерполяция ближайшего соседа:** Присваивает интенсивность ближайшего дискретного пикселя. Вычислительная сложность составляет $O(1)$, сохраняет точные исходные значения, но создает блочные артефакты при увеличении разрешения (upsampling) и сильные зазубренные края при уменьшении разрешения (downsampling).
- **Билинейная интерполяция:** Вычисляет взвешенное по расстоянию среднее значение из $2 \times 2$ (4 ближайших) соседних пикселей, используя линейную интерполяцию вдоль обеих осей, что обеспечивает плавные переходы с умеренным размытием.
- **Бикубическая интерполяция:** Выбирает окрестность $4 \times 4$ (16 ближайших) пикселей, используя кубические полиномиальные ядра. Она захватывает локальные градиенты интенсивности, создавая более резкие края и более плавные кривые, чем билинейная, но может вызывать артефакты перерегулирования/звона (overshoot/ringing) вокруг резких переходов.
- **Интерполяция по площади (Box):** Вычисляет дробное перекрытие площади целевых пикселей, проецируемых на исходные пиксели, и усредняет базовые исходные интенсивности. Особенно эффективна для уменьшения разрешения без эффекта муара.
**Механика эффекта наложения частот (алиасинга) против размытия:**
- **Алиасинг** возникает при уменьшении разрешения, когда высокочастотное содержимое превышает частоту Найквиста ($f_s / 2$) новой частоты дискретизации без достаточной низкочастотной фильтрации. Высокие частоты «сворачиваются» (fold back) в более низкие частотные диапазоны, создавая ложные узоры, муар и зазубренные края.
- **Размытие** происходит, когда интерполяционные ядра действуют как низкочастотные сглаживающие фильтры, ослабляющие легитимные высокие частоты (например, билинейное сглаживание), или когда высокочастотные детали усредняются при уменьшении разрешения.
6По отношению к каким реальным режимам отказа визуальных систем следует оценивать систему машинного зрения, и как они смещают входное распределение?
Режимы отказа визуальных систем в реальном мире делятся на несколько широких категорий: условия окружающей среды (низкая освещенность, прямые блики, дождь, снег, туман), сенсорные и оптические эффекты (размытие движения, расфокусировка, шум сенсора при высоком ISO, искажение от эффекта `rolling shutter`), деградация при сжатии и передаче (блочность JPEG, ограничение битрейта видео, уменьшение разрешения), а также семантические/пространственные сдвиги (частичное перекрытие, обрезка, позы объектов вне обучающего распределения). Эти режимы отказа смещают входное распределение от нормальных условий обучения на нескольких уровнях. На уровне пикселей они изменяют гистограммы яркости и цветности, разрушают локальный контраст, снижают отношение сигнал/шум (SNR) и привносят искусственные высокочастотные артефакты или ядра размытия. На структурном и семантическом уровне они ослабляют градиенты краев, затемняют ключевые визуальные признаки, искажают силуэты и скрывают критически важные диагностические области. Когда модели, обученные на чистых данных, сталкиваются с этими смещенными входными данными, низкоуровневые сверточные или внимательные экстракторы признаков не срабатывают корректно, что приводит к пропущенным обнаружениям, галлюцинированным ложным срабатываниям на шумовых паттернах и чрезмерно уверенным ошибкам.
7Как классические дескрипторы, такие как HOG (Histogram of Oriented Gradients), представляют структуру изображения, и какие ограничения они имеют по сравнению с признаками, извлекаемыми свёрточными нейронными сетями (CNN)?
HOG (Histogram of Oriented Gradients) — это классический дескриптор признаков, разработанный вручную для захвата локальной формы и внешнего вида объектов через распределение ориентаций градиентов интенсивности. Конвейер вычисления HOG включает:
(1) вычисление горизонтальных и вертикальных градиентов изображения (например, с одномерными производными фильтрами `[-1, 0, 1]`) для получения величины и ориентации градиента;
(2) деление изображения на небольшие пространственные области, называемые «ячейками» (например, 8x8 пикселей), и накопление одномерных гистограмм ориентаций градиентов, взвешенных по величине градиента;
(3) группировка соседних ячеек в более крупные перекрывающиеся «блоки» (например, 2x2 ячейки) и нормализация векторов признаков блоков (с использованием L2-нормы или L1-sqrt) для достижения устойчивости к локальным изменениям освещенности, контрастности и теней;
(4) конкатенация нормализованных векторов блоков в конечное одномерное представление признаков, исторически использовавшееся в паре с линейными SVM (Support Vector Machine) для обнаружения пешеходов и объектов.
По сравнению с признаками, извлекаемыми свёрточными нейронными сетями (CNN), HOG имеет серьезные ограничения: Во-первых, признаки HOG фиксированы и созданы вручную, они захватывают только низкоуровневую статистику ориентации локальных границ без возможности изучения иерархических представлений, специфичных для задачи (таких как текстуры, части объектов и семантические концепции). Во-вторых, HOG обеспечивает очень ограниченную геометрическую инвариантность: хотя нормализация блоков обрабатывает монотонные изменения освещенности и небольшие пространственные сдвиги внутри ячеек, HOG неустойчив при трёхмерных поворотах вне плоскости, значительных изменениях масштаба, нежёстких изменениях позы и сильном фоновом шуме. В отличие от этого, CNN изучают многослойные нелинейные абстракции, оптимизированные сквозным образом для целевой задачи.
8Как шаг (stride), дополнение (padding), диляция (dilation) и размер ядра (kernel size) определяют размер выхода свертки и рецептивное поле?
Пространственные размеры выхода сверточного слоя и его кумулятивное рецептивное поле определяются размером ядра $k$, шагом $s$, дополнением $p$ и диляцией $d$: 1. **Пространственный размер выхода**: Диляция вводит $(d - 1)$ промежутков между элементами ядра, что дает эффективный размер ядра $k' = d(k - 1) + 1$. Размер выхода вдоль оси определяется по формуле: $$O = \left\lfloor \frac{I + 2p - k'}{s} \right\rfloor + 1 = \left\lfloor \frac{I + 2p - d(k - 1) - 1}{s} \right\rfloor + 1$$ Здесь шаг уменьшает разрешение, перемещая ядро на $s$ пикселей за один шаг, дополнение добавляет виртуальные граничные пиксели для сохранения или корректировки пространственных размеров, а диляция расширяет область действия фильтра без добавления дополнительных параметров. 2. **Рецептивное поле (RF)**: Теоретическое рецептивное поле описывает пространственную протяженность во входном изображении, которая влияет на конкретную активацию. В последовательных слоях рецептивное поле $RF_l$ и кумулятивный шаг (прыжок $j_l$) обновляются рекурсивно:
* Прыжок: $j_l = j_{l-1} \cdot s_l$, с $j_0 = 1$
* Рецептивное поле: $RF_l = RF_{l-1} + (k'_l - 1) \cdot j_{l-1}$, с $RF_0 = 1$
Шаги и пулинг мультипликативно расширяют рецептивное поле по глубине, потому что шаги ядра последующих слоев соответствуют большим скачкам пикселей в исходном координатном пространстве входа. Диляция аддитивно расширяет рецептивное поле в пределах одного слоя за счет увеличения $k'_l$ без уменьшения пространственного разрешения.
9Как ядро свертки соотносится с классическим линейным фильтром изображений, и когда двумерный (2D) фильтр может быть сделан разделимым?
В классической обработке линейных сигналов и изображений ядро свертки представляет собой пространственную импульсную характеристику (функцию рассеяния точки) линейной сдвигово-инвариантной (ЛСИ) системы. Применение ядра является операцией линейной фильтрации в пространственной области, которая формирует частотную характеристику изображения (его двумерное преобразование Фурье). Низкочастотные ядра (например, Гаусса, усредняющий фильтр) ослабляют высокие пространственные частоты для подавления шума и сглаживания текстур, тогда как высокочастотные или полосовые ядра (например, Собеля, Лапласиана, Прюитта) усиливают высокие частоты для обнаружения границ и градиентов. Двумерное ядро фильтра $K \in \mathbb{R}^{M \times N}$ является пространственно разделимым, если его можно разложить на внешнее произведение двух одномерных фильтров: $K = u \cdot v^T$, где $u \in \mathbb{R}^{M \times 1}$ и $v \in \mathbb{R}^{N \times 1}$. В терминах линейной алгебры, двумерная матрица разделима тогда и только тогда, когда ее ранг равен 1. Это можно проверить с помощью сингулярного разложения (SVD), когда только одно сингулярное число является ненулевым ($ \sigma_1 > 0, \sigma_2 = \dots = 0$). Разделимость значительно снижает вычислительную сложность. Применение неразделимого ядра $K \times K$ к изображению $H \times W$ требует $O(H \cdot W \cdot K^2)$ умножений и сложений. При разложении на два последовательных одномерных прохода (сначала горизонтальный, затем вертикальный) сложность снижается до $O(H \cdot W \cdot 2K)$. Для ядра $15 \times 15$ это обеспечивает примерно $7.5\times$ ускорение.
10Как изменение размера, центральная обрезка, случайная обрезка с изменением размера, растягивание и леттербоксинг влияют на распределение входных данных?
Различные стратегии изменения размера и обрезки смещают распределение входных данных по геометрии, масштабу, охвату содержимого и пространственным границам: 1. **Прямое изменение размера (растягивание/сжатие):** Неизотропно масштабирует изображение до целевых размеров $(H, W)$, искажая исходные пропорции. Это вынуждает модель обрабатывать деформированные формы объектов (например, круглые объекты становятся вытянутыми эллипсами). 2. **Центральная обрезка (Center Cropping):** Извлекает центральную область фиксированного размера или соотношения. Она сохраняет естественное соотношение сторон и локальный масштаб, но вводит сильное смещение к центру (предполагая, что целевые объекты расположены по центру) и отбрасывает периферийный контекст или обрезает объекты, расположенные по краям. 3. **Случайная обрезка с изменением размера (RRC, Random-Resized Cropping):** Извлекает случайные подобласти с различными масштабами площади и соотношениями сторон, а затем изменяет их размер до фиксированного. Это расширяет распределение масштабов для обучения и стимулирует обучение признакам на основе частей, но чрезмерные обрезки могут полностью исключить целевой объект. 4. **Леттербоксинг (Letterboxing, изотропное изменение размера с заполнением):** Равномерно масштабирует изображение до тех пор, пока его самая длинная сторона не достигнет целевого размера, а затем заполняет оставшиеся границы постоянным значением. Это сохраняет истинные пропорции объектов и соотношения сторон, но вводит искусственные высококонтрастные границы и неинформативные заполняющие пиксели.
11Какие типы шума в разметке возникают в наборах данных компьютерного зрения и как их можно обнаружить или смягчить?
Наборы данных компьютерного зрения обычно демонстрируют четыре основных типа шума в разметке:
1. **Шум в категориальных метках (Categorical Label Noise):** Изображению или объекту присваивается неверная метка класса (например, ошибочная классификация кошки как собаки, или путаница тонких мелкозернистых классов).
2. **Пропущенные аннотации (Missing Annotations / Omission Noise):** Действительные объекты переднего плана остаются без аннотации. При обнаружении объектов пропущенные цели трактуются как отрицательные фоновые элементы, что напрямую штрафует правильные обнаружения модели во время обучения.
3. **Дрожание ограничивающих рамок / ключевых точек (Bounding-Box / Keypoint Jitter / Localization Noise):** Неточные, слишком свободные или смещенные координаты ограничивающих рамок и положения ключевых точек, вызванные непоследовательностью аннотатора-человека.
4. **Неоднозначность границ маски (Mask Boundary Ambiguity):** Непоследовательные или грубые контуры сегментации вдоль сложных или размытых границ (например, волосы, полупрозрачные поверхности, размытие движения).
**Стратегии обнаружения и смягчения:**
- **Отслеживание выбросов по функции потерь и уверенное обучение (Loss Outlier Tracking & Confident Learning):** Отслеживание потерь по выборкам на протяжении эпох обучения выявляет стойкие выбросы с высокими потерями, которые часто указывают на ошибочно помеченные или пропущенные экземпляры. Алгоритмы, такие как Confident Learning, оценивают распределения шума для удаления или исправления ошибок.
- **Расхождения в предсказаниях Out-of-Fold (OOF) Prediction Discrepancies:** Обучение кросс-валидационных моделей и сравнение предсказаний на отложенных данных с истиной (ground truth) выявляет ошибочно помеченные изображения и отсутствующие ограничивающие рамки.
- **Согласованность между аннотаторами (Inter-Annotator Agreement, IAA) и разрешение разногласий (Adjudication):** Измерение метрик, таких как коэффициент Каппа Коэна (Cohen's Kappa) для классификации или среднее пересечение-по-объединению (mean Intersection-over-Union, IoU) для локализации, между несколькими аннотаторами выделяет образцы с низким уровнем согласованности для совместного рассмотрения.
- **Робастные формулировки функций потерь (Robust Loss Formulations):** Использование сглаживания меток (label smoothing), устойчивых к шуму функций потерь классификации или робастных регрессионных функций потерь на основе IoU снижает чувствительность к дрожанию и ошибочной разметке.
import torch
import torch.nn.functional as F
def find_label_noise_candidates(model, dataloader, device, top_k=50):
model.eval()
sample_losses = []
with torch.no_grad():
for batch_idx, (images, targets, sample_ids) in enumerate(dataloader):
images, targets = images.to(device), targets.to(device)
logits = model(images)
loss_per_sample = F.cross_entropy(logits, targets, reduction='none')
for sid, l, target, pred in zip(sample_ids, loss_per_sample.cpu(), targets.cpu(), logits.argmax(dim=-1).cpu()):
sample_losses.append({'id': sid, 'loss': l.item(), 'target': target.item(), 'pred': pred.item()})
sample_losses.sort(key=lambda x: x['loss'], reverse=True)
return sample_losses[:top_k]
12Как дисбаланс классов влияет на обучение классификации изображений, обнаружения и плотного предсказания?
Дисбаланс классов влияет на динамику оптимизации и ландшафты функции потерь в задачах компьютерного зрения: 1. **Классификация изображений:** Когда мажоритарные классы численно превосходят миноритарные классы, минимизация эмпирического риска приводит к тому, что обновления параметров доминируются градиентами мажоритарного класса. Модель изучает эмпирическое априорное распределение классов $P(Y)$ и смещает свою границу принятия решений против редких классов. Это приводит к высокой общей точности top-1 при катастрофическом снижении полноты для миноритарных классов. 2. **Обнаружение объектов:** - *Дисбаланс между передним планом и фоном:* В плотных одноэтапных и анкерных детекторах сотни тысяч кандидатных областей оцениваются для каждого изображения, где >99% относятся к фону. Даже если отдельные «легкие» фоновые анкеры дают небольшие потери, их огромный совокупный градиент подавляет информативные градиентные сигналы от разреженных объектов переднего плана. - *Дисбаланс классов объектов переднего плана:* Распространенные категории объектов появляются на порядки чаще, чем редкие категории, что уменьшает эффективный размер выборки и обучающий сигнал для редких классов. 3. **Плотное предсказание (сегментация):** Дисбаланс на уровне пикселей является серьезным, потому что большие фоновые классы и классы «массы» (например, дорога, небо) занимают миллионы пикселей, тогда как малые классы «объектов» (например, дорожные знаки, пешеходы) могут занимать менее 0,1% пикселей изображения. Стандартная перекрестная энтропия на уровне пикселей доминируется классами большой площади, что приводит к недостаточной сегментации или полному исчезновению малых, тонких структур.
13Как бы вы отлаживали NaN (Not a Number) или нестабильные потери при крупномасштабном распределенном обучении компьютерного зрения?
Отладка NaN или нестабильности потерь в крупномасштабном распределенном параллельном обучении данных (DDP) в компьютерном зрении требует изоляции корневой причины, будь то некорректные входные данные, численное переполнение/недополнение при смешанной точности (AMP) или нестабильность оптимизации между рабочими процессами. Во-первых, обеспечьте детерминизм и механизмы безопасности: включите обнаружение аномалий (`torch.autograd.set_detect_anomaly(True)`), зарегистрируйте хуки градиентов/активаций для определения точного слоя, где появляются NaN, и добавьте строгую валидацию данных в DataLoader (проверка на конечные значения, проверка на поврежденные изображения нулевого размера, пустые ограничивающие рамки или делители нормализации с нулевой дисперсией). Журналирование на уровне мини-батчей должно отслеживать потери для каждого ранга, URI входных данных, норму градиента до отсечения и коэффициенты масштабирования GradScaler. Во-вторых, проверьте автоматическое смешанное умножение (AMP) и динамическое масштабирование потерь: в FP16 большие градиенты легко переполняются (`> 65504`), в результате чего масштабатор потерь пропускает шаги и многократно уменьшает свой коэффициент масштабирования вдвое, пока масштаб не достигнет нуля; переключение нестабильных операций (например, softmax, LayerNorm, экспоненты фокальной потери или знаменатели IoU (Intersection over Union) ограничивающей рамки) на FP32 или использование BF16 (который соответствует динамическому диапазону FP32) обычно стабилизирует обучение. Наконец, проверьте специфические для DDP проблемы, такие как операции all-reduce, распространяющие NaN от одного рабочего процесса ко всем рангам, масштабирование разогрева скорости обучения (например, правило линейного масштабирования с большими глобальными размерами батчей) и отсечение градиентов.
import torch
from torch.cuda.amp import autocast, GradScaler
scaler = GradScaler()
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4)
for step, (images, targets, uris) in enumerate(dataloader):
# 1. Input sanitization
if not torch.isfinite(images).all():
print(f"Corrupt input detected from URIs: {uris}")
continue
optimizer.zero_grad(set_to_none=True)
with autocast(dtype=torch.float16):
outputs = model(images)
loss = criterion(outputs, targets)
if not torch.isfinite(loss):
print(f"NaN/Inf loss at step {step} on rank {torch.distributed.get_rank()}; skipping step.")
continue
scaler.scale(loss).backward()
# Unscale before clipping to inspect true gradient norms
scaler.unscale_(optimizer)
grad_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
if torch.isnan(grad_norm) or torch.isinf(grad_norm):
print(f"Warning: Grad norm is {grad_norm}. Scaler will adjust.")
scaler.step(optimizer)
scaler.update()
14Как бы вы спроектировали компонент онлайн-цифровой стабилизации видео для камеры с дрожанием кадров?
Проектирование конвейера онлайн-цифровой стабилизации видео для устранения дрожания камеры в реальном времени включает четыре основные стадии: оценка движения, сглаживание движения, компенсация движения (деформация) и обработка границ.
1. **Межкадровая оценка движения**: Извлечь 2D разреженные ключевые точки по последовательным кадрам с использованием быстрых детекторов признаков (например, ORB, FAST или углы Ши-Томаси) и вычислить соответствия с использованием оптического потока Лукаса-Канаде или сопоставления дескрипторов признаков. Оценить межкадровое геометрическое преобразование (такое как аффинная или гомографическая модель) с использованием RANSAC (RANdom SAmple Consensus) для отклонения выбросов-совпадений, вызванных независимо движущимися объектами переднего плана.
2. **Накопление траектории движения и онлайн-сглаживание**: Интегрировать покадровые преобразования во времени для поддержания кумулятивного пути камеры $P_t = P_{t-1} \cdot H_t$. Применить онлайн-фильтр сглаживания — такой как 1D/2D фильтр Калмана или причинное скользящее среднее с коротким окном — для отделения высокочастотного непреднамеренного дрожания от низкочастотного преднамеренного панорамирования камеры.
3. **Компенсация и деформация изображения**: Вычислить корректирующее преобразование $C_t = S_t \cdot P_t^{-1}$ (где $S_t$ — сглаженный путь) и деформировать текущий кадр с использованием билинейной/бикубической интерполяции.
4. **Обработка границ и ограничения задержки**: Деформация приводит к появлению отсутствующих пикселей по краям / черных границ; решить это путем применения фиксированного динамического коэффициента обрезки (например, 5-10% увеличения) с экстраполяцией границ или адаптивным масштабом. В онлайн-среде поддерживать минимальную буферизацию (1–3 кадра с опережением) для ограничения задержки обработки.
15Как оптимизировать конвейер обработки изображений в реальном времени, если детектор работает медленнее целевой частоты кадров?
Когда детектор объектов не может поддерживать целевую частоту кадров (например, работает со скоростью 15-20 FPS при видеопотоке 60 FPS), надежная производственная архитектура отделяет детектирование от цикла представления в реальном времени, используя асинхронный многопоточный конвейер, сочетающий тяжелое детектирование с легковесным отслеживанием. В этой гибридной архитектуре поток ввода (ingestion thread) непрерывно захватывает видеокадры. Тяжелый детектор асинхронно работает как «детектор ключевых кадров» в фоновом рабочем потоке. Тем временем легковесный трекер (такой как оптический поток Лукаса-Канаде, ByteTrack/BoT-SORT или быстрый корреляционный фильтр/фильтр Калмана) работает синхронно на каждом кадре с полной скоростью 60 FPS, поддерживая состояние объекта, его идентификацию и плавные траектории ограничивающих рамок. Для обработки задержек и обратного давления без возникновения неограниченной задержки или устаревших кадров используются ограниченные кольцевые буферы и политики отбрасывания устаревших кадров. Когда детектор заканчивает обработку кадра T_0 в момент времени T_curr, его результат устарел. Конвейер выполняет перепривязку координат/обратную проекцию: он связывает результаты задержанного детектирования с состоянием исторической траектории в момент T_0, обновляет идентификаторы и пропущенные треки, и распространяет исправления вперед до T_curr с помощью векторов движения отслеживания или шагов предсказания фильтра Калмана.
import queue
import threading
frame_queue = queue.Queue(maxsize=1) # Drop stale frames, keep latest
det_result_queue = queue.Queue()
def detector_worker():
while True:
frame, frame_id, timestamp = frame_queue.get()
boxes, scores, classes = heavy_detector.infer(frame)
det_result_queue.put({'frame_id': frame_id, 'boxes': boxes, 'timestamp': timestamp})
def realtime_pipeline(video_stream):
tracker = FastTracker() # e.g. Optical flow or Kalman tracker
for frame, frame_id, timestamp in video_stream:
if frame_queue.empty():
frame_queue.put((frame, frame_id, timestamp))
if not det_result_queue.empty():
det_result = det_result_queue.get()
tracker.reconcile_and_correct(det_result, current_frame_id=frame_id)
active_tracks = tracker.update(frame)
display_or_downstream(frame, active_tracks)