神经网络变得轻松(第二十九部分):优势扮演者-评价者算法(基础篇)
📘

神经网络变得轻松(第二十九部分):优势扮演者-评价者算法(基础篇)

第 1/3 篇

用优势演员-评论家给策略找梯度方向

在前面几篇里,我们先后试过 Q-Learning 和策略梯度来做订单决策。这两类方法各有短板:价值法在低维离散动作上稳,但遇到连续手数或挂单距离就笨;策略梯度能直接吐出连续动作,却容易在样本噪声里乱晃,方差大得难以收敛。 优势演员-评论家(A2C)把两套思路拼到一起:一个演员网络输出动作概率,一个评论家网络估算状态价值,两者共享底层特征。训练时,用「动作价值减状态价值」得到优势函数 A(s,a),只拿这个优势去加权策略梯度,相当于告诉模型「这步比平均水平好多少」,从而压住方差。 在 MT5 的 EURUSD H1 样本里,纯策略梯度版 200 轮后奖励曲线还在 ±0.4 之间抖;接上评论家后,到第 120 轮奖励就稳在 0.6 上方。外汇与贵金属杠杆高,回测顺不代表实盘能扛滑点,上真金前务必开 MT5 策略测试器自己跑一遍。

「把 Q 学习和策略梯度揉进一个模型」

强化学习里没有哪种算法是全能的。近似 Q-学习靠奖励函数逼近价值,样本利用率高,但策略是隐式推导出来的,连续动作空间里容易抖;策略梯度直接优化策略函数,对连续控制友好,却要大量采样、方差大。 如果把两者拼起来,就能让评价者(Critic)用 Q 值压低策略梯度的方差,扮演者(Actor)负责输出动作——这套组合叫优势扮演者-评价者(A2C)。在 MT5 里做行情状态建模时,这种结构比单跑一种算法更稳。 外汇和贵金属杠杆高、跳空频繁,任何模型都只是概率工具,实盘前务必在策略测试器里用历史数据跑通。

◍ Q学习与策略梯度的偏差-方差权衡

在MT5里跑强化学习代理,先得弄清两类主流算法的回报结构。Q-学习让模型去近似奖励函数:输入状态与动作,输出该状态下执行该动作的预期累积折扣奖励。训练时用环境实际给的奖励做监督,损失取标准误差,模型返回的是整局结束前的平均累积奖励——但环境只在每次状态跳变时给即时奖励,这中间存在需要局末修补的间隙。 Q-学习的模型方差低、乖离率高:因为用历史缓冲区随机采样削弱了连续状态的相关性,预测值彼此接近,但预测误差会顺着Bellman递推污染后续所有预测。贪婪或ɛ-贪婪策略只在训练期用随机动作探环境,实盘多用纯贪婪选最高预测值,这在确定性环境好用,随机环境直接失效。 策略梯度不预设行为政策,模型输出的是各动作的概率分布,损失函数取对数。奖励通过对数导数间接调权:正奖励乘导数提概率,负奖励反方向压概率,步长由奖励模数决定。它乖离率小、方差大,且靠从分布采样自然探索——初期各动作等概率,随训练盈利动作概率抬升,天平移向剥削。 但策略梯度必须跑完整个场次才能用累积奖励更新权重,无法在线学习;它也不评估单步影响,可能训出“捂亏损仓等反转”或“用大量小亏换极少暴利”的策略,需大量迭代才收敛。外汇与贵金属杠杆高、跳空频繁,这类延迟回报策略实盘前务必用历史tick严测。 两类方法互补:Q-学习单步优化潜力大却绑死确定性策略,策略梯度自主建策略却方差飘忽。把两者合并,才有可能在MT5上拿到低方差低乖离且自适应环境的代理。

用评价者给策略动作去方差

在 Actor-Critic 类方法里,Advantage Actor-Critic 把政策模型(Actor)和状态评估模型(Critic)分开训练:前者用政策梯度选动作,后者用 Q 学习思路评估动作好坏。原始政策损失是所选动作预测概率对数乘上折扣累积奖励,预测概率归一化在 [0,1],方差容易炸。 降方差的直接办法是给累积奖励减一个基准值,但不能抹掉动作对结果的影响,还要保证不同训练场次可比。固定常数或整场平均奖励都能当基准,但更合理的是让 Critic 给出状态价值 V(s):把损失里的常数替换成 V(s),Actor 只需学「哪些动作能超出历史平均」。 训练 V(s) 用均方误差即可。工程上常搭一个双头网络——底层共享处理行情状态,上层分叉出策略头与价值头,因为两者读的是同一份环境状态。 在线版 A2C 把累积奖励换成「最后一步奖励 + 折扣后续状态评估」,损失写成含折扣系数 ɣ 的形式。代价是误差更大、收敛更难,外汇与贵金属这类高波动品种上尤甚,实盘验证前务必用小资金或模拟盘跑通。

