Zero-Host-Copy : faire tourner YOLOv8m à 165–215 FPS en sortant le CPU de la boucle critique
Quand les modèles INT8 s'exécutent en quelques millisecondes, ce n'est plus le calcul qui ralentit, mais tout ce qui l'entoure : copies d'images via PCIe et synchronisation cachée due à cudaMalloc. Les auteurs de l'analyse ont construit un pipeline bare-metal en C++/CUDA, sans DeepStream, où les images restent en mémoire GPU du décodeur à l'encodeur. YOLOv8m en 1024x1024 et INT8 atteint 165–215 FPS sur une RTX 3060 Ti et environ 38 FPS sur un Jetson Orin Nano Super.
Traité par IA depuis Хабр: Машинное обучение ; édité par Hamidun News
Vous avez optimisé votre modèle, vous l'avez quantifié en INT8, et l'inférence ne prend plus que quelques millisecondes. Pourtant, les FPS restent loin de ce que l'on attendait. L'histoire est classique : le goulot d'étranglement n'est pas l'unité de calcul, mais tout ce qui l'entoure. Une analyse publiée sur Habr montre comment y remédier concrètement.
Où les images se perdent réellement
Sur une carte graphique dédiée, chaque image haute résolution envoyée vers la mémoire vive puis renvoyée paie un tribut au bus PCIe. Si l'on fait en plus des allers-retours avec des résultats intermédiaires, par exemple les bounding boxes de la détection, la bande passante chute nettement. Plus le modèle est rapide, plus ce coût saute aux yeux : le calcul prend 2 ms, et la copie dure plus longtemps que le calcul lui-même.
L'idée de Zero-Host-Copy est simple : depuis la lecture sur disque et le décodage jusqu'à l'encodage final et l'écriture, les données restent en mémoire GPU. Seule la carte graphique les traite, et les copies GPU → CPU et inversement sont réduites au minimum. Le principe voisin du Zero-Copy consiste à transmettre entre les étapes du pipeline un pointeur vers le bloc de données, et non le bloc lui-même.
Le tueur silencieux : cudaMalloc
Le second problème est moins évident. Un appel à cudaMalloc entraîne une synchronisation implicite : le CPU doit attendre le GPU, et le pipeline asynchrone cesse de l'être. Un seul appel de ce type dans la boucle de traitement des images peut provoquer une chute de performances que le profileur présentera sous forme de pauses mystérieuses.
La solution est un cycle de vie en trois phases :
- Initialisation. L'application alloue à l'avance des pools de mémoire, des tampons et des files d'attente avec une profondeur initiale.
- Préchauffage. La file de traitement complète est lancée. Si des tampons supplémentaires sont nécessaires, le système les alloue à ce moment-là.
- Fonctionnement actif. Après les premières images, toute allocation dynamique est interdite : pas de cudaMalloc ni de new, uniquement la réutilisation des blocs déjà alloués.
C'est en somme une technique bien connue des moteurs de jeu et du traitement audio : on fait tout le travail lourd avant le démarrage, et dans la boucle critique on se contente de réutiliser.
Les résultats
L'auteur a implémenté un pipeline sans DeepStream, en C++/CUDA pur. YOLOv8m en résolution 1024x1024 et INT8 affiche environ 165–215 FPS sur une RTX 3060 Ti et près de 38 FPS sur un Jetson Orin Nano Super. Pour une plateforme embarquée, c'est un très bon résultat avec une telle taille d'entrée.
Limites et conclusion
Le prix de cette approche est la complexité. Un pipeline bare-metal exige une gestion manuelle des pools, de la synchronisation des flux et du cycle de vie des tampons. Une erreur de dimensionnement d'un pool provoquera un plantage ou une dégradation silencieuse en phase critique. La maintenance coûte plus cher qu'une solution fondée sur DeepStream ou un framework prêt à l'emploi. De plus, les chiffres ont été obtenus sur un modèle et un matériel précis, et l'article, d'après son annonce, ne compare pas cette approche aux piles existantes dans les mêmes conditions : il faut donc vérifier le gain sur vos propres données.
Conclusions pratiques pour ceux qui font de l'analyse vidéo ou travaillent avec des appareils edge :
- Avant d'optimiser davantage le modèle, mesurez le temps consacré aux copies et aux allocations.
- Repérez dans la boucle critique tous les cudaMalloc, new et synchronisations implicites, et déplacez-les vers l'initialisation.
- Concevez le pipeline pour que l'image ne quitte jamais le GPU : décodage matériel, prétraitement, inférence, post-traitement, encodage.
- Prévoyez une phase de préchauffage et vérifiez qu'aucune allocation n'a lieu après elle.
Quand le modèle est déjà rapide, le gain se trouve dans la rigueur d'ingénierie qui l'entoure. Pour le temps réel sur des flux vidéo, c'est souvent le moyen le moins coûteux d'obtenir un gain de FPS multiplié.
- 12 nov. 2026Jensen Huang quitte son poste de PDG de Nvidia : l’entreprise perd 1 400 milliards de dollars en deux semaines
- 12 nov. 2026Deux ingénieurs ont intégré SGLang à IBM Spyre en une semaine et multiplié le débit par 3,6
- 12 nov. 2026SpaceX remplace les câbles NVLink par une seule carte de 84 couches dans le rack Kessel pour l'IA
- 12 nov. 2026Alibaba prépare l'introduction en Bourse de sa division de puces T-Head à Hong Kong — un test pour l'IA chinoise
Questions clés sur cet article
Que sait-on sur Où les images se perdent réellement ?
Sur une carte graphique dédiée, chaque image haute résolution envoyée vers la mémoire vive puis renvoyée paie un tribut au bus PCIe. Si l'on fait en plus des allers-retours avec des résultats intermédiaires, par exemple les bounding boxes de la détection, la bande passante chute nettement. Plus le modèle est rapide, plus ce coût saute aux yeux : le calcul prend 2 ms, et la copie dure plus longtemps que le calcul lui-même.
Que sait-on sur Le tueur silencieux : cudaMalloc ?
Le second problème est moins évident. Un appel à cudaMalloc entraîne une synchronisation implicite : le CPU doit attendre le GPU, et le pipeline asynchrone cesse de l'être. Un seul appel de ce type dans la boucle de traitement des images peut provoquer une chute de performances que le profileur présentera sous forme de pauses mystérieuses. La solution est un cycle de vie en trois phases : Initialisation.
Que sait-on sur Les résultats ?
L'auteur a implémenté un pipeline sans DeepStream, en C++/CUDA pur. YOLOv8m en résolution 1024x1024 et INT8 affiche environ 165–215 FPS sur une RTX 3060 Ti et près de 38 FPS sur un Jetson Orin Nano Super. Pour une plateforme embarquée, c'est un très bon résultat avec une telle taille d'entrée.
Test Frontier LLMs & Autonomous Agents in One Workspace
Run Claude Opus 5.5, GPT-6, Gemini 3.1, and DeepSeek side-by-side in Nomad AI (nomadnet.ai) — unified model routing, deep research, and multimodal workflows under one subscription.
L'essentiel de l'IA — une fois par semaine
Sept actus qui ont vraiment compté, choisies à la main. Sans bruit ni communiqués.
C'est fait ! Vérifiez votre boîte mail pour la confirmation.