Strutture dati

Le seguenti strutture dati sono utilizzate per operazioni con modelli ONNX:

OnnxTypeInfo #

La struttura descrive il tipo di un ingresso o parametro d'uscita di un modello ONNX

struct OnnxTypeInfo
 {
  ENUM_ONNX_TYPE        type;          // tipo di parametro
  OnnxTensorTypeInfo    tensor;        // descrizione del tensore
  OnnxMapTypeInfo       map;           // descrizione della mappa
  OnnxSequenceTypeInfo  sequence;      // descrizione della sequenza
 };

Solo il tensore (ONNX_TYPE_TENSOR) può essere usato come ingresso. In questo caso, solo il campo OnnxTypeInfo::tensor è riempito con valori, mentre gli altri campi (mappa e sequenza) non sono definiti.

Solo uno dei tre tipi OnnxTypeInfo (ONNX_TYPE_TENSOR, ONNX_TYPE_MAP o ONNX_TYPE_SEQUENCE) può essere utilizzato come ingresso. La sottostruttura corrispondente (OnnxTypeInfo::tensor, OnnxTypeInfo::map o OnnxTypeInfo::sequence) viene riempita a seconda del tipo.

 

OnnxTensorTypeInfo

La struttura descrive il tensore in ingresso o parametro d'uscita di un modello ONNX

struct OnnxTensorTypeInfo
 {
  const ENUM_ONNX_DATA_TYPE  data_type;      // tipo di dati nel tensore
  const long                 dimensions[];   // numero di elementi nel tensore
 };

OnnxMapTypeInfo #

La struttura descrive la mappa ottenuta nel parametro d'uscita di un modello ONNX

struct OnnxMapTypeInfo
 {
  const ENUM_ONNX_DATA_TYPE  key_type;      // tipo di chiave
  const OnnxTypeInfo&        value_type;    // tipo di valore
 };

OnnxSequenceTypeInfo #

La struttura descrive la sequenza ottenuta nel parametro d'uscita di un modello ONNX

struct OnnxSequenceTypeInfo
 {
  const OnnxTypeInfo&        value_type;      // tipo di dati nella sequenza
 };

 

 

ENUM_ONNX_TYPE #

L'enumerazione ENUM_ONNX_TYPE definisce il tipo di parametro di un modello

ID

Descrizione

ONNX_TYPE_UNKNOWN

Sconosciuto

ONNX_TYPE_TENSOR

Tensore

ONNX_TYPE_SEQUENCE

Sequenza

ONNX_TYPE_MAP

Mappa

ONNX_TYPE_OPAQUE

Astratto (opaco)

ONNX_TYPE_SPARSETENSOR

Tensore sparso

ENUM_ONNX_DATA_TYPE #

L'enumerazione >ENUM_ONNX_DATA_TYPE definisce il tipo di dati usato

ID

Descrizione

ONNX_DATA_TYPE_UNDEFINED

Non definito

ONNX_DATA_TYPE_FLOAT

float

ONNX_DATA_TYPE_INT8

int 8-bit

ONNX_DATA_TYPE_UINT16

uint 16-bit

ONNX_DATA_TYPE_INT16

int 16-bit

ONNX_DATA_TYPE_INT32

int 32-bit

ONNX_DATA_TYPE_INT64

int 64-bit

ONNX_DATA_TYPE_STRING

string

ONNX_DATA_TYPE_BOOL

bool

ONNX_DATA_TYPE_FLOAT16

float 16-bit

ONNX_DATA_TYPE_DOUBLE

double

ONNX_DATA_TYPE_UINT32

uint 32-bit

ONNX_DATA_TYPE_UINT64

uint 64-bit

ONNX_DATA_TYPE_COMPLEX64

numeri complessi a 64-bit

ONNX_DATA_TYPE_COMPLEX128

numeri complessi a 128-bit

ONNX_DATA_TYPE_BFLOAT16

bfloat 16-bit (Brain Floating Point)

