交易中的神经网络:具有相对编码的变换器·进阶篇
📘

交易中的神经网络:具有相对编码的变换器·进阶篇

第 2/3 篇

◍ GPU 上的注意力归一与输出归约

这段 OpenCL 内核干了两件事:先把注意力系数 sc 做局部求和再归一,再把加权后的 value 向量归约写回输出缓冲。外汇与贵金属行情的高频序列喂进这类算子时,浮点异常必须先掐掉——NaN 或 Inf 直接置 0,否则后续累加会污染整块显存。

内核开头对 sc 做了防御:`if(isnan(sc)isinf(sc)) sc = 0;`,随后进入按局部大小 ls 分块的循环,把每个线程算出的 sc 累加到 temp 本地数组,并用 `barrier(CLK_LOCAL_MEM_FENCE)` 保证本地内存可见性。归约采用二分法:`count = (count+1)/2` 直到 count<=1,把 temp 前半段不断加给自身,复杂度为 O(log ls) 而非 O(ls)。

sum 取出 temp[0] 后再次防异常,若 sum<=1e-6f 则兜底为 1,最后 sc /= sum 完成归一,写回 score[shift_s]。这一步决定了注意力权重是否真的和为 1,黄金 1 分钟图上若窗口内有效样本过少,sum 容易掉到 1e-6 量级,归一后被放大的噪声可能误导信号。 输出阶段对 dimension 维每个特征 d,取 v 与 bv 之和乘 sc 得 val,同样做本地归约,仅 k_id==0 的线程把 temp[0] 写进 out[shift_q+d]。想验证可自行把这段塞进 MT5 的 OCL 模板,把 kunits 设成 256、ls 设成 64,看 GPU 占用与数值稳定性。

MQL5 / C++
  if(isnan(sc) || isinf(sc))
      sc = class="num">0;
class=class="str">"cmt">//--- sum of exp
   for(class="type">int cur_k = class="num">0; cur_k < kunits; cur_k += ls)
     {
       if(k_id >= cur_k && k_id < (cur_k + ls))
         {
          class="type">int shift_local = k_id % ls;
          temp[shift_local] = (cur_k == class="num">0 ? class="num">0 : temp[shift_local]) + sc;
         }
       barrier(CLK_LOCAL_MEM_FENCE);
     }
   class="type">uint count = min(ls, (class="type">uint)kunits);
class=class="str">"cmt">//---
   do
     {
      count = (count + class="num">1) / class="num">2;
      if(k_id < ls)
        temp[k_id] += (k_id < count && (k_id + count) < kunits ? temp[k_id + count] : class="num">0);
      if(k_id + count < ls)
        temp[k_id + count] = class="num">0;
      barrier(CLK_LOCAL_MEM_FENCE);
     }
   while(count > class="num">1);
class=class="str">"cmt">//--- score
   class="type">class="kw">float sum = temp[class="num">0];
   if(isnan(sum) || isinf(sum) || sum <= 1e-6f)
      sum = class="num">1;
   sc /= sum;
   score[shift_s] = sc;
   barrier(CLK_LOCAL_MEM_FENCE);
