本文主要根究莫凡大大的RL教程总结下Nature DQN, Double DQN, Prioritized Replay DQN, Dueling DQN, Policy Gradient, Actor-Critic, DDPG, PPO 算法的流程。
1、将环境信息s输入到eval网络, 输出为action的Q值,选择最大Q值对应的action,
或者随机生成一个action(所谓的探索),将action输入环境, 得到奖励r和下一个环境信息s_, 存储当前环境s,选择的action, 得到的奖励r这4个信息, 然后再将s_输入到eval网络, 循环步骤1, 直到存储了一定量的[(s, a, r, s_), …], 注意这个过程中eval网络没有更新。
2、从存储的[(s, a, r, s_), …]中sample出一部分(s, a, r, s_),将sample出来的多个s做为batch输入到eval 网络, 得到batch的action的Q值q_eval,然后根据sample出来的action选出其在q_eval中对应的Q值q_action_eval(对应gather过程)。
3、将sample出来的多个s_做为batch输入到target网络(eval与target有相同的网络结构), 得到batch的action的Q值q_next, 取q_next中最大的Q值(dim=1)并乘以一个系数gamma, 然后再加上sample出来的奖励r, 得到q_target。
4、计算loss:loss 为第2步的结果q_action_eval与第3步的结果q_target的MSE, 然后根据loss反向传播更新eval网络。
5、循环1到4步骤, 每过一定的步数后,将eval网络的权重更新到target网络上。
Double DQN 大部分和Nature DQN是一样的, 只是在计算q_target的时候不一样:
Nature DQN计算q_target时, 直接将sample的s_输入到target网络, 得到动作的Q值, 选出最大Q值。
而Double DQN 计算q_target,是先将sample的s_输入到target网络, 得到动作的Q值q_next, 同时将sample的s_输入到eval网络,得到动作的Q值q_eval`, 选出其最大Q值对应的动作,再通过这个动作找到对应q_next中的Q值(图中蓝色线表示的部分)也就是说用当前的Q网络来选择动作,用目标Q网络来计算目标Q值
Prioritized Replay DQN 与DQN不同的地方:
1、在于对记忆的选取是按照TD error相关的, TD error较大的记忆被选择的概率也会大一些,用sumtree这种二叉树比较容易实现这个功能。
2、loss
改成
其中 w_j 是第j个样本的优先级权重。
下面介绍Sumtree是如何实现的:
Sumtree:设记忆量为capacity = 8, 也就是只能存储8条信息,sumtree实现上会使用2* capacity -1个节点去存储,其中最下面capacity个叶子节点存储capacity条记忆的优先级值,上面的每个节点值只是自己两个孩子节点值的和。
接下来,示范第一次batch sample并更新:
假设batch为4, sample到7, 9, 11, 14节点(第一次因为优先级全是1, sample到的节点概率是一样的, 后面会讲解到如何进行sample),并假设这个batch经过DQN出来的td_error算出优先级[0.23729765, 0.30110887, 0.3370803, 0.2293545]
简写为[0.23, 0.30, 0.33. 0.22],则此时更新suntree树如下:
存储新的记忆:
每learn一步后, 又会和环境互动一步,然后存储一步记忆, 记忆是在叶子节点循环存储的, 因首次存储时已经循环完一遍, 那么本次存储就循环到7号节点(7号节点为存储记忆的第一个节点, 0-6号只是算加和), 存储新记忆时, 使用的优先值为所有记忆有限值的最大值, 这里为便是1了,图如下:
以上batch sample, updata, store新记忆这三个步骤循环, 就是Prioritized Replay DQN了。
1、 先将总的优先级值5.85分为4份为:(0, 1.4625), (1.4625, 2.925), (2.925, 4.3875), (4.3875, 5.85),然后在每个区间随机选一个值, 假设选的分别是:1.01,1.98, 3.50, 5.11, 那么 1.01比左边3.30小, 则选3.30, 然后又比左边2小, 则选2,然后比左边1大,则选右边8号节点的1做为样本1。1.98同理选到8号节点为样本2。
2、 3.50:比3.30大, 选2.55, 但此时3.50要减去3.30剩0.20, 0.20再去和5号节点比,小于1.33,选1.33, 然后又小于0.33,最终则选择11号节点为样本3。同理可选到13号节点为样本4.
这种算法的直观解释是:叶子节点的值(优先级)表示的是区间长度(如上图最下面的两排区间表示), 值越大区间长度就越长, 落在这个区间的概率就越大,1.01落在区间(1,2),那么选的就是8号节点, 3.50落在区间 (3.3,3.63) ,所以选择的就是节点11。
Policy Gradient是一个回合完了才会learn, 也就是更新网络。
1、将环境信息s输入到NN网络, 经过softmax后输出为action的概率(经过softmax后概率之和为1),选择概率比较大的对应的action,将action输入环境, 得到奖励r和下一个环境信息s_, 存储当前环境s, 选择的action, 得到的奖励r这4个信息,然后再将s_输入到eval网络, 循环步骤1, 直到一个回合结束, 注意这个过程中NN网络没有更新。
2、回合结束后:
i. 将存储的所有s组合为一个batch输入到NN,经过softmax后输出为actions的概率actions_prob。
ii.将存储的所有action组合为actions, 然后将actions 转化为one
hot形式actions_label(当前动作的位置为1(概率), 其他位置为0)。iii. 将存储的奖励r经过如下公式:
R[i] = r[i]+ σ*r[i+1]+ σ2 * r[i+2]+……+ σt-i * r[t]
得到R = [R[0], R[1],…,R[t],…,R[T]]
iv. 求loss, loss = mean(cross_entropy(actions_prob, actions_label) * R)
v. 更新NN网络。
Actor用来选动作, critic用来评估选出来的动作作用在环境上后, 得到的状态是好是坏。
1、将环境信息s输入到actor网络NN1,
输出为action的概率action_prob,选择较大概率对应的action,将action输入环境, 得到奖励r和下一个环境信息s_。2、将s和s_分别输入到critic网络NN2, 得到输出v和v_ (评估状态的好坏)。
3、计算td_error = r + gamma * v_ - v
4、计算actor的loss = mean(td_error * (log(第一步action对应的那个概率action_prob))),
并反向传播更新actor网络NN1。5、 计算critic的loss=square(td_error), 并反向传播更新critic网络NN2。
1、将环境信息s输入到actor eval网络, 输出为action, 将action输入环境, 得到奖励r和下一个环境信息s_,
存储当前环境s, 选择的action, 得到的奖励r这4个信息, 然后再将s_输入到actor eval网络, 循环步骤1,
直到存储了一定量的记忆[(s, a, r, s_), …], 注意这个过程中actor eval网络没有更新。2、从第一步中存储的记忆中sample出部分[(s, a, r, s_), …]
3、将sample出来的s输入到actor eval网络中得到action, 再将此action与s输入到critic
eval网络中得到q值。4、求a_loss = mean(q), 反向传播更新actor eval网络 (注:虽然a_loss是通过actor eval网络和critic eval网络最终求得, 但是此处只更新actor eval网络)。
5、重复步骤3, 得到更新actor eval网络后算出来的q值。
6、将sample出来的s_输入到actor target网络得到action_。
7、将sample出来的s_和第6步得到的action_一起输入critic target网络, 得到q_值。
8、计算q_target = sample出来的r + gamma * q_ 。
9、计算c_loss = MSE(第5步的结果q, q_target) 。
10、通过c_loss反向传播更新critic eval网络(注:虽然c_loss是通过actor eval、critic
eval、actor target、critic target四个网络最终求得, 但是此处只更新critic eval网络)11、循环1-10步骤, 在一定步骤后更新actor target、critic target网络,更新方式为:
W(actor target) = W(actor eval) * μ + W(actor target) * (1- μ)
W(critic target) = W(critic eval) * μ + W(critic target) * (1- μ)
openai官网在实现上网络架构与莫凡大大的不太一样,比莫凡实现的要复杂一些。
1、将环境信息s输入到actor-new网络, 得到两个值, 一个是mu, 一个是sigma,
然后将这两个值分别当作正态分布的均值和方差构建正态分布(意义是表示action的分布),然后通过这个正态分布sample出来一个action,
再输入到环境中得到奖励r和下一步的状态s_,然后存储[(s,a,r),…], 再将s_输入到actor-new网络,循环步骤1,
直到存储了一定量的[(s, a, r), …], 注意这个过程中actor-new网络没有更新。2、将1循环完最后一步得到的s_输入到critic-NN网络中, 得到状态的v_值, 然后计算折扣奖励:
R[t] = r[t] + γ*r[t+1] + γ2 * r[t+1] + … + γT-t+1 * r[T-1] + γT-t *
v_, 得到R = [R[0], R[1],…,R[t],…,R[T]],其中T为最后一个时间步。3、将存储的所有s组合输入到critic-NN网络中, 得到所有状态的V_值, 计算At = R – V_ (论文公式10,
openai官网代码则实现的是论文公式11和12)4、求c_loss = mean(square(At )), 然后反向传播更新critic-NN网络。
5、将存储的所有s组合输入actor-old和actor-new网络(网络结构一样), 分别得到正态分布Normal1和Normal2,
将存储的所有action组合为actions输入到正态分布Normal1和Normal2,
得到每个actions对应的prob1和prob2, 然后用prob2除以prob1得到important weight,
也就是ratio。6、根据论文公式7计算a_loss = mean(min((ration* At, clip(ratio, 1-ξ, 1+ξ)*
At))), 然后反向传播, 更新actor-new网络。7、循环5-6步骤, 一定步后, 循环结束, 用actor-new网络权重来更新actor-old网络(莫凡代码是在循环开始前更新的,
效果是一样的)。
8、循环1-7步骤。