Discussão do artigo "Uso de modelos ONNX em MQL5" - página 6

 
Erro ao usar o model-classifier.

A regressão funciona com tudo, a saída é um número.

Mas quando você pede a qualquer chat para escrever o MLP-classifier, o Expert Advisor não consegue reconhecer os dados de saída desse modelo: "Buy", "Sell", "Hold". Ou "1", "2", "3", ou "0", "1", "2".

O erro aparece

2025.02.12 08:13:46.866 Core 01 2021.01.01 00:00:00 Erro ao definir o formulário de saída: 5808
2025.02.12 08:13:46.866 Core 01 2021.01.01 00:00:00 ONNX: identificador inválido passado para a função OnnxRelease, inspecione o código 'X È$Zë3E' (291:7)

Nenhum dos chats, nem mesmo o Dipsic, entende ou sabe como corrigir o problema, gerando possíveis códigos que também levam a esse erro.

Todos os chats dizem a mesma coisa: como esse é um classificador MLP, ele tem apenas 3 saídas, de acordo com seus rótulos (eu o alimentei com um arquivo csv, em que a última coluna é um dos três rótulos de uma classificação simples: comprar, vender, manter. Tentei valores numéricos e de cadeia de caracteres nessa coluna).

Em seguida, este bloco

.
const long output_shape[] = {1,1};
   if(!OnnxSetOutputShape(ExtHandle,0,output_shape))
     {
      Print("OnnxSetOutputShape error ",GetLastError());
      return(INIT_FAILED);
     }
Ele altera a inicialização da matriz

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


E aparece um erro.

Estou tentando imprimir.

Print(OnnxGetOutputCount(ExtHandle));

Recebo 2.

Não entendo nada.



Se alguém entender o que é o erro, por favor, me avise.

Código Python para classificador - qualquer um, todos geram o mesmo erro.

Por exemplo, uma das implementações:

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

# Carregando dados
file_path = '....csv'
data = pd.read_csv(file_path)

# Dividido em atributos (X) e rótulos (y)
X = data.iloc[:, :160].values  # As primeiras 160 colunas são dados de entrada
y = data.iloc[:, 160].values   # A última coluna é o rótulo de destino

# Codificação de rótulos de string em rótulos numéricos
label_encoder = LabelEncoder()
y_encoded = label_encoder.fit_transform(y)

# Normalização de dados
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# Dividido em amostras de treinamento e teste
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y_encoded, test_size=0.2, random_state=42)

# Criação de um classificador MLP
mlp = MLPClassifier(hidden_layer_sizes=(128, 64), activation='relu', solver='adam', max_iter=500, random_state=42)
mlp.fit(X_train, y_train)

# Estimativa da precisão do modelo
accuracy = mlp.score(X_test, y_test)
print(f"Accuracy: {accuracy * 100:.2 f}%")

# Salvando o modelo no formato ONNX
initial_type = [('float_input', FloatTensorType([None, 160]))]  # 160 recursos de entrada
onnx_model = convert_sklearn(mlp, initial_types=initial_type)

# Salvando o modelo 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}")


Ou seja, o próprio modelo - executado em python. Ele está calculando algo

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

Mas o consultor não pode aceitá-lo.

[Excluído]  
Em uma comunidade saudável, a geração de código não é discutida nem mesmo considerada. Não é ruim saber sobre o bug do ONNX, por causa do qual não há suporte para multiclasse.
 
Isso não precisa ser discutido
Não é a questão.
[Excluído]  
Ivan Butko #:
Isso não precisa ser discutido
Não é a questão.

Tente {2,3} ou {3}.

peça ao script python para gerar a dimensão correta da saída.

mas provavelmente apenas {1}, ele retorna uma estrutura em que os campos já correspondem às saídas.


Por exemplo, o que tenho para um classificador binário é

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

Em seguida, basta criar uma estrutura no código

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];

Onde o campo de rótulo são os valores de classe e o tensor são as probabilidades

[Excluído]  
Errado: o rótulo contém valores de classe e o tensor contém probabilidades. Bem, a dimensão de saída é essencialmente 2,2, mas como a estrutura é retornada, ela deve ser definida como 1
 
Maxim Dmitrievsky #:
Errado: o rótulo contém valores de classe e o tensor contém probabilidades. Portanto, a dimensão de saída é essencialmente 2,2, mas como a estrutura é retornada, você deve colocar 1
Agradecimentos

UPD

Sobre a essência das arquiteturas: a regressão no artigo trata de vangulação. E a classificação parece fazer mais sentido. E eis que isso acaba sendo um problema na funcionalidade nativa.

Subjetivamente: se a meta estiver marcada como o próximo preço (ou outra indicação quantitativa), o NS começa a oscilar de um lado para o outro.

E se o alvo estiver marcado como comprar-vender-manter, pelo menos, o NS se ajusta ao número de entradas bem-sucedidas sem prestar atenção ao tamanho. E na distância, essa "ignorância" é compensada por algum nivelamento, como se fosse uma terapia de ruído. É claro que isso é uma opinião minha, que pouco tentou a classificação em outra implementação. Por isso, eu queria ver aqui
[Excluído]  
Ivan Butko #:
Obrigado
Você também pode visualizar sua malha por meio do Netron e ele exibirá a dimensão e o tipo de saída
[Excluído]  
Ivan Butko #:
Obrigado

ATUALIZAÇÃO

Sobre a questão das arquiteturas: a regressão no artigo trata de vangulação. E a classificação parece fazer mais sentido. E aqui estamos nós - o problema acaba sendo a funcionalidade nativa.

Subjetivamente: se a meta for marcada como o próximo preço (ou outra indicação quantitativa), o NS começa a oscilar de um lado para o outro.

E se o alvo estiver marcado como comprar-vender-manter, pelo menos, o NS se ajusta ao número de entradas bem-sucedidas, sem prestar atenção ao tamanho. E na distância, essa "ignorância" é compensada por algum nivelamento, como se fosse uma terapia de ruído. É claro que eu não sei, mas tentei pouco a classificação em outra implementação. Então, eu queria ver aqui

É para isso que serve o pré-processamento, que você não respeita :) para separar primeiro os grãos do joio e depois treiná-lo para prever os grãos separados.

Se o pré-processamento for bom, o resultado também não será uma porcaria

 

Há alguma chance de corrigir esse script para que funcione com versões mais recentes do python (3.10-3.12)?

Estou tendo muitos problemas ao tentar fazê-lo funcionar na versão 3.9.

tx