Discussione sull’articolo "Come utilizzare i modelli ONNX in MQL5" - pagina 6

 
Errore durante l'utilizzo del modello-classificatore.

La regressione funziona con tutto, l'output è un numero.

Ma quando si chiede a qualsiasi chat di scrivere MLP-classificatore, l'Expert Advisor non è in grado di riconoscere i dati di output di questo modello: "Buy", "Sell", "Hold". O "1", "2", "3", o "0", "1", "2".

L'errore si risolve

2025.02.12 08:13:46.866 Core 01 2021.01.01 00:00:00 Errore nell'impostazione del modulo di output: 5808
2025.02.12 08:13:46.866 Core 01 2021.01.01 00:00:00 ONNX: handle non valido passato alla funzione OnnxRelease, codice di ispezione 'X È$Zë3E' (291:7)

Nessuna delle chat, nemmeno Dipsic, capisce o sa come risolvere il problema, generando possibili codici che portano anch'essi a questo errore.

Tutte le chat dicono la stessa cosa: trattandosi di un classificatore MLP, ha solo 3 uscite, in base alle vostre etichette (gli do in pasto un file csv, dove l'ultima colonna è una delle tre etichette di una semplice classificazione: buy, sell, hold. Ho provato valori stringa e numerici in questa colonna).

Poi questo blocco

.
const long output_shape[] = {1,1};
   if(!OnnxSetOutputShape(ExtHandle,0,output_shape))
     {
      Print("OnnxSetOutputShape error ",GetLastError());
      return(INIT_FAILED);
     }
Cambia l'inizializzazione dell'array

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


E appare un errore.

Sto cercando di stampare.

Print(OnnxGetOutputCount(ExtHandle));

Ottengo 2.

Non capisco nulla.



Se qualcuno capisce qual è l'errore, per favore me lo faccia sapere.

Codice Python per il classificatore - qualsiasi, generano tutti lo stesso errore.

Per esempio, una delle implementazioni:

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

# Caricamento dei dati
file_path = '....csv'
data = pd.read_csv(file_path)

# Dividere in attributi (X) ed etichette (y)
X = data.iloc[:, :160].values  # Le prime 160 colonne sono dati di input
y = data.iloc[:, 160].values   # L'ultima colonna è l'etichetta di destinazione

# Codifica delle etichette di stringa in etichette numeriche.
label_encoder = LabelEncoder()
y_encoded = label_encoder.fit_transform(y)

# Normalizzazione dei dati
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# Dividere in campioni di allenamento e di prova
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y_encoded, test_size=0.2, random_state=42)

# Creazione di un classificatore MLP
mlp = MLPClassifier(hidden_layer_sizes=(128, 64), activation='relu', solver='adam', max_iter=500, random_state=42)
mlp.fit(X_train, y_train)

# Stimare l'accuratezza del modello
accuracy = mlp.score(X_test, y_test)
print(f"Accuracy: {accuracy * 100:.2 f}%")

# Salvataggio del modello in formato ONNX
initial_type = [('float_input', FloatTensorType([None, 160]))]  # 160 caratteristiche di input
onnx_model = convert_sklearn(mlp, initial_types=initial_type)

# Salvataggio del modello 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}")


Cioè, il modello stesso - in esecuzione in python. Sta calcolando qualcosa

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

Ma il consulente non può accettarlo.

[Eliminato]  
In una comunità sana la generazione di codice non viene discussa e nemmeno presa in considerazione. Non è male sapere del bug di ONNX, a causa del quale la multiclasse non è supportata.
 
Non è necessario discuterne
Non è la domanda.
[Eliminato]  
Ivan Butko #:
Non è necessario discuterne
Non è la domanda.

Provare con {2,3} o {3}.

chiedere allo script python di restituire la dimensione corretta dell'output.

ma molto probabilmente solo {1}, restituisce una struttura in cui i campi corrispondono già agli output.


Ad esempio, il mio classificatore binario è

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

Quindi è sufficiente creare una struttura nel codice

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

Dove il campo etichetta è costituito dai valori della classe e il tensore dalle probabilità

[Eliminato]  
Sbagliato: l'etichetta contiene i valori della classe e il tensore contiene le probabilità. Beh, la dimensione di output è essenzialmente 2,2, ma poiché la struttura viene restituita, dovrebbe essere impostata a 1
 
Maxim Dmitrievsky #:
Sbagliato: l'etichetta contiene i valori della classe e il tensore contiene le probabilità. Quindi la dimensione di output è essenzialmente 2,2, ma dato che la struttura viene restituita, si dovrebbe mettere 1.
Grazie

UPD

Sull'essenza delle architetture: la regressione nell'articolo si occupa di vangulazione. E la classificazione sembra avere più senso. Ed ecco che si scopre un problema con esso nella funzionalità nativa.

Soggettivamente: se il target è contrassegnato come prezzo successivo (o altra indicazione quantitativa), il NS inizia a oscillare da una parte all'altra.

E se il target è contrassegnato come buy-sell-hold, almeno, il NS si adegua al numero di ingressi riusciti senza prestare attenzione alla dimensione. E sulla distanza questa "ignoranza" è compensata da un certo livellamento, come se fosse una terapia del rumore. Imho, naturalmente, poco provato la classificazione in un'altra implementazione. Così ho voluto qui
[Eliminato]  
Ivan Butko #:
Grazie
È anche possibile visualizzare la rete tramite Netron e visualizzare le dimensioni e il tipo di uscita.
[Eliminato]  
Ivan Butko #:
Grazie

UPD

Per quanto riguarda le architetture, la regressione riportata nell'articolo riguarda la vangulazione. E la classificazione sembra avere più senso. Ed ecco che si scopre un problema con la funzionalità nativa.

Soggettivamente: se l'obiettivo è segnato come prezzo successivo (o altra indicazione quantitativa), il NS inizia a oscillare da una parte all'altra.

E se l'obiettivo è contrassegnato come buy-sell-hold, almeno, il NS si adegua al numero di ingressi riusciti, senza prestare attenzione alla dimensione. E sulla distanza questa "ignoranza" è compensata da un certo livellamento, come se fosse una terapia del rumore. Imho, naturalmente, poco provato la classificazione in un'altra implementazione. Così ho voluto qui

Il preprocessing, che tu non rispetti, serve a questo :) a separare prima i grani dalla pula, e poi ad addestrarla a prevedere i grani separati.

Se la preelaborazione è buona, anche l'output non è del tutto scadente.

 

C'è qualche possibilità di aggiustare questo script per farlo funzionare con le nuove versioni di python (3.10-3.12)?

Ho un sacco di problemi nel cercare di farlo funzionare con la 3.9.

tx