Обсуждение статьи "Использование ONNX-моделей в MQL5" - страница 6

 
Ошибка при использовании модели-классификатора. 

С регрессией всё работает, на выходе - одно число. 

Но когда просишь любой чат написать MLP-классификатор, то советник не может распознать выходные данные у этой модели: "Бай", "Сел", "Холд". Или "1", "2", "3", или "0", "1", "2". 

Ошибка вылетает

2025.02.12 08:13:46.866 Core 01 2021.01.01 00:00:00   Ошибка установки выходной формы: 5808
2025.02.12 08:13:46.866 Core 01 2021.01.01 00:00:00   ONNX: invalid handle passed to OnnxRelease function, inspect code 'X– È$œZžë3E' (291:7)

Ни один из чатов, даже Дипсик, не понимает и не знает, как исправить проблему, генерируя возможные коды, которые также приводят к этой ошибке. 

Все чаты говорят одно и тоже: поскольку это MLP-классифкатор, то и выходов у него всего 3, согласно вашим меткам (я ему скармливают csv-файл, где последний столбик - это одна из трёх меток простой классификации: бай, сел, холд. Пробовал строковые и пробовал числовые значения в этот столбик вписывать). 

Затем вот этот блок 

const long output_shape[] = {1,1};
   if(!OnnxSetOutputShape(ExtHandle,0,output_shape))
     {
      Print("OnnxSetOutputShape error ",GetLastError());
      return(INIT_FAILED);
     }
Он изменяет в части инициализации массива

const long output_shape[] = {1,3};
   if(!OnnxSetOutputShape(ExtHandle,0,output_shape))
     {
      Print("OnnxSetOutputShape error ",GetLastError());
      return(INIT_FAILED);
     }


Ну и появляется ошибка. 

Я пробую принтовать 

Print(OnnxGetOutputCount(ExtHandle));

Выдаёт 2. 

Ничего не понимаю.



Если кто понял, в чём ошибка, сообщите, пожалуйста. 

Код питона на классификатор - любой, они все генерируют с одной и той же ошибкой. 

Ради примера, одна из реализаций:

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.neural_network import MLPClassifier
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType

# Загрузка данных
file_path = '....csv'
data = pd.read_csv(file_path)

# Разделение на признаки (X) и метки (y)
X = data.iloc[:, :160].values  # Первые 160 столбцов - входные данные
y = data.iloc[:, 160].values   # Последний столбец - целевая метка

# Кодирование строковых меток в числовые
label_encoder = LabelEncoder()
y_encoded = label_encoder.fit_transform(y)

# Нормализация данных
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# Разделение на обучающую и тестовую выборки
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y_encoded, test_size=0.2, random_state=42)

# Создание MLP-классификатора
mlp = MLPClassifier(hidden_layer_sizes=(128, 64), activation='relu', solver='adam', max_iter=500, random_state=42)
mlp.fit(X_train, y_train)

# Оценка точности модели
accuracy = mlp.score(X_test, y_test)
print(f"Accuracy: {accuracy * 100:.2f}%")

# Сохранение модели в формате ONNX
initial_type = [('float_input', FloatTensorType([None, 160]))]  # 160 входных признаков
onnx_model = convert_sklearn(mlp, initial_types=initial_type)

# Сохранение ONNX-модели
onnx_file_path = 'model.onnx'
with open(onnx_file_path, "wb") as f:
    f.write(onnx_model.SerializeToString())

print(f"Model saved as {onnx_file_path}")


То есть, сама модель - работает в питоне. Она там вычисляет что-то

runfile('....py', wdir='...')
Accuracy: 54.16%
Model saved as model.onnx

Но советник её не может принять. 

[Удален]  
В здоровом обществе генерации кода не обсуждаются и даже не рассматриваются вроде. Неплохо знать о баге ONNX, из-за которого не поддерживается мультикласс. 
 
А еë и не надо обсуждать
Вопрос не про неë
[Удален]  
Ivan Butko #:
А еë и не надо обсуждать
Вопрос не про неë

попробуй {2,3} или {3}

попроси вывести корректную размерность выхода в питон скрипте

а скорее всего просто {1}, он же возвращает структуру, в которой уже поля соответствуют аутпутам


Например у меня для бинарного классификатора стоит

const long output_shape[] = {1};
   if(!OnnxSetOutputShape(ExtHandle, 0, output_shape))
     {
      Print("OnnxSetOutputShape 1 error ", GetLastError());
      return(INIT_FAILED);
     }
[Удален]  

Потом ты просто создаешь структуру в коде

static vector out(1);

   struct output
     {
      long           label[];
      float          tensor[];
     };

   output out2[];
   
   OnnxRun(ExtHandle, ONNX_DEBUG_LOGS, f, out, out2);

   double sig = out2[0].tensor[1];

Где поле label это значения классов, а tensor вероятности

[Удален]  
Не так: label содержит значения классов, а tensor вероятности. Ну то есть размерность выхода по сути 2,2, но поскольку возвращается структура, то нужно ставить 1
 
Maxim Dmitrievsky #:
Не так: label содержит значения классов, а tensor вероятности. Ну то есть размерность выхода по сути 2,2, но поскольку возвращается структура, то нужно ставить 1
Благодарю

UPD

По сути архитектур: регрессия в статье занимается вангованием. А классификация кажется разумней. И вот те на - оказывается с ней проблемы в родном функционале. 

Субьективно: если целевую размечать как следующую цену (или иное количественное показание), то НС начинает колыхать из стороны в сторону. 

А если разметить бай-сел-холд, как минимум, то НС подстраивается под количество удачных входов, не обращая внимание на размер. И на дистанции это "незнание" компенсируется неким выравниванием, как будто шумо-терапия. Имхо,конечно, мало пробовал классификацию в другой реализации. Поэтому хотелось тут
[Удален]  
Ivan Butko #:
Благодарю
Можешь еще через Netron визуализировать свою сетку и он отобразит размерность и тип аутпута
[Удален]  
Ivan Butko #:
Благодарю

UPD

По сути архитектур: регрессия в статье занимается вангованием. А классификация кажется разумней. И вот те на - оказывается с ней проблемы в родном функционале. 

Субьективно: если целевую размечать как следующую цену (или иное количественное показание), то НС начинает колыхать из стороны в сторону. 

А если разметить бай-сел-холд, как минимум, то НС подстраивается под количество удачных входов, не обращая внимание на размер. И на дистанции это "незнание" компенсируется неким выравниванием, как будто шумо-терапия. Имхо,конечно, мало пробовал классификацию в другой реализации. Поэтому хотелось тут

Для этого, в том числе, и делается не уважаемый тобой препроцессинг :) чтобы отделить сначала зерна от плевел, а потом обучить предсказывать отделенное.

Если препроцессинг хороший, то и на выходе уже не совсем мусор

 

Есть ли шанс, что вы сможете исправить этот скрипт для работы с более новыми версиями python (3.10-3.12)?

У меня возникли проблемы при попытке заставить его работать на 3.9.

tx