class=class="str">"cmt">//--- out
   for(class="type">int d = class="num">0; d < dimension; d++)
     {
      class="type">class="kw">float val_v = v[shift_kv + d];
      class="type">class="kw">float val_bv = bv[shift_kv + d];
      class="type">class="kw">float val = sc * (val_v + val_bv);
      if(isnan(val) || isinf(val))
        val = class="num">0;
      class=class="str">"cmt">//--- sum of value
      for(class="type">int cur_v = class="num">0; cur_v < kunits; cur_v += ls)
        {
         if(k_id >= cur_v && k_id < (cur_v + ls))
           {
            class="type">int shift_local = k_id % ls;
            temp[shift_local] = (cur_v == class="num">0 ? class="num">0 : temp[shift_local]) + val;
           }
         barrier(CLK_LOCAL_MEM_FENCE);
        }
      class=class="str">"cmt">//---
      count = min(ls, (class="type">uint)kunits);
      do
        {
         count = (count + class="num">1) / class="num">2;
         if(k_id < count && (k_id + count) < kunits)
           temp[k_id] += temp[k_id + count];
         if(k_id + count < ls)
           temp[k_id + count] = class="num">0;
         barrier(CLK_LOCAL_MEM_FENCE);
        }
      while(count > class="num">1);
      class=class="str">"cmt">//---
      if(k_id == class="num">0)
        out[shift_q + d] = (isnan(temp[class="num">0]) || isinf(temp[class="num">0]) ? class="num">0 : temp[class="num">0]);
     }
}
class CNeuronRelativeSelfAttention   :  class="kw">public CNeuronBaseOCL
  {
class="kw">protected:
   class="type">uint                iWindow;

相对自注意力层的类成员与接口

在 MT5 的 OpenCL 神经网络扩展里,CNeuronRelativeSelfAttention 用一组 uint 和 int 记录窗口与头数等元参数:iWindowKey 存键窗口长度,iHeads 是多头数量,iUnits 为单元数,iScore 初始化为 -1 表示尚未计算注意力分数。 该类把卷积、转置与偏置层都包成成员对象:cQuery/cKey/cValue 是 CNeuronConvOCL 卷积核,cTranspose 做转置卷积,cBKey/cBValue 及若干 CLayer 偏置负责相对位置编码。cTemp 作为 CBufferFloat 中间缓冲,避免每次前向重复申请显存。 虚函数覆盖体现了训练链路:feedForward 做前向,calcInputGradients 反传梯度,updateInputWeights 更新权重;AttentionOut 与 AttentionGraadient(原文拼写)分别管注意力输出与梯度。Init 接收 window、units_count、heads、batch 等参数,defNeuronRelativeSelfAttention 作为 Type() 返回值区分层类型。

MQL5 / C++
class="type">uint iWindowKey;
class="type">uint iHeads;
class="type">uint iUnits;
class="type">int iScore;
class=class="str">"cmt">//---
CNeuronConvOCL cQuery;
CNeuronConvOCL cKey;
CNeuronConvOCL cValue;
CNeuronTransposeOCL cTranspose;
CNeuronBaseOCL cDistance;
CLayer cBKey;
CLayer cBValue;
CLayer cGlobalContentBias;
CLayer cGlobalPositionalBias;
CLayer cMHAttentionPooling;
CLayer cScale;
CBufferFloat cTemp;
class=class="str">"cmt">//---
class="kw">virtual class="type">bool AttentionOut(class="type">void);
class="kw">virtual class="type">bool AttentionGraadient(class="type">void);
class=class="str">"cmt">//---
class="kw">virtual class="type">bool feedForward(CNeuronBaseOCL *NeuronOCL) class="kw">override;
class="kw">virtual class="type">bool calcInputGradients(CNeuronBaseOCL *NeuronOCL) class="kw">override;
class="kw">virtual class="type">bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) class="kw">override;
class="kw">public:
 CNeuronRelativeSelfAttention(class="type">void) : iScore(-class="num">1) {};
 ~CNeuronRelativeSelfAttention(class="type">void) {};
class=class="str">"cmt">//---
class="kw">virtual class="type">bool Init(class="type">uint numOutputs, class="type">uint myIndex, COpenCLMy *open_cl,
 class="type">uint window, class="type">uint window_key,
 class="type">uint units_count, class="type">uint heads,
 ENUM_OPTIMIZATION optimization_type, class="type">uint batch);
