Erste Schritte mit ORT für C
Inhalt
Builds
| Artefakt | Beschreibung | Unterstützte Plattformen |
|---|---|---|
| Microsoft.ML.OnnxRuntime | CPU (Release) | Windows, Linux, Mac, X64, X86 (nur Windows), ARM64 (nur Windows)…weitere Details: Kompatibilität |
| Microsoft.ML.OnnxRuntime.Gpu | GPU - CUDA (Release) | Windows, Linux, Mac, X64…weitere Details: Kompatibilität |
| Microsoft.ML.OnnxRuntime.DirectML | GPU - DirectML (Release) | Windows 10 1709+ |
| onnxruntime | CPU, GPU (Dev), CPU (On-Device Training) | Dasselbe wie bei Release-Versionen |
| Microsoft.ML.OnnxRuntime.Training | CPU On-Device Training (Release) | Windows, Linux, Mac, X64, X86 (nur Windows), ARM64 (nur Windows)…weitere Details: Kompatibilität |
.zip und .tgz Dateien sind auch als Assets in jedem Github Release enthalten.
API-Referenz
Siehe onnxruntime_c_api.h
- Includieren Sie onnxruntime_c_api.h.
- Rufen Sie OrtCreateEnv auf
- Session erstellen: OrtCreateSession(env, model_uri, nullptr,…)
- Optional weitere Ausführungsanbieter hinzufügen (z. B. für CUDA verwenden Sie OrtSessionOptionsAppendExecutionProvider_CUDA)
- Tensor erstellen 1) OrtCreateMemoryInfo 2) OrtCreateTensorWithDataAsOrtValue
- OrtRun
Features
- Erstellen einer InferenceSession aus einer lokalen Modelldatei und einer Reihe von SessionOptions.
- Registrieren von benutzerdefinierten Loggern.
- Registrieren von benutzerdefinierten Allocators.
- Registrieren von vordefinierten Anbietern und Festlegen der Prioritätsreihenfolge. ONNXRuntime verfügt über eine Reihe von vordefinierten Ausführungsanbietern wie CUDA und DNNL. Der Benutzer kann Anbieter für seine InferenceSession registrieren. Die Reihenfolge der Registrierung gibt auch die Präferenzreihenfolge an.
- Ausführen eines Modells mit Eingaben. Diese Eingaben müssen sich im CPU-Speicher befinden, nicht in der GPU. Wenn das Modell mehrere Ausgaben hat, kann der Benutzer angeben, welche Ausgaben er wünscht.
- Konvertieren eines ONNX-Tensors im Arbeitsspeicher, der im protobuf-Format kodiert ist, in einen Zeiger, der als Modelleingabe verwendet werden kann.
- Festlegen der Thread-Pool-Größe für jede Sitzung.
- Festlegen des Graphenoptimierungsgrads für jede Sitzung.
- Dynamisches Laden benutzerdefinierter Ops. Anweisungen
- Möglichkeit, ein Modell aus einem Byte-Array zu laden. Siehe
OrtCreateSessionFromArrayin onnxruntime_c_api.h. - Globale/gemeinsame Thread-Pools: Standardmäßig erstellt jede Sitzung ihre eigenen Thread-Pools. In Situationen, in denen mehrere Sitzungen im selben Prozess erstellt werden müssen (um verschiedene Modelle abzuleiten), enden Sie mit mehreren Thread-Pools, die von jeder Sitzung erstellt werden. Um diese Ineffizienz zu beheben, führen wir ein neues Feature namens globale/gemeinsame Thread-Pools ein. Die Grundidee besteht darin, eine Reihe globaler Thread-Pools über mehrere Sitzungen hinweg gemeinsam zu nutzen. Die typische Verwendung dieses Features ist wie folgt:
- Füllen Sie
ThreadingOptionsaus. Verwenden Sie den Wert 0, damit ORT die Standardwerte wählt. - Erstellen Sie die Umgebung mit
CreateEnvWithGlobalThreadPools() - Erstellen Sie die Sitzung und rufen Sie
DisablePerSessionThreads()für das SessionOptions-Objekt auf - Rufen Sie
Run()wie gewohnt auf
- Füllen Sie
- Allocator(s) zwischen Sitzungen gemeinsam nutzen
- Beschreibung: Dieses Feature ermöglicht es mehreren Sitzungen im selben Prozess, dieselben Allocator(s) zu verwenden.
- Szenario: Sie haben mehrere Sitzungen im selben Prozess und stellen einen hohen Speicherverbrauch fest. Einer der Gründe dafür ist wie folgt. Jede Sitzung erstellt ihren eigenen CPU-Allocator, der standardmäßig auf einem Arena-basierten Prinzip beruht. ORT implementiert eine vereinfachte Version eines Arena-Allocators, der auf Doug Leas Best-First-with-Coalescing-Algorithmus basiert. Jeder Allocator lebt in seiner eigenen Sitzung. Er weist zur Initialisierungszeit eine große Speicherregion zu und zerteilt, vereinigt und erweitert diese initiale Region anschließend gemäß den Anforderungen an die Zuordnung/Freigabe. Im Laufe der Zeit enthält die Arena ungenutzte Speicherbereiche pro Sitzung. Darüber hinaus wird der von der Arena zugewiesene Speicher nie an das System zurückgegeben; sobald er zugewiesen ist, bleibt er immer zugewiesen. All diese Faktoren summieren sich bei der Verwendung mehrerer Sitzungen (jeweils mit eigener Arena), was den gesamten Speicherverbrauch des Prozesses erhöht. Daher ist es wichtig, den Arena-Allocator zwischen den Sitzungen gemeinsam zu nutzen.
- Verwendung:
- Erstellen und registrieren Sie einen gemeinsamen Allocator in der Umgebung mit der API
CreateAndRegisterAllocator. Dieser Allocator wird dann von allen Sitzungen wiederverwendet, die dieselbe Umgebungsinstanz verwenden, es sei denn, eine Sitzung überschreibt dies durch Setzen vonsession_state.use_env_allocatorsauf "0". - Setzen Sie
session.use_env_allocatorsauf "1" für jede Sitzung, die die in der Umgebung registrierten Allocator verwenden möchte. - Siehe Test
TestSharedAllocatorUsingCreateAndRegisterAllocatorunter https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/test/shared_lib/test_inference.cc für ein Beispiel. - Konfiguration von OrtArenaCfg (verwenden Sie die API
CreateArenaCfgV2, um eineOrtArenaCfg-Instanz ab ORT-Version 1.8 zu erstellen; frühere Versionen verwendeten das nun veralteteCreateArenaCfg, um die Instanz zu erstellen)CreateArenaCfgV2nimmt eine Liste von Schlüsseln wie unten beschrieben und entsprechende Werte (einen für jeden Schlüssel). Standardwerte für diese Konfigurationen finden Sie in der BFCArena-Klasse. Siehe TestConfigureCudaArenaAndDemonstrateMemoryArenaShrinkageunter https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/test/shared_lib/test_inference.cc für ein Beispiel für die Verwendung vonCreateArenaCfgV2.max_mem: Dies ist die maximale Menge an Speicher, die die Arena zuweist. Wenn ein Block nicht von einer vorhandenen Region bedient werden kann, erweitert die Arena sich durch Zuweisung einer weiteren Region in Abhängigkeit vom verfügbaren Speicher (max_mem - zugewiesen_bis_jetzt). Ein Fehler wird zurückgegeben, wenn der verfügbare Speicher kleiner ist als die angeforderte Erweiterung.arena_extend_strategy: Dies kann derzeit nur 2 Werte annehmen: kSameAsRequested oder kNextPowerOfTwo. Wie der Name schon sagt, erweitert kNextPowerOfTwo (der Standardwert) die Arena um eine Zweierpotenz, während kSameAsRequested die Arena jedes Mal um eine Größe erweitert, die der Zuweisungsanforderung entspricht. kSameAsRequested eignet sich für fortgeschrittenere Konfigurationen, bei denen Sie die erwartete Speichernutzung im Voraus kennen.initial_chunk_size_bytes: Diese Konfiguration ist nur relevant, wenn die Arena-Erweiterungsstrategie kNextPowerOfTwo ist. Dies ist die (mögliche) Größe der Region, die die Arena bei der ersten Zuweisung zuweist (wenn die erste Speicheranforderung größer als dieser Wert ist, ist die Zuweisungsgröße größer als dieser angegebene Wert). Blöcke werden aus dieser Region für Zuweisungsanforderungen bereitgestellt. Wenn die Protokolle zeigen, dass die Arena viel stärker erweitert wird als erwartet, ist es besser, hier eine ausreichend große Anfangsgröße zu wählen.initial_growth_chunk_size_bytes: Bitte lesen Sie den AbschnittSpeicher-Arena-Verkleinerung, bevor Sie diesen Abschnitt lesen. Diese Konfiguration ist nur relevant, wenn die Arena-Erweiterungsstrategie kNextPowerOfTwo ist. Derzeit ist dieser Wert die (mögliche) Größe der ersten Zuweisung nach einer Arena-Verkleinerung (eine Speicheranforderung, die nach der Arena-Verkleinerung größer als dieser Wert ist, führt zu einer höheren Zuweisungsgröße). Die (mögliche) erste Zuweisung durch eine Arena wird durchinitial_chunk_size_bytesbestimmt, und die möglichen nachfolgenden Zuweisungen sindinitial_chunk_size_bytes * 2,initial_chunk_size_bytes * 4und so weiter. Wenn die Arena schrumpfen würde (d. h. diese Speicherregionen freigibt), möchten wir die Größe der ersten Zuweisung nach dem Schrumpfen zurücksetzen. Dies ist die aktuelle Definition. In Zukunft kann diese Konfiguration verwendet werden, um andere "wachstumsbezogene" Aktionen der Arena zu steuern (d. h. die zweite Zuweisung, die von der Arena (Arena-Wachstum) nach der allerersten Zuweisung (Anfangsblock) vorgenommen wird, kann durch diesen Parameter definiert werden).max_dead_bytes_per_chunk: Dies steuert, ob ein Block zum Bedienen einer Zuweisungsanforderung aufgeteilt wird. Derzeit, wenn die Differenz zwischen der Blockgröße und der angeforderten Größe kleiner als dieser Wert ist, wird der Block nicht aufgeteilt. Dies kann potenziell Speicher verschwenden, indem ein Teil des Blocks während des gesamten Prozesses ungenutzt bleibt (daher als tote Bytes bezeichnet), wodurch der Speicherverbrauch erhöht wird (bis dieser Block an die Arena zurückgegeben wird).
- Erstellen und registrieren Sie einen gemeinsamen Allocator in der Umgebung mit der API
- Speicher-Arena-Verkleinerung
- Beschreibung: Standardmäßig schrumpfen Speicher-Arenen nicht (geben ungenutzten Speicher an das System zurück). Dieses Feature ermöglicht es Benutzern, die Arena in einem bestimmten Takt zu "schrumpfen". Derzeit ist der einzige unterstützte Takt das Ende jedes Run() (d. h. wenn dieses Feature verwendet wird, wird der Arenaspeicher gescannt, um möglicherweise ungenutzten Speicher am Ende jedes Run() freizugeben). Dies wird durch eine RunOption erreicht.
- Szenario: Sie haben ein dynamisches Shape-Modell, das gelegentlich eine Anfrage bedienen kann, die viel Speicher erfordert. Da die Arena standardmäßig keinen Speicher freigibt, wird dieses "Wachstum" der Arena als Teil der Bearbeitung dieser Anfrage für immer beibehalten. Dies ist suboptimal, da die meisten anderen Anfragen wahrscheinlich nicht so viel Speicher benötigen (d. h. es wird zu viel Speicher nur zur Verarbeitung eines oder zweier Ausreißer zugewiesen). Wenn dies das ORT-Nutzungsszenario am besten beschreibt, ist die Verwendung dieses Schrumpfungs-Features eine Option. Dieses Feature ist nur anwendbar, wenn der relevante Speicherallocator überhaupt ein Arena-basierter Allocator ist.
- Verwendung: Siehe Test
ConfigureCudaArenaAndDemonstrateMemoryArenaShrinkageunter https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/test/shared_lib/test_inference.cc für ein Beispiel. Um dieses Feature optimal zu nutzen, muss die zu verkleinernde Speicherarena für den Anwendungsfall entsprechend konfiguriert werden. Bitte lesen Sie oben, wie ein Arena-Allocator mit einerOrtArenaCfg-Instanz konfiguriert wird. Dieses Feature ist leicht auf die beiden verfügbaren Arena-Erweiterungsstrategien (kSameAsRequested und kNextPowerOfTwo) abgestimmt, wie unten beschrieben:kNextPowerOfTwo: Wenn dies die gewählte Konfiguration ist, werden alle Speicherzuweisungen außer der initialen Zuweisung bei der Verkleinerung zur Freigabe berücksichtigt. Die Idee ist, dass der Benutzer eine ausreichend hoheinitial_chunk_size_byteseinstellt, um die meisten Modellanfragen zu verarbeiten, ohne mehr Speicher zuzuweisen (d. h. dieser initiale Speicher reicht aus, um jede durchschnittliche Anfrage zu bedienen). Alle nachfolgenden Zuweisungen, die als Teil der Bearbeitung einer Ausreißeranfrage zugewiesen werden, sind die einzigen Kandidaten für die Freigabe.kSameAsRequestedWenn dies die gewählte Konfiguration ist, werden alle Speicherzuweisungen zum Zeitpunkt der Verkleinerung berücksichtigt. Dies liegt daran, dassinitial_chunk_size_bytesfür diese Strategie derzeit nicht relevant ist.
- Speicher für Initialisierer aus Nicht-Arena-Speicher zuweisen (für fortgeschrittene Benutzer)
- Beschreibung: Wenn der Allocator für das Gerät, auf dem die Inhalte der Initialisierer gespeichert werden sollen, ein Arena-basierter Allocator ist und man ein potenziell übermäßiges Arena-Wachstum aufgrund der Zuweisung von Speicher für diese Initialisierer verhindern möchte, bietet dieses Feature diese Möglichkeit.
- Szenario: Sie haben ein recht einfaches Modell, das während der Ausführung selbst nicht viel Speicher benötigt, aber das Modell hat relativ viele Initialisierer, so dass, wenn der Speicher für diese mit einer Arena zugewiesen würde, der ungenutzte Speicher im gesamten zugewiesenen Arena-Speicher weit über das hinausgehen könnte, was für das Modell während der Ausführung tatsächlich benötigt wird. Unter solchen Umständen und wenn das Modell in einer speicherbeschränkten Umgebung bereitgestellt werden soll, wäre die Verwendung eines solchen Features sinnvoll, um ein übermäßiges Wachstum der Arena zu verhindern, das durch die Zuweisung von Speicher für Initialisierer in der Arena entstehen würde. Die Verwendung dieses Features würde bedeuten, dass die Arena nur verwendet wird, um den von den Operatoren des Modells benötigten Speicher zuzuweisen. Es scheint, dass die Einstellung einer ausreichend hohen Anfangs-Chunk-Größe für die Arena (
initial_chunk_size_bytes), um die Initialisierer und den erwarteten während der Ausführung benötigten Speicher zu berücksichtigen, das problematische Szenario vermeiden würde. Das Problem dabei ist, dass einige EPs intern Thread-lokale Allocator verwenden und jede hohe Anfangs-Chunk-Größe, die in der Konfiguration festgelegt wird, für jeden dieser Allocator gilt und zu Speicherverschwendung führt, da nur ein Thread-lokaler Allocator letztendlich den Speicher der Initialisierer zuweist. - Verwendung: Siehe Test
AllocateInitializersFromNonArenaMemoryunter https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/test/shared_lib/test_inference.cc für ein Beispiel.
- Initialisierer und deren ORT-vorverarbeitete Versionen zwischen Sitzungen gemeinsam nutzen
- Beschreibung: Dieses Feature ermöglicht es einem Benutzer, dieselbe Instanz eines Initialisierers (und deren ORT "vorverarbeitete" Versionen) über mehrere Sitzungen hinweg gemeinsam zu nutzen.
- Szenario: Sie haben mehrere Modelle, die dieselben Initialisierer verwenden, abgesehen von den letzten paar Schichten des Modells, und Sie laden diese Modelle im selben Prozess. Wenn jedes Modell (Sitzung) eine separate Instanz desselben Initialisierers erstellt, führt dies zu übermäßigem und verschwenderischem Speicherverbrauch, da es sich in diesem Fall um denselben Initialisierer handelt. Sie möchten den Speicherverbrauch optimieren und gleichzeitig die Flexibilität haben, die Initialisierer zuzuweisen (möglicherweise sogar im gemeinsam genutzten Speicher zu speichern).
- Verwendung: Verwenden Sie die API
AddInitializer, um einen vorab zugewiesenen Initialisierer zu den SessionOptions hinzuzufügen, bevor SieCreateSessionaufrufen. Verwenden Sie dieselbe Instanz von SessionOptions, um mehrere Sitzungen zu erstellen, wodurch die Initialisierer zwischen den Sitzungen gemeinsam genutzt werden können. Siehe C-API-Beispielverwendung (TestSharingOfInitializerAndItsPrepackedVersion) und C#-API-Beispielverwendung (TestSharingOfInitializerAndItsPrepackedVersion). - In einigen ORT-Operator-Implementierungen werden Initialisierer beim Laden des Modells vorverarbeitet (ein Prozess namens "Pre-Packing"), um eine optimale Operatoreninferenz auf einigen Plattformen zu fördern. Standardmäßig werden diese vorverarbeiteten Versionen von Initialisierern pro Sitzung verwaltet (d. h. sie werden nicht zwischen Sitzungen geteilt). Um die gemeinsame Nutzung zwischen Sitzungen zu ermöglichen, erstellen Sie einen Container (mit
CreatePrepackedWeightsContainer) und übergeben Sie diesen zum Zeitpunkt der Sitzungserstellung, damit die gemeinsame Nutzung von vorverpackten Versionen gemeinsam genutzter Initialisierer zwischen Sitzungen stattfindet und diese nicht im Speicher dupliziert werden. Dieselben Tests, die oben in C und C# erwähnt werden, zeigen auch ein Beispiel für die Verwendung dieses Features. HINWEIS: Jeder Kernel-Entwickler, der Pre-Packing implementieren möchte, MUSS einen Test schreiben, der das Pre-Packing aller Gewichte auslöst, die mit dem Kernel vorverpackt werden können, und muss die gemeinsame Nutzung dieser vorverpackten Gewichte zwischen den Sitzungen testen. Siehe Kernel-Test (SharedPrepackedWeights).
Bereitstellung
Windows 10
Ihr Installer sollte die onnxruntime.dll im selben Ordner wie Ihre Anwendung ablegen. Ihre Anwendung kann entweder Load-Time Dynamic Linking oder Run-Time Dynamic Linking verwenden, um sich mit der DLL zu verbinden.
Suchreihenfolge für dynamische Link-Bibliotheken
Dies ist ein wichtiger Artikel darüber, wie Windows unterstützende DLLs findet: Dynamic Link Library Search Order.
Es gibt Fälle, in denen die App die onnxruntime nicht direkt nutzt, sondern stattdessen eine DLL aufruft, die onnxruntime nutzt. Personen, die diese DLLs erstellen, die onnxruntime nutzen, müssen auf die Ordnerstrukturen achten. Ändern Sie nicht die Systemvariable %path%, um Ihre Ordner hinzuzufügen. Dies kann zu Konflikten mit anderer Software auf dem Computer führen, die ebenfalls onnxruntime verwendet. Platzieren Sie stattdessen Ihre DLL und die onnxruntime DLL im selben Ordner und verwenden Sie Run-Time Dynamic Linking, um sich explizit mit dieser Kopie zu verbinden. Sie können Code wie in diesem Beispiel in GetModulePath() verwenden, um herauszufinden, aus welchem Ordner Ihre DLL geladen wird.
Telemetrie
Um die Telemetriesammlung auf offiziellen Windows-Builds zu aktivieren/deaktivieren, verwenden Sie Enable/DisableTelemetryEvents() in der C-API. Weitere Informationen zur Telemetriesammlung und Microsofts Datenschutzrichtlinie finden Sie auf der Datenschutzseite.
Beispiele
Siehe Candy Style Transfer