自组织特征映射 (Kohonen 映射) - 再访主题·进阶篇
🧠

自组织特征映射 (Kohonen 映射) - 再访主题·进阶篇

(2/3)· 上篇铺了概念,这篇直接拆开基础类、范形加载与训练循环的代码骨架

含代码示例偏理论 第 2/3 篇
不少人在 MT5 里跑 Kohonen 网络时,初始化权重随手用 rand() 就开训,结果一堆神经元从头到尾没赢过竞争,白白占着内存。死神经元不是玄学,是初始化和抽样方式两个环节同时失控的产物。

自组织映射网络的类继承骨架

在 MT5 里做自组织映射(SOM)聚类,先得把网络对象的结构搭清楚。下面这段定义用三层继承把「数据—训练—可视化」拆开,实际跑的时候你只要实例化最底层的 CSOM_Net_Demonstration 就能复用全部能力。 CSOM_Net_Train 继承自 CSOM_Net_Data,负责拿参数和跑训练。InitParameters 接收三个整型:迭代次数、网格横向格数 xcells、纵向格数 ycells;Train 执行训练循环;SaveNet 把权重落盘到指定文件。它里面两个虚函数 Render 和 ShowBMP 是空壳,专门留给子类填图形逻辑。 CSOM_Net_Img 在训练层之上接管图像。它的 InitParameters 重载后多了 bmpwidth、bmpheight 以及六边形格点开关、边框/标题显示、配色方案和最大图案数等 7 个参数,说明可视化维度完全可配。Render 和 ShowBMP 在这里有了实体,NetDeinit 负责把图表上的位图清掉,避免重复叠加。 最外层的 CSOM_Net_Demonstration 只加了一个 ShowTrainPatterns,演示怎么用子类扩展来把训练样本投到网格上。继承链越长,越方便你在不碰训练核心的前提下改显示逻辑。外汇与贵金属行情高波动,用 SOM 做状态划分时样本窗口过短可能令聚类结果失真,建议先用历史数据离线验证。

MQL5 / C++
class CSOM_Net_Train : class="kw">public CSOM_Net_Data
  {
class="kw">public:
  class=class="str">"cmt">//--- 函数初始化网络, 获取参数
  class="type">void              InitParameters(class="type">int iterations,class="type">int xcells,class="type">int ycells);
  class=class="str">"cmt">//--- 函数用于训练网络
  class="type">void              Train();
  class=class="str">"cmt">//--- 函数用于保存网络到文件中 
  class="type">void              SaveNet(class="type">class="kw">string file_name);
  class=class="str">"cmt">//--- 虚函数 (实体描述在 CSOM_Net_Img 子类中) 
  class="kw">virtual class="type">void      Render(){};
  class="kw">virtual class="type">void      ShowBMP(class="type">bool back){};
  };
  
class CSOM_Net_Img : class="kw">public CSOM_Net_Train
  {
class="kw">public:
  class=class="str">"cmt">//--- 函数初始化网络, 获取参数
   class="type">void             InitParameters(class="type">int iterations,class="type">int xcells,class="type">int ycells,
                                  class="type">int bmpwidth,class="type">int bmpheight,
                                  class="type">bool p_HexagonalCell,class="type">bool p_ShowBorders,class="type">bool p_ShowTitles,
                                  class="type">int p_ColorScheme,class="type">int p_MaxPictures);
  class=class="str">"cmt">//--- 函数用来显示网络状态
  class="type">void              Render();
  class=class="str">"cmt">//--- 函数用来在图表上显示 bmp 图像  
  class="type">void              ShowBMP(class="type">bool back);
  class=class="str">"cmt">//--- 函数用于保存资源到 bmp 文件中
  class="type">void              SaveBMP();
  class=class="str">"cmt">//--- 逆初函数, 从图表上移除 BMP 图像
  class="type">void              NetDeinit();
  };
  
class CSOM_Net_Demonstration : class="kw">public CSOM_Net_Img
  {
class="kw">public:
  class=class="str">"cmt">//--- 函数 - 使用子类来增加机会的例子
  class="type">void              ShowTrainPatterns();
  };

「从 somnet 文件把训练好的 SOM 网络挂进 EA」