ENUM_ONNX_FLAGS #

L'enumerazione ENUM_ONNX_FLAGS descrive la modalità di esecuzione del modello

ID

Descrizione

ONNX_LOGLEVEL_VERBOSE

Registra tutti i messaggi

ONNX_LOGLEVEL_INFO

Registra messaggi informativi, avvisi ed errori (questo flag sostituisce ONNX_DEBUG_LOGS)

ONNX_LOGLEVEL_WARNING

Registra avvisi ed errori (predefinito)

ONNX_LOGLEVEL_ERROR

Registra solo gli errori

ONNX_NO_CONVERSION

Disabilita la conversione automatica, utilizza i dati utente così come sono

ONNX_COMMON_FOLDER  

Carica un file modello dalla cartella Common\Files; il valore è uguale al flag FILE_COMMON

ONNX_USE_CPU_ONLY

Esegue il modello ONNX utilizzando solo la CPU

ONNX_GPU_DEVICE_0

Dispositivo CUDA con indice 0 (predefinito)

ONNX_GPU_DEVICE_1

Dispositivo CUDA con indice 1 *

ONNX_GPU_DEVICE_2

Dispositivo CUDA con indice 2 *

ONNX_GPU_DEVICE_3

Dispositivo CUDA con indice 3 *

ONNX_GPU_DEVICE_4

Dispositivo CUDA con indice 4 *

ONNX_GPU_DEVICE_5

Dispositivo CUDA con indice 5 *

ONNX_GPU_DEVICE_6

Dispositivo CUDA con indice 6 *

ONNX_GPU_DEVICE_7

Dispositivo CUDA con indice 7 *

ONNX_ENABLE_PROFILING

Abilita la profilazione del modello ONNX

* I flag del formato ONNX_GPU_DEVICE_N devono essere utilizzati sui sistemi con due o più GPU compatibili con CUDA. Se vengono specificati più flag di selezione GPU, verrà utilizzato il dispositivo con l'indice più basso.

Se viene specificato un indice del dispositivo inesistente, la GPU verrà selezionata automaticamente.

 

Profilazione ONNX

Il flag ONNX_ENABLE_PROFILING consente la profilazione dell'esecuzione del modello ONNX. Quando questo flag è impostato, in <data_folder>/MQL5/Files/OnnxProfileReports viene creato il seguente file: <nome_modulo>_data_ora.json.

Qui <nome_modulo> è il nome del file EX5 del programma MQL.

Il file contiene un report dettagliato sulla profilazione dell'esecuzione del modello ONNX in formato JSON, che include:

  • ora di caricamento e inizializzazione della sessione;
  • tempo di esecuzione dei singoli nodi del grafico (Conv, Relu, MaxPool, Gemm, ecc.);
  • il fornitore di esecuzione utilizzato (ad esempio, CUDAExecutionProvider);
  • informazioni sulla dimensione del tensore di ingresso e di uscita;
  • statistiche di pianificazione dei thread.

 

Un esempio dei dati di profilazione del report:

