Discusión sobre el artículo "Uso de modelos ONNX en MQL5" - página 6

 
Error al utilizar el modelo-clasificador.

La regresión funciona con todo, la salida es un número.

Pero cuando se le pide a cualquier chat que escriba MLP-clasificador, el Asesor Experto no puede reconocer los datos de salida de este modelo: "Comprar", "Vender", "Mantener". O "1", "2", "3", o "0", "1", "2".

El error sale volando

2025.02.12 08:13:46.866 Core 01 2021.01.01 00:00:00 Error configurando la forma de salida: 5808
2025.02.12 08:13:46.866 Core 01 2021.01.01 00:00:00 ONNX: handle inválido pasado a la función OnnxRelease, inspeccionar código 'X È$Zë3E' (291:7)

Ninguno de los chats, ni siquiera Dipsic, entiende o sabe cómo solucionar el problema, generando posibles códigos que también conducen a este error.

Todos los chats dicen lo mismo: como se trata de un clasificador MLP, sólo tiene 3 salidas, según sus etiquetas (lo alimento con un archivo csv, donde la última columna es una de las tres etiquetas de una clasificación simple: comprar, vender, mantener. Probé con valores de cadena y numéricos en esta columna).

Entonces este bloque

.
const long output_shape[] = {1,1};
   if(!OnnxSetOutputShape(ExtHandle,0,output_shape))
     {
      Print("OnnxSetOutputShape error ",GetLastError());
      return(INIT_FAILED);
     }
Cambia la inicialización del array

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


Y aparece un error.

Estoy intentando imprimir.

Print(OnnxGetOutputCount(ExtHandle));

Me sale 2.

No entiendo nada.



Si alguien entiende cuál es el error, por favor que me lo diga.

Código Python para clasificador - cualquiera, todos generan el mismo error.

Por ejemplo, una de las implementaciones:

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

# Cargando datos
file_path = '....csv'
data = pd.read_csv(file_path)

# Dividir en atributos (X) y etiquetas (y)
X = data.iloc[:, :160].values  # Las primeras 160 columnas son datos de entrada
y = data.iloc[:, 160].values   # La última columna es la etiqueta de destino

# Codificación de etiquetas de cadena en etiquetas numéricas
label_encoder = LabelEncoder()
y_encoded = label_encoder.fit_transform(y)

# Normalización de datos
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# Dividir en muestras de entrenamiento y de prueba
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y_encoded, test_size=0.2, random_state=42)

# Creación de un clasificador MLP
mlp = MLPClassifier(hidden_layer_sizes=(128, 64), activation='relu', solver='adam', max_iter=500, random_state=42)
mlp.fit(X_train, y_train)

# Estimación de la precisión del modelo
accuracy = mlp.score(X_test, y_test)
print(f"Accuracy: {accuracy * 100:.2 f}%")

# Guardar el modelo en formato ONNX
initial_type = [('float_input', FloatTensorType([None, 160]))]  # 160 características de entrada
onnx_model = convert_sklearn(mlp, initial_types=initial_type)

# Guardar el 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}")


Es decir, el modelo en sí - que se ejecuta en python. Está calculando algo

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

Pero el asesor no puede aceptarlo.

[Eliminado]  
En una comunidad sana la generación de código no se discute, ni siquiera se considera amable. No está mal conocer el bug ONNX, por el cual no se soporta multiclase.
 
No hace falta discutirlo
No es la cuestión.
[Eliminado]  
Ivan Butko #:
No hace falta discutirlo
No es la cuestión.

Prueba {2,3} o {3}.

pide al script python que te devuelva la dimensión correcta de la salida.

pero lo mas probable es que solo {1}, devuelva una estructura donde los campos ya corresponden a salidas.


Por ejemplo, tengo para un clasificador binario es

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

Entonces sólo tienes que crear una estructura en el 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];

Donde el campo etiqueta son los valores de clase y el tensor son las probabilidades

[Eliminado]  
Incorrecto: la etiqueta contiene valores de clase y el tensor contiene probabilidades. Bueno, la dimensión de salida es esencialmente 2,2, pero ya que se devuelve la estructura, se debe establecer en 1
 
Maxim Dmitrievsky #:
Incorrecto: la etiqueta contiene valores de clase y el tensor contiene probabilidades. Así que la dimensión de salida es esencialmente 2,2, pero como se devuelve la estructura, debe poner 1
Gracias

UPD

Sobre la esencia de las arquitecturas: la regresión en el artículo trata de la vangulación. Y la clasificación parece tener más sentido. Y he aquí - resulta que es un problema con él en la funcionalidad nativa.

Subjetivamente: si el objetivo está marcado como el siguiente precio (u otra indicación cuantitativa), el NS comienza a oscilar de lado a lado.

Y si el objetivo está marcado como comprar-vender-mantener, al menos, el NS se ajusta al número de entradas exitosas sin prestar atención al tamaño. Y en la distancia esta "ignorancia" se compensa con un poco de nivelación, como si la terapia de ruido. Imho, por supuesto, poco probado la clasificación en otra aplicación. Así que quería aquí
[Eliminado]  
Ivan Butko #:
Gracias
También puede visualizar su malla a través de Netron y se mostrará la dimensión y el tipo de salida
[Eliminado]  
Ivan Butko #:
Gracias

UPD

Sobre el punto de las arquitecturas: la regresión en el artículo trata de la vangulación. Y la clasificación parece tener más sentido. Y aquí estamos - resulta ser un problema con él en la funcionalidad nativa.

Subjetivamente: si el objetivo está marcado como el próximo precio (u otra indicación cuantitativa), el NS comienza a oscilar de lado a lado.

Y si el objetivo está marcado como comprar-vender-mantener, al menos, el NS se ajusta al número de entradas exitosas, sin prestar atención al tamaño. Y en la distancia esta "ignorancia" se compensa con un poco de nivelación, como si la terapia de ruido. Imho, por supuesto, poco probado la clasificación en otra aplicación. Así que quería aquí

Para eso está el preprocesamiento, que no respetas :) para separar primero los granos de la paja, y luego entrenarlo para predecir los granos separados.

Si el preprocesado es bueno, la salida tampoco es una basura del todo

 

¿Hay alguna posibilidad de que puedas arreglar este script para que funcione con versiones más recientes de python (3.10-3.12)?

Tengo un montón de problemas tratando de hacerlo funcionar en 3.9.

tx