Graph-Optimierungen in ONNX Runtime

ONNX Runtime bietet verschiedene Graph-Optimierungen zur Leistungssteigerung. Graph-Optimierungen sind im Wesentlichen Transformationen auf Graphen-Ebene, die von einfachen Graph-Vereinfachungen und Knoteneliminationen bis hin zu komplexeren Knotenfusionen und Layout-Optimierungen reichen.

Graph-Optimierungen sind nach Komplexität und Funktionalität in mehrere Kategorien (oder Levels) unterteilt. Sie können entweder online oder offline durchgeführt werden. Im Online-Modus werden die Optimierungen vor der Inferenz durchgeführt, während im Offline-Modus die Laufzeitumgebung den optimierten Graphen auf die Festplatte speichert. ONNX Runtime bietet Python-, C#-, C++- und C-APIs, um verschiedene Optimierungsstufen zu ermöglichen und zwischen Offline- und Online-Modus zu wählen.

Im Folgenden finden Sie Details zu den Optimierungsstufen, dem Online/Offline-Modus und den verschiedenen APIs zur Steuerung.

Inhalt

Graph-Optimierungsstufen

Graph-Optimierungen sind in drei Stufen unterteilt:

  1. Basic
  2. Extended
  3. Layout-Optimierungen

Die Optimierungen einer Stufe werden nach Anwendung der Optimierungen der vorherigen Stufe durchgeführt (z. B. werden Extended-Optimierungen nach Anwendung der Basic-Optimierungen angewendet).

Alle Optimierungen sind standardmäßig aktiviert.

Basis-Graph-Optimierungen

Dies sind semantik-erhaltende Graph-Neuschreibungen, die redundante Knoten und redundante Berechnungen entfernen. Sie werden vor der Graph-Partitionierung ausgeführt und gelten daher für alle Ausführungsanbieter. Verfügbare Basis-Graph-Optimierungen sind:

  • Constant Folding: Berechnet statisch Teile des Graphen, die nur von konstanten Initialisierern abhängen. Dies eliminiert die Notwendigkeit, diese zur Laufzeit zu berechnen.

  • Entfernung redundanter Knoten: Entfernt alle redundanten Knoten, ohne die Graph-Struktur zu verändern. Folgende solche Optimierungen werden derzeit unterstützt:
    • Identitätseliminierung
    • Slice-Eliminierung
    • Unsqueeze-Eliminierung
    • Dropout-Eliminierung
  • Semantik-erhaltende Knoten-Fusionen: Fusioniert/Faltet mehrere Knoten zu einem einzigen Knoten. Beispielsweise fusioniert Conv Add Fusion den Add-Operator als Bias des Conv-Operators. Folgende solche Optimierungen werden derzeit unterstützt:
    • Conv Add Fusion
    • Conv Mul Fusion
    • Conv BatchNorm Fusion
    • Relu Clip Fusion
    • Reshape Fusion

Erweiterte Graph-Optimierungen

Diese Optimierungen umfassen komplexe Knoten-Fusionen. Sie werden nach der Graph-Partitionierung ausgeführt und gelten nur für Knoten, die dem CPU-, CUDA- oder ROCm-Ausführungsanbieter zugewiesen sind. Verfügbare erweiterte Graph-Optimierungen sind:

Optimierung Ausführungsanbieter Kommentar
GEMM Activation Fusion CPU  
Matmul Add Fusion CPU  
Conv Activation Fusion CPU  
GELU Fusion CPU, CUDA, ROCm  
Layer Normalization Fusion CPU, CUDA, ROCm  
BERT Embedding Layer Fusion CPU, CUDA, ROCm BERT-Embedding-Layer, Layer-Normalisierung und Aufmerksamkeitsmaskenlänge fusionieren
Attention Fusion* CPU, CUDA, ROCm  
Skip Layer Normalization Fusion CPU, CUDA, ROCm Bias einer vollständig verbundenen Schicht, Skip-Verbindung und Layer-Normalisierung fusionieren
Bias GELU Fusion CPU, CUDA, ROCm Bias einer vollständig verbundenen Schicht und GELU-Aktivierung fusionieren
GELU Approximation* CUDA, ROCm Standardmäßig deaktiviert. Aktivieren mit kOrtSessionOptionsEnableGeluApproximation
Approximations (click to expand)

Zur Optimierung der Leistung von BERT wird bei GELU Approximation und Attention Fusion für CUDA- und ROCm-Ausführungsanbieter eine Approximation verwendet. Die Auswirkung auf die Genauigkeit ist nach unserer Einschätzung vernachlässigbar: Der F1-Score für ein BERT-Modell auf SQuAD v1.1 ist nahezu gleich (87,05 vs. 87,03).

Layout-Optimierungen

Diese Optimierungen ändern das Datenlayout für anwendbare Knoten, um höhere Leistungssteigerungen zu erzielen. Sie werden nach der Graph-Partitionierung ausgeführt und gelten nur für Knoten, die dem CPU-Ausführungsanbieter zugewiesen sind. Verfügbare Layout-Optimierungen sind:

  • NCHWc Optimizer: Optimiert den Graphen durch Verwendung des NCHWc-Layouts anstelle des NCHW-Layouts.