{"cat" : "Session","pid" :34368,"tid" :39520,"dur" :698,"ts" :11,"ph" : "X","name" :"model_loading_array","args" : {}},
{"cat" : "Session","pid" :34368,"tid" :39520,"dur" :15496,"ts" :869,"ph" : "X","name" :"session_initialization","args" : {}},
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :66055,"ts" :16800,"ph" : "X","name" :"Convolution28_kernel_time","args" : {"parameter_size" : "832","provider" : "CUDAExecutionProvider","op_name" : "Conv","input_type_shape" : [{"float":[1,1,28,28]},{"float
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :775,"ts" :82867,"ph" : "X","name" :"ReLU32_kernel_time","args" : {"parameter_size" : "0","provider" : "CUDAExecutionProvider","op_name" : "Relu","input_type_shape" : [{"float":[1,8,28,28]}],"node_index" : "3
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :8818,"ts" :83647,"ph" : "X","name" :"Pooling66_kernel_time","args" : {"parameter_size" : "0","provider" : "CUDAExecutionProvider","op_name" : "MaxPool","input_type_shape" : [{"float":[1,8,28,28]}],"node_inde
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :1120,"ts" :92476,"ph" : "X","name" :"Convolution110_kernel_time","args" : {"parameter_size" : "12864","provider" : "CUDAExecutionProvider","op_name" : "Conv","input_type_shape" : [{"float":[1,8,14,14]},{"flo
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :23,"ts" :93603,"ph" : "X","name" :"ReLU114_kernel_time","args" : {"parameter_size" : "0","provider" : "CUDAExecutionProvider","op_name" : "Relu","input_type_shape" : [{"float":[1,16,14,14]}],"node_index" : "
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :21,"ts" :93629,"ph" : "X","name" :"Pooling160_kernel_time","args" : {"parameter_size" : "0","provider" : "CUDAExecutionProvider","op_name" : "MaxPool","input_type_shape" : [{"float":[1,16,14,14]}],"node_inde
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :16,"ts" :93654,"ph" : "X","name" :"Times212_reshape0_kernel_time","args" : {"parameter_size" : "16","provider" : "CUDAExecutionProvider","op_name" : "Reshape","input_type_shape" : [{"float":[1,16,4,4]},{"int
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :32264,"ts" :93673,"ph" : "X","name" :"Times212/MatMulAddFusion_kernel_time","args" : {"parameter_size" : "10280","provider" : "CUDAExecutionProvider","op_name" : "Gemm","input_type_shape" : [{"float":[1,256]
{"cat" : "Session","pid" :34368,"tid" :39520,"dur" :109165,"ts" :16794,"ph" : "X","name" :"SequentialExecutor::Execute","args" : {}},
{"cat" : "Session","pid" :34368,"tid" :39520,"dur" :109600,"ts" :16433,"ph" : "X","name" :"model_run","args" : {}},
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :87,"ts" :126313,"ph" : "X","name" :"Convolution28_kernel_time","args" : {"parameter_size" : "832","provider" : "CUDAExecutionProvider","op_name" : "Conv","input_type_shape" : [{"float":[1,1,28,28]},{"float":
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :23,"ts" :126403,"ph" : "X","name" :"ReLU32_kernel_time","args" : {"parameter_size" : "0","provider" : "CUDAExecutionProvider","op_name" : "Relu","input_type_shape" : [{"float":[1,8,28,28]}],"node_index" : "3
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :31,"ts" :126431,"ph" : "X","name" :"Pooling66_kernel_time","args" : {"parameter_size" : "0","provider" : "CUDAExecutionProvider","op_name" : "MaxPool","input_type_shape" : [{"float":[1,8,28,28]}],"node_index
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :35,"ts" :126466,"ph" : "X","name" :"Convolution110_kernel_time","args" : {"parameter_size" : "12864","provider" : "CUDAExecutionProvider","op_name" : "Conv","input_type_shape" : [{"float":[1,8,14,14]},{"floa
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :15,"ts" :126505,"ph" : "X","name" :"ReLU114_kernel_time","args" : {"parameter_size" : "0","provider" : "CUDAExecutionProvider","op_name" : "Relu","input_type_shape" : [{"float":[1,16,14,14]}],"node_index" : 
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :22,"ts" :126523,"ph" : "X","name" :"Pooling160_kernel_time","args" : {"parameter_size" : "0","provider" : "CUDAExecutionProvider","op_name" : "MaxPool","input_type_shape" : [{"float":[1,16,14,14]}],"node_ind
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :12,"ts" :126548,"ph" : "X","name" :"Times212_reshape0_kernel_time","args" : {"parameter_size" : "16","provider" : "CUDAExecutionProvider","op_name" : "Reshape","input_type_shape" : [{"float":[1,16,4,4]},{"in
{"cat" : "Node","pid" :34368,"tid" :39520,"dur" :40,"ts" :126562,"ph" : "X","name" :"Times212/MatMulAddFusion_kernel_time","args" : {"parameter_size" : "10280","provider" : "CUDAExecutionProvider","op_name" : "Gemm","input_type_shape" : [{"float":[1,256]},

 

Ulteriori informazioni sulla profilazione ONNX: https://onnxruntime.ai/docs/performance/tune-performance/profiling-tools.html

 

Conversione di array quando si lavora con i modelli ONNX

I compiti di apprendimento automatico non richiedono sempre una grande precisione computazionale. Per accelerare i calcoli, alcuni modelli utilizzano tipi di dati di precisione inferiore come Float16 e persino Float8. Per consentire agli utenti di inserire i dati rilevanti nei modelli, MQL5 fornisce quattro funzioni speciali che convertono i tipi standard MQL5 in tipi speciali FP16 e FP8.

Funzione

Azione

ArrayToFP16

Copia un array di tipo float o double in un array di tipo ushort con il formato specificato

ArrayToFP8

Copia un array di tipo float o double in un array di tipo uchar con il formato specificato

ArrayFromFP16

Copia un array di tipo ushort in un array di tipo float o double con il formato specificato

ArrayFromFP8

Copia un array di tipo uchar in un array di tipo float o double con il formato specificato

Queste funzioni di conversione degli array utilizzano formati speciali specificati nelle enumerazioni seguenti.

ENUM_FLOAT16_FORMAT #

L'enumerazione ENUM_FLOAT16_FORMAT descrive due formati di tipo FP16.

ID

Descrizione

FLOAT_FP16

Formato standard a 16 bit, noto anche come half

FLOAT_BFP16

Formato speciale brain float point

Ognuno di questi formati ha i suoi vantaggi e limitazioni. FLOAT16 fornisce una maggiore precisione, ma richiede più risorse di archiviazione e di calcolo. BFLOAT16, d'altra parte, fornisce maggiori prestazioni ed efficienza nell'elaborazione dei dati, ma può essere meno accurata.

ENUM_FLOAT8_FORMAT #

L'enumerazione ENUM_FLOAT8_FORMAT descrive quattro formati di tipo FP8.

FP8 (8-bit floating point) è uno dei tipi di dati utilizzati per rappresentare i numeri in virgola mobile. In FP8, ogni numero è rappresentato da 8 bit di dati, tipicamente divisi in tre componenti: segno, esponente e mantissa. Questo formato offre un equilibrio tra precisione ed efficienza di archiviazione, rendendolo attraente per le applicazioni che richiedono memoria ed efficienza computazionale.  

ID

Descrizione

FLOAT_FP8_E4M3FN

Numero in virgola mobile a 8 bit, 4 bit per l'esponente e 3 bit per la mantissa. Tipicamente utilizzato come coefficiente.

FLOAT_FP8_E4M3FNUZ

Numero in virgola mobile a 8 bit, 4 bit per l'esponente e 3 bit per la mantissa. Supporta Nan, non supporta zero negativo e Inf. Tipicamente utilizzato come coefficiente.

FLOAT_FP8_E5M2FN

Numero in virgola mobile a 8 bit, 5 bit per l'esponente e 2 bit per la mantissa. Supporta Nan e Inf. Tipicamente utilizzato per i gradienti.

FLOAT_FP8_E5M2FNUZ

Numero in virgola mobile a 8 bit, 5 bit per l'esponente e 2 bit per la mantissa. Supporta Nan, non supporta zero negativo e Inf. Utilizzato anche per i gradienti.

Uno dei principali vantaggi di FP8 è la sua efficienza nell'elaborazione di grandi set di dati. Con l'impiego della rappresentazione numerica compatta, FP8 riduce i requisiti di memoria e accelera i calcoli. Ciò è particolarmente importante nelle applicazioni di apprendimento automatico e di intelligenza artificiale che spesso elaborano grandi set di dati.