Das Problem an der üblichen Dimensionierung von Edge AI
Wer ein funktionierendes Modell auf ein Embedded-Modul gebracht hat, kennt den Moment. Auf der Workstation ist es genau und schnell. Auf dem Zielsystem passt es nicht, die Bildrate bleibt hinter dem zurück, was die Anwendung braucht, und das zweite Modell war ohnehin nie realistisch.
Das ist keine Grenze der Hardware. NVIDIA Jetson Module haben die Rechenleistung. Das Problem ist, dass der größte Teil des Software-Stacks darüber nie für ein festes Speicherbudget geschrieben wurde. Desktop-Frameworks setzen Page Cache, Swap und eine diskrete GPU mit eigenem Speicher voraus. Auf einem Jetson teilen sich CPU und GPU einen physischen Speicherpool, und jedes Byte, das ein Framework aus Bequemlichkeit hält, ist ein Byte, das dem neuronalen Netz fehlt.
Die übliche Antwort ist, das Modell zu verkleinern: eine kleinere Variante, INT8, Pruning, geringere Auflösung. Das funktioniert, und es geht schnell. Es verändert aber auch, was das Netz ausgibt. Damit muss das Wahrnehmungsmodell des Kunden neu getestet und in einer regulierten Domäne neu zertifiziert werden.
Wir sind den anderen Weg gegangen: Wir haben die Runtime neu gebaut, statt das Modell zu verkleinern.
Warum der Speicher selten im Modell steckt
Bevor man etwas optimiert, lohnt es sich zu wissen, was auf einem Jetson zur Inferenzzeit tatsächlich Speicher hält. Wir haben unseren eigenen Detektionsprozess vom Kaltstart bis in den eingeschwungenen Zustand instrumentiert und den residenten Speicher in jeder Stufe gemessen. Die Last ist ein einstufiger Detektor, 640x640 Eingabe, FP16 TensorRT Engine, 80 Klassen.
Lesen Sie die Zuwächse, denn sie stellen die ganze Diskussion neu auf.
Die FP16 Engine auf der Festplatte ist 21 MB groß. Sie auf INT8 zu quantisieren spart davon rund 10 MB, also unter zwei Prozent eines 538 MB großen Prozesses, im Tausch gegen eine Kalibrierungskampagne und ein Gespräch mit dem Kunden über Genauigkeit.
Die beiden großen Sprünge sind der CUDA-Kontext mit der hochfahrenden TensorRT Runtime (283 MB) und die Allokation beim Warmup (177 MB), in der Aktivierungsspeicher, Device-I/O-Puffer und die beim ersten Aufruf nachgeladenen CUDA-Module stecken. Die erste Zahl rührt Quantisierung überhaupt nicht an. Von der zweiten kann sie den Aktivierungsanteil verkleinern, nicht aber die Runtime-Module und nicht den Kontext, und in diesem Profil sind genau diese festen Kosten der größere Block. Sie werden kleiner, wenn Sie aufhören, ein zweites Framework darüber zu instanziieren, wenn Sie aufhören, pro Prozess einen eigenen CUDA-Kontext zu bezahlen, und wenn Sie aufhören, Puffer zu allokieren, die Sie nicht verwenden.
Genau dorthin ist unsere Entwicklungsarbeit gegangen.
Was wir gemessen haben
KINEVA ist eine native C++ Inferenz-Engine, rb_vision eine native C Video-Pipeline, beide von Grund auf für Jetson geschrieben. Alle folgenden Zahlen wurden auf dem oben genannten Modul erhoben, im vollen Power-Modus, mit tegrastats über die exakte Dauer jedes Laufs.
Eine vollständige Detektions-Pipeline in 501 MB
501 MB Spitzenwert an residentem Speicher für den gesamten Pfad, also CUDA-Kontext, TensorRT Runtime, Engine-Gewichte, Video-Dekodierung, Vorverarbeitung, Inferenz und NMS, bei 6,92 ms Inferenz pro Bild: 145 fps Inferenz-Durchsatz, 104 fps Ende zu Ende einschließlich H.264-Decode auf 720p Video. Der Kaltstart kostet 1,17 s Engine-Ladezeit plus 67 ms Warmup, einmalig.
Der Detektor-Output ist unverändert. Keine Quantisierung unter FP16, kein Pruning, keine Reduktion der Auflösung. Gegen die PyTorch-Referenz validiert, auf subpixelgenaue Boxen und drei Nachkommastellen der Konfidenz.
Kein Interpreter, kein ML-Framework, kein Media-Framework auf dem Zielsystem. Es gibt keine Python-Umgebung, die gepinnt werden muss, keine Framework-Version, die über JetPack-Upgrades hinweg nachgehalten werden muss, und keinen Dependency-Drift im Feld.
Vier Modelle auf einem Modul zum Preis von anderthalb
Die meisten realen Anwendungen betreiben mehr als ein Modell, und das übliche Muster ist ein Prozess pro Modell. Auf Jetson ist dieses Muster teuer, aus einem Grund, der nichts mit den Modellen zu tun hat: jeder Prozess bezahlt seinen eigenen CUDA-Kontext und seine eigene TensorRT Runtime, rund 350 MB, bevor ein einziges Gewicht geladen ist.
Wir haben vier im Haus trainierte Detektoren in einen einzigen Prozess gelegt, alle warm und pro Bild adressierbar:
kineva_coco, allgemeine Detektion über 80 Klassenillegalwaste, Erkennung illegaler Müllablagerunghead, Kopf- und Personenerkennunglicenseplate, Kennzeichenerkennung
1,4 GB auf einem Modul freigemacht, ohne Änderung an einem einzigen Modell. Auf einem 4-GB-Modul ist dieser Unterschied das gesamte Deployment.
82 Millijoule pro inferiertem Bild
Erfasst mit tegrastats in 500-ms-Intervallen über einen durchgehenden Lauf von 1200 Bildern, 104 fps Ende zu Ende einschließlich H.264-Decode.
8,5 W zusätzliche Boardleistung bei 104 fps Ende zu Ende sind 82 mJ pro inferiertem Bild, eine Größe, die ein Flottenplaner hochrechnen kann. Geteilt durch die reine Inferenzrate ergäbe sich eine geschmeichelte 58, wir nennen die Ende-zu-Ende-Zahl, weil das Deployment die Ende-zu-Ende-Zahl bezahlt. Und bei 62 % durchschnittlicher GPU-Auslastung ist das Modul nicht ausgelastet: Es bleibt Luft für eine zweite Last auf demselben Silizium, und genau das macht ein kleineres Modul zu einem realistischen Ziel statt zu einer Hoffnung.
Eine Feldnotiz, kostenlos für das Ökosystem
Dieser Punkt hat uns echte Zeit gekostet. Er ist eine Eigenschaft der Plattform und keine Methode von uns, deshalb veröffentlichen wir ihn.
Setzen Sie den Power-Modus, bevor Sie irgendetwas messen. Unsere erste Dual-Stream-Messung entstand versehentlich im 15-W-Modus: vier von acht Kernen online, gedeckelt bei 1,42 GHz. Sie las 33,5 fps pro Stream, und wir schlossen daraus, dass das Ziel nicht erreichbar sei. Im vollen Power-Modus hält derselbe Code 110,7 fps. Eine einzige nvpmodel-Einstellung hat ein Engineering-Urteil umgedreht und uns beinahe eine Produktentscheidung gekostet.
Zur Ehrlichkeit im Berichten
Zwei Gewohnheiten, weil sie der Grund dafür sind, dass man den obigen Zahlen trauen kann.
Wir veröffentlichen Ergebnisse, die gegen unsere eigene Erwartung ausfielen. Dieselbe Engine und dieselben 300 Bilder einmal über die native CLI und einmal über die Python-Bindings gemessen ergaben 501 MB gegenüber 541 MB, also 40 MB Unterschied (rund 8 %) und 1,4 % Latenz. Die Aussage "wir haben Python entfernt und Gigabytes gespart" ist damit durch die Messung nicht gedeckt, und wir treffen sie nicht. Der Interpreter ist billig, das Framework ist teuer. Entfernt haben wir das ML-Framework aus dem Inferenzpfad, nicht die Sprache. Die Bindings existieren, damit Integrationscode in Python bleiben kann, während der speicherrelevante Teil nativ ist.
Wir haben außerdem zwei eigene Optimierungen dokumentiert, die schlechter maßen als die Ausgangsversion, und sie auf Basis der Evidenz verworfen, statt sie auf Basis einer Annahme weiterzuverfolgen. Beide stehen im technischen Report, mitsamt der Instrumentierung dahinter.
Warum das von REBOTNIX kommt
Drei Eigenschaften ergeben sich daraus, den gesamten Stack zu besitzen statt einer Schicht davon.
Wir liefern das vollständige System, nicht eine Komponente. Kamera-Hardware, Carrier-Integration, die Inferenz-Engine, die Modelle, die Video-Pipeline, Lizenzierung und IP-Schutz, aus einer Hand und über einen Supportweg. Speicher- und Leistungsverhalten sind damit Entwicklungsentscheidungen, die wir auf das Budget eines Kunden zubewegen können, und keine Eigenschaften eines Frameworks, um die wir herumarbeiten müssen.
Die Modelle gehören uns. Die vier gemessenen Detektoren sind kein Sonderfall, sondern ein Ausschnitt aus der Palette, die vollständig im Haus trainiert wird:
- Kopf- und Personenerkennung
- Kennzeichenerkennung
- Erkennung illegaler Entsorgung
- Abfallkategorie
- PKW- und LKW-Erkennung
- COCO 80-Klassen
- Graffiti-Erkennung
- Verkehrszeichenerkennung
- Gesichtsanonymisierung
- WiFi Person Scanner
- Virtual RTK GPS
- Fahrzeugerkennung und Klassifizierung
- Flugzeugerkennung
- Schiffs- und Maritimerkennung
- Multi-Sensor Flugverfolgung
- Industrial Scene Understanding
- Infrastructure Report Generator
Siebzehn Modelle, drei Familien, eine Runtime. Details unter KINEVA.
In der Runtime steckt kein fremder Inferenz-Wrapper. Der Kunde erbt damit keine Copyleft-Verpflichtung aus dem Wahrnehmungs-Stack. Auf der Video-Seite haben wir dieselbe Überlegung angewandt und einen permissiv lizenzierten Software-Encoder gegenüber der GPL-Alternative gewählt, damit das Produkt closed-source ausgeliefert werden kann.
IP-Schutz ist Teil der Runtime. Modelle werden AES/ChaCha versiegelt ausgeliefert und im Speicher gegen ihren registrierten Namen entschlüsselt. Lizenzierung und Maschinenbindung sind in die Engine eingebaut, ohne OpenSSL auf dem Zielsystem.
Den technischen Report anfordern
Dieser Artikel berichtet, was wir erreicht haben. Ein zweites Dokument beschreibt, wie, und ist auf Anfrage unter NDA erhältlich:
- Die acht Runtime-Techniken hinter den obigen Zahlen, jeweils mit gemessener Wirkung und Trade-off
- Das Host-Staging pro Bild, das aus dem Inferenzpfad entfernt wurde, und wie
- Die Verteilung der Arbeit über das SoC, also welche Pipeline-Stufe auf welcher Engine läuft und was jede Verschiebung gekostet oder gespart hat
- Die zwei Optimierungen, die schlechter maßen als die Ausgangsversion, mit der Instrumentierung, die es gezeigt hat
- Die Residenz-Architektur hinter den 1,4 GB und die Entscheidungskurve zwischen Nachladen und Residenz
- Vollständige Reproduktionsbefehle für jede Messung in beiden Dokumenten
Sie arbeiten an einem Jetson-Deployment, das nicht in das geplante Modul passt? Die Antwort ist nicht immer ein kleineres Modell. Sehr oft ist es eine kleinere Runtime. Bringen Sie uns die Last und das Modul, auf dem sie laufen soll.
Alle Messwerte beziehen sich auf die oben genannte Konfiguration und können je nach Hardware, Software-Stand und Last abweichen. Änderungen und Irrtümer vorbehalten.
