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 würde rund 10 MB von 538 MB Prozessgröße einsparen, unter zwei Prozent, 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 der Aktivierungsspeicher mit den Device-I/O-Puffern, die beim Warmup allokiert werden (177 MB). Keiner von beiden wird kleiner, wenn Sie das Modell quantisieren. 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, bei MAXN, mit tegrastats über die exakte Dauer jedes Laufs.
Eine vollständige Detektions-Pipeline in 513 MB
513 MB Spitzenwert an residentem Speicher für den gesamten Pfad, also CUDA-Kontext, TensorRT Runtime, Engine-Gewichte, Video-Dekodierung, Vorverarbeitung, Inferenz und NMS, bei 144,5 fps auf 720p Video und 6,92 ms pro Bild. 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.
58 Millijoule pro inferiertem Bild
Erfasst mit tegrastats in 500-ms-Intervallen über einen durchgehenden Lauf von 1200 Bildern bei 147,7 fps.
8,586 W zusätzliche Boardleistung bei 147,7 fps sind 58 mJ pro Bild, eine Größe, die ein Flottenplaner hochrechnen kann. 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.
Zwei 1080p60 H.264 Streams auf einem Modul ohne Hardware-Encoder
Jetson Orin Nano hat keinen NVENC. Wenn die Kodierung nicht in Software im Budget erledigt werden kann, braucht das Deployment ein größeres Modul. Unser Software-Encode-Pfad wurde genau für diese Einschränkung gebaut.
110,7 fps pro Stream, durchgehend über 1500 Bilder bei 50 bis 53 °C ohne thermisches Throttling. Zwei Streams erreichen eine höhere Rate pro Stream als einer, weil zwei unabhängige Encoder alle acht Kerne auslasten, während ein einzelner seine eigene Slice-Pipeline aushungert.
Die Nano-Zahlen sind aus einer Sechs-Kern-Emulation plus Taktskalierung hochgerechnet, ±10 %, und wir weisen sie als Projektion aus. Wir geben keine Zusage zur Modulauswahl auf Basis einer Extrapolation. Was die Daten heute tragen, ist die sorgfältige Formulierung: diese Last, gemessen, passt in dieses Modul.
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. Bei MAXN 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 513 MB gegenüber 541 MB, also 28 MB Unterschied 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. kineva_coco, illegalwaste, head und licenseplate sind im Haus auf eigenen Daten trainiert, und es steckt kein fremder Inferenz-Wrapper in der Runtime. 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.