NeuralBottlesCBN es un pipeline de visión artificial de alto rendimiento diseñado para el control de calidad en líneas de empaque de la Cervecería Boliviana Nacional (CBN). Su objetivo singular es la validación binaria ("pasa/no pasa") de casilleros de 12 botellas, determinando su completitud mediante arquitecturas de detección de objetos (YOLO).
Este repositorio está arquitectónicamente dividido para aislar el entorno de entrenamiento profundo (basado en Python/PyTorch) del motor de inferencia determinista (basado en C++/OpenVINO), garantizando una ejecución óptima y de baja latencia sobre hardware industrial heredado (Legacy Edge Computing).
Cambios recientes relevantes:
El nodo de inferencia final está sujeto a restricciones computacionales severas que dictan la arquitectura de este repositorio:
- Procesador: Intel Celeron J1900 (Microarquitectura Silvermont, 4 núcleos @ 2.41 GHz).
- Limitaciones Críticas: Ausencia total de instrucciones vectoriales AVX/AVX2/AVX-512. Soporte máximo para SSE4.2.
La arquitectura del repositorio segrega las responsabilidades lógicas y procedimentales:
NeuralBottlesCBN/
├── ws_py/ # Entorno de Entrenamiento y Cuantización (Python)
│ ├── train.py # Script de entrenamiento de arquitectura YOLO
│ └── export_int8.py # Congelación de grafo y conversión a OpenVINO IR (.xml / .bin)
├── ws_cpp/ # Entorno de Inferencia y Despliegue (C++)
│ ├── CMakeLists.txt # Manifiesto de compilación (OpenCV, OpenVINO, ImGui, GLFW)
│ ├── config/ # Configuraciones YAML y layouts de ImGui (imgui.ini)
│ ├── src/ # Fuentes C++ (laboratorio_cbn.cpp, pipeline.cpp)
│ ├── include/ # Cabeceras C++ (pipeline.h)
│ ├── test/ # Scripts de validación de hardware
│ └── models/ # Directorio receptor para la Representación Intermedia INT8
├── docker-compose.yaml # Orquestador local para compilación y desarrollo
└── Dockerfile # Receta multi-etapa para compilación C++ y despliegue
El flujo de Machine Learning se ejecuta estrictamente dentro del contenedor cbn_train, el cual empaqueta PyTorch, Ultralytics (YOLO) y las herramientas de OpenVINO en un entorno Debian aislado. ¡No instales dependencias localmente!
El contenedor soporta tres backends de aceleración. Selecciona el que corresponda a tu hardware editando GPU_BACKEND en docker-compose.yaml o pasándolo como build arg:
# AMD ROCm (RX 580, Vega, RDNA) — default en docker-compose.yaml
podman-compose build --build-arg GPU_BACKEND=rocm cbn_train
# NVIDIA CUDA (GTX/RTX)
podman-compose build --build-arg GPU_BACKEND=cuda cbn_train
# CPU solamente (sin GPU)
podman-compose build --build-arg GPU_BACKEND=cpu cbn_train
⚠️ Nota AMD RX 580: Esta GPU (gfx803) es hardware legacy para ROCm. Se usaHSA_OVERRIDE_GFX_VERSION=8.0.3para forzar compatibilidad. Para GPUs Vega/RDNA más nuevas, esta variable no es necesaria.
⚠️ Nota NVIDIA: Requierenvidia-container-toolkitinstalado y CDI generado:sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml. Además, descomentar la sección NVIDIA endocker-compose.yaml.
-
Construir el entorno de entrenamiento:
podman-compose build cbn_train
-
Verificar detección de GPU:
podman-compose run --rm cbn_train python3 test/test_env.py
-
Preparar y Aumentar el Dataset: Toma las imágenes de la cámara (crudos + txt), hace un split de entrenamiento/validación y genera el YAML. El flag
--offline-augaplica transformaciones extremas (blur, ruido, giros) simulando el entorno de la fábrica.podman-compose run --rm cbn_train python3 prepare_dataset.py --input-dir dataset/lote_1 --offline-aug
-
Ejecutar el Entrenamiento: Inicia el ajuste fino de la arquitectura YOLO. La GPU se detecta automáticamente (
--device autoes el default).podman-compose run --rm cbn_train python3 train.py --data dataset/lote_1_done/cbn_dataset.yaml --epochs 50 --batch 16
-
Exportar y Cuantizar a Producción (OpenVINO INT8): Toma los mejores pesos del entrenamiento (
best.pt), los cuantiza a enteros de 8-bits para máxima aceleración en el procesador Celeron J1900, y auto-copia el modelo resultante a la carpeta C++ (ws_cpp/models/).podman-compose run --rm cbn_train python3 export_int8.py --data dataset/lote_1_done/cbn_dataset.yaml
El entorno C++ local (cbn_test_cpp) integra una interfaz gráfica basada en Dear ImGui para configurar parámetros, inspeccionar visualmente los casilleros de botellas y operar las cámaras en tiempo real.
Debido a que el contenedor debe comunicarse con la pantalla principal, es obligatorio habilitar el acceso al servidor gráfico X11 antes de arrancarlo.
-
Permitir la conexión de la interfaz gráfica local:
xhost +local:
-
Construir la imagen de contenedor C++:
podman-compose build cbn_test_cpp
-
Lanzar la interfaz visual (Laboratorio CBN):
podman-compose run --rm cbn_test_cpp
-
Probar el nodo de inferencia puro (solo modelo):
podman-compose run --rm cbn_test_cpp /bin/bash -lc "cd build && cmake .. -G Ninja && ninja cbn_inference_node && cd .. && ./build/cbn_inference_node" -
Ejecutar la Inferencia Principal con la lógica de negocio (Botellas y Casilleros): Este comando compilará (vía Ninja por velocidad extrema) el binario final
mainy lo ejecutará, abriendo la cámara y aplicando la validación (PASA/RECHAZADO) si se detectan los 12 espacios:podman-compose run --rm cbn_test_cpp /bin/bash -lc "cd build && cmake .. -G Ninja && ninja main && ./main --show"
Nota: En caso de fallos de descarga al compilar (DNS en Podman), el contenedor usa por defecto
network_mode: hostpara resolver conexiones.
El entorno final se compila utilizando un método de cross-compiling optimizado para el procesador Celeron J1900. No se necesitan compiladores en la máquina destino.
Este comando compila el binario con soporte SSE4.2 y lo aísla en una micro-imagen limpia:
podman build --target edge_runtime -t localhost/neuralbottles_edge:latest .Luego, empaqueta la imagen para transferirla a un USB/red:
podman save -o neuralbottles_edge.tar localhost/neuralbottles_edge:latestTransfiere el .tar, la carpeta ws_cpp/models y ws_cpp/config al equipo final, y carga la imagen:
podman load -i neuralbottles_edge.tarFinalmente, levanta el contenedor mapeando la cámara industrial y los modelos. Podman debe correr como tu usuario normal, pero se elimina el cambio de usuario interno para no perder el mapeo de permisos de /dev/video0:
podman run -d \
--name neuralbottles_inference \
--device /dev/video0:/dev/video0 \
--group-add video \
-v ./ws_cpp/models:/app/models:ro \
-v ./ws_cpp/config:/app/config:ro \
--restart unless-stopped \
localhost/neuralbottles_edge:latestPara consultar detalles a fondo sobre resolución de problemas (Gaps resueltos) y decisiones arquitectónicas, revisa el archivo context.md.
Hallazgos principales:
- Throttle único de captura: La única fuente de verdad para el control de tasa de captura es
capture_interval_msenws_cpp/src/cbn_camera.cpp. El pipeline descarta buffers en cámara si el intervalo no ha transcurrido. - Redimensionado único: La tubería está diseñada para realizar un solo
resizeal tamaño de entrada del modelo.ws_cpp/src/pipeline.cppefectúa el resize yws_cpp/src/cbn_detector_inference.cppevita re-redimensionar si la imagen ya tiene el tamaño del modelo. - Operaciones costosas detectadas (y su ubicación):
- Compresión JPEG en vivo:
ws_cpp/src/cbn_web_server.cppusacv::imencode()con un throttle a ~5 FPS (200 ms). Esto es intencional para ahorrar CPU en presencia de clientes web. - Non-Maximum Suppression (NMS):
ws_cpp/src/cbn_detector_inference.cppinvocacv::dnn::NMSBoxes()una vez por inferencia (sync y async paths). Es costosa pero necesaria para eliminar duplicados. - Escritura de imágenes (
cv::imwrite) usada en modos laboratorio/depuración (ws_cpp/src/laboratorio_cbn.cpp,ws_cpp/src/pipeline.cpp) — no forma parte del flujo de producción.
- Compresión JPEG en vivo:
- Usos de sleep intencionales: Varias rutas de prueba y simulación usan
std::this_thread::sleep_for()(tests, simuladores y el servidor web). En producción, solocbn_camera.cppaplica el throttling de captura; los sleeps en test/lab son esperados.
Recomendaciones inmediatas:
- Re-exportar el IR a una resolución menor (ej. 384×384 o 320×320) y preferiblemente FP16 o INT8 calibrado para reducir la latencia de inferencia en el J1900.
- Ejecutar
benchmark_appde OpenVINO sobrews_cpp/models/cbn_model.xmlpara validar latencias y probar-nstreams/-nireq. - Si la carga por compresión JPEG sigue siendo un problema, mover
cv::imencode()a un hilo consumidor dedicado o reducir la calidad JPEG aún más.
Archivos clave revisados (puntos de interés):
ws_cpp/src/cbn_camera.cppws_cpp/src/pipeline.cppws_cpp/src/cbn_detector_inference.cppws_cpp/src/cbn_web_server.cpp
Si quieres que ejecute la exportación del modelo a FP16/384 o prepare un benchmark_app con flags recomendados, indícame y lo preparo.