class=class="str">"cmt">//---
class="kw">virtual class="type">int Type(class="type">void) class="kw">override const { class="kw">return defNeuronRelativeSelfAttention; }
class=class="str">"cmt">//---
class="kw">virtual class="type">bool Save(class="type">int const file_handle) class="kw">override;
class="kw">virtual class="type">bool Load(class="type">int const file_handle) class="kw">override;
class=class="str">"cmt">//---
class="kw">virtual class="type">bool WeightsUpdate(CNeuronBaseOCL *source, class="type">class="kw">float tau) class="kw">override;
逐行看:前 4 行声明注意力元参数,iScore 默认 -1;随后 CNeuronConvOCL 与 CNeuronTransposeOCL 是 GPU 卷积组件,CLayer 系列承载偏置与缩放;AttentionOut / AttentionGraadient 为注意力专用虚接口;feedForward 等三个 override 接入基类训练流程;构造函数把 iScore 置 -1,Init 用 window_key 与 heads 等决定显存布局;Type 返回 defNeuronRelativeSelfAttention 供序列化识别;Save/Load/WeightsUpdate 覆盖持久化与更新。 想验证结构,可在 MT5 的 Include/OpenCL 目录搜 CNeuronRelativeSelfAttention,把 window 设 16、heads 设 4 看显存占用是否随 units_count 线性增长。外汇与贵金属模型训练波动剧烈,GPU 超时与过拟合风险均偏高,参数调整请先用历史数据小批量试跑。

MQL5 / C++
class="type">uint iWindowKey;
class="type">uint iHeads;
class="type">uint iUnits;
class="type">int iScore;
class=class="str">"cmt">//---
CNeuronConvOCL cQuery;
CNeuronConvOCL cKey;
CNeuronConvOCL cValue;
CNeuronTransposeOCL cTranspose;
CNeuronBaseOCL cDistance;
CLayer cBKey;
CLayer cBValue;
CLayer cGlobalContentBias;
CLayer cGlobalPositionalBias;
CLayer cMHAttentionPooling;
CLayer cScale;
CBufferFloat cTemp;
class=class="str">"cmt">//---
class="kw">virtual class="type">bool AttentionOut(class="type">void);
class="kw">virtual class="type">bool AttentionGraadient(class="type">void);
class=class="str">"cmt">//---
class="kw">virtual class="type">bool feedForward(CNeuronBaseOCL *NeuronOCL) class="kw">override;
class="kw">virtual class="type">bool calcInputGradients(CNeuronBaseOCL *NeuronOCL) class="kw">override;
class="kw">virtual class="type">bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) class="kw">override;
class="kw">public:
 CNeuronRelativeSelfAttention(class="type">void) : iScore(-class="num">1) {};
 ~CNeuronRelativeSelfAttention(class="type">void) {};
class=class="str">"cmt">//---
class="kw">virtual class="type">bool Init(class="type">uint numOutputs, class="type">uint myIndex, COpenCLMy *open_cl,
 class="type">uint window, class="type">uint window_key,
 class="type">uint units_count, class="type">uint heads,
 ENUM_OPTIMIZATION optimization_type, class="type">uint batch);
class=class="str">"cmt">//---
class="kw">virtual class="type">int Type(class="type">void) class="kw">override const { class="kw">return defNeuronRelativeSelfAttention; }
class=class="str">"cmt">//---
class="kw">virtual class="type">bool Save(class="type">int const file_handle) class="kw">override;
class="kw">virtual class="type">bool Load(class="type">int const file_handle) class="kw">override;
class=class="str">"cmt">//---
class="kw">virtual class="type">bool WeightsUpdate(CNeuronBaseOCL *source, class="type">class="kw">float tau) class="kw">override;

「相对自注意力层的初始化链路」

