準備訓練#
在邊緣裝置上開始訓練之前,需要在離線步驟中生成訓練工件。
這些工件包括
訓練 ONNX 模型
檢查點狀態
最佳化器 ONNX 模型
評估 ONNX 模型(可選)
假設已有一個僅包含前向計算的 ONNX 模型。如果使用 PyTorch,可以透過 torch.onnx.export() API 匯出 PyTorch 模型來生成此模型。
注意
如果使用 PyTorch 匯出模型,請使用以下匯出引數,以確保訓練工件生成成功
export_params:Truedo_constant_folding:Falsetraining:torch.onnx.TrainingMode.TRAINING
一旦僅包含前向計算的 ONNX 模型可用,就可以使用 onnxruntime.training.artifacts.generate_artifacts() API 生成訓練工件。
示例用法
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]#
新增到訓練模型的損失型別。
與 generate_artifacts 函式的 loss 引數一起使用。
- MSELoss = 1#
- CrossEntropyLoss = 2#
- BCEWithLogitsLoss = 3#
- L1Loss = 4#
- class onnxruntime.training.artifacts.OptimType(value)[source]#
生成訓練最佳化器模型時使用的最佳化器型別。
與 generate_artifacts 函式的 optimizer 引數一起使用。
- 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]#
生成使用 ORT 訓練 API 進行訓練所需的工件。
- 此函式生成以下工件
訓練模型 (onnx.ModelProto):包含基礎模型圖、損失子圖和梯度圖。
評估模型 (onnx.ModelProto):包含基礎模型圖和損失子圖
檢查點(目錄):包含模型引數。
最佳化器模型 (onnx.ModelProto):包含最佳化器圖的模型。
所有生成的 ModelProto 將使用由 model 定義的相同 opsets。
- 引數:
model – 用於生成梯度圖的基礎模型或基礎模型的路徑。對於大於 2GB 的模型,請使用基礎模型的路徑。
requires_grad – 需要計算梯度的模型引數名稱列表
frozen_params – 應凍結的模型引數名稱列表。
loss – 用於訓練的損失函式列舉或 onnxblock。如果為 None,則圖中不新增損失節點。
optimizer – 用於訓練的最佳化器列舉或 onnxblock。如果為 None,則不生成最佳化器模型。
artifact_directory – 儲存生成工件的目錄。如果為 None,則使用當前工作目錄。
prefix – 用於生成工件的字首。如果未指定,則不使用字首。
ort_format – 是否以 ORT 格式儲存生成工件。預設為 False。
custom_op_library – 自定義操作庫的路徑。如果未指定,則不使用自定義操作庫。
additional_output_names – 除了損失輸出之外,新增到訓練/評估模型的附加輸出名稱列表。預設為 None。
nominal_checkpoint – 除了完整檢查點外,是否生成名義檢查點。預設為 False。名義檢查點是一個包含有關模型引數名義資訊的檢查點。它可用於在裝置上構建訓練模型時減少開銷,以及減小裝置上應用程式打包的檢查點大小。
loss_input_names – 指定專門用於損失計算的輸入名稱列表。提供時,只有這些輸入將傳遞給損失函式。如果為 None,則所有圖輸出都將傳遞給損失函式。
- 引發:
RuntimeError – 如果提供的損失既不是支援的損失之一,也不是 onnxblock.Block 的例項
RuntimeError – 如果提供的最佳化器不是支援的最佳化器之一。
自定義損失#
如果需要自定義損失,使用者可以將自定義損失函式提供給 onnxruntime.training.artifacts.generate_artifacts() API。這可以透過繼承 onnxruntime.training.onnxblock.Block 類並實現 build 方法來完成。
以下示例展示瞭如何實現自定義損失函式
假設我們要將自定義損失函式與模型一起使用。在此示例中,我們假設模型生成兩個輸出。自定義損失函式必須對每個輸出應用損失函式,並對輸出執行加權平均。數學上,
loss = 0.4 * mse_loss1(output1, target1) + 0.6 * mse_loss2(output2, target2)
由於這是自定義損失函式,因此此損失型別不作為 LossType 列舉公開。
為此,我們使用 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)
高階用法#
onnxblock 是一個庫,可以透過相互堆疊簡單的塊來構建複雜的 ONNX 模型。例如,上面所示的構建自定義損失函式的功能。
onnxblock 還提供了一種方法,透過 onnxruntime.training.onnxblock.ForwardBlock 和 onnxruntime.training.onnxblock.TrainingBlock 類分別構建自定義的僅前向或訓練(前向+後向)ONNX 模型。這些塊繼承自基礎 onnxruntime.training.onnxblock.Block 類,並提供構建推理和訓練模型的附加功能。
- class onnxruntime.training.onnxblock.ForwardBlock[source]#
基類:
Block所有需要自動構建前向模型的塊的基類。
需要透過在現有模型之上堆疊塊來構建前向模型的塊必須繼承此類。子類對 build 方法的實現必須返回圖輸出的名稱。此塊將自動將該輸出註冊為圖輸出並構建模型。
示例
>>> 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)
以上示例將自動構建前向圖,該圖由現有模型和堆疊在其上的交叉熵損失函式組成。
- to_model_proto()[source]#
返回前向模型。
- 返回:
前向模型。
- 返回型別:
模型 (onnx.ModelProto)
- 引發:
RuntimeError – 如果尚未呼叫 build 方法(即尚未構建前向模型)。
- infer_shapes_on_base()#
對全域性模型執行形狀推斷。如果使用了路徑,則使用 infer_shapes_path API 支援具有外部資料的模型。
返回形狀推斷後的 ModelProto。
- class onnxruntime.training.onnxblock.TrainingBlock[source]#
基類:
Block所有需要自動構建梯度模型的塊的基類。
需要根據塊的輸出來計算梯度圖的塊必須繼承此類。子類對 build 方法的實現必須返回反向傳播開始的輸出名稱(通常是損失函式的輸出名稱)。
示例
>>> 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)
以上示例將自動構建從損失函式輸出開始的整個模型的梯度圖。
- abstract build(*args, **kwargs)[source]#
透過在此函式的輸入之上堆疊塊來定製此模型的前向圖。
此方法應由子類重寫。此方法的輸出應為反向傳播開始的輸出名稱(通常是損失函式的輸出名稱)。
- requires_grad(argument_name: str, value: bool =True)[source]#
指定引數是否需要梯度。
自動微分將僅計算需要梯度的引數的梯度圖。預設情況下,沒有引數需要梯度。使用者必須明確指定哪些引數需要梯度。
- parameters() Tuple[List[TensorProto], List[TensorProto]][source]#
模型的可訓練引數和不可訓練引數(凍結引數)。
構建訓練模型時提取的模型引數將由此方法返回。
請注意,在構建訓練模型之前引數是未知的。因此,如果在構建訓練模型之前呼叫此方法,將引發異常。
- 返回:
模型的可訓練引數。frozen_params (onnx.TensorProto 列表):模型的不可訓練引數。
- 返回型別:
trainable_params (list of onnx.TensorProto)
- 引發:
RuntimeError – 如果尚未呼叫 build 方法(即尚未構建訓練模型)。
- to_model_proto() Tuple[ModelProto, ModelProto][source]#
返回訓練和評估模型。
一旦構建了梯度圖,就可以透過呼叫此方法檢索訓練和評估模型。
- 返回:
訓練模型。eval_model (onnx.ModelProto): 評估模型。
- 返回型別:
training_model (onnx.ModelProto)
- 引發:
RuntimeError – 如果尚未呼叫 build 方法(即尚未構建訓練模型)。
- infer_shapes_on_base()#
對全域性模型執行形狀推斷。如果使用了路徑,則使用 infer_shapes_path API 支援具有外部資料的模型。
返回形狀推斷後的 ModelProto。