Структуры данных

Для работы с моделями ONNX используются следующие структуры данных:

OnnxTypeInfo #

Структура описывает тип входного или выходного параметра модели ONNX

struct OnnxTypeInfo
  {
   ENUM_ONNX_TYPE         type;           // тип параметра
   OnnxTensorTypeInfo     tensor;         // описание тензора
   OnnxMapTypeInfo        map;            // описание map
   OnnxSequenceTypeInfo   sequence;       // описание последовательности
  };

В качестве входного параметра может использоваться только тензор (ONNX_TYPE_TENSOR), в этом случае заполняется значениями только поле OnnxTypeInfo::tensor, остальные поля (map и sequence) не определены.

В качестве выходного параметра может использоваться только один из трех типов OnnxTypeInfo (ONNX_TYPE_TENSOR, ONNX_TYPE_MAP или ONNX_TYPE_SEQUENCE), в зависимости от типа заполняется соответствующая подструктура (OnnxTypeInfo::tensor, OnnxTypeInfo::map или OnnxTypeInfo::sequence).

 

OnnxTensorTypeInfo

Структура описывает тензор во входном или выходном параметре модели ONNX

struct OnnxTensorTypeInfo
  {
   const ENUM_ONNX_DATA_TYPE    data_type;      // тип данных в тензоре
   const long                   dimensions[];   // количество элементов в тензоре
  };

OnnxMapTypeInfo #

Структура описывает map, который получается в выходном параметре модели ONNX

struct OnnxMapTypeInfo
  {
   const ENUM_ONNX_DATA_TYPE    key_type;       // тип ключа
   const OnnxTypeInfo&          value_type;     // тип значения
  };

OnnxSequenceTypeInfo #

Структура описывает последовательность, которая получается в выходном параметре модели ONNX

struct OnnxSequenceTypeInfo
  {
   const OnnxTypeInfo&          value_type;      // тип данных в последовательности
  };

 

ENUM_ONNX_TYPE #

Перечисление ENUM_ONNX_TYPE описывает тип параметра модели

Идентификатор

Описание

ONNX_TYPE_UNKNOWN

Неизвестен

ONNX_TYPE_TENSOR

Тензор

ONNX_TYPE_SEQUENCE

Последовательность

ONNX_TYPE_MAP

Карта

ONNX_TYPE_OPAQUE

Абстрактный

ONNX_TYPE_SPARSETENSOR

Разреженный тензор

ENUM_ONNX_DATA_TYPE #

Перечисление ENUM_ONNX_DATA_TYPE описывает тип используемых данных

Идентификатор

Описание

ONNX_DATA_TYPE_UNDEFINED

Не определен

ONNX_DATA_TYPE_FLOAT

float

ONNX_DATA_TYPE_INT8

8-битный int

ONNX_DATA_TYPE_UINT16

16-битный uint

ONNX_DATA_TYPE_INT16

16-битный int

ONNX_DATA_TYPE_INT32

32-битный int

ONNX_DATA_TYPE_INT64

64-битный int

ONNX_DATA_TYPE_STRING

string

ONNX_DATA_TYPE_BOOL

bool

ONNX_DATA_TYPE_FLOAT16

16-битный float

ONNX_DATA_TYPE_DOUBLE

double

ONNX_DATA_TYPE_UINT32

32-битный uint

ONNX_DATA_TYPE_UINT64

64-битный uint

ONNX_DATA_TYPE_COMPLEX64

64-битное комплексное число

ONNX_DATA_TYPE_COMPLEX128

128-битное комплексное число

ONNX_DATA_TYPE_BFLOAT16

16-битный bfloat (Brain Floating Point)

ENUM_ONNX_FLAGS #

Перечисление ENUM_ONNX_FLAGS описывает режим запуска модели  

Идентификатор

Описание

ONNX_LOGLEVEL_VERBOSE

Логировать все сообщения

ONNX_LOGLEVEL_INFO

Логировать информационные сообщения, предупреждения и ошибки (этот флаг заменяет ONNX_DEBUG_LOGS)

ONNX_LOGLEVEL_WARNING

Логировать предупреждения и ошибки (по умолчанию)

ONNX_LOGLEVEL_ERROR

Логировать только ошибки

ONNX_NO_CONVERSION

Запрет на автоконверсию, использовать данные пользователя как есть

ONNX_COMMON_FOLDER  

Загрузка файла модели из папки Common\Files, по значению равен флагу FILE_COMMON

ONNX_USE_CPU_ONLY

При выполнении ONNX модели использовать только CPU

ONNX_GPU_DEVICE_0

Устройство CUDA с номером 0 (по умолчанию)

ONNX_GPU_DEVICE_1

Устройство CUDA с номером 1  *

ONNX_GPU_DEVICE_2

Устройство CUDA с номером 2  *

ONNX_GPU_DEVICE_3

Устройство CUDA с номером 3  *

