文章 "如何在 MQL5 中使用 ONNX 模型" - 页 6

 
使用模型分类器时出错。

回归对一切都有效,输出是一个数字。

但当您要求任何聊天工具编写 MLP 分类器时,EA 无法识别该模型的输出数据:"买入"、"卖出"、"持有"。要么是 "1"、"2"、"3",要么是 "0"、"1"、"2"。

错误飞出

2025.02.12 08:13:46.866 核心 01 2021.01.01 00:00:00 错误设置输出形式:5808
2025.02.12 08:13:46.866 核心 01 2021.01.01 00:00:00 ONNX:传递给 OnnxRelease 函数的无效句柄,检查代码 '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。

我什么也不明白。



如果有人明白这个错误是什么,请告诉我。

分类器的 Python 代码 - 任何,它们都产生相同的错误。

例如,其中一个实现:

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:.2 f}%")

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


即模型本身--在 python 中运行。它正在计算

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

但顾问无法接受。

 
在一个健康的社区中,代码生成是不需要讨论的,甚至不需要考虑。知道 ONNX 的错误也不错,因为它不支持多类。
 
不需要讨论
这不是问题所在。
 
Ivan Butko #:
不需要讨论
这不是问题所在。

试试 {2,3} 或 {3}。

请 python 脚本输出正确的输出维度。

但很可能只是{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];

其中标签字段是类值,张量是概率

 
错误:标签包含类别值,而张量包含概率。输出维度本质上是 2,2,但由于返回的是结构,所以应该设为 1
 
Maxim Dmitrievsky #:
错误:标签包含类别值,而张量包含概率。因此,输出维度本质上是 2,2,但由于返回的是结构,因此应为 1
谢谢

更新

关于结构的本质:文章中的回归处理的是 vangulation。而分类似乎更有意义。看,原来在本地功能中也有问题。

主观方面:如果目标被标记为下一个价格(或其他定量指示),NS 就会开始左右摇摆。

而如果目标被标记为买入-卖出-持有,至少 NS 会根据成功进入的数量进行自我调整,而不关注大小。而在距离上,这种 "无知 "会得到一定的补偿,就像噪音疗法一样。当然,我并没有尝试过在另一种方法中进行分类。所以我想在这里
 
Ivan Butko #:
谢谢
您还可以通过 Netron 将网格可视化,它将显示尺寸和输出类型
 
Ivan Butko #:
谢谢

UPD

关于架构的问题:文章中的回归处理的是 vangulation。分类似乎更有意义。而我们现在的情况是--在本地功能中出现了问题。

主观方面:如果目标被标记为下一个价格(或其他定量指示),NS 就会开始左右摇摆。

而如果目标被标记为买入-卖出-持有,至少,NS 会根据成功入场的次数进行调整,而不关注大小。而在距离上,这种 "无知 "会得到一定的补偿,就像噪音疗法一样。当然,我并没有在另一个实施方案中尝试过这种分类。所以我想在这里

这就是你所不尊重的预处理的作用:)首先将谷物从谷壳中分离出来,然后训练它预测分离出来的谷物。

如果预处理做得好,输出结果也不会太垃圾

 



我在尝试让它在 3.9 上运行时遇到了很多问题。

tx