Vorbereitung für das Training#

Bevor das Training auf Edge-Geräten beginnen kann, müssen die Trainingsartefakte in einem Offline-Schritt generiert werden.

Diese Artefakte umfassen

  1. Das ONNX-Trainingsmodell

  2. Der Checkpoint-Status

  3. Das ONNX-Optimierungsmodell

  4. Das Eval-ONNX-Modell (optional)

Es wird davon ausgegangen, dass ein reines Forward-ONNX-Modell bereits verfügbar ist. Dieses Modell kann durch Exportieren des PyTorch-Modells mit der torch.onnx.export() API generiert werden, wenn PyTorch verwendet wird.

Hinweis

Wenn Sie PyTorch zum Exportieren des Modells verwenden, verwenden Sie bitte die folgenden Exportargumente, damit die Generierung von Trainingsartefakten erfolgreich ist:

  • export_params: True

  • do_constant_folding: False

  • training: torch.onnx.TrainingMode.TRAINING

Sobald das reine Forward-ONNX-Modell verfügbar ist, können die Trainingsartefakte mit der onnxruntime.training.artifacts.generate_artifacts() API generiert werden.

Beispielnutzung

from onnxruntime.training import artifacts

# Load the forward only onnx model
model = onnx.load(path_to_forward_only_onnx_model)

# Generate the training artifacts
artifacts.generate_artifacts(model,
                             requires_grad = ["parameters", "needing", "gradients"],
                             frozen_params = ["parameters", "not", "needing", "gradients"],
                             loss = artifacts.LossType.CrossEntropyLoss,
                             optimizer = artifacts.OptimType.AdamW,
                             artifact_directory = path_to_output_artifact_directory)
class onnxruntime.training.artifacts.LossType(value)[source]#

Art des Verlusts, der dem Trainingsmodell hinzugefügt werden soll.

Zur Verwendung mit dem Parameter loss der Funktion generate_artifacts.

MSELoss = 1#
CrossEntropyLoss = 2#
BCEWithLogitsLoss = 3#
L1Loss = 4#
class onnxruntime.training.artifacts.OptimType(value)[source]#

Art des Optimierers, der beim Generieren des Optimierermodells für das Training verwendet werden soll.

Zur Verwendung mit dem Parameter optimizer der Funktion generate_artifacts.

AdamW = 1#
SGD = 2#
onnxruntime.training.artifacts.generate_artifacts(model: Union[ModelProto, str], requires_grad: Optional[List[str]] = None, frozen_params: Optional[List[str]] = None, loss: Optional[Union[LossType, Block]] = None, optimizer: Optional[Union[OptimType, Block]] = None, artifact_directory: Optional[Union[str, bytes, PathLike]] = None, prefix: str = '', ort_format: bool = False, custom_op_library: Optional[Union[str, bytes, PathLike]] = None, additional_output_names: Optional[List[str]] = None, nominal_checkpoint: bool = False, loss_input_names: Optional[List[str]] = None) None[source]#

Generiert Artefakte, die für das Training mit der ORT-Trainings-API benötigt werden.

Diese Funktion generiert die folgenden Artefakte:
  1. Trainingsmodell (onnx.ModelProto): Enthält den Basismodellgraphen, den Loss-Subgraphen und den Gradientengraphen.

  2. Eval-Modell (onnx.ModelProto): Enthält den Basismodellgraphen und den Loss-Subgraphen.

  3. Checkpoint (Verzeichnis): Enthält die Modellparameter.

  4. Optimierermodell (onnx.ModelProto): Modell, das den Optimierergraphen enthält.

Alle generierten ModelProtos verwenden dieselben Opsets, die durch model definiert sind.