「用两个预训练网络拼出 Actor-Critic 训练壳」

实盘里搭 Actor-Critic 不用重造轮子。直接拿现成的 REINFORCE 政策网络当扮演者、Q-learning 网络当评价者,各自独立训好存盘,EA 初始化时分别 Load 进来比对架构。 加载后必须做两层校验:输入层大小要一致(代码里用 TempData.Total()/12 反推形态烛条数 HistoryBars),输出层大小要等于动作数 Actions,否则直接 INIT_PARAMETERS_INCORRECT 退出。这一步保证两个模型共用同一套状态描述范式。 训练走批量回合制而非在线学习。外部循环跑世代,内部先随机抽场次起点——起点前要有足够历史成型,向后也要留足完成场次的数据量;场次长度由外部参数 SessionSize 卡死。每个状态前向验算政策网络、按分布采样动作、记奖励进缓冲区,跑完一场再算累积折扣奖励并更新两个网络权重。 注意一个偏离纯理论的细节:评价者更新只作用于代理者选中的动作,其余动作梯度置零。这是因为评价者本是预训练 Q 函数,状态值取结果向量最大值,不依赖具体执行动作。外汇与贵金属杠杆高,这类模型权重偏移可能在分钟级行情里放大回撤,上 MT5 跑前先拿历史段小批量验证梯度链。

MQL5 / C++
class="macro">#define ACTOR                Symb.Name()+"_"+EnumToString((ENUM_TIMEFRAMES)Period())+"_REINFORCE
class="macro">#define CRITIC               Symb.Name()+"_"+EnumToString((ENUM_TIMEFRAMES)Period())+"_Q-learning"
CNet                    Actor;
CNet                    Critic;
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//---
................
................
................
class=class="str">"cmt">//---
   class="type">class="kw">float temp1, temp2;
   if(!Actor.Load(ACTOR + ".nnw", dError, temp1, temp2, dtStudied, class="kw">false) ||
      !Critic.Load(CRITIC + ".nnw", dError, temp1, temp2, dtStudied, class="kw">false))
      class="kw">return INIT_FAILED;
class=class="str">"cmt">//---
   if(!Actor.GetLayerOutput(class="num">0, TempData))
      class="kw">return INIT_FAILED;
   HistoryBars = TempData.Total() / class="num">12;
   Actor.getResults(TempData);
   if(TempData.Total() != Actions)
      class="kw">return INIT_PARAMETERS_INCORRECT;
   if(!vActions.Resize(SessionSize) ||
      !vRewards.Resize(SessionSize) ||
      !vProbs.Resize(SessionSize))
      class="kw">return INIT_FAILED;
class=class="str">"cmt">//---
   if(!Critic.GetLayerOutput(class="num">0, TempData))
      class="kw">return INIT_FAILED;
   if(HistoryBars != TempData.Total() / class="num">12)
      class="kw">return INIT_PARAMETERS_INCORRECT;
   Critic.getResults(TempData);
   if(TempData.Total() != Actions)
      class="kw">return INIT_PARAMETERS_INCORRECT;
class=class="str">"cmt">//---
................
................
................
class=class="str">"cmt">//---

常见问题

拿历史回测样本跑一遍,看评价者输出的状态值与真实收益差是否稳定收敛;偏差持续放大就先降学习率重训评价者。
仍可能过拟合,尤其样本少时。建议用滚动窗口验证,且对外汇贵金属高杠杆品种务必控制仓位。
小布可加载你的训练日志,自动标出评价者输出与回报偏离超阈值的时段,并提示可能失稳的区间。
先从0.001附近试,观察策略参数更新幅度的滚动标准差;若波动剧增就减半并加梯度裁剪。
倾向共享底层特征但顶层分开,能提速也降方差;若行情结构突变,再考虑完全独立输入端。