强化学习算法——Reinforce with baseline

强化学习算法——Reinforce with baseline

最近在看一篇强化学习求解组合优化问题的论文,在使用的算法Reinforce with rollout baseline 这个地方看了很久,终于弄懂了真实网络(我们称为Actor)和基线网络(我们称为baseline)这两者之间的关系和逻辑,下面结合具体代码总结一下。
论文:Solve routing problems with a residual edge-graph attention neural network
https://github.com/leikun-starting/DRL-and-graph-neural-network-for-routing-problems
Reinforce 算法是基于策略的最基本的算法,原理和实现都比较简单。

基线b可以看成是对当前策略网络的性能的平均评估(可以看成班上所有同学的平均分)。基线b的选择是多样化的,可以是一个常数(平均值),但大多时候为了提升算法的性能会选择用另一个网络来拟合基线baseline,即用一个网络来估计平均成绩,我们称之为critic网络,这样的REINFORCE算法可以看成AC算法的一种。
但这篇文献里采用的baseline是和Actor结构一样的网络,因此只需要训练一个网络,只在必要的时候将Actor复制给baseline,当成两个网络使用。
文件1.VRP_Rollout_train.py

1.创建两个数据集
data_loder:用于训练
valid_loder:用于比较Actor和baseline的性能差距(数据量小很多,毕竟只是用来检验一下两个网络的性能)在这里插入图片描述2.baseline初始化在这里插入图片描述
初始时baseline和Actor网络参数完全相同

3.Actor更新
在这里插入图片描述100-105行:同一个batch,分别用Actor和baseline计算奖励函数值,作差得到优势函数值
开始训练后,每过一个batch,进行一次loss反向传播,Actor进行一次更新

4.baseline更新
在这里插入图片描述
通过T-检验,判断Actor和baseline之间的差距,当Actor以一定的程度优于baseline时,则用当前的Actor替换baseline.
为什么要这么做呢?因为随着Actor的参数更新,输出的动作肯定是越来越优,那么真正意义上的基线值也是在随之变化的;但基线值只是反应一个大致的平均水平,因此它并不需要十分准确,但它要能实时地反映Actor的性能,所以只有当Actor以一定程度优于baseline时,才需要对baseline进行更新。
注意:Actor在每个batch都会进行更新,而baseline只在必要的时候更新(可以看成Actor一直在往前跑,而baseline跑一会停一会,当发现和Actor之间的距离太大时就跑一下)

文件2.rolloutBaseline1.py

def rollout(model, dataset, n_nodes):

    model.eval()
    def eval_model_bat(bat):
        with torch.no_grad():
            cost, _= model(bat,n_nodes*2,True)
            cost = reward1(bat.x,cost.detach(), n_nodes)
        return cost.cpu()
    totall_cost = torch.cat([eval_model_bat(bat.to(device))for bat in dataset], 0)
    return totall_cost

class RolloutBaseline():

    def __init__(self, model,  dataset, n_nodes=50,epoch=0):
        super(RolloutBaseline, self).__init__()
        self.n_nodes = n_nodes
        self.dataset = dataset
        self._update_model(model, epoch) # 传入RolloutBaseline的模型传入 _updata_model
    # 更新模型 使用当前模型计算所有样本的路径长度的平均值
    def _update_model(self, model, epoch, dataset=None):
        self.model = copy.deepcopy(model)  # 基线网络
        self.bl_vals = rollout(self.model, self.dataset, n_nodes=self.n_nodes).cpu().numpy()
        self.mean = self.bl_vals.mean() # 所有样本的平均路径长度
        self.epoch = epoch
    #  使用当前模型评估当前batch的路径长度
    def eval(self, x, n_nodes):

        with torch.no_grad():
            tour, _ = self.model(x,n_nodes,True)
            v= reward1(x.x, tour.detach(), n_nodes)
        # There is no loss
        return v

    def epoch_callback(self, model, epoch): # 和_updata_model不是同一个model

        print("Evaluating candidate model on evaluation dataset")
        candidate_vals = rollout(model, self.dataset, self.n_nodes).cpu().numpy() # 最新的actor

        candidate_mean = candidate_vals.mean() # 所有样本的路径长度的平均值

        print("Epoch {} candidate mean {}, baseline epoch {} mean {}, difference {}".format(
            epoch, candidate_mean, self.epoch, self.mean, candidate_mean - self.mean))
        if candidate_mean - self.mean < 0: # 新的网络达到一定程度的更优
            # Calc p value
            t, p = ttest_rel(candidate_vals, self.bl_vals)
            p_val = p / 2  # one-sided
            assert t < 0, "T-statistic should be negative"  # 达到一定程度的更优
            print("p-value: {}".format(p_val))
            if p_val < 0.05:
                print('Update baseline')
                self._update_model(model, epoch) # 更新基线网络

需要注意的是,epoch_callback里的model是自己传入的model,计算candidate_mean的model实际上是Actor,而self.mean是由_update_model中的model计算得到的,这个model最初由RolloutBaseline初始化得到(rolloutBaseline1.py 77行),后面经过epoch_callback方法调用_update_model方法来更新。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值