期货量化交易软件:神经网络变指引的扮演者评论者(BAC)

本文探讨了软性扮演者-评论者算法的局限性,提出了一种新的方法——行为指引扮演者-评论者(BAC),它通过状态-动作配对模型评估学习水平,无需依赖熵正则化的复杂性。文章还介绍了如何在MQL5环境中实现这一改进的模型架构。
摘要由CSDN通过智能技术生成

概述

最后两篇文章专门讨论软性扮演者-评论者算法。如您所知,该算法用于在连续动作空间中训练随机模型。该方法的主要特点是在奖励函数中引入了熵分量,这令我们能够调整环境探索和模型操作之间的平衡。同时,这种方式给所训练模型施加了一些限制。使用熵需要对采取动作的概率有一定的了解,这对于连续动作空间来说是相当困难的。

我们使用了分位数分布方式。此处,我们加上了对分位数分布超参数的调整。使用分位数分布的方式令我们稍微远离了连续动作空间。毕竟,每次我们选择一个动作时,我们都会从学习概率分布中选择一个分位数,并以其平均值作为动作。有了足够多的分位数和足够小的可能值范围,我们就接近了一个连续动作空间。但这导致模型越来越复杂,其训练和操作成本增加。此外,这对训练模型的架构施加了限制。

在本文中,我们将谈及另一替代方式,即 2021 年 4 月推出的行为指引扮演者-评论者(BAC)。

1. 算法构造特点

首先,我们谈谈研究环境的必要性。我想每个人都同意这个过程是必要的。但究竟是为了什么,在什么阶段?

我们从一个简单的例子开始。假设我们发现自己身处一间有三扇相同房门的屋内,我们需要走到街上。我们该怎么办?我们逐扇打开房门,直至找到我们需要的那扇。当我们再次进入同一间屋时,我们外出就不再需要打开所有房门,取而代之的是立即前往已知的出口。如果我们有不同的任务,那么可能有一些选项。我们可以再次打开除已知出口外的所有门,并寻找合适的。或者我们可以先记住早前我们在寻找出路时打开了哪些门,以及我们需要的那扇门是否在其中。如果我们记得正确的门,我们就会走向它。否则,我们会检查以前没有尝试过的门。

结论:我们需要在不熟悉的情况下研究环境,据此选择正确的动作。找到所需的路线后,对环境的额外探索只会成为阻碍。

不过,当任务在已知状态下发生变化时,我们也许需要额外研究环境。这可能包括寻找更优化的路线。在上面的例子中,如果我们需要穿过更多的房间,或者我们发现自己在建筑物的错误一侧,也许就会发生这种情况。

因此,我们需要一种算法,允许我们能够在未探索的状态下强化环境探索,并在先前探索的状态中将其最小化。

软性扮演者-评价者中使用的熵正则化可以满足此要求,但仅在满足一定数量条件的情况下。当动作概率越低时,动作的熵越高。实际上,我们在低概率行动后进入的状态可能知之甚少。熵正则化促使我们重复它,以便更好地研究后续状态。但是在研究了这个运动矢量之后会发生什么?如果我们发现了一条更优路径,那么在训练模型的过程中,则动作的概率会提升,熵会降低。这符合我们的需求。不过,其它动作的概率降低,它们的熵提升。这促使我们在其它方向上进行更多研究。只有明显的积极回报才能令我们专注于这条路径。

另一方面,如果新路线不满足我们的需求,那么我们在训练模型时会降低此类动作的可能性。同时,它的熵增长得更多,这促使我们再次这样做。只有重大的负面奖励(罚款)才能推动我们避免再次轻率地迈出一步。

因此,这就是为什么正确选择温度比率的权重对于确保模型研究和操作之间的期望平衡非常重要。

这也许看看似有点奇怪。我们从ε-贪婪策略开始,在这种策略中,勘探和开发之间的平衡依据概率常数调节。现在,我们将模型复杂化,并再次谈及选择比率的重要性。这纯粹是一种似曾相识的感觉。

为了寻找其它的解决方案,我们将注意力转向《行为指引扮演者-评论者:针对深度强化学习通过学习政策行为表征改进探索》一文中介绍的行为指引扮演者-评论者(BAC) 算法。该方法的作者建议用某个值代替奖励函数中的熵分量,以便通过状态-动作配对模型评估学习水平。

