Structures de données

Les structures de données suivantes sont utilisées pour les opérations avec les modèles ONNX :

OnnxTypeInfo #

La structure décrit le type d'un paramètre d'entrée ou de sortie  d'un modèle ONNX

struct OnnxTypeInfo
 {
  ENUM_ONNX_TYPE        type;          // type de paramètre
  OnnxTensorTypeInfo    tensor;        // description du tenseur
  OnnxMapTypeInfo       map;           // description de la carte
  OnnxSequenceTypeInfo  sequence;      // description de la séquence
 };

Seul le tenseur (ONNX_TYPE_TENSOR) peut être utilisé comme entrée. Dans ce cas, seul le champ OnnxTypeInfo::tensor est rempli de valeurs, tandis que les autres champs (carte et séquence) ne sont pas définis.

Un seul des trois types OnnxTypeInfo (ONNX_TYPE_TENSOR, ONNX_TYPE_MAP ou ONNX_TYPE_SEQUENCE) peut être utilisé comme entrée. La sous-structure correspondante (OnnxTypeInfo::tensor, OnnxTypeInfo::map ou OnnxTypeInfo::sequence) est remplie en fonction du type.

 

OnnxTensorTypeInfo

La structure décrit le tenseur dans le paramètre d'entrée ou de sortie d'un modèle ONNX

struct OnnxTensorTypeInfo
 {
  const ENUM_ONNX_DATA_TYPE   data_type;     // type de données dans le tenseur
  const long                  dimensions[];  // nombre d'éléments dans le tenseur
 };

OnnxMapTypeInfo #

La structure décrit la carte obtenue dans le paramètre de sortie d'un modèle ONNX

struct OnnxMapTypeInfo
 {
  const ENUM_ONNX_DATA_TYPE  key_type;      // type clé
  const OnnxTypeInfo&        value_type;    // type de valeur
 };

OnnxSequenceTypeInfo #

La structure décrit la séquence obtenue dans le paramètre de sortie d'un modèle ONNX

struct OnnxSequenceTypeInfo
 {
  const OnnxTypeInfo&        value_type;      // type de données dans la séquence
 };

 

 

ENUM_ONNX_TYPE #

L'énumération ENUM_ONNX_TYPE décrit le type de paramètre d'un modèle

ID

Description

ONNX_TYPE_UNKNOWN

Inconnu

ONNX_TYPE_TENSOR

Tenseur

ONNX_TYPE_SEQUENCE

Séquence

ONNX_TYPE_MAP

Carte (map)

ONNX_TYPE_OPAQUE

Abstrait (opaque)

ONNX_TYPE_SPARSETENSOR

Tenseur creux (sparse tensor)

ENUM_ONNX_DATA_TYPE #

L'énumération ENUM_ONNX_DATA_TYPE décrit le type de données utilisées

ID

Description

ONNX_DATA_TYPE_UNDEFINED

Indéfini

ONNX_DATA_TYPE_FLOAT

float

ONNX_DATA_TYPE_INT8

int 8 bits

ONNX_DATA_TYPE_UINT16

uint 16 bits

ONNX_DATA_TYPE_INT16

int 16 bits

ONNX_DATA_TYPE_INT32

int 32 bits

ONNX_DATA_TYPE_INT64

int 64 bits

ONNX_DATA_TYPE_STRING

string

ONNX_DATA_TYPE_BOOL

bool

ONNX_DATA_TYPE_FLOAT16

float 16 bits

ONNX_DATA_TYPE_DOUBLE

double

ONNX_DATA_TYPE_UINT32

uint 32 bits

ONNX_DATA_TYPE_UINT64

uint 64 bits

ONNX_DATA_TYPE_COMPLEX64

nombre complexe 64 bits

ONNX_DATA_TYPE_COMPLEX128

nombre complexe 128 bits

ONNX_DATA_TYPE_BFLOAT16

bfloat 16 bits (Brain Floating Point)

ENUM_ONNX_FLAGS #

L'énumération ENUM_ONNX_FLAGS décrit le mode d'exécution du modèle

ID

Description

ONNX_LOGLEVEL_VERBOSE

Ecrit tous les messages

ONNX_LOGLEVEL_INFO

Ecrit les messages d'informations, les avertissements et les erreurs (cet indicateur remplace ONNX_DEBUG_LOGS)

ONNX_LOGLEVEL_WARNING

Ecrit les avertissements et les erreurs (valeur par défaut)

ONNX_LOGLEVEL_ERROR

Ecrit les erreurs uniquement

ONNX_NO_CONVERSION

Désactive la conversion automatique, utilise les données utilisateur telles quelles

ONNX_COMMON_FOLDER  

Charge un fichier de modèle à partir du dossier Common\Files - la valeur est égale au flag FILE_COMMON

ONNX_USE_CPU_ONLY

Exécute le modèle ONNX en utilisant uniquement le CPU

ONNX_GPU_DEVICE_0

Périphérique CUDA avec l'index 0 (par défaut)

ONNX_GPU_DEVICE_1

Périphérique CUDA avec l'index 1 *

ONNX_GPU_DEVICE_2

Périphérique CUDA avec l'index 2 *

ONNX_GPU_DEVICE_3

Périphérique CUDA avec l'index 3  *

