MQL5 中的矩阵和向量:激活函数(基础篇)
📘

MQL5 中的矩阵和向量:激活函数(基础篇)

第 1/3 篇

在 MQL5 里给矩阵喂激活函数

MQL5 自 Build 3510 起原生支持矩阵(matrix)与向量(vector)类型,这让策略原型可以直接在 MT5 里做轻量张量运算,而不必外挂 Python。对做价格行为特征工程的人来说,这意味着能把一串 K 线数值压成向量,再套一层激活函数做非线性变换。 激活函数本身不改变矩阵维度,只逐元素映射。比如把价格变化率向量过一层 Tanh,就能把极端波动压缩到 [-1,1],后续做相似度计算时不会被个别跳空吞掉信号。下面这段演示了如何用 MQL5 对矩阵做 Tanh 激活。 [CODE]matrix a(2,2); a[0][0]=2.5; a[0][1]=-1.3; a[1][0]=0.0; a[1][1]=4.1; matrix b = a.Tanh(); Print(b);[/CODE] 逐行看:先声明 2x2 矩阵 a;四行分别给四个元素赋原始值,包含正、负、零、大正值;调用 Tanh() 成员函数生成新矩阵 b,原矩阵不被改写;Print 输出后可在专家日志看到 b 约等于 [0.987, -0.862; 0.0, 0.999]。外汇与贵金属波动有跳空风险,实盘前务必用历史数据核对激活后的数值分布。 开 MT5 新建脚本粘入上面代码,把 a 的元素换成你某段 EURUSD 的收益率序列,跑一遍看压缩效果,比纯口头理解快得多。

MQL5 / C++
matrix a(class="num">2,class="num">2);
a[class="num">0][class="num">0]=class="num">2.5; a[class="num">0][class="num">1]=-class="num">1.3;
a[class="num">1][class="num">0]=class="num">0.0; a[class="num">1][class="num">1]=class="num">4.1;
matrix b = a.Tanh();
Print(b);

「为什么只聊激活函数」

市面讲神经网络训练的资料已经堆成山,MQL5 社区里也有人写过多个系列长文,从反向传播到损失函数都覆盖过。 我们这一篇不重复造轮子,只切一个最容易被忽视、却直接影响模型表达能力的点——激活函数。把这一块的内部机制拆清楚,比泛泛而谈整个训练流程更有实操价值。 后续你会看到具体的 MQL5 代码片段,直接在 MT5 里建个脚本跑一遍,就能验证不同激活函数对输出分布的扰动。外汇和贵金属市场高杠杆、高波动,任何模型信号都只是概率倾向,实盘前务必用小资金验证。

◍ 激活函数为何必须可微

人工神经网络里,神经元激活函数负责把一组输入信号映射成输出信号值。它要在整个实数域上可微分,否则反向传播这一步就断了——训练时误差要从输出层往回传,必须能算出激活函数对每一个输入分量的偏导数向量。 非线性激活函数常被认为更利于模型学到复杂边界,但 ReLU 这种分段线性函数(x>0 输出 x,x≤0 输出 0)在大量实证里也跑得通,说明“非线性的必要神话”在外汇量化里未必成立。 对做 MT5 信号模型的交易者来说,选激活函数时先确认你的训练框架是否依赖梯度链;若用 ReLU,注意它在 0 点不可导,实现层通常用左导数 0 近似,这属于工程妥协而非理论完美。

用脚本把激活函数和它的导数画出来

要把激活函数和导数的形状看清楚,最直观的办法是在 MT5 图表上直接描图。我们构造了一个从 -5 到 5 的单调递增序列作为横轴输入,逐点计算函数值与导数值,这样曲线形态一眼可辨。 脚本跑起来后会弹出文件对话框,按 Page Down 键就能指定把图像存成什么文件;随时按 ESC 可终止脚本,不占用图表资源。 图上蓝色线是激活函数本身,红色线是它的导数。把两者叠在一起看,能马上判断该函数在哪段区间梯度饱和、哪段还有有效学习信号——调神经网络隐层时这是个很实用的先验检查。外汇与贵金属市场波动剧烈、杠杆风险高,这类工具只用于辅助验证模型假设,不构成任何交易结论。

「ELU 的负区饱和特性与 alpha 调参」

ELU 在输入大于等于 0 时原样输出,负区则走 alpha*(e^x - 1),比 ReLU 多了负向饱和能力,能让均值更靠近 0,缓解神经元死亡。它多带一个 alpha 参数,不传时默认 1,传了就直接改变负区斜率与下界。 导数侧同样分段:正区恒为 1,负区是 alpha*e^x,在 x=0 处左极限为 alpha、右极限为 1,alpha=1 时恰好连续可微。若把 alpha 设成 3.0,负区下界就压到 -3,梯度负区更陡。 下面这段 MT5 向量激活调用,第一行用默认 alpha=1,第二行显式传 3.0,跑完可对比 vector_c 在负输入段的数值分布。外汇与贵金属模型里用 ELU 做特征变换,可能因分布偏移放大回测误差,属高风险实验,建议先在小样本验证。

MQL5 / C++
  if(x >= class="num">0)
      f = x;
  else
      f = alpha*(exp(x) - class="num">1);
  if(x >= class="num">0)
      d = class="num">1;
  else
      d = alpha*exp(x);
  vector_a.Activation(vector_c,AF_ELU);      class=class="str">"cmt">// call with the class="kw">default parameter
  vector_a.Activation(vector_c,AF_ELU,class="num">3.0);  class=class="str">"cmt">// call with alpha=class="num">3.0

◍ 指数激活函数靠 exp 自导自演

指数激活函数的核心就是 f(x)=exp(x),而 exp 的导数还是它自己,这一性质让反向传播里的梯度计算省掉额外分支。 在 MQL5 的 vector 体系里,这类激活没有可训练参数,调用时只需指定 AF_EXP 标志,不附带任何系数。 外汇与贵金属模型若用指数激活,需注意输出无上下界,价格序列归一化不当会放大波动风险,建议先在 MT5 用历史 tick 跑一遍数值稳定性。

MQL5 / C++
  f = exp(x);
vector_a.Activation(vector_c,AF_EXP);

常见问题

写个脚本用 vector 或 matrix 的逐元素运算,把激活函数公式直接映射到每个元素即可,不需要循环手写。
反向传播要靠导数算梯度,不可微点在更新权重时会断链,所以选激活函数先看它导数是否处处有定义。
可以,把公式丢给小布,它能逐步推导出导数并标出易错的可微断点,省去手算时间。
默认 1.0 常见,负区饱和快慢随 alpha 增大而平缓,实盘模型里多在 0.1~1.0 之间试。
它导数就是自己,代码里算梯度时直接复用原值,不用再调一次 exp,能少一次浮点开销。