状态-行动配对的选择非常明显 — 这是我们在特定时刻所知道的。发现我们自己处于某种状态,我们选择一种动作。在某种程度上,我们取决于它向下一个状态过渡,以及得到过渡的回报。在相同动作背后,也许会过渡到预期的新状态,或也许存在不同的状态(具有一定程度的概率)。例如,要打开一扇门,我们先需要接近它。此处可以预料到,在每一步之后,我们都会离门更近。然后我们打开它,转动门把手。但它可能会被锁住(这是我们无法控制的因素)。门外有奖励或罚款等着我们。但我们到达那里之前,我们不会知道是哪个。因此,只有考虑到所有可能的动作,我们才能谈论对一个独立状态的完整研究。

该方法的作者建议使用自动编码器作为研究“状态-动作”配对的衡量标准。我们已在不同的算法中多次遇到过自动编码器的使用。但这总是与数据压缩、或某些相互依赖模型的构造有关。经验表明,建立金融市场模型是一项相当艰巨的任务,因为有大量的影响因素并非始终显而易见。在这种情况下,要用到自动编码器的另一个属性。

纯形式的自动编码器可以很好地复制源数据。但自动编码器是一种神经网络。在最开始,我就说过神经网络只在已研究过的数据上工作良好。否则,它们的结果也许不可预测。这就是为什么我们始终关注训练样本的代表性,和模型超参数在训练和操作过程中的不变性。

方法作者利用了神经网络这个属性的优点。在依据一组特定的状态和相应动作进行训练之后,我们在自动编码器的输出端得到了一个不错的副本。但是,一旦我们在模型输入端提交未知的“状态-动作”配对,数据复制错误就会大大增加。我们将用数据复制错误来衡量单独的“状态-动作”配对的知识。

与熵正则化相比,这种方式具有许多优点。首先,该方式适用于随机模型和确定性模型两者。使用自动编码器不会影响扮演者架构的选择。

其次,状态-动作配对的激励奖励随着训练的增加而减少,与获得的奖励和未来执行动作的可能性无关。由于自动编码器已训练过,它趋于 “0”,这会导致模型全部操作。

不过,当出现新状态时(考虑到神经网络的泛化能力,它与之前研究的并不相似),环境探索模式会立即被激活。

一个状态-动作配对的刺激奖励,与同一状态下另一个动作的训练程度、表现概率、或其它因素绝对无依赖。

当然,我们正在与一个连续行动空间打交道,并且该模型能够概括所获得的经验。在研究一个“状态-行动”配对时,它可以应用以前在类似状态和类似行动上获得的经验。但同时,数据传输误差也会不断变化,并取决于状态和动作的接近程度(相似性)。

从数学上讲,政策训练可以表示如下:

添加图片注释,不超过 140 字(可选)

其中 γ 是折扣因子, α — 温度比率, ψ(St+1,At=1) — 后续状态行为的函数(自动编码器的复制误差)。

我们再次看到温度比率用来调节模型探索和开发之间的平衡。这又导致了上述超参数优调和模型训练的困难。方法作者建议略微改变策略训练函数。

添加图片注释,不超过 140 字(可选)

α 温度比率本身应采用以下公式判定

添加图片注释,不超过 140 字(可选)

其中 σ 是西格玛函数, ω 等于 10, Q — 用于评估动作质量的神经网络。

这里使用的 Q-神经网络类似于评论者,它评估特定状态下的动作质量,同时考虑到当前政策。

从所提出的方程中可以看出,温度比(1−α)的范围为 0 至 0.5。它随着动作质量的评估提高而增加。显然,此时自动编码器复制数据的误差趋于 “0”。由于概率很高,该模型目前处于某种局部最小值,研究环境可以帮助从这种状态摆脱。

当数据复制的准确性较低时,给定状态下的动作评估质量也会降低。这导致西格玛函数内部表达式的分母增加。因此,西格玛参数的整体值降低,其结果趋于 0.5。