ONNX_GPU_DEVICE_4

Périphérique CUDA avec l'index 4  *

ONNX_GPU_DEVICE_5

Périphérique CUDA avec l'index 5  *

ONNX_GPU_DEVICE_6

Périphérique CUDA avec l'index 6  *

ONNX_GPU_DEVICE_7

Périphérique CUDA avec l'index 7  *

ONNX_ENABLE_PROFILING

Active le profilage du modèle ONNX

* Les flags sous la forme ONNX_GPU_DEVICE_N doivent être utilisés sur les systèmes dotés de 2 GPU compatibles CUDA ou plus. Si plusieurs flags de sélection GPU sont spécifiés, le périphérique avec l'index le plus bas sera utilisé.

Si un index de périphérique inexistant est spécifié, le GPU sera sélectionné automatiquement.

 

Profilage ONNX

L'indicateur ONNX_ENABLE_PROFILING permet le profilage de l'exécution du modèle ONNX. Lorsque ce flag est défini dans <data_folder>/MQL5/Files/OnnxProfileReports, le fichier suivant est créé : <module_name>_date_time.json.

Ici <module_name> est le nom du fichier EX5 du programme MQL.

Le fichier contient un rapport détaillé de profilage d'exécution du modèle ONNX au format JSON, comprenant :

  • le temps de chargement et d'initialisation de la session ;
  • le temps d'exécution des nœuds de graphe individuels (Conv, Relu, MaxPool, Gemm, etc.) ;
  • le fournisseur d'exécution utilisé (par exemple, CUDAExecutionProvider) ;
  • les informations sur la taille du tenseur d'entrée et de sortie ;
  • les statistiques de planification des threads.

 

Exemple de données de rapport de profilage :

{"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]},

 

Informations supplémentaires sur le profilage ONNX : https://onnxruntime.ai/docs/performance/tune-performance/profiling-tools.html

 

Array conversion when working with ONNX models

Les tâches d'apprentissage automatique ne nécessitent pas toujours une grande précision de calcul. Pour accélérer les calculs, certains modèles utilisent des types de données de moindre précision tels que Float16 et même Float8. Pour permettre aux utilisateurs de saisir les bonnes données dans les modèles, MQL5 propose 4 fonctions spéciales qui convertissent les types MQL5 standard en types spéciaux FP16 et FP8.

Fonction

Action

ArrayToFP16

Copie un tableau de type float ou double dans un tableau de type ushort au format donné

ArrayToFP8

Copie un tableau de type float ou double dans un tableau de type uchar au format donné

ArrayFromFP16

Copie un tableau de type ushort dans un tableau de type float ou double avec le format donné

ArrayFromFP8

Copie un tableau de type uchar dans un tableau de type float ou double avec le format donné

Ces fonctions de conversion de tableau utilisent des formats spéciaux spécifiés dans les énumérations ci-dessous.

ENUM_FLOAT16_FORMAT #

L'énumération ENUM_FLOAT16_FORMAT décrit 2 formats de type FP16.

ID

Description

FLOAT_FP16

Format standard 16 bits, également appelé moitié

FLOAT_BFP16

Format spécial brain float point

Chacun de ces formats a ses avantages et ses limites. FLOAT16 offre une plus grande précision mais nécessite plus de ressources de stockage et de calcul. BFLOAT16, en revanche, offre des performances et une efficacité supérieures dans le traitement des données, mais peut être moins précis.

ENUM_FLOAT8_FORMAT #

L'énumération ENUM_FLOAT8_FORMAT décrit 4 formats de type FP8.

FP8 (virgule flottante 8 bits) est l'un des types de données utilisés pour représenter les nombres à virgule flottante. Dans FP8, chaque nombre est représenté par 8 bits de données, généralement divisés en 3 composants : signe, exposant et mantisse. Ce format offre un équilibre entre précision et efficacité de stockage, ce qui le rend attrayant pour les applications nécessitant de la mémoire et de l'efficacité informatique.  

ID

Description

FLOAT_FP8_E4M3FN

Nombre à virgule flottante de 8 bits, 4 bits pour l'exposant et 3 bits pour la mantisse. Généralement utilisé comme coefficients.

FLOAT_FP8_E4M3FNUZ

Nombre à virgule flottante de 8 bits, 4 bits pour l'exposant et 3 bits pour la mantisse. Supporte NaN, ne supporte pas le zéro négatif et Inf. Généralement utilisé comme coefficients.

FLOAT_FP8_E5M2FN

Nombre à virgule flottante de 8 bits, 5 bits pour l'exposant et 2 bits pour la mantisse. Supporte NaN et Inf. Généralement utilisé pour les gradients.

FLOAT_FP8_E5M2FNUZ

Nombre à virgule flottante de 8 bits, 5 bits pour l'exposant et 2 bits pour la mantisse. Supporte NaN, ne supporte pas le zéro négatif et Inf. Egalement utilisé pour les gradients.

L'un des principaux avantages de FP8 est son efficacité dans le traitement de grands ensembles de données. En utilisant une représentation compacte des nombres, FP8 réduit les besoins en mémoire et accélère les calculs. Ceci est particulièrement important dans les applications d’apprentissage automatique et d’intelligence artificielle qui traitent souvent de grands ensembles de données.