Questo documento descrive lo schema di controllo delle versioni delle operazioni di LiteRT. Il controllo delle versioni delle operazioni consente agli sviluppatori di aggiungere nuove funzionalità e nuovi parametri alle operazioni esistenti. Inoltre, garantisce quanto segue:
- Compatibilità con le versioni precedenti: la nuova implementazione di LiteRT deve gestire un vecchio file del modello.
- Compatibilità in avanti: la vecchia implementazione di LiteRT deve gestire un nuovo file del modello prodotto dalla nuova versione del convertitore, a condizione che non vengano utilizzate nuove funzionalità.
- Rilevamento dell'incompatibilità in avanti: se una vecchia implementazione di LiteRT legge un nuovo modello che contiene una nuova versione di un'operazione non supportata, deve segnalare l'errore.
Esempio: aggiunta della dilatazione alla convoluzione depthwise
La parte restante di questo documento spiega il controllo delle versioni delle operazioni in TFLite mostrando come aggiungere parametri di dilatazione all'operazione di convoluzione depthwise.
Per comprendere questo documento non è necessaria la conoscenza della dilatazione. Ricorda:
- Verranno aggiunti due nuovi parametri interi:
dilation_width_factoredilation_height_factor. - I vecchi kernel di convoluzione depthwise che non supportano la dilatazione sono equivalenti a impostare i fattori di dilatazione su 1.
Modificare lo schema FlatBuffer
Per aggiungere nuovi parametri a un'operazione, modifica la tabella delle opzioni in
lite/schema/schema.fbs.
Ad esempio, la tabella delle opzioni della convoluzione separabile in profondità è simile alla seguente:
table DepthwiseConv2DOptions {
padding:Padding;
stride_w:int;
stride_h:int;
depth_multiplier:int;
fused_activation_function:ActivationFunctionType;
}
Quando aggiungi nuovi parametri:
- Aggiungi commenti che indichino quali parametri sono supportati da quale versione.
- Quando la nuova implementazione riceve i valori predefiniti per i parametri appena aggiunti, dovrebbe funzionare esattamente come la vecchia implementazione.
Dopo l'aggiunta dei nuovi parametri, la tabella sarà simile a questa:
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;
}
Il file lite/schema/schema_generated.h deve essere rigenerato per il nuovo schema.
Modificare le strutture C e l'implementazione del kernel
In LiteRT, l'implementazione del kernel è disaccoppiata dalla definizione di FlatBuffer.
I kernel leggono il parametro dalle strutture C definite in
lite/c/builtin_op_data.h.
Il parametro di convoluzione depthwise originale è il seguente:
typedef struct {
TfLitePadding padding;
int stride_width;
int stride_height;
int depth_multiplier;
TfLiteFusedActivation activation;
} TfLiteDepthwiseConvParams;
Come per lo schema FlatBuffer, aggiungi commenti che indicano quali parametri sono supportati a partire da quale versione. Il risultato è riportato di seguito:
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;
Modifica anche l'implementazione del kernel per leggere i parametri appena aggiunti dalle strutture C. I dettagli sono omessi qui.
Modificare il codice di lettura di FlatBuffer
La logica per leggere FlatBuffer e produrre la struttura C si trova in
lite/core/api/flatbuffer_conversions.cc.
Aggiorna il file per gestire i nuovi parametri, come mostrato di seguito:
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;
}
Non è necessario controllare la versione dell'app qui. Quando la nuova implementazione legge un vecchio file del modello in cui mancano i fattori di dilatazione, utilizza 1 come valore predefinito e il nuovo kernel funziona in modo coerente con il vecchio kernel.
Modifica registrazione kernel
MutableOpResolver (definito in lite/mutable_op_resolver.h) fornisce alcune
funzioni per registrare i kernel delle operazioni. Per impostazione predefinita, la versione minima e massima è 1:
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);
Le operazioni integrate sono registrate in lite/kernels/register.cc. In questo esempio,
abbiamo implementato un nuovo kernel op che può gestire le versioni DepthwiseConv2D1 e
2, quindi dobbiamo modificare questa riga:
AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D());
a:
AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D(),
/* min_version = */ 1,
/* max_version = */ 2);
Modifica la versione dell'operatore TFLite
Il passaggio successivo consiste nel fare in modo che TFLite inserisca la versione minima richiesta per eseguire l'operazione. In questo esempio, significa:
- Compila version=1 quando tutti i fattori di dilatazione sono 1.
- Altrimenti, compila version=2.
Modifica la funzione GetBuiltinOperatorVersion per l'operatore in
lite/tools/versioning/op_version.cc aggiungendo la nuova versione al caso di
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;
Aggiorna la mappa delle versioni degli operatori
L'ultimo passaggio consiste nell'aggiungere le informazioni sulla nuova versione alla mappa delle versioni degli operatori. Questo passaggio è obbligatorio perché dobbiamo generare la versione minima richiesta del runtime del modello in base a questa mappa delle versioni.
Per farlo, devi aggiungere una nuova voce della mappa in
lite/tools/versioning/runtime_version.cc.
In questo esempio, devi aggiungere la seguente voce in op_version_map:
{ {BuiltinOperator_DEPTHWISE_CONV_2D, 2}, %CURRENT_RUNTIME_VERSION%}
dove %CURRENT_RUNTIME_VERSION% corrisponde alla versione attuale del runtime
definita in release_version.h.
Implementazione della delega
LiteRT fornisce un'API di delega che consente di delegare le operazioni ai backend hardware. Nella funzione Prepare del delegato, controlla se la versione è
supportata per ogni nodo nel codice di delega.
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.
}
Questo è necessario anche se la delega supporta solo le operazioni della versione 1, in modo che possa rilevare l'incompatibilità quando riceve un'operazione di versione superiore.