请记住,我们总是从较大的误差中减去较小的误差。因此,西格玛参数始终大于 “0”。它几乎不会等于 “0”,因为我们不能除以 “0”。

所提出的算法仍然是扮演者-评论者算法大家族的成员,并使用该算法家族的一般方式。与软性扮演者-评论者一样,该算法用于在连续动作空间中学习扮演者政策。我们将用 2 个评论者模型来评估动作的品质,以及从奖励到动作的误差梯度分布。我们还要用目标模型的软更新,经验缓冲区,和其它常用方式来训练扮演者-评论者模型。

2. 利用 MQL5 实现

在研究了所建议方式的理论层面之后,我们来利用 MQL5 实现它。我们首先从模型的架构开始。为了令方法具有可比性,我没有对上一篇文章中的模型架构进行太多更改。不过,我稍微简化了扮演者架构,并删除了我们创建的最后一个复杂神经层,从软性扮演者-评论者方法中实现随机扮演者算法。不过,我保留了随机扮演者政策的使用。但这一次,它是通过使用变分自编码器隐性层来实现的。如您所记得,该神经层的输入随数据张量一起提供,其大小正好是其结果缓冲区的两倍。指定的源数据张量包含结果的每个元素的分布均值和方差。以这种方式,我们降低了计算复杂性,但将随机扮演者模型留在连续动作空间当中。

 
 

bool CreateDescriptions(CArrayObj *actor, CArrayObj *critic, CArrayObj *autoencoder) { //--- CLayerDescription *descr; //--- if(!actor) { actor = new CArrayObj(); if(!actor) return false; } if(!critic) { critic = new CArrayObj(); if(!critic) return false; } if(!autoencoder) { autoencoder = new CArrayObj(); if(!autoencoder) return false; } //--- Actor actor.Clear(); //--- Input layer if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronBaseOCL; int prev_count = descr.count = (HistoryBars * BarDescr); descr.activation = None; descr.optimization = ADAM; if(!actor.Add(descr)) { delete descr; return false; } //--- layer 1 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronBatchNormOCL; descr.count = prev_count; descr.batch = 1000; descr.activation = None; descr.optimization = ADAM; if(!actor.Add(descr)) { delete descr; return false; } //--- layer 2 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronConvOCL; prev_count = descr.count = prev_count - 1; descr.window = 2; descr.step = 1; descr.window_out = 8; descr.activation = LReLU; descr.optimization = ADAM; if(!actor.Add(descr)) { delete descr; return false; } //--- layer 3 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronConvOCL; prev_count = descr.count = prev_count; descr.window = 8; descr.step = 8; descr.window_out = 8; descr.activation = LReLU; descr.optimization = ADAM; if(!actor.Add(descr)) { delete descr; return false; } //--- layer 4 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronBaseOCL; descr.count = 256; descr.optimization = ADAM; descr.activation = LReLU; if(!actor.Add(descr)) { delete descr; return false; } //--- layer 5 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronBaseOCL; prev_count = descr.count = 128; descr.activation = LReLU; descr.optimization = ADAM; if(!actor.Add(descr)) { delete descr; return false; } //--- layer 6 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronConcatenate; descr.count = LatentCount; descr.window = prev_count; descr.step = AccountDescr; descr.optimization = ADAM; descr.activation = SIGMOID; if(!actor.Add(descr)) { delete descr; return false; } //--- layer 7 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronBaseOCL; descr.count = 256; descr.activation = LReLU; descr.optimization = ADAM; if(!actor.Add(descr)) { delete descr; return false; } //--- layer 8 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronBaseOCL; descr.count = 256; descr.activation = LReLU; descr.optimization = ADAM; if(!actor.Add(descr)) { delete descr; return false; } //--- layer 9 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronBaseOCL; descr.count = 2*NActions; descr.activation = LReLU; descr.optimization = ADAM; if(!actor.Add(descr)) { delete descr; return false; } //--- layer 10 if(!(descr = new CLayerDescription())) return false; descr.type = defNeuronVAEOCL; descr.count = NActions; descr.optimization = ADAM; if(!actor.Add(descr)) { delete descr; return false; }

评论者模型已经转换,没有变化,我们不再详述它。

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值