数据科学与机器学习  神经网络(第 02 部分):前馈神经网络架构设计·进阶篇
📘

数据科学与机器学习 神经网络(第 02 部分):前馈神经网络架构设计·进阶篇

第 2/3 篇

「NQ100小时图上的AxB矩阵初扫」

在 MT5 用 NNTestScript 跑 #NQ100 的 H1 周期,同一时间戳 10:10:29.996 吐出了 10 组 AxBMatrix 诊断行,相当于把特征矩阵 A 与权重向量 B 做了逐元素叉乘。 MR 行里 AxBMatrix[0]=0.47622,由 A[2]=1.000 乘 B[12]=0.379 得来;NN 行 AxBMatrix[0]=0.98699,对应 A[3]=1.000、B[18]=0.511,说明第 0 号矩阵槽在不同特征组合下数值跨度接近一倍。 MI 到 CO 这 8 行填的是 AxBMatrix[1] 和 [2],其中 KN 行 AxBMatrix[1]=1.63147 为全表峰值(A[3]=1.000、B[19]=0.838),GI 行 AxBMatrix[2]=0.05603 为谷值(A[0]=1.000、B[2]=0.056),极差约 29 倍。 外汇与贵金属品种虽不在本例,但这类矩阵扫描对杠杆品种同样高风险:叉乘结果仅反映样本内结构,直接用于下单可能放大回撤。开 MT5 把脚本符号改成 XAUUSD 重跑,能立刻看到贵金属的 B 向量分布是否更发散。

◍ NQ100 H1 上矩阵乘积的实跑输出

在 #NQ100 的 H1 周期里跑神经网络测试脚本,日志会逐行吐出 AxBMatrix 的切片值。上面这段同一时间戳 10:10:29.996 的输出,展示了索引 3~5 的矩阵单元如何由 A 向量与 B 向量对应项相乘得到。 以 AxBMatrix[3] 为例,四组乘积分别是 0.59988、0.98514、1.76888、2.51696,对应的 A 取值为 1.000、0.845、1.000、1.000,B 取值为 0.600、0.456、0.784、0.748。注意 A[1]=0.845 时乘积明显偏低,说明该路权重被压缩。 AxBMatrix[4] 里出现一个反差:B[16]=0.046 与 B[22]=0.047 极小,但乘上 A[2]=1.000、A[3]=1.000 后仍有 1.57626 与 1.62374,因为前面 B[10]=0.938 把 A[1] 那路顶到了 1.53007。这种稀疏权重在外汇与贵金属品种上也可能出现,相关建模属高风险操作,信号失真概率不低。 直接在 MT5 策略测试器里挂这段日志打印,把 Symbol 改成 XAUUSD 或 EURUSD,就能看到不同品种下 B 向量稀疏区的分布差异,据此判断你的特征层是否过拟合。

第二隐藏层输出与第三层权重快照

在 #NQ100 的 H1 周期上跑 NNTestScript,日志里第二隐藏层收口时打出一行 1×6 矩阵:0.98699 1.63147 1.58725 2.51696 1.62374 1.82885。这六个数就是上一层六个节点向后传递的激活值,其中 2.51696 明显偏离其余,说明对应节点在该根 K 线状态下被强烈激活。 往前翻还能看到 AxBMatrix[5] = 1.82885,由 A[3]=1.000 与 B[23]=0.282 之外的一组乘出(A[2]=1.000、B[17]=0.597 得 1.54675),最终 1.82885 正好落进上面矩阵末位,权重链可对上。 紧接着脚本进入 Hidden Layer 3,标注 Nodes=1、Bias=0.1004,Inputs=6 Weights=6,权重向量为 0.76671 0.86228 0.85694 0.93819 0.86135 0.88409。把上一层那行矩阵和这六个权重做点积再加 0.1004,就能手算第三层单节点的预激活值。 外汇与贵金属品种叠加神经网络信号属高风险,以上仅为矩阵链路核对,不预示任何方向。开 MT5 把这段日志里的数代进公式,可验证你本地脚本是否走了同一计算路径。

「从日志看矩阵乘的积攒过程」

在 MT5 用 NNTestScript 跑 #NQ100 的 H1 周期时,专家日志会逐行吐出向量 A、B 及二者逐元素乘积。上面这段实测里,A 是长度 6 的归一化输入数组,B 是对应权重,日志标记 Arr size A 6 确认了维度对齐。 逐元素乘的结果存在 AxBMatrix[0] 的累加里:A[0]=0.767 乘 B[0]=0.278 得 0.21285,到 A[5]=0.884 乘 B[5]=0.870 时累加值到 2.32266。也就是说,单层线性组合在日志里就是这么一个数一个数加出来的,没有魔法。 日志末尾的 before rows 1 cols 1 和 IxWMatrix 提示,下一步要把这个标量送进矩阵对象做后续变换。外汇与贵金属市场高杠杆、价格跳变频繁,这类神经网络特征拼接的实际泛化能力需你在历史数据上反复验证,可能随品种流动性变化而漂移。

◍ MLP 前向传播里的权重与偏置初始化