做 SOM 网络实测时,第一步往往是把离线训练好的网络加载进智能交易程序。示例里约定用带 somnet 扩展名的二进制文件存网络,加载时只需传文件名,扩展名会自动补上,避免把不适于算法识别的文件误读进来。 加载逻辑集中在 DownloadNet(string file_name) 函数。文件头部先写三个双精度单元:第一个存「范形维度 + 6」,多出的 6 个字段留给节点坐标;后两个分别是 m_xcells 与 m_ycells,即网络可视范围的 x、y 尺寸,两者相乘就是节点总数。头部之后按序读入各节点数据向量,直到整个网络读完。 网络就位后,示例用常数填充待识别的 vector[] 仅作演示。核心在 BestMatchingNode 的三种用法:不传掩码时遍历全部字段;先用 InitSetByteMap 设掩码可按字段过滤,实现不完整信息匹配;或调用带 dimension 参数的重载,直接指定参与比对的字段数。 参数里指定网络路径时,注意相对 MT5 的 Files 目录。下面这行输入就是告诉 EA 去 SOM 子目录找 SOM_Net 这个网络。

MQL5 / C++
class="kw">input class="type">class="kw">string SOM_Net="SOM\\SOM_Net";

◍ 用 CSOM_Net_Data 把范形文件喂给网络

Sample2_SOM_Net_Data 演示了 CSOM_Net_Data 类的用法,它继承自 CSOM_Net_Base,因此自带基类全部方法,并额外提供加载范形数据的接口。这个类本质是为后续接解析器做准备:解析出来的范形既能用于训练,也能直接拿去做识别。 文件名的传递靠一个 input 参数,必须带扩展名写全名,例如 "SOM\\optim.csv"。底层用 FILE_CSV 标志打开文件,随后复用前一示例的网络加载、文件加载、文件解析、循环识别与打印流程即可。 解析器对格式有硬要求:首行必须是列名标题,缺失的话解析器会切掉首行样本并自动补列名。每一列存同一深度的范形字段,每一行是一个完整向量,也就是向量横向排、同字段纵向对齐。 解析后,范形进入内置的 m_patterns_sets_array,列头写入 m_som_titles,行号写入 m_patterns_titles。这样按行号回查某个范形毫无障碍,开 MT5 把 optim.csv 丢进 SOM 目录就能验证加载链路。外汇与贵金属品种波动剧烈,范形识别仅作概率参考,实盘前务必小仓位验证。

MQL5 / C++
class="kw">input class="type">class="kw">string DataFileName="SOM\optim.csv";

训练循环与网络落盘的格式约定

Sample3_SOM_Net_Train 是系列里最值得扒的一段:它挂上 CSOM_Net_Train 基类之后,就能脱离图表自动跑 Kohonen 映射训练,后面继承的类只负责图形外壳。Render() 和 ShowBMP(bool back) 被声明成虚函数且空实现,真正画图的逻辑丢到 CSOM_Net_Img 子类里,这样无图训练时不报冲突。 训练前要用 InitParameters(int iterations,int xcells,int ycells) 把迭代次数和网络网格尺寸塞进网络;Train() 里先初始化均匀分布、算范形最大最小列、在随机范围内置节点,再把实际迭代抽成 TrainIterations(int &p_iter),方便改算法的人直接定位。 落盘格式是硬约定:网络数据全转成 double 一维数组。头部前 5 个 double 分别是 6+dimension_node(范形维数加 6 个节点附加坐标字段)、m_xcells、m_ycells、m_xsize、m_ysize;随后逐个节点抄 6 个基准坐标加权重。标题枚举放在文件尾,因为预测所需内存大小事先算不出。外汇与贵金属模型训练涉及高风险,回测结论仅代表历史样本概率倾向。 读网和存网必须成对写,DownloadNet 按相同 double 流解析才不会错位。下面两个函数签名就是这套机制的出入口,开 MT5 把 Sample3 跑通后,改文件名就能验证存读同步。

MQL5 / C++
class="type">void CSOM_Net_Train::SaveNet(class="type">class="kw">string file_name)
class="type">bool CSOM_Net_Base::DownloadNet(class="type">class="kw">string file_name)
把重复劳动交给小布
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到范形分布与死神经元占比的自动标注,你只需决定要不要重训。

常见问题

默认用欧氏空间距离比对输入范形与各神经元权重向量,差异最小的那个神经元胜出,实现上就在 CSOM_Net_Base 类的 BestMatchingNode 里。
可以,小布盯盘对应品种页内置了 AIGC 诊断,会标出学习半径收缩曲线和疑似死神经元,省去你手动打日志。
rand()/N 不保证 N 次迭代里每个范形都出现,C_PRNG_UD 能让随机范形在训练集上均匀分布,降低死神经元概率。
初期大半径高速度让权重粗略平均,末期缩小只调邻近胜者,权重才收敛到输入参数,避免后期抖动。