In diesem Dokument wird das operative Versionsverwaltungsschema von LiteRT beschrieben. Op-Versionsverwaltung ermöglicht es Entwicklern, neue Funktionen und Parameter in vorhandene Abläufe zu integrieren. Darüber hinaus wird Folgendes garantiert:
- Abwärtskompatibilität: Die neue LiteRT-Implementierung sollte eine alten Modelldatei.
- Aufwärtskompatibilität: Die alte LiteRT-Implementierung sollte eine Neue Modelldatei, die von der neuen Version des Konverters erstellt wird, solange keine neuen Funktionen verwendet werden.
- Erkennung von Inkompatibilitäten bei Weiterleitung: Wenn eine alte LiteRT-Implementierung ein neues Modell liest, das eine neue Version eines Vorgangs enthält, unterstützt, sollte der Fehler gemeldet werden.
Beispiel: Dilation zur tiefen Faltung hinzufügen
Im weiteren Verlauf dieses Dokuments wird die Versionsverwaltung in TFLite erläutert, indem gezeigt wird, wie um Dilatationsparameter zur tiefenweisen Faltung hinzuzufügen.
Zum Verständnis dieses Dokuments sind keine Kenntnisse der Dilatation erforderlich. Hinweis:
- Zwei neue Ganzzahlparameter werden hinzugefügt:
dilation_width_factor
unddilation_height_factor
. - Alte Kernel mit tiefgehender Faltung, die keine Dilatation unterstützen, sind äquivalent Dilatationsfaktoren auf 1 zu setzen.
FlatBuffer-Schema ändern
Um einem Vorgang neue Parameter hinzuzufügen, ändern Sie die Optionstabelle in
lite/schema/schema.fbs
Die Optionstabelle für die tiefe Faltung sieht beispielsweise so aus:
table DepthwiseConv2DOptions {
padding:Padding;
stride_w:int;
stride_h:int;
depth_multiplier:int;
fused_activation_function:ActivationFunctionType;
}
Beim Hinzufügen neuer Parameter:
- Fügen Sie Kommentare hinzu, die angeben, welche Parameter von welcher Version unterstützt werden.
- Wenn die neue Implementierung die Standardwerte für neu hinzugefügte Parameter verwenden, sollte sie genauso funktionieren wie die alte Implementierung.
Die Tabelle sieht nach dem Hinzufügen der neuen Parameter so aus:
table DepthwiseConv2DOptions {
// Parameters for DepthwiseConv version 1 or above.
padding:Padding;
stride_w:int;
stride_h:int;
depth_multiplier:int;
fused_activation_function:ActivationFunctionType;
// Parameters for DepthwiseConv version 2 or above.
dilation_w_factor:int = 1;
dilation_h_factor:int = 1;
}
Die Datei lite/schema/schema_generated.h
sollte für die neue
Schema.
C-Strukturen und Kernel-Implementierung ändern
In LiteRT ist die Kernel-Implementierung von FlatBuffer entkoppelt
Definition. Die Kernel lesen den Parameter aus den C-Strukturen, die in
lite/c/builtin_op_data.h
Der ursprüngliche Parameter für die tiefeseitige Faltung lautet wie folgt:
typedef struct {
TfLitePadding padding;
int stride_width;
int stride_height;
int depth_multiplier;
TfLiteFusedActivation activation;
} TfLiteDepthwiseConvParams;
Wie beim FlatBuffer-Schema können Sie auch hier Kommentare hinzufügen, die angeben, welche Parameter ab welcher Version unterstützt wird. Das Ergebnis sieht so aus:
typedef struct {
// Parameters for DepthwiseConv version 1 or above.
TfLitePadding padding;
int stride_width;
int stride_height;
int depth_multiplier;
TfLiteFusedActivation activation;
// Parameters for DepthwiseConv version 2 or above.
int dilation_width_factor;
int dilation_height_factor;
} TfLiteDepthwiseConvParams;
Ändern Sie auch die Kernel-Implementierung, damit die neu hinzugefügten Parameter gelesen werden. aus den C-Strukturen. Die Details werden hier weggelassen.
FlatBuffer-Lesecode ändern
Die Logik zum Lesen von FlatBuffer und Erstellen der C-Struktur befindet sich in
lite/core/api/flatbuffer_conversions.cc
Aktualisieren Sie die Datei so, dass die neuen Parameter verarbeitet werden:
TfLiteStatus ParseDepthwiseConv2D(const Operator* op,
ErrorReporter* error_reporter,
BuiltinDataAllocator* allocator,
void** builtin_data) {
CheckParsePointerParams(op, error_reporter, allocator, builtin_data);
SafeBuiltinDataAllocator safe_allocator(allocator);
std::unique_ptr<TfLiteDepthwiseConvParams,
SafeBuiltinDataAllocator::BuiltinDataDeleter>
params = safe_allocator.Allocate<TfLiteDepthwiseConvParams>();
TF_LITE_ENSURE(error_reporter, params != nullptr);
const DepthwiseConv2DOptions* schema_params =
op->builtin_options_as_DepthwiseConv2DOptions();
if (schema_params != nullptr) {
params->padding = ConvertPadding(schema_params->padding());
params->stride_width = schema_params->stride_w();
params->stride_height = schema_params->stride_h();
params->depth_multiplier = schema_params->depth_multiplier();
params->activation =
ConvertActivation(schema_params->fused_activation_function());
params->dilation_width_factor = schema_params->dilation_w_factor();
params->dilation_height_factor = schema_params->dilation_h_factor();
}
*builtin_data = params.release();
return kTfLiteOk;
}
Es ist nicht erforderlich, die Op-Version hier zu prüfen. Wenn die neue Implementierung eine alte Modelldatei liest, bei der Dilatationsfaktoren fehlen, wird 1 als Der neue Kernel funktioniert dann einheitlich mit dem alten.
Kernel-Registrierung ändern
Der MutableOpResolver (definiert in lite/mutable_op_resolver.h
) bietet einige
zum Registrieren von Vorgangs-Kerneln. Die Mindest- und Höchstversion sind 1 zu
Standardeinstellung:
void AddBuiltin(tflite::BuiltinOperator op, TfLiteRegistration* registration,
int min_version = 1, int max_version = 1);
void AddCustom(const char* name, TfLiteRegistration* registration,
int min_version = 1, int max_version = 1);
Die integrierten Vorgänge sind in lite/kernels/register.cc
registriert. In diesem Beispiel
Wir haben einen neuen Operations-Kernel implementiert, der DepthwiseConv2D
Version 1 und
2, also müssen wir diese Zeile ändern:
AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D());
in
AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D(),
/* min_version = */ 1,
/* max_version = */ 2);
TFLite-Vorgangsversion ändern
Im nächsten Schritt legen Sie fest, dass TFLite die Mindestversion ausfüllt, die für die Ausführung den Vorgang ausführen. In diesem Beispiel bedeutet das:
- Füllen Sie Version=1 aus, wenn die Dilatationsfaktoren alle 1 sind.
- Andernfalls füllen Sie Version 2 aus.
Funktion GetBuiltinOperatorVersion
für den Operator ändern in
lite/tools/versioning/op_version.cc
, indem Sie die neue Version zum Fall von
DepthwiseConv2D
:
case BuiltinOperator_DEPTHWISE_CONV_2D:
auto depthwise_conv_params =
reinterpret_cast<TfLiteDepthwiseConvParams*>(op_sig.builtin_data);
TFLITE_DCHECK(depthwise_conv_params != nullptr);
if (depthwise_conv_params->dilation_width_factor != 1 ||
depthwise_conv_params->dilation_height_factor != 1) {
return 2;
}
return 1;
Operatorversionszuordnung aktualisieren
Im letzten Schritt werden die Informationen zur neuen Version zur Versionszuordnung des Operators hinzugefügt. Dieses Schritt ist erforderlich, da wir das Minimum für das Modell generieren müssen, Laufzeitversion basierend auf dieser Versionszuordnung.
Dazu müssen Sie in
lite/tools/versioning/runtime_version.cc
In diesem Beispiel müssen Sie op_version_map
den folgenden Eintrag hinzufügen:
{ {BuiltinOperator_DEPTHWISE_CONV_2D, 2}, %CURRENT_RUNTIME_VERSION%}
wobei %CURRENT_RUNTIME_VERSION%
der aktuellen Laufzeitversion entspricht
definiert in tensorflow/core/public/version.h.
Implementierung der Delegierung
LiteRT bietet ein Delegations-API, das das Delegieren von Vorgängen an
Hardware-Back-Ends. Prüfen Sie in der Funktion Prepare
des Bevollmächtigten, ob die Version
wird für jeden Knoten im Delegationscode unterstützt.
const int kMaxVersion = 1;
TfLiteNode* node;
TfLiteRegistration* registration = nullptr;
TF_LITE_ENSURE_STATUS(context->GetNodeAndRegistration(context, node_index, &node, ®istration));
if (registration->version > kMaxVersion) {
// Reject the node if the version isn't supported.
}
Dies ist auch dann erforderlich, wenn die Delegierung nur Vorgänge der Version 1 unterstützt, sodass der Die Delegierung kann Inkompatibilität erkennen, wenn ein höherer Versionsvorgang abgerufen wird.