在 MT5 的 OpenCL 神经网络扩展里,CNeuronRelativeSelfAttention::Init 负责把多头相对注意力所需的所有子层一次性登记到计算图。它先调用基类 CNeuronBaseOCL::Init,输入维度被强行拉成 window * units_count,这一步若失败直接返回 false,后续全免谈。 紧接着用 idx 从 0 开始自增,依次初始化 cQuery、cKey、cValue 三个卷积类成员,它们的核宽都是 iWindowKey * iHeads,输出通道为 iUnits。任何一层 Init 不通过就退出,这说明该结构对显存与参数连续性相当敏感,外汇高频序列里 units_count 设太大可能直接爆显存。 后面还挂了 cTranspose、cDistance 以及多组 CNeuronConvOCL:其中两组显式设了 TANH 激活,用来逼出有界的关键/价值偏置;最后塞进 cGlobalContentBias 的两个 CNeuronBaseOCL 中,第一个输出缓冲被 BufferInit(1,1) 后立刻 BufferWrite,相当于写死一个全局偏置种子。 开 MT5 把这段抄进自定义 EA 的神经网络头文件,改 iHeads=4、iUnits=16 跑一次 Init,看 idx 能否走到末尾不报 false,就能验证你本地 OpenCL 环境是否真接住了相对注意力层。

MQL5 / C++
class="kw">virtual class="type">void      SetOpenCL(COpenCLMy *obj) class="kw">override;
};
class="type">bool CNeuronRelativeSelfAttention::Init(class="type">uint numOutputs, class="type">uint myIndex, COpenCLMy *open_cl,
                                        class="type">uint window, class="type">uint window_key, class="type">uint units_count, class="type">uint heads,
ENUM_OPTIMIZATION optimization_type, class="type">uint batch)
  {
   if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, window * units_count, optimization_type, batch))
      class="kw">return false;
   iWindow = window;
   iWindowKey = window_key;
   iUnits = units_count;
   iHeads = heads;
   class="type">int idx = class="num">0;
   if(!cQuery.Init(class="num">0, idx, OpenCL, iWindow, iWindow, iWindowKey * iHeads, iUnits, class="num">1, optimization, iBatch))
      class="kw">return false;
   idx++;
   if(!cKey.Init(class="num">0, idx, OpenCL, iWindow, iWindow, iWindowKey * iHeads, iUnits, class="num">1, optimization, iBatch))
      class="kw">return false;
   idx++;
   if(!cValue.Init(class="num">0, idx, OpenCL, iWindow, iWindow, iWindowKey * iHeads, iUnits, class="num">1, optimization, iBatch))
      class="kw">return false;
   idx++;
   if(!cTranspose.Init(class="num">0, idx, OpenCL, iUnits, iWindow, optimization, iBatch))
      class="kw">return false;
   idx++;
   if(!cDistance.Init(class="num">0, idx, OpenCL, iUnits * iUnits, optimization, iBatch))
      class="kw">return false;
   idx++;
   CNeuronConvOCL *conv = new CNeuronConvOCL();
   if(!conv ||
      !conv.Init(class="num">0, idx, OpenCL, iUnits, iUnits, iWindow, iUnits, class="num">1, optimization, iBatch) ||
      !cBKey.Add(conv))
      class="kw">return false;
   idx++;
   conv.SetActivationFunction(TANH);
   conv = new CNeuronConvOCL();
   if(!conv ||
      !conv.Init(class="num">0, idx, OpenCL, iWindow, iWindow, iWindowKey * iHeads, iUnits, class="num">1, optimization, iBatch) ||
      !cBKey.Add(conv))
      class="kw">return false;
   idx++;
   conv = new CNeuronConvOCL();
   if(!conv ||
      !conv.Init(class="num">0, idx, OpenCL, iUnits, iUnits, iWindow, iUnits, class="num">1, optimization, iBatch) ||
      !cBValue.Add(conv))
      class="kw">return false;
   idx++;
   conv.SetActivationFunction(TANH);
   conv = new CNeuronConvOCL();
   if(!conv ||
      !conv.Init(class="num">0, idx, OpenCL, iWindow, iWindow, iWindowKey * iHeads, iUnits, class="num">1, optimization, iBatch) ||
      !cBValue.Add(conv))
      class="kw">return false;
   idx++;
   CNeuronBaseOCL *neuron = new CNeuronBaseOCL();
   if(!neuron ||
      !neuron.Init(iWindowKey * iHeads * iUnits, idx, OpenCL, class="num">1, optimization, iBatch) ||
      !cGlobalContentBias.Add(neuron))
      class="kw">return false;
   idx++;
   CBufferFloat *buffer = neuron.getOutput();
   buffer.BufferInit(class="num">1, class="num">1);
   if(!buffer.BufferWrite())
      class="kw">return false;
   neuron = new CNeuronBaseOCL();
   if(!neuron ||
      !neuron.Init(class="num">0, idx, OpenCL, iWindowKey * iHeads * iUnits, optimization, iBatch) ||
      !cGlobalContentBias.Add(neuron))
      class="kw">return false;