ONNX_GPU_DEVICE_4

Устройство CUDA с номером 4  *

ONNX_GPU_DEVICE_5

Устройство CUDA с номером 5  *

ONNX_GPU_DEVICE_6

Устройство CUDA с номером 6  *

ONNX_GPU_DEVICE_7

Устройство CUDA с номером 7  *

ONNX_ENABLE_PROFILING

Включает профилировку ONNX модели

* Флаги вида ONNX_GPU_DEVICE_N следует использовать в системах с двумя и более CUDA-совместимыми GPU. Если указано несколько флагов выбора GPU, будет использовано устройство с наименьшим индексом.

Если указать номер несуществующего устройства, то будет сделан автоматический выбор.

 

Профилировка ONNX

Флаг ONNX_ENABLE_PROFILING включает профилировку выполнения ONNX-модели. При установке  данного флага в каталоге <data_folder>/MQL5/Files/OnnxProfileReports  будет создан файл вида <module_name>_date_time.json.

Здесь <module_name> — имя EX5-файла MQL-программы.

Файл содержит подробный отчёт профилировки выполнения ONNX-модели (в формате JSON), включая:

  • время загрузки и инициализации сессии;
  • время выполнения отдельных узлов графа (Conv, Relu, MaxPool, Gemm и др.);
  • используемый execution provider (например, CUDAExecutionProvider);
  • информацию о размерах входных и выходных тензоров;
  • статистику планирования потоков.

 

Пример данных отчёта профилировки:

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

 

Дополнительная информация о профилировке ONNX: https://onnxruntime.ai/docs/performance/tune-performance/profiling-tools.html

 

Конвертация массивов при работе с ONNX моделями

В задачах машинного обучения не всегда нужна большая точность вычислений. Для ускорения расчетов некоторые модели используют типы данных с меньшей точностью, такие как Float16 и даже Float8. Чтобы пользователи могли подавать такие данные на вход моделей, в MQL5 добавлены 4 специальные функции, которые преобразует стандартные типы MQL5 в специальные типы FP16 и FP8.

Функция

Действие

ArrayToFP16

Производит копирование массива типа float или double в массив типа ushort с заданным форматом

ArrayToFP8

Производит копирование массива типа float или double в массив типа uchar с заданным форматом

ArrayFromFP16

Производит копирование массива типа ushort в массив типа float или double с заданным форматом

ArrayFromFP8

Производит копирование массива типа uchar в массив типа float или double с заданным форматом

Данные функции для преобразования массивов используют специальные форматы, заданные в перечислениях ниже.

ENUM_FLOAT16_FORMAT #

Перечисление ENUM_FLOAT16_FORMAT описывает 2 формата типа FP16.

Идентификатор

Описание

FLOAT_FP16

Стандартный 16-битный формат, так же известный как half

FLOAT_BFP16

Специальный формат brain float point

Оба этих формата имеют свои преимущества и ограничения. FLOAT16 обеспечивает более высокую точность, но требует больше ресурсов для хранения и вычислений. BFLOAT16, с другой стороны, обеспечивает более высокую производительность и эффективность при обработке данных, но может быть менее точным.

ENUM_FLOAT8_FORMAT #

Перечисление ENUM_FLOAT8_FORMAT описывает 4 формата типа FP8.

Формат FP8 (8-битное число с плавающей запятой) представляет собой один из типов данных, используемых для представления чисел с плавающей точкой. В FP8 каждое число представлено 8 битами данных, которые обычно разделяются на три компонента: знак, экспоненту и мантиссу. Этот формат обеспечивает компромисс между точностью и эффективностью хранения данных, что делает его привлекательным для использования в приложениях, где требуется экономия памяти и вычислительных ресурсов.  

Идентификатор

Описание

FLOAT_FP8_E4M3FN

8-битное число с плавающей точкой, 4 бита порядок и 3 бита мантисса. Обычно используется как коэффициенты.

FLOAT_FP8_E4M3FNUZ

8-битное число с плавающей точкой, 4 бит порядок и 3 бита мантисса. Поддерживает NaN, не поддерживается отрицательный ноль и Inf. Обычно используется как коэффициенты.

FLOAT_FP8_E5M2FN

8-битное число с плавающей точкой, 5 бит порядок и 2 бита мантисса. Поддерживает NaN и Inf. Обычно используется для градиентов.

FLOAT_FP8_E5M2FNUZ

8-битное число с плавающей точкой, 5 бит порядок и 2 бита мантисса. Поддерживает NaN и Inf, не поддерживает отрицательный ноль. Также используется для градиентов.

Одним из ключевых преимуществ FP8 является его эффективность при обработке больших объемов данных. Благодаря компактному представлению чисел, FP8 позволяет уменьшить требования к памяти и ускорить вычисления. Это особенно важно в приложениях машинного обучения и искусственного интеллекта, где обработка больших наборов данных является обычным делом.