Parameter:
  • model – Das Basismodell oder der Pfad zum Basismodell, das für die Generierung des Gradientengraphen verwendet werden soll. Für Modelle >2GB verwenden Sie den Pfad zum Basismodell.

  • requires_grad – Liste der Namen von Modellparametern, für die eine Gradientenberechnung erforderlich ist.

  • frozen_params – Liste der Namen von Modellparametern, die eingefroren werden sollen.

  • loss – Die Verlustfunktion als Enum oder onnxblock, die für das Training verwendet werden soll. Wenn None, wird kein Loss-Knoten zum Graphen hinzugefügt.

  • optimizer – Der Optimierer als Enum oder onnxblock, der für das Training verwendet werden soll. Wenn None, wird kein Optimierermodell generiert.

  • artifact_directory – Das Verzeichnis zum Speichern der generierten Artefakte. Wenn None, wird das aktuelle Arbeitsverzeichnis verwendet.

  • prefix – Das Präfix, das für die generierten Artefakte verwendet werden soll. Wenn nicht angegeben, wird kein Präfix verwendet.

  • ort_format – Ob die generierten Artefakte im ORT-Format gespeichert werden sollen oder nicht. Standard ist False.

  • custom_op_library – Der Pfad zur benutzerdefinierten Operator-Bibliothek. Wenn nicht angegeben, wird keine benutzerdefinierte Operator-Bibliothek verwendet.

  • additional_output_names – Liste der zusätzlichen Ausgabenamen, die zum Trainings-/Eval-Modell hinzugefügt werden sollen, zusätzlich zur Loss-Ausgabe. Standard ist None.

  • nominal_checkpoint – Ob der nominale Checkpoint zusätzlich zum vollständigen Checkpoint generiert werden soll. Standard ist False. Ein nominaler Checkpoint ist ein Checkpoint, der nominale Informationen über die Modellparameter enthält. Er kann auf dem Gerät verwendet werden, um den Overhead bei der Konstruktion des Trainingsmodells zu reduzieren und die Größe des mit der On-Device-Anwendung gebündelten Checkpoints zu verringern.

  • loss_input_names – Gibt eine Liste von Eingabenamen an, die speziell für die Verlustberechnung verwendet werden sollen. Wenn angegeben, werden nur diese Eingaben an die Verlustfunktion übergeben. Wenn None, werden alle Graphenausgaben an die Verlustfunktion übergeben.

Ausnahmen:
  • RuntimeError – Wenn der angegebene Verlust weder einer der unterstützten Verluste noch eine Instanz von onnxblock.Block ist.

  • RuntimeError – Wenn der angegebene Optimierer nicht einer der unterstützten Optimierer ist.

Benutzerdefinierter Verlust#

Wenn ein benutzerdefinierter Verlust benötigt wird, kann der Benutzer eine benutzerdefinierte Verlustfunktion an die API onnxruntime.training.artifacts.generate_artifacts() übergeben. Dies geschieht durch Ableiten von der Klasse onnxruntime.training.onnxblock.Block und Implementieren der Methode build.

Das folgende Beispiel zeigt, wie eine benutzerdefinierte Verlustfunktion implementiert wird.

Nehmen wir an, wir möchten eine benutzerdefinierte Verlustfunktion mit einem Modell verwenden. Für dieses Beispiel nehmen wir an, dass unser Modell zwei Ausgaben erzeugt. Und die benutzerdefinierte Verlustfunktion muss eine Verlustfunktion auf jede der Ausgaben anwenden und einen gewichteten Durchschnitt der Ausgabe durchführen. Mathematisch gesehen,

loss = 0.4 * mse_loss1(output1, target1) + 0.6 * mse_loss2(output2, target2)

Da es sich um eine benutzerdefinierte Verlustfunktion handelt, wird dieser Verlusttyp nicht als Enum von der LossType-Enumeration exponiert.

Dafür nutzen wir onnxblock.

import onnxruntime.training.onnxblock as onnxblock
from onnxruntime.training import artifacts

# Define a custom loss block that takes in two inputs
# and performs a weighted average of the losses from these
# two inputs.
class WeightedAverageLoss(onnxblock.Block):
    def __init__(self):
        self._loss1 = onnxblock.loss.MSELoss()
        self._loss2 = onnxblock.loss.MSELoss()
        self._w1 = onnxblock.blocks.Constant(0.4)
        self._w2 = onnxblock.blocks.Constant(0.6)
        self._add = onnxblock.blocks.Add()
        self._mul = onnxblock.blocks.Mul()

    def build(self, loss_input_name1, loss_input_name2):
        # The build method defines how the block should be stacked on top of
        # loss_input_name1 and loss_input_name2

        # Returns weighted average of the two losses
        return self._add(
            self._mul(self._w1(), self._loss1(loss_input_name1, target_name="target1")),
            self._mul(self._w2(), self._loss2(loss_input_name2, target_name="target2"))
        )

my_custom_loss = WeightedAverageLoss()

# Load the onnx model
model_path = "model.onnx"
base_model = onnx.load(model_path)