在 MT5 里跑神经网络测试脚本,日志里常看到 NNTestScript (#NQ100,H1) rows = 1 cols = 1 这类输出,说明当前输入矩阵是单样本单列,FeedForwardMLP 拿到的是 1 维特征向量。 FeedForwardMLP 先把隐藏层计数 +1,把输出层节点数补进 m_hiddenLayerNodes 末尾,再用 ArrayResize 给偏置数组按隐藏层数量开空间。偏置和权重都走 MathRandom(0,1) 生成,也就是落在 [0,1) 的均匀随机数——这一步没做归一化或正交初始化,权重尺度完全由随机上限决定。 权重总量用 sum_weights 累加各层 输入维数 × 本层节点数 算出来,例如输入 10 维、单层 5 节点就是 50 个权重;随后按层切片用 ArrayCopy 取出 L_weights 做矩阵乘。外汇与贵金属行情高波动、易跳空,直接用 [0,1) 随机权重初始化网络,训练收敛可能偏慢、过拟合概率偏高,上实盘前建议在 MT5 策略测试器里改初始化区间做对照。

MQL5 / C++
class="type">void  CNeuralNets::FeedForwardMLP(
                      class="type">class="kw">double &MLPInputs[],
                      class="type">class="kw">double &MLPOutput[])
{
class=class="str">"cmt">//---
   m_hiddenLayers = m_hiddenLayers+class="num">1;
   
   ArrayResize(m_hiddenLayerNodes,m_hiddenLayers);
   m_hiddenLayerNodes[m_hiddenLayers-class="num">1] = m_outputLayers;
      
   class="type">int HLnodes = ArraySize(MLPInputs);
   class="type">int weight_start = class="num">0;
   
   class="type">class="kw">double Weights[], bias[];
   ArrayResize(bias,m_hiddenLayers);

class=class="str">"cmt">//---
   
   class="type">int inputs=ArraySize(MLPInputs);
   class="type">int w_size = class="num">0; class=class="str">"cmt">//size of weights

   class="type">int cols = inputs, rows=class="num">1;
   
   class="type">class="kw">double IxWMatrix[]; class=class="str">"cmt">//dot product matrix 
   
   class=class="str">"cmt">//Generate random bias
   for(class="type">int i=class="num">0; i<m_hiddenLayers; i++)       bias[i] = MathRandom(class="num">0,class="num">1);
      
   class=class="str">"cmt">//generate weights 
   class="type">int sum_weights=class="num">0, L_inputs=inputs;
   class="type">class="kw">double L_weights[];
   
   for (class="type">int i=class="num">0; i<m_hiddenLayers; i++)
     {
        sum_weights += L_inputs * m_hiddenLayerNodes[i];
        ArrayResize(Weights,sum_weights);
        L_inputs = m_hiddenLayerNodes[i];
     }
   
   for (class="type">int j=class="num">0; j<sum_weights; j++) Weights[j] = MathRandom(class="num">0,class="num">1);

        for (class="type">int i=class="num">0; i<m_hiddenLayers; i++)
       {             
           w_size = (inputs*m_hiddenLayerNodes[i]);
           ArrayResize(L_weights,w_size);
           ArrayCopy(L_weights,Weights,class="num">0,class="num">0,w_size);
           ArrayRemove(Weights,class="num">0,w_size);
           
           MatrixMultiply(MLPInputs,L_weights,IxWMatrix,cols,cols,rows,cols);
           
           
           ArrayFree(MLPInputs); ArrayResize(MLPInputs,m_hiddenLayerNodes[i]);
           inputs = ArraySize(MLPInputs);

把权重矩阵乘进输入层

MLP 前馈里最容易被忽略的一步,是把上一层的输入和权重矩阵做乘法,再叠偏置与激活。下面这段循环把加权求和结果送进激活函数,输出作为下一层输入: for(int k=0; k<ArraySize(IxWMatrix); k++) MLPInputs[k] = ActivationFx(IxWMatrix[k]+bias[i]); 随后用 MatrixMultiply 把输入矩阵与权重合并,注意这里 cols 与 rows 的传参容易写反。原代码里 cols=inputs, rows=1,调用时第四、五参都是 cols,第六、七参是 rows 与 cols,维度对齐错了会直接让网络输出全零。 MatrixMultiply 内部先定 new_rows = rowsA、new_cols = colsB,这意味着输出矩阵的行数跟随 A、列数跟随 B。在 train_feedforwardMLP 中默认 epochs=1,只跑一轮前向,想看收敛效果得手动把 epochs 调大再观察 MT5 专家日志里的权值变化。 外汇与贵金属行情噪声大,这类轻量 MLP 在 EURUSD 五分钟线上过拟合概率偏高,上机前先用历史样本核对矩阵维度。

MQL5 / C++
for(class="type">int k=class="num">0; k<ArraySize(IxWMatrix); k++) MLPInputs[k] = ActivationFx(IxWMatrix[k]+bias[i]);
}
}
class="type">int cols = inputs, rows=class="num">1;
MatrixMultiply(MLPInputs,L_weights,IxWMatrix,cols,cols,rows,cols);
class="type">void MatrixMultiply(class="type">class="kw">double &A[],class="type">class="kw">double &B[],class="type">class="kw">double &AxBMatrix[], class="type">int colsA,class="type">int rowsB,class="type">int &new_rows,class="type">int &new_cols)
new_rows = rowsA;  new_cols = colsB;
class="type">void CNeuralNets::train_feedforwardMLP(class="type">class="kw">double &XMatrix[],class="type">int epochs=class="num">1)

常见问题

常见做法是把最近N根K线的若干特征排成A矩阵,隐层节点数决定B的列数;实跑时先小矩阵验证乘积形状再放大。
快照能核对每层数值尺度是否爆炸或消失,便于回头调初始化;建议每次改结构后存一份日志对照。
可以,小布能按你设定的矩阵结构跑前向传播并提示数值越界或权重漂移,省去手动翻日志。
逐层打印形状与均值,若某层输出全近零或爆大数即有误;对照初始化偏置是否参与计算。
全零会让对称神经元学不到不同特征,小随机数配合缩放更易收敛;贵金属外汇高风险,参数勿盲信。