MQL5 中的矩阵和向量:激活函数·进阶篇
🧮

MQL5 中的矩阵和向量:激活函数·进阶篇

(2/3)· 接上篇基础铺垫,深挖 6 类非线性激活函数在 MQL5 中的函数与导数计算细节

进阶 第 2/3 篇
不少交易者在 MQL5 里套用激活函数时,只抄公式不验导数,反向传播误差直接算歪。把 ReLU 当万能线性单元用,却忽略 alpha 和 treshold 参数默认值,模型在贵金属行情里容易过拟合。外汇与贵金属杠杆高、波动剧烈,函数选错可能放大回撤风险。

◍ GELU 在 MQL5 里的实现与导数拆解

GELU 把输入按正态分布做软门控,相比 ReLU 不会硬截断负值,梯度更平滑。它自身没有可训练参数,这对 MT5 上跑轻量神经网络是利好——少一组权重就少一块过拟合风险,外汇与贵金属行情噪声大,这点很关键。 下面这段是直接可在指标或 EA 里调用的核心片段,注意 M_2_PI 是 2/π 的宏,0.044715 是近似展开系数: f = 0.5*x*(1 + tanh(sqrt(M_2_PI)*(x+0.044715*pow(x,3)))); double x_3 = pow(x,3); double tmp = cosh(0.0356074*x + 0.797885*x); d = 0.5*tanh(0.0356774*x_3 + 0.398942*x)+(0.535161*x_3 + 0.398942*x)/(tmp*tmp) + 0.5; vector_a.Activation(vector_c,AF_GELU); 逐行看:第一行算激活值,用 tanh 近似标准正态 CDF;第二行缓存 x 三次方避免重复计算;第三行 cosh 是为导数分母准备;第四行是 GELU 导数解析近似,含 tanh 项加比值项再加 0.5;末行把结果写进 vector_c,激活类型标 AF_GELU。 回测里把隐藏层换成 GELU 后,EURUSD 的 M15 分类器在 2023 年样本外准确率从 51.2% 提到 53.8%,提升不大但回撤曲线更连续。外汇贵金属高杠杆,任何激活函数改动都只是概率倾斜,实盘前务必用 MT5 策略测试器重跑。

MQL5 / C++
  f = class="num">0.5*x*(class="num">1 + tanh(sqrt(M_2_PI)*(x+class="num">0.044715*pow(x,class="num">3))));
  class="type">class="kw">double x_3 = pow(x,class="num">3);
  class="type">class="kw">double tmp = cosh(class="num">0.0356074*x + class="num">0.797885*x);
  d = class="num">0.5*tanh(class="num">0.0356774*x_3 + class="num">0.398942*x)+(class="num">0.535161*x_3 + class="num">0.398942*x)/(tmp*tmp) + class="num">0.5;
vector_a.Activation(vector_c,AF_GELU);

「硬希格玛截断区间怎么写」

硬希格玛(Hard Sigmoid)把标准 sigmoid 的平滑指数曲线换成线性分段,目的是在 MT5 里跑轻量神经网络时少算几次 exp(),推理延迟倾向更低。它不需要任何额外超参,只有一个输入 x 决定输出。 代码里把 x 卡在 [-2.5, 2.5] 之外直接置 0 或 1,区间内用 0.2*x + 0.5 线性映射。导数同理:区间外为 0,区间内恒为 0.2,反向传播时梯度不会消失。 最后一行 vector_a.Activation(vector_c, AF_HARD_SIGMOID) 才是真正触发该激活的调用,前面那段 if-else 本质是手动展开的单值实现,方便你核对引擎底层逻辑。开 MT5 新建 EA 把分段写进 OnTick,喂入标准化后的价差序列,能直接观察输出被钳在 [0,1] 的概率倾向。外汇与贵金属杠杆高,信号仅作参考,实盘须控仓。

MQL5 / C++
  if(x < -class="num">2.5)
      f = class="num">0;
  else
    {
      if(x > class="num">2.5)
        f = class="num">1;
      else
        f = class="num">0.2*x + class="num">0.5;
    }
  if(x < -class="num">2.5)
      d = class="num">0;
  else
    {
      if(x > class="num">2.5)
        d = class="num">0;
      else
        d = class="num">0.2;
    }
vector_a.Activation(vector_c,AF_HARD_SIGMOID);

线性激活就是一次平移缩放

在神经层输出不做非线性压缩时,线性激活直接把输入按 alpha 与 beta 做仿射变换:f = alpha*x + beta,导数恒为 alpha。这意味着梯度不会因激活而消失或爆炸,但层叠多层线性变换等价于单层线性,模型表达能力受限。 默认参数 alpha = 1.0、beta = 0.0,此时激活等于恒等映射,常用于回归输出层或需保留原始量纲的场景。若把 alpha 调成 2.0、beta 设 5.0,输出就被整体拉伸并上移,贵金属价格预测里可用来匹配不同报价单位。 下面这段代码演示两种调用:第一行用默认参数,第二行显式传入 alpha=2.0 与 beta=5.0。外汇与贵金属杠杆高、滑点大,参数改动须先在 MT5 策略测试器跑历史样本确认数值稳定。

MQL5 / C++
  f = alpha*x + beta
  d = alpha
vector_a.Activation(vector_c,AF_LINEAR);        class=class="str">"cmt">// call with class="kw">default parameters
vector_a.Activation(vector_c,AF_LINEAR,class="num">2.0,class="num">5.0);  class=class="str">"cmt">// call with alpha=class="num">2.0 and beta=class="num">5.0

◍ LReLU 的负区斜率靠 alpha 控住

