Skill de Microservice d'Inférence DeepStream SOP
Cette compétence guide les assistants de codage IA dans la construction, l'extension et le débogage du Microservice d'Inférence DeepStream SOP (Standard Operating Procedure) NVIDIA — un pipeline accéléré par GPU pour la détection d'actions temporelles et la surveillance de conformité SOP basée sur VLM sur des flux vidéo industriels.
Référence de dépôt : https://github.com/NVIDIA/sop-monitoring-blueprints/tree/main/microservices/sop-inference-bp
Code de référence local : répertoire sop-inference-bp/ (à partir d'un clone local du dépôt)
Modèles
Agnostique aux modèles aux deux étapes d'inférence — permutable via variable d'environnement (et répertoire Triton pour GEBD).
| Étape | Rôle | Classe de modèle | Par défaut | Permutable via |
|---|---|---|---|---|
| Étape 1 (CV) | Scoring de limites par image → segmentation par chunk | Generic Event Boundary Detection (GEBD) | DDM (MCG-NJU/DDM) via backend Python Triton | Remplacer triton_model_repo/<model>/ + DDM_MODEL_PATH (§ 5) |
| Étape 3 (VLM) | Classification d'actions par chunk | Vision-language model via vLLM | Cosmos Reason 1 7B (Reason 2 également supporté) | Définir VLLM_MODEL_PATH à un ID HF différent ou chemin local |
« GEBD » = slot Étape-1 permutable ; « DDM » = l'architecture par défaut (termes utilisés de manière interchangeable).
Le chunking est sélectionnable par requête (§ 2) : le ddm-net par défaut utilise GEBD ; uniform produit des chunks de longueur fixe et contourne l'Étape-1 GEBD (§ 3, § 6). La fenêtre temporelle DDM est configurable via FRAMES_PER_SIDE / SEQUENCE_BATCH (§ 4, § 5), avec TensorRT optionnel (§ 5).
Aperçu de l'Architecture
S'exécute dans un conteneur Docker (nvds-action-sop) aux côtés d'un conteneur Kafka. Diagramme complet : references/sop_architecture.svg.
Flux de données à travers le pipeline SOPVideoProcessor en 4 étapes (par requête) :
Sources d'entrée Conteneur Docker : nvds-action-sop
───────────────── ──────────────────────────────────────────────────
Fichiers vidéo ─┐ Serveur FastAPI (port 8300)
Flux RTSP ──────┤── base64/ ├─ /v1/chat/completions → SOPProcessManager
Caméra Basler ──┘ fichier/ │
rtsp/ │ ModelInitializer : VLM d'abord, puis pipeline DDM fictif
caméra │ 4 pools de threads : cv(32), clip(32), vlm(64), vlm_req(64)
│
▼ SOPVideoProcessor (par requête)
┌────────────────────────────────────────────────┐
│ Étape 1 : Pipeline DeepStream (GPU) │
│ Source → nvstreammux → tee1 │
│ ├─[inference] queue1 → nvdspreprocess │
│ │ → nvinferserver (Triton CAPI + DDM) │
│ │ → InferOutputTensorParser → score_queue │
│ ├─[frames] queue3 → nvvideoconvert │
│ │ → capsfilter → appsink │
│ │ → DecodedFrameRetriever → frame_queue │
│ └─[RTSP out] queue → convert → enc H.264 │ (optionnel, § 18)
│ → rtppay → udpsink → RTSPServer (§ 18) │ opt-in uniquement
│ │ scores de limites │
│ ▼ │
│ Étape 2 : Post-traitement Clip │
│ Détection de limites → segmentation chunk │
│ │ images vidéo + timestamps │
│ ▼ │
│ Étape 3 : Inférence VLM │
│ VLM embarqué (Cosmos Reason 1/2) │
│ Échantillonnage d'images à VLM_FPS → classif │
│ │ étiquettes d'actions │
│ ▼ │
│ Étape 4 : Vérificateur SOP │
│ Validation de séquence → manquantes/mal ord. │
│ │ résultats chunk │
│ ▼ │
│ final_queue │
└────────────────────────────────────────────────┘
│
Sortie ▼
────── ┌─────────────────┐
Flux SSE (chat.completion.chunk) │ Messages Kafka │
Sans streaming (chat.completion) │ (JSON/Protobuf) │
Métriques Prometheus (/v1/metrics) └────────┬────────┘
▼
Conteneur Docker : kafka
(apache/kafka:3.7.0)
Index des Sections
Chaque section est un fichier autonome dans references/ — charger uniquement ce que votre tâche nécessite.
| § | Fichier | Responsabilité |
|---|---|---|
| 1 | skill_01_fastapi_endpoints.md |
Points d'accès FastAPI, init serveur, métriques Prometheus |
| 2 | skill_02_pydantic_schemas.md |
Modèles Pydantic requête/réponse (api_types.py) |
| 3 | skill_03_deepstream_pipeline.md |
Pipeline DeepStream pyservicemaker, analyseur tensor, pipeline fictif |
| 4 | skill_04_config_templates.md |
Modèles de config nvdspreprocess / nvinferserver + rendu |
| 5 | skill_05_triton_ddm_model.md |
Dépôt de modèle Triton, config.pbtxt, model.py, ddm_net.py |
| 5b | skill_05b_custom_postprocess.md |
Plugin post-traitement C++, Makefile, API IOptions |
| 6 | skill_06_sop_process_manager.md |
SOPProcessManager, SOPVideoProcessor, VLLMInference, Kafka |
| 6b | skill_06b_sop_checker.md |
Conformité vérificateur SOP et séquence : MissingNumberDetector, SopCheckerCache, SopCheckerRequest/Response |
| 7 | skill_07_sse_streaming.md |
Générateur SSE, formatage de réponse de flux, mode test fictif |
| 8 | skill_08_basler_camera.md |
Support caméra Basler, SDK Pylon, émulation, formats |
| 9 | skill_09_docker_build_deploy.md |
Build Docker, déploiement, configuration .env |
| 10 | skill_10_test_suite.md |
Couverture de suite de tests, assertions, exécution des tests |
| 11 | skill_11_env_variables.md |
Référence de toutes les variables d'environnement |
| 12 | skill_12_evaluation_workflow.md |
Flux d'éval de bout en bout : vérifications statiques, build, lancement, tests, vérifications API/caméra/Kafka, rapport |
| 13 | skill_13_verification_curl.md |
Étapes de vérification et exemples curl |
| 14 | skill_14_implementation_checklist.md |
Liste de contrôle d'implémentation : liste de copie de fichiers, fichiers générés, prérequis Docker, vérification |
| 15 | skill_15_latency_measurement.md |
Mesure de latence TTFC et C2C pour entrée fichier via streaming SSE |
| 16 | skill_16_message_schema.md |
Sélection de schéma de message Kafka (JSON par défaut vs NvProtoSchema) et extension de messages avec données personnalisées |
| 17 | skill_17_camera_latency_measurement.md |
Mesure de latence caméra / flux en direct chunk_e2e utilisant les timestamps internes du pipeline |
| 18 | skill_18_rtsp_streaming_output.md |
OPT-IN Sortie streaming RTSP : re-diffusion tap tee1, RTSPStreamingServer, basculement SW_ENCODER. Générer uniquement quand l'utilisateur demande explicitement RTSP |
Pour l'évaluation de bout en bout, lire d'abord § 12 ; charger build/test/curl/latency/camera/Kafka au besoin.
§ 18 est opt-in — générer uniquement quand l'utilisateur demande explicitement la sortie RTSP ; sinon ignorer § 18 et les règles RTSP_* ci-dessous.
Cartographie des Fichiers Clés
La cartographie complète source-vers-cible se trouve dans
skill_14_implementation_checklist.md :
- Fichiers copiés textuellement depuis
references/(algorithmes non triviaux — détection de cycles, prétraitement qwen_vl_utils, API DeepStreamIOptions, sources protobuf) avec la justification par fichier. - Fichiers copiés comme modèles adaptables (Dockerfile, compose.yaml, config Triton et
model.py,ddm_net.py, config émulation Pylon, etc.). - Fichiers générés à partir des sections de compétence — chacun annoté avec les règles critiques ci-dessous que la génération doit suivre exactement.
Les fichiers de config (nvds_preprocess_template.txt, nvds_inference_template.txt,
vlm_prompts.txt) sont utilisés tels quels depuis configs/.
Quand skill_06b est chargée, lire configs/actions.json depuis la racine du projet et exécuter le flux de génération § 6b-G pour produire nvds_action_detector/missing_number_detector.py.
Si configs/actions.json est absent ou invalide, revenir à copier le fichier de référence.
Règles Critiques
Le détail complet de chaque règle se trouve dans le fichier de référence
skill_NN_*.mdlié.
| Tag | Résumé de règle | Détails dans |
|---|---|---|
MANAGER_INIT_IN_MAIN |
Init SOPProcessManager dans main() avant uvicorn.run() — pas dans lifespan() |
skill_01_fastapi_endpoints.md |
NAMED_KWARGS |
create_video_processor() utilise des kwargs nommés ; args caméra comme kwargs séparés |
skill_06_sop_process_manager.md |
LIVE_REQUIRES_STREAM_TRUE |
stream: true requis pour entrées en direct (RTSP / caméra) |
skill_08_basler_camera.md |
VLM_DISABLED_DISABLES_SOP_CHECKER |
DISABLE_VLM_INFERENCE=true désactive automatiquement le vérificateur SOP à l'import |
skill_06_sop_process_manager.md |
CHUNK_PARAMS_MAX_LENGTH |
ChunkParams.max_length_sec = 10s interne ; 60s par défaut API |
skill_06_sop_process_manager.md |
VLM_WARMUP_BEFORE_DDM |
ModelInitializer : warmup VLM EN PREMIER, puis pipeline CV fictif |
skill_06_sop_process_manager.md |
VLM_WARMUP_3_FRAMES |
Warmup VLM nécessite 3 images (torch.zeros) — Qwen3VL se bloque sur < 3 |
skill_06_sop_process_manager.md |
THREAD_POOL_SIZES |
4 pools de threads : cv(32), clip(32), vlm_inference(64), vlm_request(64) |
skill_06_sop_process_manager.md |
MEDIA_INFO_PYMEDIAINFO |
Info média via pymediainfo ; sources en direct définissent fps=30/duration=inf directement |
skill_06_sop_process_manager.md |
CAMERA_EMULATION_PYLON_CAMEMU |
PYLON_CAMEMU=1 pour émulation caméra (serial 0815-0000) |
skill_08_basler_camera.md |
DEEPSTREAM_LIB_HIDE |
Astuce masquage lib DeepStream : renommer lib → lib.tmp pendant build gst-plugin-pylon | skill_08_basler_camera.md |
VLM_REAL_GPU_FRAMES |
VLM utilise images GPU réelles via DecodedFrameRetriever ; jamais torch.zeros pour inférence |
skill_06_sop_process_manager.md |
BUFFER_RETRIEVER_STATIC_BASE |
DecodedFrameRetriever DOIT hériter BufferRetriever statiquement via super().__init__() ; mutation runtime __class__.__bases__ bloque pipeline.attach() |
skill_06_sop_process_manager.md |
FRAME_RETRIEVER_PRIORITY |
create_inference_pipeline : kwarg frame_retriever= a la priorité sur frame_queue |
skill_03_deepstream_pipeline.md |
MUX_ORIGINAL_RESOLUTION |
nvstreammux utilise résolution originale (pas 224) ; passer mux_width/mux_height depuis get_media_info() (prober RTSP en direct pour entrées non-caméra ; chemin caméra inaffecté) |
skill_03_deepstream_pipeline.md, skill_06_sop_process_manager.md |
FILE_URI_NO_DOUBLE_PREFIX |
Source fichier create_inference_pipeline : vérifier file_path.startswith("file://") avant préfixe — API passe URLs file:// directement |
skill_03_deepstream_pipeline.md |
CLEANUP_ON_DISCONNECT |
Nettoyage du pipeline sur déconnexion client via trigger_stop_processors dans try/finally |
skill_07_sse_streaming.md |
UNIFIED_CLIP_POST_PROCESS |
clip_post_process() unifié pour fichier + en direct ; stop() met None dans _score_queue |
skill_06_sop_process_manager.md |
ABORT_INFLIGHT_VLM |
Abandon des requêtes VLM en vol sur stop() via llm.abort(req_id) |
skill_06_sop_process_manager.md |
LOGGER_EXPORT_GET_LOGGER |
ds_logger.py doit exporter get_logger |
skill_06_sop_process_manager.md |
KAFKA_USE_CREATE_PRODUCER |
Kafka : utiliser create_producer() depuis messager.py ; pas de classe Messager |
skill_06_sop_process_manager.md |
USER_PROMPT_PRIORITY |
Le texte de la requête utilisateur a priorité sur fichier VLM_PROMPT_PATH ; {"type":"text"} dans la requête écrase le prompt du fichier de config |
skill_06_sop_process_manager.md |
EVAL_USE_CONFIG_PROMPT |
Requêtes eval/latency omettent le texte de requête par défaut pour que VLM utilise VLM_PROMPT_PATH |
skill_12_evaluation_workflow.md, skill_13_verification_curl.md, skill_15_latency_measurement.md, skill_17_camera_latency_measurement.md |
CHUNK_SCHEMA_FIELD_NAMES |
Schéma chunk : chunk_idx, cv_boundary_score, checker_result ; résumé chunk_idx=-1 |
skill_06_sop_process_manager.md |
SEQUENTIAL_FRAME_DRAIN |
Drainer decoded_frame_queue (FIFO, partagée entre chunks) dans UN SEUL thread et soumettre VLM par chunk de manière incrémentale ; drain parallèle vole les images → chunks 0-image / entrée VLM erronée |
skill_06_sop_process_manager.md |
WALL_CLOCK_BEFORE_GPU |
DecodedFrameRetriever.consume() : capturer wall_clock_entry = time.time() AVANT dlpack GPU ; queue 3-tuple (timestamp, wall_clock_entry, tensor) |
skill_06_sop_process_manager.md, skill_17_camera_latency_measurement.md |
CHUNK_E2E_PIPELINE_TIMESTAMPS |
Écrire pipeline_chunk_end_timestamp (wall_clock dernière image) et pipeline_vlm_ready_timestamp (tm_e2e.now()) dans chunk_info pour latence caméra (§ 17) |
skill_06_sop_process_manager.md, skill_17_camera_latency_measurement.md |
VLM_INFERENCE_REQUIRED_KWARGS |
Tout appel VLLMInference.inference() doit passer video_fps, system_prompt, max_completion_tokens |
skill_06_sop_process_manager.md |
UNIFORM_CHUNKING_BYPASSES_DDM |
chunking_options.algorithm="uniform" → chunks longueur fixe ; create_inference_pipeline(uniform_chunk=True) omet DDM mais garde fanout tee1 ; Étape 2 utilise uniform_clip_post_process |
skill_02_pydantic_schemas.md, skill_03_deepstream_pipeline.md, skill_06_sop_process_manager.md |
DDM_TEMPORAL_CONFIGURABLE |
SLIDING_WINDOWS_SIZE = 2*FRAMES_PER_SIDE + SEQUENCE_BATCH rendu dans preprocess/nvinferserver (pas hardcodé 18) ; dim séquence Triton config.pbtxt = -1 |
skill_04_config_templates.md, skill_05_triton_ddm_model.md |
DDM_TRT_OPTIONAL_PATH |
DDM_TRT_OPTIMIZATION=true exécute DDM via TensorRT (contextes par-thread, batch fixe = SEQUENCE_BATCH) ; fallback PyTorch ; jamais les deux. PyTorch par défaut |
skill_05_triton_ddm_model.md |
DDM_TRT_STREAM_ORDERING |
DDMTensorRTEngine.infer() : wait_stream(current) → execute_async_v3 → torch.cuda.synchronize(device) (PAS par-stream). Sync par-stream laisse travail stream-aux TRT en vol → gst-CV SIGSEGV (NVBug 6289256) |
skill_05_triton_ddm_model.md |
METADATA_LICENSE_FROM_FILE |
/v1/metadata lit licenseInfo depuis DS_SOP_LICENSE_PATH (défaut /opt/nvidia/nvds_sop/license.txt) ; jamais hardcoder texte licence |
skill_01_fastapi_endpoints.md |
CAMERA_EMULATION_FRAMES_RGB |
PNGs émulation Pylon doivent être explicitement 3-canaux RGB (correspond à Emulation_0815-0000.pfs PixelFormat=RGB8Packed) ; générer via nvvideoconvert ! videoconvert ! "video/x-raw,format=RGB" ! pngenc |
skill_08_basler_camera.md |
COMPOSE_ENV_PASSTHROUGH |
docker compose substitue uniquement références ${VAR} ; chaque var env runtime doit être explicitement listée sous environment: pour atteindre le conteneur. |
skill_09_docker_build_deploy.md |
Les quatre règles
RTSP_*ci-dessous s'appliquent uniquement quand la fonctionnalité optionnelle sortie streaming RTSP (§ 18) est demandée. Elles ne s'appliquent pas au build par défaut — les ignorer si l'utilisateur n'a pas demandé la sortie RTSP.
| RTSP_OUTPUT_TAPS_TEE1 | La branche sortie RTSP se lie depuis le tee1 existant (ajouté après le lien d'inférence principal) uniquement quand rtsp_port est présent. | skill_18_rtsp_streaming_output.md |
| RTSP_LEAKY_QUEUE_TINY | Queue branche RTSP doit avoir leaky=2 + cap minuscule (max-size-buffers=2) pour prévenir contre-pression et épuisement pool NVMM. | skill_18_rtsp_streaming_output.md |
| RTSP_KEYINT_MAX_30 | Encodeur H.264 RTSP doit définir key-int-max=30 (et B-frames désactivés) pour permettre recherche en aval. | skill_18_rtsp_streaming_output.md |
| RTSP_ENCODER_FALLBACK | Sélectionner encodeur H.264 logiciel/matériel basé sur SW_ENCODER avec fallback MJPEG. | skill_18_rtsp_streaming_output.md |