◍ 相对自注意力模块的初始化链路

这段初始化代码把多头注意力里的偏置、池化与缩放三层子网络逐个挂到对象上,任何一步 Init 或 Add 失败就直接 return false,意味着在 MT5 里跑自定义 OCL 神经网络时,层参数错位会令整个模型构建中断。 先看全局位置偏置:先 new 一个 CNeuronBaseOCL 做偏置载体,Init 的第二个参数是 idx(神经元索引),第三个 1 是输出维度;随后又建一个输入为 0、输出为 iWindowKey*iHeads*iUnits 的基元神经元加入 cGlobalPositionalBias,两个 idx 各加 1。 多头注意力池化 cMHAttentionPooling 里连续堆了 4 个算子:两个基元神经元、两个卷积(CNeuronConvOCL)。第一个卷积核宽 iWindow、输出通道 iUnits,激活设 TANH;第二个卷积激活设 None;SoftMax 层显式调了 SetHeads(iUnits) 切分头数。 缩放分支 cScale 用两个卷积收口,中间激活 LReLU、末尾 None,第二个卷积的窗口参数写死 4 * iWindow 做通道扩张。最后 SetGradient(conv.getGradient(), true) 把梯度回传打开,再 SetOpenCL 绑定上下文。 在 MT5 策略测试器里若报 false,优先查 idx 是否和前层连续、iWindowKey*iHeads*iUnits 乘积是否超出显存申请上限,外汇与贵金属品种上这类 GPU 网络过拟合概率偏高,需以小样本验证。

MQL5 / C++
  idx++;
  neuron = new CNeuronBaseOCL();
  if(!neuron ||
     !neuron.Init(iWindowKey * iHeads * iUnits, idx, OpenCL, class="num">1, optimization, iBatch) ||
     !cGlobalPositionalBias.Add(neuron))
     class="kw">return false;
  idx++;
  buffer = neuron.getOutput();
  buffer.BufferInit(class="num">1, class="num">1);
  if(!buffer.BufferWrite())
     class="kw">return false;
  neuron = new CNeuronBaseOCL();
  if(!neuron ||
     !neuron.Init(class="num">0, idx, OpenCL, iWindowKey * iHeads * iUnits, optimization, iBatch) ||
     !cGlobalPositionalBias.Add(neuron))
     class="kw">return false;
  idx++;
  neuron = new CNeuronBaseOCL();
  if(!neuron ||
     !neuron.Init(class="num">0, idx, OpenCL, iWindowKey * iHeads * iUnits, optimization, iBatch) ||
     !cMHAttentionPooling.Add(neuron)
     )
     class="kw">return false;
  idx++;
  conv = new CNeuronConvOCL();
  if(!conv ||
     !conv.Init(class="num">0, idx, OpenCL, iWindowKey * iHeads, iWindowKey * iHeads, iWindow, iUnits, class="num">1,
optimization, iBatch) ||
     !cMHAttentionPooling.Add(conv)
     )
     class="kw">return false;
  idx++;
  conv.SetActivationFunction(TANH);
  conv = new CNeuronConvOCL();
  if(!conv ||
     !conv.Init(class="num">0, idx, OpenCL, iWindow, iWindow, iHeads, iUnits, class="num">1, optimization, iBatch) ||
     !cMHAttentionPooling.Add(conv)
     )
     class="kw">return false;
  idx++;
  conv.SetActivationFunction(None);
  CNeuronSoftMaxOCL *softmax = new CNeuronSoftMaxOCL();
  if(!softmax ||
     !softmax.Init(class="num">0, idx, OpenCL, iHeads * iUnits, optimization, iBatch) ||
     !cMHAttentionPooling.Add(conv)
     )
     class="kw">return false;
  softmax.SetHeads(iUnits);
  idx++;
  neuron = new CNeuronBaseOCL();
  if(!neuron ||
     !neuron.Init(class="num">0, idx, OpenCL, iWindowKey * iUnits, optimization, iBatch) ||
     !cScale.Add(neuron)
     )
     class="kw">return false;
  idx++;
  conv = new CNeuronConvOCL();
  if(!conv ||
     !conv.Init(class="num">0, idx, OpenCL, iWindowKey, iWindowKey, class="num">4 * iWindow, iUnits, class="num">1, optimization, iBatch) ||
     !cScale.Add(conv)
     )
     class="kw">return false;
  conv.SetActivationFunction(LReLU);
  idx++;
  conv = new CNeuronConvOCL();
  if(!conv ||
     !conv.Init(class="num">0, idx, OpenCL, class="num">4 * iWindow, class="num">4 * iWindow, iWindow, iUnits, class="num">1, optimization, iBatch) ||
     !cScale.Add(conv)
     )
     class="kw">return false;
  conv.SetActivationFunction(None);
