Preparación para entrevistas de Visión por Computadora
Preguntas de Entrevista para Ingenieros de Visión por Computadora
15 preguntas seleccionadas de entrevista sobre visión por computadora, agrupadas por nivel de experiencia. Úsalas para repasar los fundamentos, las compensaciones prácticas y el razonamiento de producción a nivel senior.
1¿Qué es una convolución 2D discreta en una imagen y cómo se relaciona con los kernels, filtros y la correlación cruzada?
La convolución 2D discreta en una imagen es una operación de filtrado lineal y espacial donde una matriz de pesos (un kernel) se desliza a través de la imagen de entrada. En cada ubicación espacial, calcula un producto elemento a elemento entre los pesos del kernel y el parche de imagen local superpuesto (campo receptivo) y suma los resultados (a menudo añadiendo un término de sesgo) para producir un único valor de píxel en el mapa de características de salida.
En matemáticas clásicas y procesamiento de señales, la verdadera convolución implica voltear (rotar 180 grados) el kernel horizontal y verticalmente antes de calcular el producto escalar deslizante: $(I * K)(i, j) = \sum_m \sum_n I(i - m, j - n) K(m, n)$. Por el contrario, la correlación cruzada calcula el producto punto deslizante directamente sin voltear el kernel: $(I \star K)(i, j) = \sum_m \sum_n I(i + m, j + n) K(m, n)$.
En frameworks de aprendizaje profundo como PyTorch y TensorFlow, la operación implementada bajo el nombre de "convolución" es en realidad una correlación cruzada. Dado que los pesos del kernel son parámetros que se pueden aprender y se optimizan directamente mediante retropropagación (backpropagation), la red simplemente aprende los pesos con la orientación adecuada, lo que hace que el volteo matemático del kernel sea computacionalmente redundante tanto durante el entrenamiento como en la inferencia.
2¿Cuándo utilizaría representaciones RGB, HSV, Lab, YCbCr o en escala de grises en un pipeline de visión?
Utilice la representación que conserve los indicios necesarios para la tarea y coincida con el preprocesamiento de entrenamiento del modelo. RGB es común para modelos aprendidos; muchas API de OpenCV utilizan BGR, por lo que debe verificar el orden de los canales en lugar de asumir que un framework lo impone. HSV/HSL puede hacer que la umbralización por color sea conveniente, pero el tono es inestable cerca de la saturación cero y generalmente no es invariante a los cambios de iluminación o de balance de blancos. CIE Lab separa la luminosidad de las coordenadas de color oponente y es aproximadamente uniforme en términos perceptuales bajo supuestos específicos de visualización/blanco de referencia; la distancia euclidiana Delta E 1976 es solo una medida aproximada de diferencia perceptual. YCbCr separa la luma Y' de los canales de diferencia de color y admite submuestreo de croma en muchos formatos de imagen/video; los coeficientes, el rango y las funciones de transferencia dependen del estándar. La escala de grises es útil cuando el color no es necesario, reduciendo el almacenamiento de canales sin procesar de tres canales a uno con la misma precisión, pero no garantiza una reducción de dos tercios en el cómputo total del modelo. Conserve el color cuando contenga información de etiquetas y verifique las convenciones de escalado y conversión.
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¿Por qué son importantes la normalización de imágenes por canal, la normalización por imagen y el escalado consistente de píxeles en los sistemas de visión?
Utilice el rango de píxeles, el orden de los canales y la normalización esperados por el modelo entrenado de manera consistente tanto en el entrenamiento como en la inferencia. Para imágenes de 8 bits, la división por 255 asigna los valores a [0,1], lo cual reescala pero no los centra en cero; el mapeo a [-1,1] centra el rango, no necesariamente la media de los datos. Las imágenes también pueden utilizar otras profundidades de enteros o unidades físicas en punto flotante. Los valores grandes no escalados pueden hacer que la optimización esté mal condicionada, pero no provocan inevitablemente gradientes explosivos. La estandarización por canales del conjunto de datos utiliza (x-mu_c)/sigma_c con estadísticas del conjunto de entrenamiento o las constantes prescritas del modelo preentrenado; proporciona media cero y varianza unitaria en la distribución utilizada para estimarlas, no en cada nueva imagen o conjunto de datos. La puntuación z (z-score) por imagen utiliza la media y la desviación estándar de esa imagen con protección contra varianzas cercanas a cero; el escalado min-max es una operación diferente. InstanceNorm es una capa de red neuronal que normalmente normaliza cada muestra y canal en las dimensiones espaciales, no un sinónimo de todo el preprocesamiento por imagen. La normalización por imagen puede reducir la variación de brillo/contraste, pero puede eliminar información útil de intensidad absoluta, por lo que debe validarse para la tarea.
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¿Cómo fomentan los aumentos geométricos y fotométricos la invarianza, y cómo se decide si un aumento preserva las etiquetas?
Los aumentos geométricos (como rotación, traslación, escalado y volteo) alteran el mapeo de coordenadas espaciales de los píxeles, mientras que los aumentos fotométricos (como brillo, contraste, fluctuación de tono (`hue jitter`) y desenfoque) alteran la intensidad de píxeles y los canales de color sin modificar las coordenadas espaciales. En la clasificación, ambas categorías exponen el modelo a variaciones realistas, fomentando que aprenda representaciones invariantes donde las predicciones permanecen estables a pesar de los cambios en la pose, el punto de vista o las condiciones de iluminación. En tareas de predicción espacial (detección y segmentación), las transformaciones geométricas requieren transformaciones coincidentes a las cajas o máscaras de verdad fundamental (`ground-truth boxes`) para preservar la equivariancia. Decidir si un aumento preserva las etiquetas requiere evaluar la semántica del dominio y los priors físicos. Una transformación que preserva la etiqueta es aquella en la que la imagen resultante sigue siendo una instancia plausible de la clase objetivo original sin alterar su identidad semántica. Por ejemplo, el volteo horizontal preserva la identidad para objetos generales (como coches o animales), pero altera la identidad o invalida caracteres en el reconocimiento óptico de caracteres (OCR) y la clasificación de dígitos. De manera similar, la rotación completa de 360 grados es válida en histología o imágenes satelitales donde no existe una orientación canónica, pero antinatural en la conducción autónoma donde los objetos invertidos violan las restricciones físicas del mundo real.
5¿Qué son las interpolaciones de vecino más cercano, bilineal, bicúbica y de área, y cómo puede el redimensionamiento introducir aliasing o desenfoque?
Los métodos de interpolación estiman las intensidades de píxeles en coordenadas continuas al remuestrear en una nueva cuadrícula discreta:
- **Vecino más cercano:** Asigna la intensidad del píxel discreto más cercano. Es computacionalmente $O(1)$ y conserva los valores originales exactos, pero crea artefactos de bloques al sobremuestrear y bordes dentados severos al submuestrear.
- **Interpolación bilineal:** Calcula un promedio ponderado por distancia de los $2 \times 2$ (4 más cercanos) píxeles vecinos utilizando interpolación lineal a lo largo de ambos ejes, produciendo transiciones suaves con un desenfoque moderado.
- **Interpolación bicúbica:** Muestra un vecindario de $4 \times 4$ (16 más cercanos) utilizando kernels polinomiales cúbicos. Captura gradientes de intensidad locales, produciendo bordes más nítidos y curvas más suaves que la bilineal, pero puede producir artefactos de sobreimpulso/ringing alrededor de transiciones bruscas.
- **Interpolación de área (caja):** Calcula la superposición fraccional de área de los píxeles objetivo proyectados sobre los píxeles fuente y promedia las intensidades de fuente subyacentes. Es especialmente efectiva para el submuestreo sin moiré.
**Mecánica del Aliasing vs. Desenfoque:**
- El **aliasing** ocurre durante el submuestreo cuando el contenido de alta frecuencia excede la frecuencia de Nyquist ($f_s / 2$) de la nueva tasa de muestreo sin suficiente filtrado de paso bajo. Las altas frecuencias se pliegan en bandas de frecuencia más bajas, produciendo patrones falsos, moiré y bordes dentados.
- El **desenfoque** ocurre cuando los kernels de interpolación actúan como filtros de suavizado de paso bajo que atenúan las frecuencias altas legítimas (por ejemplo, el suavizado bilineal) o cuando los detalles de alta frecuencia se promedian durante el submuestreo.
6¿Contra qué modos de fallo visuales del mundo real debe evaluarse un sistema de visión, y cómo desplazan la distribución de entrada?
Los modos de fallo visuales del mundo real se agrupan en varias categorías amplias: condiciones ambientales (poca luz, deslumbramiento directo, lluvia, nieve, niebla), efectos del sensor y ópticos (desenfoque por movimiento, desenfoque por falta de foco, ruido del sensor ISO alto, distorsión por persiana enrollable), degradación por compresión y transmisión (pixelación JPEG, limitación del bitrate de vídeo, submuestreo), y cambios semánticos/espaciales (oclusión parcial, truncamiento, poses de objetos fuera de distribución).
Estos modos de fallo desplazan la distribución de entrada lejos de los dominios de entrenamiento nominales en múltiples niveles. A nivel de píxel, alteran los histogramas de luminancia y crominancia, destruyen el contraste local, reducen la relación señal-ruido (SNR) e introducen artefactos artificiales de alta frecuencia o núcleos de desenfoque. A nivel estructural y semántico, atenúan los gradientes de los bordes, oscurecen las características visuales clave, distorsionan las siluetas y ocultan regiones de diagnóstico críticas. Cuando los modelos entrenados con datos limpios encuentran estas entradas desplazadas, los extractores de características convolucionales o de atención de bajo nivel no se activan correctamente, produciendo detecciones perdidas, falsos positivos alucinatorios en patrones de ruido y errores sobreconfiados.
7¿Cómo representan los descriptores clásicos como HOG la estructura de la imagen, y qué limitaciones tienen en comparación con las características aprendidas de las CNN?
El HOG (Histograma de Gradientes Orientados) es un descriptor de características clásico, diseñado manualmente, que captura la forma y apariencia local de los objetos a través de la distribución de las orientaciones de los gradientes de intensidad. El proceso de cálculo de HOG implica: (1) calcular los gradientes de imagen horizontales y verticales (por ejemplo, con filtros de derivada 1D [-1, 0, 1]) para obtener la magnitud y orientación del gradiente; (2) dividir la imagen en pequeñas regiones espaciales llamadas 'celdas' (como 8x8 píxeles) y acumular histogramas 1D de orientaciones de gradientes ponderados por la magnitud del gradiente; (3) agrupar celdas adyacentes en 'bloques' superpuestos más grandes (como 2x2 celdas) y normalizar los vectores de características del bloque (usando la norma L2 o L1-sqrt) para lograr robustez contra variaciones locales de iluminación, contraste y sombreado; y (4) concatenar los vectores de bloque normalizados en una representación final de características 1D, históricamente emparejada con máquinas de vectores de soporte (SVM) lineales para la detección de peatones y objetos. En comparación con las características aprendidas de las redes neuronales convolucionales (CNN), HOG tiene limitaciones importantes: Primero, las características HOG son fijas y elaboradas manualmente, capturando solo estadísticas de orientación de bordes locales de bajo nivel sin la capacidad de aprender representaciones jerárquicas específicas de la tarea (como texturas, partes de objetos y conceptos semánticos). Segundo, HOG proporciona una invarianza geométrica muy limitada: si bien la normalización de bloques maneja cambios de iluminación monótonos y pequeños desplazamientos espaciales dentro de las celdas, HOG es frágil ante rotaciones 3D fuera del plano, variaciones de escala significativas, articulaciones de pose no rígidas y fuerte desorden de fondo. En contraste, las CNN aprenden abstracciones no lineales multicapa optimizadas de extremo a extremo para el objetivo deseado.
8¿Cómo determinan el `stride`, el `padding`, la `dilation` y el tamaño del kernel (`kernel size`) el tamaño de salida de la convolución y el campo receptivo?
Las dimensiones espaciales de salida de una capa convolucional y su campo receptivo acumulativo están determinadas por el tamaño del kernel $k$, el `stride` $s$, el `padding` $p$ y la `dilation` $d$:
1. **Tamaño espacial de salida**: La `dilation` introduce $(d - 1)$ espacios entre los elementos del kernel, dando un tamaño de kernel efectivo de $k' = d(k - 1) + 1$. La dimensión de salida a lo largo de un eje se calcula como:
$$O = \left\lfloor \frac{I + 2p - k'}{s} \right\rfloor + 1 = \left\lfloor \frac{I + 2p - d(k - 1) - 1}{s} \right\rfloor + 1$$
Aquí, el `stride` submuestra la resolución avanzando el kernel $s$ píxeles por paso, el `padding` añade píxeles de borde virtuales para preservar o ajustar las dimensiones espaciales, y la `dilation` expande la huella del filtro sin añadir parámetros extra.
2. **Campo Receptivo (RF)**: El campo receptivo teórico describe la extensión espacial en la imagen de entrada que influye en una activación particular. A través de capas apiladas, el campo receptivo $RF_l$ y el `stride` acumulativo (salto $j_l$) se actualizan recursivamente:
* Salto: $j_l = j_{l-1} \cdot s_l$, con $j_0 = 1$
* Campo Receptivo: $RF_l = RF_{l-1} + (k'_l - 1) \cdot j_{l-1}$, con $RF_0 = 1$
Los `strides` y el `pooling` expanden el campo receptivo multiplicativamente a través de la profundidad porque los pasos del kernel de capas subsiguientes corresponden a saltos de píxeles más grandes en el espacio de coordenadas de entrada original. La `dilation` expande el campo receptivo aditivamente dentro de una sola capa al aumentar $k'_l$ sin submuestreo espacial.
9¿Cómo se corresponde un núcleo de convolución con un filtro de imagen lineal clásico, y cuándo se puede hacer que un filtro 2D sea separable?
En el procesamiento clásico de señales e imágenes lineales, un núcleo de convolución representa la respuesta impulsional espacial (función de dispersión de punto) de un sistema Lineal Invariante en el Espacio (LSI). La aplicación del núcleo es una operación de filtrado lineal en el dominio espacial que da forma a la respuesta en frecuencia de la imagen (su transformada de Fourier 2D). Los núcleos pasabajos (por ejemplo, Gaussiano, desenfoque de caja) atenúan las altas frecuencias espaciales para suprimir el ruido y suavizar las texturas, mientras que los núcleos pasabajos o pasabanda (por ejemplo, Sobel, Laplaciano, Prewitt) amplifican las altas frecuencias para detectar bordes y gradientes. Un núcleo de filtro 2D $K \in \mathbb{R}^{M \times N}$ es espacialmente separable si se puede descomponer en el producto exterior de dos filtros 1D: $K = u \cdot v^T$, donde $u \in \mathbb{R}^{M \times 1}$ y $v \in \mathbb{R}^{N \times 1}$. En términos de álgebra lineal, una matriz 2D es separable si y solo si su rango de matriz es 1. Esto se puede verificar mediante la Descomposición en Valores Singulares (SVD), donde exactamente un valor singular es distinto de cero ($\sigma_1 > 0, \sigma_2 = \dots = 0$). La separabilidad reduce significativamente la complejidad computacional. Aplicar un núcleo $K \times K$ no separable a una imagen $H \times W$ requiere $O(H \cdot W \cdot K^2)$ multiplicaciones y adiciones. Cuando se descompone en dos pasadas 1D consecutivas (horizontal y luego vertical), la complejidad se reduce a $O(H \cdot W \cdot 2K)$. Para un núcleo de $15 \times 15$, esto proporciona aproximadamente una aceleración de $7.5\times$.
10¿Cómo cambian el redimensionamiento, el recorte central, el recorte aleatorio redimensionado, el estiramiento y el letterboxing la distribución de entrada?
Las diferentes estrategias de redimensionamiento y recorte cambian la distribución de los datos de entrada en cuanto a geometría, escala, cobertura de contenido y límites espaciales: 1. **Redimensionamiento Directo (Estiramiento/Comprimir):** Reajusta la imagen de forma no isotrópica a una dimensión objetivo $(H, W)$, distorsionando las relaciones de aspecto originales. Esto obliga al modelo a procesar formas de objetos deformadas (por ejemplo, los objetos circulares se convierten en elipses alargadas). 2. **Recorte Central (Center Cropping):** Extrae un recorte central de tamaño o proporción fijos. Preserva la relación de aspecto nativa y la escala local, pero introduce un fuerte sesgo central (asumiendo que los objetos objetivo están encuadrados centralmente) y descarta el contexto periférico o corta objetos posicionados en los bordes. 3. **Recorte Aleatorio Redimensionado (Random-Resized Cropping, RRC):** Extrae subregiones aleatorias en diversas escalas de área y relaciones de aspecto, y luego las redimensiona a una dimensión fija. Esto amplía la distribución de la escala de entrenamiento y fomenta el aprendizaje de características basado en partes, pero los recortes extremos pueden excluir el objeto objetivo por completo. 4. **Letterboxing (Redimensionamiento Isotropico con Relleno):** Escala la imagen uniformemente hasta que su dimensión más larga encaja en el tamaño objetivo, luego rellena los bordes restantes con un valor constante. Mantiene las proporciones y relaciones de aspecto reales del objeto, pero introduce bordes artificiales de alto contraste y píxeles de relleno no informativos.
11¿Qué modos de ruido de anotación ocurren en los conjuntos de datos de visión y cómo los detectarías o mitigarías?
Los conjuntos de datos de visión por computadora exhiben comúnmente cuatro modos principales de ruido en la anotación:
1. **Ruido en la Etiqueta Categórica**: Una imagen u objeto se le asigna la etiqueta de clase incorrecta (por ejemplo, clasificar erróneamente un gato como un perro, o confundir clases sutiles de grano fino).
2. **Anotaciones Faltantes (Ruido por Omisión)**: Objetos válidos en primer plano se dejan sin anotar. En la detección de objetos, los objetivos omitidos se tratan como negativos de fondo, penalizando directamente las detecciones correctas del modelo durante el entrenamiento.
3. **Jitter de Caja Delimitadora / Punto Clave (Ruido de Localización)**: Coordenadas de la caja delimitadora y ubicaciones de puntos clave imprecisas, sueltas o desplazadas, causadas por inconsistencia del anotador humano.
4. **Ambigüedad del Contorno de la Máscara**: Contornos de segmentación inconsistentes o gruesos a lo largo de límites complejos o borrosos (por ejemplo, cabello, superficies semitransparentes, desenfoque de movimiento).
**Estrategias de Detección y Mitigación:**
- **Seguimiento de Valores Atípicos en la Pérdida y Aprendizaje Confiable**: El seguimiento de la pérdida de la muestra a través de las épocas de entrenamiento identifica valores atípicos persistentes de alta pérdida, que a menudo indican instancias mal etiquetadas u omitidas. Algoritmos como el Aprendizaje Confiable (_Confident Learning_) estiman las distribuciones de ruido para podar o corregir errores.
- **Discrepancias de Predicción Fuera de la Carpeta (OOF - _Out-of-Fold_)**: Entrenar modelos de validación cruzada y comparar las predicciones de la muestra de retención (_holdout_) con la verdad fundamental (_ground truth_) resalta imágenes mal etiquetadas y cajas delimitadoras faltantes.
- **Acuerdo Inter-Anotador (IAA) y Adjudicación**: Medir métricas como la Kappa de Cohen (clasificación) o la Intersection-over-Union (IoU) media (localización) entre múltiples anotadores señala muestras de bajo acuerdo para su revisión por consenso.
- **Formulaciones de Pérdida Robustas**: Usar suavizado de etiquetas (_label smoothing_), pérdidas de clasificación tolerantes al ruido o pérdidas de regresión robustas basadas en IoU reduce la sensibilidad al _jitter_ y el etiquetado erróneo.
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¿Cómo afecta el desequilibrio de clases al entrenamiento de clasificación, detección y predicción densa de imágenes?
El desequilibrio de clases afecta las dinámicas de optimización y los paisajes de pérdida en las tareas de visión: 1. **Clasificación de imágenes:** Cuando las clases mayoritarias superan en número a las minoritarias, la minimización del riesgo empírico hace que las actualizaciones de los parámetros estén dominadas por los gradientes de las clases mayoritarias. El modelo aprende la probabilidad a priori empírica de clase $P(Y)$ y sesga su límite de decisión en contra de las clases raras. Esto produce una alta precisión top-1 general, pero sufre un colapso severo de la exhaustividad (recall) para las clases minoritarias. 2. **Detección de objetos:** - *Desequilibrio entre primer plano y fondo:* En los detectores densos de una sola etapa y basados en anclas, se evalúan cientos de miles de ubicaciones candidatas por imagen, donde >99% son de fondo. Incluso si las anclas de fondo individuales fáciles producen pequeñas pérdidas, su vasto gradiente agregado ahoga las señales de gradiente informativas de los objetos dispersos en primer plano. - *Desequilibrio de clases en primer plano:* Las categorías de objetos comunes aparecen con órdenes de magnitud más frecuencia que las categorías raras, lo que reduce el tamaño efectivo de la muestra y la señal de aprendizaje para las clases raras. 3. **Predicción densa (Segmentación):** El desequilibrio a nivel de píxel es severo porque las grandes clases de fondo y de 'relleno' (por ejemplo, carretera, cielo) ocupan millones de píxeles, mientras que las clases de 'objetos' pequeños (por ejemplo, señales de tráfico, peatones) pueden ocupar menos del 0,1% de los píxeles de la imagen. La pérdida de entropía cruzada estándar por píxel está dominada por las clases de área grande, lo que lleva a la subsegmentación o a la desaparición completa de estructuras pequeñas y delgadas.
13¿Cómo depuraría la presencia de NaN o una pérdida inestable durante el entrenamiento de visión distribuido a gran escala?
Depurar la presencia de NaN o la inestabilidad de la pérdida en el entrenamiento de visión a gran escala con Distributed Data Parallel (DDP) requiere aislar si la causa raíz se origina en datos de entrada defectuosos, desbordamiento numérico por exceso o por defecto (overflow/underflow) en precisión mixta (AMP), o inestabilidades de optimización entre workers. En primer lugar, capture entradas, semillas y configuraciones reproducibles y añada enlaces de diagnóstico (la detección de anomalías por sí misma no hace que la ejecución sea determinista): active la detección de anomalías (`torch.autograd.set_detect_anomaly(True)`), registre enlaces (hooks) de gradiente y activación para capturar la capa exacta donde aparecen los NaN, y añada una validación estricta de datos en el DataLoader (asegurando valores finitos, verificando que no haya imágenes corruptas de 0 bytes, cuadros delimitadores vacíos o divisores de normalización con varianza cero). El registro a nivel de minilote debe rastrear la pérdida por rango, los URI de entrada, la norma del gradiente antes del recorte y los factores de escala de GradScaler. En segundo lugar, inspeccione la precisión mixta automática (Automatic Mixed Precision, AMP) y el escalado dinámico de pérdida: en FP16, los gradientes grandes se desbordan fácilmente (`> 65504`), lo que provoca que GradScaler descarte actualizaciones no válidas y reduzca su escala según su factor de reducción configurado. El colapso persistente de la escala es un síntoma que se debe investigar, no una convergencia normal a cero; cambiar las operaciones inestables (por ejemplo, softmax, LayerNorm, exponentes de pérdida focal o denominadores de IoU de cuadros delimitadores) a FP32 o adoptar BF16 (que coincide con el rango dinámico de FP32) normalmente estabiliza el entrenamiento. Por último, compruebe los problemas específicos de DDP, como las operaciones all-reduce que propagan NaN de un solo worker a todos los rangos, el escalado del calentamiento (warmup) de la tasa de aprendizaje (por ejemplo, la regla de escalado lineal con tamaños de lote globales grandes) y el recorte de gradientes tras desescalar los gradientes de AMP. Las anotaciones vacías pueden ser negativos válidos, por lo que deben validarse frente al contrato de la tarea en lugar de rechazar cada imagen vacía.
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¿Cómo diseñaría un componente de estabilización digital de video en línea para una cámara con fluctuación de fotogramas?
Estime un movimiento intercuadro robusto a partir de esquinas rastreadas o descriptores emparejados, descartando el movimiento en primer plano y seleccionando un modelo adecuado de traslación, similitud, afín u homografía. Defina explícitamente las direcciones de transformación: con vectores columna y H_t mapeando las coordenadas del fotograma t-1 al fotograma t, la trayectoria de referencia a actual es P_t = H_t * P_{t-1}. Suavice esa trayectoria a S_t mediante un filtro causal o una ventana acotada de anticipación (lookahead), con un manejo adecuado de rotaciones y transformaciones en lugar de un promedio arbitrario de las entradas de la matriz. La corrección hacia adelante que mapea las coordenadas del fotograma actual al fotograma estabilizado es C_t = S_t * inverse(P_t); pase la transformación o su inversa de acuerdo con la convención de muestreo de la API de deformación (warp). Acote el recorte/zoom y la fuerza de estabilización para manejar bordes no válidos; reinicie o recupere ante la pérdida de seguimiento y cortes de escena. El paralaje fuerte y el obturador rodante (rolling shutter) pueden requerir modelos de movimiento más complejos o asistencia inercial. Una implementación estrictamente causal no utiliza fotogramas futuros; cada fotograma de anticipación añade latencia de captura, por lo que la política de almacenamiento en búfer y recorte debe elegirse a partir de la calidad de salida medida y los requisitos de latencia.
15¿Cómo optimizaría una canalización de visión en tiempo real cuando el detector es más lento que la tasa de fotogramas objetivo?
Cuando un detector de objetos no puede mantener la tasa de fotogramas objetivo (por ejemplo, ejecutándose a 15-20 FPS en una transmisión de video de 60 FPS), una arquitectura de producción robusta desacopla la detección del bucle de presentación en tiempo real utilizando una canalización multihilo asíncrona que combina una detección pesada con un seguimiento ligero. En esta arquitectura híbrida, un hilo de ingesta captura fotogramas de video continuamente. El detector pesado se ejecuta asíncronamente como un «detector de fotogramas clave» (keyframe detector) en un hilo de trabajo en segundo plano. Mientras tanto, un rastreador ligero (como el flujo óptico de Lucas-Kanade o un filtro de correlación, opcionalmente combinado con predicción de Kalman) se ejecuta sincrónicamente en cada fotograma a 60 FPS completos, manteniendo el estado predicho del objeto entre las actualizaciones del detector. ByteTrack/BoT-SORT son sistemas de seguimiento por detección (tracking-by-detection): sin nuevas detecciones necesitan una política explícita de predicción/seguimiento visual, y se deben monitorizar la antigüedad de la traza, la incertidumbre y la recuperación (recall) de nuevos objetos. Para gestionar el retardo y la contrapresión sin introducir latencia ilimitada o fotogramas obsoletos, se utilizan búferes circulares acotados y políticas de descarte que conservan el fotograma más reciente y eliminan los obsoletos. Cuando el detector termina un fotograma T_0 en el instante T_curr, su salida está desactualizada. La canalización realiza una realineación/retroproyección de coordenadas: asocia los resultados de detección demorados con el estado histórico del tracklet en T_0, actualiza identidades y trazas perdidas, y propaga las correcciones hacia adelante hasta T_curr mediante los vectores de movimiento del seguimiento o pasos de predicción del filtro de Kalman.
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)