# Define the parameters that need their gradient computed
requires_grad = ["weight1", "bias1", "weight2", "bias2"]
frozen_params = ["weight3", "bias3"]

# Now, we can invoke generate_artifacts with this custom loss function
artifacts.generate_artifacts(base_model, requires_grad = requires_grad, frozen_params = frozen_params,
                            loss = my_custom_loss, optimizer = artifacts.OptimType.AdamW)

# Successful completion of the above call will generate 4 files in the current working directory,
# one for each of the artifacts mentioned above (training_model.onnx, eval_model.onnx, checkpoint, optimizer_model.onnx)
class onnxruntime.training.onnxblock.Block(temp_file_name='temp.onnx')[source]#

Bases: ABC

Basisklasse für alle Blöcke, die aufeinander gestapelt werden können.

Alle Blöcke, die das Modell manipulieren wollen, müssen diese Klasse ableiten. Die Implementierung der build-Methode der abgeleiteten Klasse muss die Namen der Zwischenausgaben des Blocks zurückgeben.

Die Implementierung der build-Methode der abgeleiteten Klasse muss das Basismodell nach eigenem Ermessen manipulieren, aber das manipulierte Modell muss gültig sein (wie vom ONNX-Checker festgestellt).

base#

Das Basismodell, das die abgeleitete Klasse manipulieren kann.

Typ:

onnx.ModelProto

abstract build(*args, **kwargs)[source]#

Passt das Modell an, indem Blöcke auf die Eingaben dieser Funktion gestapelt werden.

Diese Methode muss von der abgeleiteten Klasse überschrieben werden.

infer_shapes_on_base()[source]#

Führt die Form-Inferenz für das globale Modell durch. Wenn ein Pfad verwendet wurde, wird die API infer_shapes_path verwendet, um Modelle mit externen Daten zu unterstützen.

Gibt das form-inferierte ModelProto zurück.

Erweiterte Nutzung#

onnxblock ist eine Bibliothek, mit der komplexe ONNX-Modelle durch Stapeln einfacher Blöcke aufeinander aufgebaut werden können. Ein Beispiel hierfür ist die Möglichkeit, eine benutzerdefinierte Verlustfunktion wie oben gezeigt zu erstellen.

onnxblock bietet auch eine Möglichkeit, ein benutzerdefiniertes reines Forward- oder Trainingsmodell (Forward + Backward) über die Klassen onnxruntime.training.onnxblock.ForwardBlock und onnxruntime.training.onnxblock.TrainingBlock zu erstellen. Diese Blöcke erben von der Basisklasse onnxruntime.training.onnxblock.Block und bieten zusätzliche Funktionalität zum Erstellen von Inferenz- und Trainingsmodellen.

class onnxruntime.training.onnxblock.ForwardBlock[source]#

Bases: Block

Basisklasse für alle Blöcke, für die ein Forward-Modell automatisch erstellt werden muss.

Blöcke, die ein Forward-Modell erstellen wollen, indem sie Blöcke auf das bestehende Modell stapeln, müssen diese Klasse ableiten. Die Implementierung der build-Methode der abgeleiteten Klasse muss den Namen der Graphenausgabe zurückgeben. Dieser Block registriert die Ausgabe automatisch als Graphenausgabe und erstellt das Modell.

Beispiel

>>> class MyForwardBlock(ForwardBlock):
>>>     def __init__(self):
>>>         super().__init__()
>>>         self.loss = onnxblock.loss.CrossEntropyLoss()
>>>
>>>     def build(self, loss_input_name: str):
>>>         # Add a cross entropy loss on top of the output so far (loss_input_name)
>>>         return self.loss(loss_input_name)

Das obige Beispiel erstellt automatisch den Forward-Graphen, der aus dem bestehenden Modell und der Kreuzentropie-Verlustfunktion, die darauf gestapelt ist, besteht.

abstract build(*args, **kwargs)[source]#

Passt den Forward-Graphen für dieses Modell an, indem Blöcke auf die Eingaben dieser Funktion gestapelt werden.

Diese Methode sollte von der abgeleiteten Klasse überschrieben werden. Die Ausgabe dieser Methode sollte der Name der Graphenausgabe sein.

to_model_proto()[source]#

Gibt das Forward-Modell zurück.

Rückgabe:

Das Forward-Modell.

Rückgabetyp:

model (onnx.ModelProto)

Ausnahmen:

RuntimeError – Wenn die build-Methode nicht aufgerufen wurde (d. h. das Forward-Modell wurde noch nicht erstellt).

infer_shapes_on_base()#

Führt die Form-Inferenz für das globale Modell durch. Wenn ein Pfad verwendet wurde, wird die API infer_shapes_path verwendet, um Modelle mit externen Daten zu unterstützen.

Gibt das form-inferierte ModelProto zurück.

class onnxruntime.training.onnxblock.TrainingBlock[source]#

Bases: Block

Basisklasse für alle Blöcke, für die ein Gradientenmodell automatisch erstellt werden muss.

Blöcke, die den Gradientengraphen basierend auf der Ausgabe des Blocks berechnen müssen, müssen diese Klasse ableiten. Die Implementierung der build-Methode der abgeleiteten Klasse muss den Namen der Ausgabe zurückgeben, von wo aus die Rückpropagation beginnen soll (typischerweise der Name der Ausgabe der Verlustfunktion).

Beispiel

>>> class MyTrainingBlock(TrainingBlock):
>>>     def __init__(self):
>>>         super().__init__()
>>>         self.loss = onnxblock.loss.CrossEntropyLoss()
>>>
>>>     def build(self, loss_input_name: str):
>>>         # Add a cross entropy loss on top of the output so far (loss_input_name)
>>>         return self.loss(loss_input_name)

Das obige Beispiel erstellt automatisch den Gradientengraphen für das gesamte Modell, beginnend mit der Ausgabe der Verlustfunktion.

abstract build(*args, **kwargs)[source]#

Passt den Forward-Graphen für dieses Modell an, indem Blöcke auf die Eingaben dieser Funktion gestapelt werden.

Diese Methode sollte von der abgeleiteten Klasse überschrieben werden. Die Ausgabe dieser Methode sollte der Name der Ausgabe sein, von wo aus die Rückpropagation beginnen soll (typischerweise der Name der Ausgabe der Verlustfunktion).

requires_grad(argument_name: str, value: bool = True)[source]#

Gibt an, ob das Argument einen Gradienten erfordert oder nicht.

Die automatische Differenzierung berechnet den Gradientengraphen nur für die Argumente, die einen Gradienten erfordern. Standardmäßig erfordert keines der Argumente einen Gradienten. Der Benutzer muss explizit angeben, welche Argumente einen Gradienten erfordern.

Parameter:
  • argument_name (str) – Der Name des Arguments, das einen Gradienten erfordert/nicht erfordert.

  • value (bool) – True, wenn das Argument einen Gradienten erfordert, False andernfalls.

parameters() Tuple[List[TensorProto], List[TensorProto]][source]#

Trainierbare sowie nicht trainierbare (eingefrorene) Parameter des Modells.

Modellparameter, die beim Erstellen des Trainingsmodells extrahiert werden, werden von dieser Methode zurückgegeben.

Beachten Sie, dass die Parameter erst bekannt sind, nachdem das Trainingsmodell erstellt wurde. Wenn diese Methode also vor dem Erstellen des Trainingsmodells aufgerufen wird, wird eine Ausnahme ausgelöst.

Rückgabe:

Die trainierbaren Parameter des Modells. frozen_params (Liste von onnx.TensorProto): Die nicht trainierbaren Parameter des Modells.

Rückgabetyp:

trainable_params (list von onnx.TensorProto)

Ausnahmen:

RuntimeError – Wenn die build-Methode nicht aufgerufen wurde (d. h. das Trainingsmodell wurde noch nicht erstellt).

to_model_proto() Tuple[ModelProto, ModelProto][source]#

Gibt die Trainings- und Eval-Modelle zurück.

Sobald der Gradientengraph erstellt wurde, können das Trainings- und Eval-Modell durch Aufrufen dieser Methode abgerufen werden.

Rückgabe:

Das Trainingsmodell. eval_model (onnx.ModelProto): Das Eval-Modell.

Rückgabetyp:

training_model (onnx.ModelProto)

Ausnahmen:

RuntimeError – Wenn die build-Methode nicht aufgerufen wurde (d. h. das Trainingsmodell wurde noch nicht erstellt).

infer_shapes_on_base()#

Führt die Form-Inferenz für das globale Modell durch. Wenn ein Pfad verwendet wurde, wird die API infer_shapes_path verwendet, um Modelle mit externen Daten zu unterstützen.

Gibt das form-inferierte ModelProto zurück.