class=class="str">"cmt">//---
  if(!SetGradient(conv.getGradient(), true))
     class="kw">return false;
class=class="str">"cmt">//---
  SetOpenCL(OpenCL);
class=class="str">"cmt">//---
  class="kw">return true;
  }
class="type">bool CNeuronRelativeSelfAttention::feedForward(CNeuronBaseOCL *NeuronOCL)
  {
  if(!cQuery.FeedForward(NeuronOCL) ||
     !cKey.FeedForward(NeuronOCL) ||
     !cValue.FeedForward(NeuronOCL)
     )

注意力层前向传播收口与 RMAT 骨架

这段是前向推理的收尾段,任何一步矩阵乘或层前向失败就直接 return false,只有全部跑通才回 true。 先看转置与距离矩阵:cTranspose 喂入 NeuronOCL 后,用 MatMul 算 NeuronOCL 输出与转置输出的乘积,维度参数是 iUnits × iWindow × iUnits × 1,这一步构建的是注意力里的相似度基底。 随后 cBKey[0]、cBValue[0] 以 cDistance 为输入做 FeedForward,而从索引 1 开始,cBKey、cBValue、cGlobalContentBias、cGlobalPositionalBias 各自链式前向,每一层吃上一层输出,循环里但凡一个节点失败就退出。 AttentionOut 之后,cMHAttentionPooling 同样链式前向,再用 MatMul 把末层与首层输出乘到 cScale[0],形状是 1 × iHeads × iWindowKey × iUnits,这是多头池化结果的缩放融合。 最后 cScale 链式前向,SumAndNormilize 以 NeuronOCL 输出和 cScale 末层为输入,在 iWindow 上做带归一化的求和写进 Output,参数里最后的 1 表示沿特定轴。外汇与贵金属行情下用这类结构做信号推断属高风险,过拟合概率不低。 收口之后类定义转向 CNeuronRMAT,它公开继承 CNeuronBaseOCL,内部只挂了一个 CLayer 成员 cLayers,并 override 了 feedForward、calcInputGradients、updateInputWeights 三个虚函数,意味着 RMAT 把多层封装进单一层对象里调度。

MQL5 / C++
   class="kw">return false;
   if(!cTranspose.FeedForward(NeuronOCL) ||
      !MatMul(NeuronOCL.getOutput(), cTranspose.getOutput(), cDistance.getOutput(), iUnits, iWindow, iUnits, class="num">1)
      )
      class="kw">return false;
   if(!((CNeuronBaseOCL*)cBKey[class="num">0]).FeedForward(cDistance.AsObject()) ||
      !((CNeuronBaseOCL*)cBValue[class="num">0]).FeedForward(cDistance.AsObject())
      )
      class="kw">return false;
   for(class="type">int i = class="num">1; i < cBKey.Total(); i++)
      if(!((CNeuronBaseOCL*)cBKey[i]).FeedForward(cBKey[i - class="num">1]))
         class="kw">return false;
   for(class="type">int i = class="num">1; i < cBValue.Total(); i++)
      if(!((CNeuronBaseOCL*)cBValue[i]).FeedForward(cBValue[i - class="num">1]))
         class="kw">return false;
   for(class="type">int i = class="num">1; i < cGlobalContentBias.Total(); i++)
      if(!((CNeuronBaseOCL*)cGlobalContentBias[i]).FeedForward(cGlobalContentBias[i - class="num">1]))
         class="kw">return false;
   for(class="type">int i = class="num">1; i < cGlobalPositionalBias.Total(); i++)
      if(!((CNeuronBaseOCL*)cGlobalPositionalBias[i]).FeedForward(cGlobalPositionalBias[i - class="num">1]))
         class="kw">return false;
   if(!AttentionOut())
      class="kw">return false;
   for(class="type">int i = class="num">1; i < cMHAttentionPooling.Total(); i++)
      if(!((CNeuronBaseOCL*)cMHAttentionPooling[i]).FeedForward(cMHAttentionPooling[i - class="num">1]))
         class="kw">return false;
   if(!MatMul(((CNeuronBaseOCL*)cMHAttentionPooling[cMHAttentionPooling.Total() - class="num">1]).getOutput(),
               ((CNeuronBaseOCL*)cMHAttentionPooling[class="num">0]).getOutput(),
               ((CNeuronBaseOCL*)cScale[class="num">0]).getOutput(),
               class="num">1, iHeads, iWindowKey, iUnits)
      )
      class="kw">return false;
   for(class="type">int i = class="num">1; i < cScale.Total(); i++)
      if(!((CNeuronBaseOCL*)cScale[i]).FeedForward(cScale[i - class="num">1]))
         class="kw">return false;
   if(!SumAndNormilize(NeuronOCL.getOutput(),
((CNeuronBaseOCL*)cScale[cScale.Total() - class="num">1]).getOutput(),
Output, iWindow, true, class="num">0, class="num">0, class="num">0, class="num">1))
      class="kw">return false;
class=class="str">"cmt">//---
   class="kw">return true;
   }
class CNeuronRMAT :  class="kw">public CNeuronBaseOCL
   {
class="kw">protected:
   CLayer          cLayers;
   class=class="str">"cmt">//---
   class="kw">virtual class="type">bool      feedForward(CNeuronBaseOCL *NeuronOCL)
   class="kw">override;
   class="kw">virtual class="type">bool      calcInputGradients(CNeuronBaseOCL *NeuronOCL) class="kw">override;
   class="kw">virtual class="type">bool      updateInputWeights(CNeuronBaseOCL *NeuronOCL) class="kw">override;
class="kw">public:

常见问题

对注意力分数先做缩放并裁剪到合理范围,归约时用稳定求和(如减去最大值再exp),可显著降低溢出概率。
把相对位置偏置、头数、维度作为构造参数暴露,前向只收查询键值与掩码,返回加权上下文,耦合最低。
可以,把代码贴给小布,它会按初始化顺序逐成员核对显存分配与形状对齐,标出缺失或错位的地方。
应在层权重就绪后、首次前向前完成相对编码矩阵注册,并绑进同一设备上下文,否则前向会报形状不符。
核对归约后特征维与RMAT输入维,用线性投影补齐或裁剪,并在配置里固定头维乘积等于主干隐维。