强化学习实操笔记(二)

代码地址: 强化学习 简明教程 代码实战
继续上一篇 强化学习实操笔记(一),继续回顾相关的算法。

六、DQN系列

对有一些游戏来说,它的state 和 action 很多,这个Q矩阵就会很膨胀,甚至有时action不是离散的,是不可数的。所以用一个Q矩阵来做评估就有点捉襟见肘了,DQN的思想就很简单,提出了可以利用神经网络来计算Q矩阵,因为Q矩阵的作用,无非就是输入一个 tate 和 action 输出一个 分数q。
而且DQN还利用了离线学习的思路,对数据的利用率高

  • DQN和平衡车demo
    state 是4个数字,表示车的位置/速度, 上面杆的角度,角速度。
    action 是0和1,代表左和右。
    在这里插入图片描述

相对于Qlearning,这里要用一个模型代替Q矩阵,回想一下原来Q矩阵都在哪里用的到?
get_value 和 get_target中,查当前状态价值, 用未来状态价值+reward估计当前状态价值时候,用到Q,分别查了当下和未来的价值。
get_action中,在选择动作的时候,需要查找Q中state 所有action的最大值。
我们把模型分为两种,一个是真正用的model,在估计当前价值get_value和get_action查表时候用,另外一个是next_model 称之为经验模型,它的更新频率慢一点,在一定步骤后在copy model的值更新。如果想用单模型也是可以的,也即两个模型合一,效果可能会差,因为学习的目标一直在变化更新,不利于训练收敛。
在这个小游戏里面这两个模型都定义为原始的2层MLP。
在这里插入图片描述

  • DQN 倒立摆游戏
    该游戏的动作空间是一个±2之间的连续值。DQN模型是不擅长玩连续动作空间的游戏的,一般需要进行离散化。
    为什么不擅长,主要原因是有一步固定s后,求某个使Q最大的a的步骤,离散的话直接穷举就能得到最大的action,连续动作空间中秋argmax的操作就行不通了,一般也就离散化处理了
  • double DQN
    **double DQN 和DQN主要区别在get_target中的处理。**思想是防止在DQN中对target的过高估计问题,至于为什么过高估计,可以简单理解为,每次都用max函数估计target,学习还要求向着target学,自然正反馈似的,容易过高。详细需要看数学推导,这里不赘述。
    处理方式对比:
	# 网络输出 target 后,面临取哪个动作的分数作为target的问题
    with torch.no_grad():
        target = next_model(next_state)
        
    # DQN 直接取所有动作中分数最大的, [b, 11] -> [b]
    # target = target.max(dim=1)[0]
    
    # double DQN 是用model也就是动作模型在next state的值取的坐标,返回来再在上面计算的target取值,因为target, model_target不一定一样,能缓解过高估计的问题。
    with torch.no_grad():
    	model_target = model(next_state)
    #取分数最高的下标 [b, 11] -> [b, 1]
    model_target_index = model_target.max(dim=1)[1]
    model_target_index = model_target.reshape(-1, 1)
    #[b, 11] -> [b]
    target = target.gather(dim=1, index=model_target_index)

  • dueling DQN
    这种方式主要是采用了不同的模型结构。这种结构下,Q不再由两层MLP直接得到。如下所示:
#DuelingDQN和其他DQN模型不同的点,它使用的是不同的模型结构
class VAnet(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.fc = torch.nn.Sequential(
            torch.nn.Linear(3, 128),
            torch.nn.ReLU(),
        )
        self.fc_A = torch.nn.Linear(128, 11)
        self.fc_V = torch.nn.Linear(128, 1)

    def forward(self, x):
        #[5, 11] -> [5, 128] -> [5, 11]
        A = self.fc_A(self.fc(x))
        #[5, 11] -> [5, 128] -> [5, 1]
        V = self.fc_V(self.fc(x))
        #[5, 11] -> [5] -> [5, 1]
        A_mean = A.mean(dim=1).reshape(-1, 1)
        #[5, 11] - [5, 1] = [5, 11]
        A -= A_mean
        #Q值由V值和A值计算得到
        #[5, 11] + [5, 1] = [5, 11]
        Q = A + V
        return Q

DQN要求模型使用足够多的数据量才能够覆盖Q。dueling DQN采用的是Q = A + V的方式计算,且列求和被限制到0,这样使的模型更新A困难。这样更新效率会更高,这样做会让Q值的学习更稳健一点。 可以参看dueling DQN多一些理解。

七、策略梯度算法

前面的算法核心都是计算Q矩阵或者是Q函数。策略梯度算法是根据reward调整不同动作的概率

  • Reinforce算法
    Reinforce算法
    解释:目标函数定义为在状态s0下,求出策略π下的V的期望,V是价值,理解为未来所有的“reward之和”,Return。期望该函数是越大越好。
    求导过程不细说,结果中的Q采用蒙特卡洛方法估计。
    实战中:
    定义网络的模型。网络输出的是每个动作的概率,所以网络最后需要经过一层softmax,保证求和为1。
    get_action函数。之前是按Q最大的对应的action选择,此时按网络输出的概率,随机选择一个动作。
    get_data 收集数据时,只需要收集state reward action 即可,不需要next state 和over状态。

train 过程的核心代码如下:

    #玩N局游戏,每局游戏训练一次
    for epoch in range(1000):
        #玩一局游戏,得到数据
        states, rewards, actions = get_data()
        optimizer.zero_grad()
        reward_sum = 0
        for i in reversed(range(len(states))):
            #反馈的和,从最后一步的反馈开始计算
            #每往前一步,>>和<<都衰减0.02,然后再加上当前步的反馈
            reward_sum *= 0.98
            reward_sum += rewards[i]
            #重新计算对应动作的概率
            state = torch.FloatTensor(states[i]).reshape(1, 4)
            #[1, 4] -> [1, 2]
            prob = model(state)
            #[1, 2] -> scaler
            prob = prob[0, actions[i]]
            #参看前面图中的求导公式,符号取反是因为这里是求loss,所以优化方向相反
            loss = -prob.log() * reward_sum
            #累积梯度
            loss.backward(retain_graph=True)
        optimizer.step()

可以看出,从最后一步开始算起,每过一步,都将reward进行衰减,加上去当前步的reward。
注意看,prob.log() 即公式图片中的 logπtheta(at|st),含义是按当前网络(策略)得到的选at的概率。而reward_sum,实际代表了这次采样下当前步的总回报,上面的for循环内的一个循环,即对上面公式E中的第一个求和符号之后的内容的实现。for循环后就是E中的所有内容。
上图中的公式,是策略梯度法的核心。一些特征:
这里面不需要计算Q或Q函数,网络输出的是不同动作的选择的概率
策略更新的方向,是使该策略下经历状态动作序列后的累积回报最高
一般是玩一局,得到完整状态动作序列,更新一次策略;单条数据不需要记录next_state

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值