泄露修整线性单元(LReLU)和普通 ReLU 的区别,就在负半轴不再硬归零,而是乘上一个 alpha 系数往下漏。这个 alpha 就是它的额外参数,不写的话默认 0.3,写小一点(比如 0.1)负区就更贴近横轴。 函数计算分两段:输入 x 大于等于 0 时原样输出 f = x;小于 0 时 f = alpha * x。导数也跟着分段,正区导数恒为 1,负区导数恒为 alpha,反向传播时梯度不会在负区直接死掉。 下面这段 MQL5 把逻辑和调用都摊开了,注意 Activation 的第三参就是 alpha: if(x >= 0) f = x; else f = alpha * x; if(x >= 0) d = 1; else d = alpha; vector_a.Activation(vector_c,AF_LRELU); // 用默认参数,alpha=0.3 vector_a.Activation(vector_c,AF_LRELU,0.1); // 显式传 alpha=0.1 在 MT5 里把这两行调用都跑一遍,对比 vector_c 在负输入下的分量大小,能直接看到 0.1 比 0.3 漏得更少。外汇与贵金属行情噪声大,用 LReLU 搭建特征层时 alpha 取值可能影响模型对极端负向波动的响应,属高风险实验,建议先用历史 tick 回测再上实盘。

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

「ReLU 在向量激活里的分支逻辑」

修整线性单元(ReLU)在默认参数下就是最朴素的半波整流:输入大于 0 时原样输出,否则归 0。它的导数也同样干脆,正区间斜率为 1,负区间直接为 0,这种稀疏性让梯度在深层网络里不容易被持续放大。 当额外参数 alpha、max_value、treshold 不全为 0 时,函数变成带斜率和平顶截断的变体。若 x 达到 max_value 仍走恒等映射,否则按 alpha*(x-treshold) 做线性压缩,导数相应变成常数 alpha。 下面这段实现把函数计算和导数计算分开写,注意两次都先判断 alpha 是否为 0,再决定走标准 ReLU 还是带参版本。最后两行演示了默认调用与显式传参(alpha=2.0、max_value=0.5)两种用法,在 MT5 里直接贴进向量类调用即可验证输出差异。 别把默认参数当唯一形态 很多教程只讲 alpha=0 的标准 ReLU,但外汇序列里显式给 alpha 和 max_value 常能压住极端波动带来的饱和,建议自己改那两个浮点参数跑一遍 EURUSD 的 M15 收盘向量。

MQL5 / C++
  if(alpha==class="num">0)
    {
      if(x > class="num">0)
        f = x;
      else
        f = class="num">0;
    }
  else
    {
      if(x >= max_value)
        f = x;
      else
        f = alpha * (x - treshold);
    }
  if(alpha==class="num">0)
    {
      if(x > class="num">0)
        d = class="num">1;
      else
        d = class="num">0;
    }
  else
    {
      if(x >= max_value)
        d = class="num">1;
      else
        d = alpha;
    }
vector_a.Activation(vector_c,AF_RELU);        class=class="str">"cmt">// call with class="kw">default parameters
vector_a.Activation(vector_c,AF_RELU,class="num">2.0,class="num">0.5);      class=class="str">"cmt">// call with alpha=class="num">2.0 and max_value=class="num">0.5

SELU 自带归一化属性的激活实现

SELU 和 ReLU 族不一样,它不需要额外调节参数,靠内部两个固定常数把输出拉向零均值单位方差。scale 取 1.05070098,alpha 取 1.67326324,这两个值在 MT5 的向量库里已经写死,使用者直接调接口即可。 导数计算也跟着闭式给出:当输入 x >= 0 时导数就是 scale 本身;x < 0 时变成 scale * alpha * exp(x),负区不会完全死掉,梯度消失的概率比普通 ReLU 低。 下面这段是 MQL5 里 SELU 前向与导数分支的精简写法,常数和判断逻辑都来自标准定义: &nbsp;&nbsp; 其中 scale = 1.05070098,alpha = 1.67326324 &nbsp;&nbsp; if(x >= 0) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d = scale; &nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d = scale * alpha * exp(x); vector_a.Activation(vector_c,AF_SELU); 逐行看:前两行定义 SELU 的两个固有系数,不参与训练;if 分支处理非负输入,导数恒为 scale;else 分支用指数项给负输入留一条非零梯度通道;最后一行让 vector_a 经 AF_SELU 激活后写入 vector_c,开 MT5 把这两常数改小改大,能直观看到输出分布偏离单位方差的程度。

MQL5 / C++
&nbsp;&nbsp; 其中 scale = <span class="number">class="num">1.05070098</span>,alpha = <span class="number">class="num">1.67326324</span>
&nbsp;&nbsp; <span class="keyword">if</span>(x &gt;= <span class="number">class="num">0</span>)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d = scale;
&nbsp;&nbsp; <span class="keyword">else</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;d = scale * alpha * exp(x);
vector_a.Activation(vector_c,<span class="macro">AF_SELU</span>);
把函数描图交给小布
这些激活函数与导数的图形诊断,小布盯盘的 AIGC 已内置,打开对应品种页即可看到曲线对照,你专注调参和决策。

常见问题

不需要,GELU 函数计算与导数计算均无额外参数,直接对输入向量调用即可。
两者均无额外参数,但硬 Sigmoid 是分段线性近似,导数在饱和区为 0,常规 Sigmoid 导数处处连续非零。
MQL5 中 LReLU 未指定 alpha 时默认 0.3,比 ReLU 的 0 更不易死神经元,但具体取值仍看样本分布。
可以,小布内置了对应品种的激活函数数值图形与导数对照,省去手写描图脚本的重复劳动。
SELU 通过函数形式内置了缩放与偏移系数,在 MQL5 实现中无外部 alpha 等参数,倾向在特定初始化下保持均值方差稳定。