Online/Offline-Modus

Alle Optimierungen können entweder online oder offline durchgeführt werden. Im Online-Modus wenden wir beim Initialisieren einer Inferenzsitzung auch alle aktivierten Graph-Optimierungen an, bevor wir die Modellinferenz durchführen. Das Anwenden aller Optimierungen jedes Mal, wenn wir eine Sitzung starten, kann den Zeitaufwand für den Modellstart erhöhen (insbesondere bei komplexen Modellen), was in Produktionsszenarien entscheidend sein kann. Hier kann der Offline-Modus einen großen Vorteil bringen. Im Offline-Modus serialisiert ONNX Runtime nach Durchführung der Graph-Optimierungen das resultierende Modell auf die Festplatte. Anschließend können wir die Startzeit reduzieren, indem wir das bereits optimierte Modell verwenden und alle Optimierungen deaktivieren.

Hinweise:

  • Stellen Sie bei der Ausführung im Offline-Modus sicher, dass Sie genau dieselben Optionen (z. B. Ausführungsanbieter, Optimierungsstufe) und dieselbe Hardware wie auf der Zielmaschine verwenden, auf der die Modellinferenz ausgeführt werden soll (z. B. können Sie kein Modell ausführen, das für einen GPU-Ausführungsanbieter voroptimiert wurde, auf einer Maschine, die nur mit einer CPU ausgestattet ist).
  • Wenn Layout-Optimierungen aktiviert sind, kann der Offline-Modus nur auf kompatibler Hardware zu der Umgebung verwendet werden, in der das Offline-Modell gespeichert wird. Wenn ein Modell beispielsweise für AVX2 mit Layout-Optimierung versehen wurde, benötigt das Offline-Modell CPUs, die AVX2 unterstützen.

Verwendung

Stufen

ONNX Runtime definiert die Enum GraphOptimizationLevel, um zu bestimmen, welche der oben genannten Optimierungsstufen aktiviert werden. Die Wahl einer Stufe aktiviert die Optimierungen dieser Stufe sowie die Optimierungen aller vorherigen Stufen. Beispielsweise aktiviert die Aktivierung von Extended-Optimierungen auch Basic-Optimierungen. Die Zuordnung dieser Stufen zur Enum ist wie folgt:

  • GraphOptimizationLevel::ORT_DISABLE_ALL -> Deaktiviert alle Optimierungen
  • GraphOptimizationLevel::ORT_ENABLE_BASIC -> Aktiviert Basis-Optimierungen
  • GraphOptimizationLevel::ORT_ENABLE_EXTENDED -> Aktiviert Basis- und erweiterte Optimierungen
  • GraphOptimizationLevel::ORT_ENABLE_ALL -> Aktiviert alle verfügbaren Optimierungen einschließlich Layout-Optimierungen

Offline-Modus

Um die Serialisierung des optimierten Modells auf die Festplatte zu aktivieren, setzen Sie die SessionOptions-Option optimized_model_filepath.

Python API-Beispiel

import onnxruntime as rt

sess_options = rt.SessionOptions()

# Set graph optimization level
sess_options.graph_optimization_level = rt.GraphOptimizationLevel.ORT_ENABLE_EXTENDED

# To enable model serialization after graph optimization set this
sess_options.optimized_model_filepath = "<model_output_path\optimized_model.onnx>"

session = rt.InferenceSession("<model_path>", sess_options)

C API-Beispiel

  const OrtApi* Ort::g_api = OrtGetApi(ORT_API_VERSION);
  OrtEnv* env;
  g_ort->CreateEnv(ORT_LOGGING_LEVEL_WARNING, "test", &env);
  OrtSessionOptions* session_options;
  g_ort->CreateSessionOptions(&session_options)

  // Set graph optimization level
  g_ort->SetSessionGraphOptimizationLevel(session_options, ORT_ENABLE_EXTENDED);

  // To enable model serialization after graph optimization set this
  const ORTCHAR_T* optimized_model_path = ORT_TSTR("optimized_model_path");
  g_ort->SetOptimizedModelFilePath(session_options, optimized_model_path);

  OrtSession* session;
  const ORTCHAR_T* model_path = ORT_TSTR("model_path");
  g_ort->CreateSession(env, model_path, session_options, &session);

C#-API-Beispiel

SessionOptions so = new SessionOptions();

// Set graph optimization level
so.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_EXTENDED;

// To enable model serialization after graph optimization set this
so.OptimizedModelFilePath = "model_output_path\optimized_model.onnx"

var session = new InferenceSession(modelPath, so);

C++ API-Beispiel

Ort::SessionOptions session_options;

// Set graph optimization level
session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);

// To enable model serialization after graph optimization set this
session_options.SetOptimizedModelFilePath("optimized_file_path");

auto session_ = Ort::Session(env, "model_file_path", session_options);