[通俗易懂]《动手学强化学习》学习笔记3-第5-13章


前言

参考:
《动手学强化学习》作者:张伟楠,沈键,俞勇
动手学强化学习 网页版
动手学强化学习 github代码
动手学强化学习 视频
强化学习入门这一篇就够了!!!万字长文(讲的很好)
+
参考:
强化学习入门(第二版)读书笔记

小总结(前文回顾)

先简单总结一下第一章所学的知识点:
我做了一个思维导图很方便理解
之后学习完会在这里一直更新。
自己学习时做的笔记:https://github.com/wild-firefox/Hands-on-RL

补充一下要下载的库
#第5章
pip install tqdm
#第7章
pip install torch
pip install gymnasium

这里仅记录下学习时遇到的问题,已经学了一个月了,只是忙于毕设没空来更新一下学习进度,发现踏入门槛后学习强化学习就轻松了,当然还有一些实验时学到的一些小细节,准备下个博客再更。

0.26.2版本gym环境问题

将原代码修改三处:
第1、2处:
将训练的函数改为如下:(同理off_policy也是如此)
在这里插入图片描述
第3处:
这里注释掉,seed =0 改到为上图的在env.reset()的函数里。
在这里插入图片描述

问题1[第8章DQN]:

第8章:DQN改进算法

在这里插入图片描述
问题1:画红色横线这句话没看懂。
答:
首先:由于V值加上任意常量,并且在A中减去这个任意常量,由于这个常量的不确定,导致V不能反映state值,A不能反映advantage值。所以要将公式改成-maxA的形式。(就是将这个常量定为maxA的意思,也就得到了V=Q+maxA = maxQ)

此时已经默认优势函数A-maxA。
而这句话意思是:强制A-maxA =0,即就是A = maxA。
通俗来说,就是限制了这个常量为一个定值,取为maxA,当此时的A=maxA(下一个状态的)时,V= maxQ。

问题2[第9章策略梯度]:

第9章:策略梯度算法

在这里插入图片描述
问题2:上图箭头这里的t是不是对应下图的代码这里?
在这里插入图片描述
答:不是,上图的意思是:每次从一个新的序列开始时,状态重置reset,return为0,可以看作每次一个序列开始时,代表的意思是在伪代码中:for e =1 ->E do。

上图伪代码的t在代码中代表是意思是下图中的i,即计算当前一个序列eposide结束后,在更新时得到的return总和G。
在这里插入图片描述

问题3[第10章AC]:

第10章 A-C算法

在这里插入图片描述
问题3:这里箭头对应下面代码这里是没错,
在这里插入图片描述
为什么下面图中,方框内td_delta也要加detach,(即不需要加梯度信息)?
(detach() 为去掉梯度信息,训练时不训练。)
在这里插入图片描述
答:
根据伪代码:
在这里插入图片描述
td_delta 在求梯度的符号的左边 所以不求梯度 加detach
td_target 只对状态函数(w参数的函数)求梯度,而不对时序差分目标求梯度, 加detach。
对应到代码里解释:
在这里插入图片描述
actor_loss只对log_prob求梯度
critic_loss只对self.critic(states)求梯度

经过训练测试后
原代码结果:(都加detach)
在这里插入图片描述
td_delta 不加detach(),td_target加detach(),测试结果如下:
在这里插入图片描述

此时我看出第二张图的效果怎么比第一张图好?
加大eposide到3000:
原文:
在这里插入图片描述
td_delta 不加detach(),td_target加detach(),测试结果如下:
在这里插入图片描述
结论:原文代码是对的。
出现单次效果时,不能妄下结论,要通过加不同随机种子求均值或加大eposide来验证。

后续又测试了td_target加 和不加的情况:
td_delta 加detach(),td_target不加detach():
在这里插入图片描述

两者都不加:
出现报错:
RuntimeError: Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed). Saved intermediate values of the graph are freed when you call .backward() or autograd.grad(). Specify retain_graph=True if you need to backward through the graph a second time or if you need to access saved tensors after calling backward.
翻译为:
RuntimeError:试图第二次向后遍历图(或者在已释放的张量之后直接访问已保存的张量)。当您调用.backward()或autograd.grad()时,将释放图中保存的中间值。如果需要第二次向后遍历图,或者在调用backward后需要访问保存的张量,则指定retain_graph=True。

参考:深度学习框架拾遗:【Pytorch(七)】——Pytorch动态计算图
了解了计算图,对这个错误的一点理解:
当着两个都进行梯度计算时,在首先进行的actor的反向传播中,结束时删除了计算图,此时的计算图包含了critic的反向传播中要进行计算的值td_target和self.critic(states)信息。
至于为什么此时计算图中包含了信息td_target和self.critic(states)?是因为在计算actor_loss时利用到了两者的信息。
而原本都带有detach时,计算图中td_delta和td_target保留了下来,然后计算他们所需要的参数也保留了下来,所以可以继续计算backward(),不会报错。

结论:原文代码没错。

追问:

想了下,为什么我会出现这个问题。
原因是前面几章的代码从来没有出现过detach()的说法,且原文没有解释为什么这里会出现detach()。
于是我翻看了一下前几章的原理,发现有些地方也确实根据原理也要加上detach而没有加,
比方说DQN的代码的这里:(类似的还有DDPG的代码)
在这里插入图片描述
我这里加上后:进行训练后和原文不加上的进行比对,发现结果一模一样。不知道为什么会如此。

最终解决

–2024.5.17–
后来请教了一下同门,发现原来自己前面的知识有个点忘记了:DQN和DDPG有两层网络:Critic网络和Critic Target网路,在定义adam优化器时,只对Critic网络进行优化而不对目标网络进行优化。
在这里插入图片描述
而在原代码处,td_target是由目标网络计算得出(来源于目标网络),所以在更新梯度时不会对原网路进行更改,因为只对原网路进行梯度更新,故,这里加不加都不会改变结果,最好是加一下,因为更符合原理。

而为什么在AC网络中,两个td_delta和td_target都必须要加detach?是因为在优化器只优化原网络的前提下,他们都是由原网络计算得出,故他们都会对参数的梯度更新有影响,且根据原理,他们也必须加上detach。

总结:在写代码的时候,看某个值要不要加detach ,看两个方面:
1.(影响因素)看优化器优化的是哪个网络:如果这个值不是由优化的网络计算得出,那这个值加不加detach不影响结果;如果是由优化的网络计算得出,则看下一个因素。
2.(决定因素)看算法的原理,如果这个值是由优化的网络计算得出,那么在计算损失的时候,基本上都是要加detach的,因为只对有参数(w)的函数进行梯度下降。(目前到第13章都适用。)

补充一点

在这里插入图片描述
第一个mean必须加上,因为backward()的必须是个标量(损失函数输出为一个标量),求mean这里意思为求期望。
第二个mean可加可不加,因为mse均方差损失函数已经有求均值的操作了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值