ONNX Runtime Architektur
Dieses Dokument beschreibt das High-Level-Design von ONNX Runtime.
Inhalt
Schlüsselziele
- Maximale und automatische Nutzung der benutzerdefinierten Beschleuniger und Laufzeiten, die auf verschiedenen Plattformen verfügbar sind.
- Bereitstellung der richtigen Abstraktion und Laufzeitunterstützung für benutzerdefinierte Beschleuniger und Laufzeiten. Wir nennen diese Abstraktion einen Execution Provider. Er definiert und macht eine Reihe seiner Fähigkeiten für ONNX Runtime verfügbar: eine Reihe von einzelnen oder fusionierten Knoten, die er ausführen kann, sein Speicher-Allocator und mehr. Benutzerdefinierte Beschleuniger und Laufzeiten sind Instanzen von Execution Providern.
- Wir gehen nicht davon aus, dass ein Execution Provider ein ONNX-Modell immer vollständig auf seinem Gerät ausführen kann. Das bedeutet, dass ONNX Runtime ein einzelnes Modell in einer heterogenen Umgebung mit mehreren Execution Providern ausführen können muss.
- Bereitstellung von Unterstützung für High-Level-Optimierungen, die als Modell-zu-Modell-Transformationen über eine Graph-Transformations-API ausgedrückt werden können. Solche Transformationen fallen in zwei Kategorien: globale Transformationen, die eine Analyse und Transformation des gesamten Graphen erfordern, und lokale Transformationen, die als einfache (algebraische) Umschreibungsregeln erfasst werden können.
High-Level-Systemarchitektur
Der Ablauf ist ziemlich einfach.
- Ausgehend von einem ONNX-Modell konvertiert ONNX Runtime zuerst den Modellgraphen in seine In-Memory-Graphenrepräsentation.
- Es führt eine Reihe von Provider-unabhängigen Optimierungen durch.
- Es partitioniert den Graphen basierend auf den verfügbaren Execution Providern in eine Reihe von Teilgraphen.
- Jeder Teilgraph wird einem Execution Provider zugewiesen. Wir stellen sicher, dass ein Teilgraph von einem Execution Provider ausgeführt werden kann, indem wir die Fähigkeiten des Execution Providers mit der
GetCapability()API abfragen.

Mehr über die Partitionierung
ONNX Runtime partitioniert einen Modellgraphen in Teilgraphen basierend auf den verfügbaren Execution Providern, einen für jeden unterschiedlichen Provider. ONNX Runtime stellt einen Standard-Execution-Provider zur Verfügung, der als Fallback-Ausführung für die Operatoren dient, die nicht auf spezialisiertere, aber effizientere Execution Provider verschoben werden können. Intuitiv wollen wir die Berechnung wann immer möglich an spezialisiertere Execution Provider verschieben.
Wir verwenden eine einfache Graph-Partitionierungstechnik. Die verfügbaren Execution Provider werden in einer bestimmten Reihenfolge berücksichtigt, und jeder erhält die maximalen Teilgraphen (möglicherweise mehr als einen), die er verarbeiten kann. Der von ONNX Runtime bereitgestellte Standard-Execution-Provider wird zuletzt berücksichtigt und stellt die Vollständigkeit sicher. Anspruchsvollere Optimierungen können in Zukunft berücksichtigt werden (oder sogar als zusammengesetzter Execution Provider implementiert werden).
Konzeptionell wird jede Partition auf einen einzelnen, fusionierten Operator reduziert. Er wird durch Aufruf der Compile()-Methode des Execution Providers erstellt und als benutzerdefinierter Operator gekapselt. Derzeit unterstützen wir nur den synchronen Ausführungsmodus. Ein Execution Provider exponiert seinen Speicher-Allocator, der zur Allokation der Eingabetensoren für den Execution Provider verwendet wird. Die Umschreibung und Partitionierung transformiert den ursprünglichen Modellgraphen in einen neuen Graphen, der aus Operatoren besteht, die entweder dem Standard-Execution-Provider oder anderen registrierten Execution Providern zugewiesen sind. Die ONNX Runtime-Ausführungs-Engine ist für die Ausführung dieses Graphen verantwortlich.
Wichtige Designentscheidungen
- Mehrere Threads können die
Run()-Methode auf demselben Inferenzsitzungsobjekt aufrufen. Weitere Details finden Sie in der API-Dokumentation. - Um dies zu erleichtern, ist die
Compute()-Funktion aller Kernel konstant, was bedeutet, dass die Kernel zustandslos sind. - Implementierungen der Operatoren durch Execution Provider werden als Kernel bezeichnet. Jeder Execution Provider unterstützt eine Teilmenge der (ONNX-)Operatoren/Kernel.
- ONNX Runtime garantiert, dass alle Operatoren vom Standard-Execution-Provider unterstützt werden.
- Tensor-Repräsentation: ONNX Runtime verwendet eine Standardrepräsentation für die Tensor-Laufzeitwerte. Die Execution Provider können intern eine andere Repräsentation verwenden, wenn sie dies wünschen, aber es liegt in ihrer Verantwortung, die Werte von/zu der Standardrepräsentation an den Grenzen ihres Teilgraphen zu konvertieren.