强化学习入门
1 强化学习概念
1.0 模仿学习的困境
- 无法处理out of distribution的问题。模型学习的对象是专家,专家经验不会犯错。比如自动驾驶中车在拐弯的时候不会走歪,甚至撞墙。所以模型并不知道如果走歪了,会发生什么,以及怎么解决。Expert only samples limited observations.
- 因果混淆causal confusion。模仿学习建模的是相关性,而不是因果性。当输入的信息过于丰富时,模型可能无法判断什么才是导致某种行为的原因。比如模型过于依赖历史轨迹,导致捷径学习shortcut learning.
- 开环训练和闭环部署的gap太大。模仿学习是没有办法和环境做互动的,不会确切知道这种行为的结果Machine does not know the influence the result of each action。强化学习是可以和环境做互动的,可以影响环境,从而影响接下来的行为,举例:AlphaGo。闭环。
1.1 MDP过程
MDP是强化学习的核心,分为如下5个部分:
- 状态state。基本要素。observation是观测到的信息,需要从中选取对于模型最重要的给到模型,那么筛选的结果就是state。比如自动驾驶中,observation是道路环境,但是可能包括无关的信息,比如路边树上有一只鸟,这就是要被筛选掉的东西。但是由于现在模型很强大,不一定要做这样的筛选,所以可以把observation=state。
- 动作。基本要素
- 状态转移概率。注意,状态转移函数是状态转移概率在确定性下的特殊形式
- 奖励函数。没有奖励函数,就没有好动作和坏动作的区别
- 折扣因子。防止无限域的奖励发散。
episode是agent与环境进行的一轮完整的互动周期,比如一轮游戏。由多个steps组成。
1.2 策略迭代
强化学习的核心,是基于MDP过程,通过策略迭代,获取最优策略的过程。
其中,策略迭代分为策略评估和策略改进的2个部分。
策略评估指的是给定一个状态,评估该状态的价值的过程。
策略改进指的是根据当前动作值函数,更新策略网络,使高价值的动作的概率更大的过程。
1.2.1 策略评估
在传统强化学习(使用表格法)时,计算状态/各个动作的价值,然后更新到表格中。
在深度强化学习中:
- Value-based 方法(如 DQN):使用神经网络作为值函数逼近器,直接输出 Q(s,a) 的估计值。
- Policy-based 方法(如 REINFORCE):通常不直接估计V,而是通过蒙特卡洛采样轨迹来估计回报 ,并以此作为 V的无偏估计。
- Actor-Critic 方法:引入一个辅助的Critic 网络来显式估计 ,用于指导策略更新。
1.2.2 策略改进
在传统强化学习(使用表格法)时,通过贪心算法,更新策略表,从而使高价值的动作的概率更大。
在深度强学习中,不显式构造新策略,而是通过梯度上升更新策略网络参数。
1.3 分类
是否理解环境
- 不理解环境 Model-free RL
a. 必须根据真实世界的反馈进行调整
b. 当前主流的算法,PPO / PG 等都是 - 理解环境 Model-based RL
a. 可以根据模型推理未来变化,不必依赖当前世界的反馈
b. Learning MPC / Deep MPC。核心思想是把传统MPC中的动力学模型替换成深度学习模型。通过模型(状态转移方程)对未来状态进行预测,选择cost最小的方案。
基于策略/价值
- 基于策略 Policy-based
a. 直接输出每个策略的概率,更直接 learn an actor
b. Policy gradients - 基于价值 Value-based
a. 输出每个动作的价值,价值指导策略更新,相当于Value间接影响策略 learn a critic
b. Q learning / Sarsa - 既基于策略 Policy-based,又基于价值 Value-based
a. 同时拥有策略模块和价值模块,即actor-critic架构,比如PPO
单步/多步/回合更新
- 单步更新 step-by-step update
a. 游戏每进行一步,就更新一次。一般有critic的单步更新,因为后续的奖励可以通过价值函数得到。 - 多步更新 n-step update
a. 游戏每进行n步,更新一次 - 回合更新 episode update
a. 游戏直到结束,才能更新一次
On-policy / off-policy
按照agent学习与交互的环境是否是同一个区分。The agent learned and the agent interacting with the environment is the same one
- 是同一个/近似是同一个 = on-policy。比如Policy gradient是同一个,PPO是近似同一个。 on-policy的特点是运行一步/多步/一个回合,就更新一次,问题是和环境互动是很花时间的,所以效率不是很高。
- 不是同一个 = off-policy,就像agent在旁边看另一个环境。比如Q learning / Deep Q network
a. 策略theta’固定,重复采样。通过theta’的数据去更新theta,由于两者分布不一样,所以需要乘以对应的权重。

b. 为了避免策略theta‘和theta差太多,在损失函数中加入正则项,计算theta’和theta的KL散度,保证两者的分布不要相差太大。

随机性策略/确定性策略
随机性策略指的是:输出动作的概率分布,最终动作需要根据概率进行采样。比如PG,PPO,SAC
确定性策略指的是:输出的就是动作本身,没有概率。比如DPG,DDPG
在强化学习的发展过程中,经历了随机性 -> 确定性 -> 随机性的螺旋上升过程。
- 在1990-2000,基础的随机性策略就被提出,比如PG,但是无法解决连续动作空间问题,因为对于高维连续动作空间,想要采样到正确的值非常难。
- 在2014年,出现了DPG,用确定性策略输出连续动作,改良后的DDPG依然饱受训练不稳定,探索能力差,难复现的困扰。
- 在2017年,出现了SAC,仍然保留了DDPG中经验回放,目标Q网络的设计,但是又改回了随机性策略,并且使用双Q网络,最大熵算法提高探索能力。
连续动作空间/离散动作空间
根据动作是否连续,可以分为连续动作空间和离散动作空间。
自动驾驶的方向盘/油门/刹车,机器人的关节角度/力矩都是连续动作空间。比如DPG。
自动驾驶的变道决策(向左/向右/不变道)是离散动作空间。比如DQN。
1.4 探索与利用的平衡
在强化学习的过程中,要注意平衡【探索】与【利用】。
所谓探索,指的是选择当前价值并不高的动作,探索未知的可能。因为有些动作的价值不高并不是因为动作不好,而是因为策略进入局部最优了,对次优动作进行反复强化。
所谓利用,指的是选择当前价值高的动作,沿着梯度下降的方向继续优化直到最优解。
以policy gradient为例,因为会根据动作的概率分布进行选取,所以高概率的选中机会更高(利用),低概率的也有几率选中(探索)。
3 Policy-based methods
3.1 Policy gradient 策略梯度 PG
最常见的策略梯度算法,REINFORCE算法 和 REINFORCE with baseline算法,采用蒙特卡洛(MC)采样轨迹回报,直接优化策略函数,通过梯度下降法最大化累计回报。
优势:没有使用价值函数,所以避免了价值函数估计的偏差和方差。
问题:
- 方差大。由于奖励方差大,环境随机性,策略随机性(策略采样得到)导致。方差大导致:
a. 梯度更新方向/大小波动,训练不稳定。
b. 低样本效率,需要大量轨迹才能获得准确的优化方向。
c. 收敛缓慢,容易陷入震荡和局部最优。 - 步长难以确定。步长大了震荡,小了收敛慢
REINFORCE示例如下(无baseline版本):
class PolicyGradient:
def __init__(self, ):
...
def compute_MonteCarlo_returns(self, rewards):
returns = []
R = 0
for i in reserved(len(rewards)):
R = rewards[i] + gamma * R # gamma为折扣系数
returns.insert(0, R) # R方差高
return returns, R
# 在进行完一个完整的episode之后调用
def update(self, imgs, states, actions, rewards):
# 计算回报
returns = self.compute_MonteCarlo_returns(rewards)
# 计算对数概率
log_probs = self.policy.get_log_prob(imgs, states, actions)
# 计算loss
policy_loss = - log_probs * returns
self.optimizer.zero_grad()
policy_loss.backward()
self.optimizer.step()
3.1.1 Loss设计
Loss = - log( P ) * G
policy_loss = - log_probs * returns
3.2 GRPO
Group reward policy optimization
是一种policy-based方法,是没有critic网络的。
- 动作采样和奖励计算:采样多个用同一个输入状态和同一个策略网络,通过调整温度系数或调整随机种子,从而获得不同的输出,形成一组多个动作和奖励。
- 优势估计:对组内奖励进行归一化,得到相对优势(Relative Advantage),以缓解奖励尺度敏感问题。
- 策略更新:根据归一化后的优势,通过策略梯度算法更新策略网络参数,强化生成高优势动作的策略。
4 Value-based method
4.1 分类
基于价值函数的方法可以分为非深度学习的方法和深度学习的方法。
价值函数可以分为动作价值函数Q和状态价值函数V。
- 状态价值函数state value function V(s),输入环境s,输出预期收益。
- 动作价值函数Q(a),输入环境s和动作a,输出预期收益。V相当于Q的期望,或者说V是Q的加权平均。
a. 预期收益和场景相关。比如星球大战游戏,很多敌人的话,critic会输出很大的值,因为如果杀掉它们可能拿很多分。
- 状态动作价值函数state-action value function Q(s,a),表征累积奖励的期望。输入环境s和对应的行为a,才能输出收益。反过来说,给定s,可以得到不同a的价值 Q。那么可以通过xx办法找到更好的策略(更好指的是V_pi’ >= V_pi),从而提升Q。
- Q-learning不适合解决连续action问题。
4.2 状态价值函数中真值的估算——TD目标
训练预期收益需要有监督真值,真值理论上是当前状态s进行无数次回合得到的回报的平均值,但是实际可操作性太低,因此需要估算。
估算的的方法有(1)蒙特卡洛方法,采用马尔可夫链计算折扣奖励,因为随机性+多步求和,方差很大;(2)时序差分(temporal-difference)目标——gamma * Vt+1 + rt,不需要像蒙特卡洛方法一样等到episode结束才能更新,反而是每步都可以更新的。,那么同时训练t和t+1时刻的V输出,监督差值是否是rt,方差较小,偏差很大。
| 蒙特卡洛 | 时序差分 |
|---|---|
| 偏差小 | 偏差大 |
| 方差大 | 方差小 |
为了更新状态价值函数的参数,使其更贴近目标,需要设计损失。
状态价值函数目标和预测之差 = 状态价值函数目标真值 - 当前状态价值函数
≈ 状态价值函数目标真值==的近似== - 当前状态价值函数
≈ TD目标 - 当前状态价值函数
≈ rt + gamma * V(t+1) - V(t)
≈ TD error
所以损失 = diff*2 = (TD error) ^ 2
4.1 Q-learning
问:为什么Q-learning与Policy gradient/AC不同,没有actor网络,也能训练出最优解?
答:因为Q-learning专门给每个动作打分,只要分打得对,那后续就能取出最优解。
Q-learning算法是基于表格的,用表格存储某状态和某动作的价值。其缺点是面临维度灾难(curse of dimensionality)。
因为当状态和动作选项太多时,Q表难以记录所用的情况。
4.2 DQN
既然Q-learning面临输入维度灾难,那么考虑是否能否用神经网络代替表格,输入状态可以无限多种,输出固定动作的概率。
DQN状态无限:DQN用神经网络解决了状态空间不能连续的问题,所以DQN的状态空间可以无穷大。
DQN动作有限:但是DQN在更新Q的时候,会取下一个状态最大的动作,这个取max的操作是只能在有限动作的前提下进行的。
DQN由于是动作空间有限的方案,因此适合解决高层决策问题。
其pipeline如下:

实现如下:
class DQN:
...
def update(self):
states, actions, rewards, next_states, dones = self.replay_buffer(batch_size) # 采用出一个mini-batch
q_values = self.q_net(states).gather(1, actions) # 选出action对应的value
with torch.no_grad():
next_q_values_max = self.target_q_net(next_states).max(1, keepdim=True)[0]
returns = rewards + (1 - dones)n * next_q_values_max * self.gamma # 用target QNet 计算目标回报,作为当前Qnet的gt
loss = F.mse(returns, q_values)
self.opt.zero_grad()
loss.backward()
self.opt.step()
# 阈值递减
self.epsilon *= self.epsilon_decay
# 定期更新target q
if ...:
self.target_q_net.load_state_dict(self.q_net.state_dict())
4.2.1 目标Q网络 提高训练稳定性
DQN有2个Q网络,一个是实时参数更新的Q网络,另一个是fix的Target Q网络。
Target Q网络用于预测t+1时刻的q值,和当前t时刻的reward相加后得到回报,在DQN中成为target。
with torch.no_grad():
next_tartget_q_max = self.target_q_net(next_states).max()
target = reward + self.gamma * next_target_q_max # 要记得折扣系数
引入目标Q网络的原因:
- 解决训练不稳定的问题。如果只有1个Q网络,这个Q网络既负责y=r+maxQ_t+1,又要负责预测当前的Q,所以就像在打一个移动的靶,不方便学习。如果能固定目标Q,那么就会提升稳定性。
目标Q网络的更新方式:
- 每隔一段时间更新为当前的Q
- 采用滑动平均缓慢更新
4.2.2 探索机制 - epsilon greedy
为了避免探索过一个好的行为后,之后一直都采取它,所以要给输出一些随机性。
通常采用epsilon greedy的方式。epsilon随着训练的进行,逐渐减小。

其实现如下所示:
class DQN:
def select_action(self, state):
if random.random() < self.epsilon:
action = random.randint(0, len_action - 1) # 有限动作
else:
q_values = self.q_net(states)
action = q_values.argmax().item()
return action
4.2.3 经验回放 replay buffer
DQN为off-policy,可以将和环境互动的信息(st, at, rt, st+1)存储到buffer中,用来更新。如果满了,就丢掉最老的。
在每轮iter中,先从buffer中采样一个batch,然后用这个batch来更新Q。
用replay buffer的好处(1)buffer中的数据可以反复使用,提高训练效率,因为强化学习中最花时间的往往是交互;(2)从buffer中采样可以让数据更多元。
这样子形成了off-policy。
其中,buffer的实现如下所示:
class ReplayBuffer:
def __init__(self, max_capacity):
self.buffer = debug(maxlen=max_capacity)
...
def push(self, ):
self.buffer.append((state, action, reward, next_state, done))
def sample(self, batch_size):
batch = random.sample(self.buffer, batch_size) # sample(population, k)
return batch
注意:DQN和PPO都使用旧策略的数据,但是区别是:
- DQN使用replay buffer存储旧策略,然后从buffer中提取一个batch来更新
- PPO使用重要性采样,旧策略乘以重要性权重,从而更新当前的梯度。
4.2.4 Loss设计— mse(r_t + gamma * max Q_t+1 - Q_t)
Loss = mse( y_t - Q_t )
其中y_t是目标价值,= r_i + gamma * max Q_t+1
Q_t时预测价值
q_values = self.q_net(states).gather(1, actions) # 选出action对应的value
with torch.no_grad():
next_q_values_max = self.target_q_net(next_states).max(1, keepdim=True)[0]
returns = rewards + (1 - dones)n * next_q_values_max * self.gamma # 用target QNet 计算目标回报,作为当前Qnet的gt
loss = F.mse(returns, q_values)
4.3 Rainbow DQN
4.3.1 Double DQN解决过估计
- DQN的Q存在过估计问题,常常高估会得到的reward。Q value is usually over-estimated.
- 所以选action的Q和评估reward的Q‘设置为2个。其中Q网络选择动作,Q‘用来评估该动作的价值。
a. if Q over-estimate a, so it is selected, Q’ would give it proper value; If Q’ over-estimate, the action will not be selected by Q. - 其核心思想类似于行政和立法相互独立。Q’相当于提案,Q相当于执行。
在后续介绍的SAC算法中,SAC使用双Q网络,选择更小的价值作为最终价值,也是用来解决过估计问题的。
4.3.2 Prioritized Reply
- 传统DQN是从buffer中随机采样,对模型进行训练。问题是有些数据比较简单,有些数据比较难(TD error更大)
- TD error指的是Qt 和 rt + Qt+1的差
- prioitized reply的思想是TD error更大的数据,有更高的概率被采样到。
4.3.3 Noise Net
- 之前的加噪声方法是epsilon greedy,在输出动作的时候有epsilon的概率去采取随机行为。
- 但是epsilon greedy的方法并不真实 No real policy works in this way,因为这导致同样的state,输出动作不一样。
- 因此考虑在Q模型中加噪声,在一轮episode中保持不变。这样state一致时,agent输出的行为就是一样的了,能够explore in a consistent way
5 Actor-critic method
actor-critic可以分为确定性策略和随机性策略。
- 确定性策略指的是输入状态s,输出一个单一的动作a,没有随机性,没有概率分布
- 随机性策略指的是输入状态s,输出概率分布。
5.0 actor-critic
来历:actor的前身是policy net,是基于回合更新的,而且是on-policy,学习效率低,且reward方差大,如果用value-based的critic,每步输出价值,那么就可以实现单步更新,且更稳定,两者互补的到actor-critic。

5.0.1 缺点:收敛慢
2点原因导致:
- critic本身以蒙特卡洛或者TD error为真值目标,它们波动大,所以critic难收敛
- critic和actor互相制约,一起更难收敛。
5.0.2 优点:单步更新
因为每步都有critic的输出,因此可以更新。而不用等到回合结束再更新。
注意:actor-critic并不是动作空间无限的,actor可以是有限的,也可以是无限的。比如DDPG就是动作空间无限的。
5.1 actor相关
- 给定theta,让actor进行一次episode,会达到一个序列的观测s/行为a/奖励r。其中,奖励之和为R_theta。

- 因为模型输出的随机性和场景的随机性,R_theta并不是固定的,因此目标不是最大化R_theta,而是最大化R_theta的期望。
- R_theta的期望是轨迹的概率==P(tao | theta)乘以该轨迹的奖励R(ta0)==之和。
- 穷举所有可能性是不现实的,因此可以采用同一个策略进行N次,N次的平均结果就是期望。

- 采用梯度上升gradient ascent的方法,最大化期望奖励。但是在实现的时候,是最小化 -期望奖励
- 最小化 -期望奖励,需要对奖励对theta求偏导。因为R(tao)不含theta,所以可以当成常数。这也解释了为什么可以用RLHF,人类反馈的奖励是没有梯度的。


5.2 确定性策略Actor-Critic
确定性策略方法是为了解决随机性策略方法的效率低,方差大的问题。
5.2.0 随机性策略方法的问题
- 效率低。在连续动作空间中,尤其是高维的连续动作空间中,正确的动作范围非常小,选中概率很低,需要大量采样才能碰到好动作。
- 方差大。就算探索到好动作,在下一次增大其概率后,依然有较大概率采样到坏动作,那样训练不稳定,方差大。
这个过程就像大海(高维连续动作空间)捞针(找到最优动作),就算知道了方向,也会去探索其他方向。
因此,考虑不输出动作概率,直接输出动作,并且让critic告诉actor动作的优化方向,即确定性策略。
确定性(deterministic)策略一般包含DPG,DDPG
5.2.1 DPG=Actor-Critic 框架+确定性策略+基于∇Q的梯度
DPG的actor直接输出动作a=μ(s),不输出概率分布。即确定性策略。
critic输出∇Q,而不是输出Q。
因为没有概率分布,所以无法计算log概率梯度,所以只能去获取信息:稍微改变动作,Q会变大还是变小,即∇Q。
- 输出Q可理解为:告诉actor要当前动作能获得多少回报;
- 输出∇Q可理解为:告诉actor要沿什么方向优化才可以。
DPG的优势:
- 高效。不会像随机性策略一样需要探索非常多的动作;
- 方差低。输出确定性的动作。
DPG的劣势:
- 训练不稳定。actor-critic架构,互相耦合,任意一方出错就会导致训练发散;
- 探索能力弱。无法像随机性策略一样探索不同的动作,需要额外加噪等方法;
- 容易陷入局部最优。一旦通过critic收敛到局部最优位置,很难跳出去。
注意:DPG只是一套理论框架,并不要求actor和critic是神经网络,也可以是线性模型等,只要可以进行函数逼近即可。这也为下一步D(deep)DPG的出现埋下伏笔。
5.2.2 DDPG=DPG+DQN技巧(经验回放,目标网络)
DDPG, deep deterministic policy gradient,将深度神经网络,和DQN的经验回放,目标网络技术引入。
- 引入DQN的经验回放,形成off-policy策略,提高样本利用效率;
- 引入DQN的目标Q网络,避免Q输出价值的方差过大,提高训练稳定性
- DQN只能处理离散动作空间,无法处理连续动作空间(比如油门刹车),DDPG能够处理连续动作空间。
DDPG的优势:
- 连续动作空间,继承于DPG
- 样本效率高,继承于DQN的经验回放
- 训练比DPG稳定一些,因为有目标Q网络
DDPG的劣势:
- 过估计。和DQN一样,因为总是在选取最大的Q(s,a),导致对最大值的高估,使模型学到错误的价值。
- 训练仍然不够稳定。
- 探索能力弱。输出确定性的动作,无法有效探索到其他可能。
5.2 A2C Advantage actor-critic
起因:critic也存在状态-动作价值函数Q方差大的问题,因此考虑减去baseline,从而减小梯度,减少训练过程的不稳定。
方法:状态价值函数适合做baseline,因为它是所有动作的加权平均。因此设新的优势函数Advantage =( Q - V ),即动作价值函数 - 状态价值函数。而 Q = r_t + gamma * V_t+1,因此 Q - V = r_t + gamma * V_t+1 - V_t,可以发现:该式恰好等于TD error。
注意:
- 这样子可以省掉一个Q网络。
- r_t是通过规则计算得到的真实奖励。比如机器人双足的平稳奖励,自动驾驶的安全奖励。
5.2.1 Critic loss设计:td_errror^2
如何更新状态价值函数V呢?使用TD error。
定义是:真实奖励 r t r_t rt和未来预期奖励 γ V ( s t + 1 ) \gamma V(s_{t+1}) γV(st+1)之和 与 本时刻的预期奖励 V ( s t ) V(s_t) V(st) 的误差
δ t = r t + γ V ( s t + 1 ) − V ( s t ) \delta_t = r_t + \gamma V(s_{t+1}) - V(s_t) δt=rt+γV(st+1)−V(st)
如果该误差>0,说明预期奖励 V ( s t ) V(s_t) V(st)太小,此刻的价值被低估了。
然后通过优化TD error的均方,用梯度下降更新critic的参数。
L critic = E [ δ t 2 ] L_{\text{critic}} = \mathbb{E} \left[ \delta_t^2 \right] Lcritic=E[δt2]
A ( s , a ) ≈ δ t A(s,a) \approx \delta_t A(s,a)≈δt
5.2.2 Actor loss设计:-log ( P ) * td_error
和policy gradient一样,loss为-log( P ) x 回报。只不过此时的回报是用优势函数来定义,优势函数和TD error形式一致,所以可以写成-log ( P ) x td_error
5.2.3 A2C可使用同步的训练
训练一般很慢,怎么增加训练速度呢?
将一份模型拷贝成多份,每份模型一个worker,提供一个优化方向,然后更新全局模型。就像火影忍者里的鸣人开影分身学螺旋丸。
需要注意的是:
- A2C可以并行,可以不并行。但是典型实现是并行,因为和环境交互很耗时,所以并行能够提高训练速度。
- 每个worker独立和环境交互,global network汇总每个worker的梯度,统一更新。
5.3 PPO 近端策略优化 = A2C + 重要性采样 + GAE
PPO近端策略优化,是一种on-policy的方法。也是actor-critic方法。需要critic评估价值,计算优势函数,来更新策略。其核心思想是用旧策略更新新策略,通过新旧策略的概率比对权重进行修正。其优势在于数据使用高效,训练过程稳定。
PPO的actor可以是离散的,可以是连续的。如果是离散的,那么就输出每个动作的概率,如果是连续的,就输出正态分布的均值和标准差。
整个训练流程示例:
for episode in range(total_episodes): # 和环境多次交互
obs = env.reset()
done = False
while not done: # 在一次完整的交互内
imgs = get_imgs(obs)
states = get_states(obs)
with torch.no_grad():
action, _, _ = policy.sample(imgs, states)
action_np = action.numpy().flatten()
reward, is_done, next_obs = env.step(imgs, states)
buffer.append(reward, is_done, next_obs, imgs, states, actions)
obs = next_obs
done = is_done
ppo.update(buffer) # 交互完一次,就用该数据进行策略网络和评论家网络进行更新
buffer.clear()
策略与评论家网络更新示例:
class PPO:
def __init__(self, epochs, batch_size):
self.epochs = epochs # 输入一次buffer,对其数据学习多少遍。
# 因为每一遍的幅度都被clip在很小的范围内,所以多次使用同一批数据,策略网络也不会偏移太多,仍然满足重要性采样的要求
self.actor = Model()
self.critic = Model()
self.batch_size = batch_size # 每学一遍数据,都是将数据拆成mini-batch进行的
# batch size指的就是mini-batch的大小
...
def compute_GAE_return(self, ):
...
def update(self, buffer):
imgs, states, actions, ... = buffer
with torch.no_grad():
_, old_policy_log_prob, _ = self.actor.sample(imgs, states)
values = self.critic(imgs, states)
for i in range(self.epochs): # 对同一批数据进行多次学习
# 要打乱数据的顺序
indices = np.arange(len(rewards))
np.shuffle.random(indices)
for start in range(len(rewards), 0, self.batch_size):
end = start + self.batch_size
idx = indices[start:end] # 随机取出一部分数据
imgs_b, states_b, actions_b, adv_b, returns_b, old_policy_log_prob_b = xx[idx]
# 当前策略
_, cur_policy_log_prob, _ = self.actor.sample(imgs_b, states_b)
#
ratio = (cur_policy_log_prob - old_policy_log_prob).exp()
# PPO 上下限
m1 = ratio * adv_b
m2 = torch.clamp(ratio, 1 - self.epsilon, 1 + self.epsilon) * adv_b
# 计算actor loss
actor_loss = -torch.min(m1, m2)
# 计算critic loss
values_b = self.critic(imgs_b, states_b)
critic_loss = F.mse_loss(values_b, ret_b)
self.actor_optimizer.zero_grad()
self.critic_optimizer.zero_grad()
actor_loss.backward()
critic_loss.backward()
self.actor_optimizer.step()
self.critic_optimizer.step()
5.3.1 广义优势估计(GAE)
相比于A2C,优势函数的计算有了进一步优化,避免其方差过大。
方法:用多步 TD Error 的加权和(GAE)优化价值函数:
A ^ t GAE = ∑ l = 0 ∞ ( γ λ ) l δ t + l \hat{A}_t^{\text{GAE}} = \sum_{l=0}^\infty (\gamma \lambda)^l \delta_{t+l} A^tGAE=∑l=0∞(γλ)lδt+l
举例如下:
def compute_GAE_return(self, rewards):
advantages = []
for i in reversed(len(rewards)):
td_error = rewards[i] + (1 - dones[i]) * values[i + 1] * gamma - values[i]
gae = td_error + (1 - dones[i]) * lambda * gae
advantages.insert(0, gae)
returns = [adv + val for adv, val in zip(advantages, values)]
return torch.tensor(advantages), torch.tensor(values)
注意:在计算完GAE之后,还是要回归计算回报。回报的计算方式就是 advantage + value,因为之前advantage = return - value。
5.3.2 Critic loss设计:mse(G_GAE - V)
td errror替换成GAE
values = critic(imgs, states)
returns = advantages + values # 有点问题
actor_loss = F.mse(values, returns)
5.3.3 actor loss
起因:每次更新幅度不能太大,否则容易偏离原来的分布,不稳定,所以对其进行限幅。
实现:有2种方法。最开始提出的是KL散度,后来使用clip。
L C L I P ( θ ) = E t [ min ( π θ ( a t ∣ s t ) π θ o l d ( a t ∣ s t ) A ^ t , clip ( r a t i o , 1 − ϵ , 1 + ϵ ) A ^ t ) L^{CLIP}(\theta) = \mathbb{E}t[ \min( \frac{\pi\theta(a_t|s_t)}{\pi_{\theta_{old}}(a_t|s_t)} \hat{A}_t, \text{clip}(ratio, 1-\epsilon, 1+\epsilon) \hat{A}_t ) LCLIP(θ)=Et[min(πθold(at∣st)πθ(at∣st)A^t,clip(ratio,1−ϵ,1+ϵ)A^t)
ratio = (cur_policy_log_prob - old_policy_log_prob).exp()
m1 = ratio * adv
m2 = torch.clamp(ratio, 1 - epsilon, 1+ epsilon) * adv
actor_loss = torch.min(m1, m2)
其实现可以参考:https://blog.youkuaiyun.com/qq_47997583/article/details/133791309
注意:近端策略优化中的近端的意思,就是指每次优化策略时对梯度进行裁剪,避免分布差异过大。
5.3.4 PPO-KL和PPO-CLIP
为了限制策略网络发生突变,从好的网络退化成性能很差的网络,所以需要限制网络的更新幅度。
限制的方法有2种,第一种是采用KL散度衡量旧策略和新策略的分布差异,然后以差异为辅助损失,作为总损失的一种,从而限制新策略的更新幅度;
第二种是采用梯度裁剪。将超出阈值的梯度进行裁剪,使其约束在规定的范围之内,也能满足该要求。
5.3.4 on-policy用重要性采样
起因:因为actor-critic是交互一次,训练一次,对于训练来说仍然速度较慢。那么能不能交互一次,训练多次呢?
交互一次,训练多次要解决的问题:交互一次,训练多次,那么每次的策略都会更新,用旧数据训新策略会有问题。重要性采样就是让旧策略对齐到新策略上,使其能够多次使用旧数据。
实现:在计算梯度时,乘以一个权重 p(theta) / p(theta’)
其中theta‘是旧策略,p(theta’)是旧策略的概率值
因此,在收集数据阶段,不仅要获得旧策略输出的动作,还要输出该动作的概率。其核心在于使用采样的方法获取策略输出,是随机的,而不是确定性argmax的。
举例如下:
- 先定义策略网络
class Policy(nn.Module):
...
def forward(self, ...):
...
...
def sample(self, images, states):
mean = self.forward(images, states) # 获取采样的均值
log_std = self.log_std.expand_as(mean)
std = torch.exp(log_std) # 获取采样的方差
dist = Normal(mean, std)
action = dist.sample() # 随机采样
log_prob = dist.log_std(action).sum(dim=-1, keepdim=True) # 获取对数概率
mean_log_prob = dist.log_std(mean).sum(dim=-1, keepdim=True)
return action, log_prob, mean_log_prob
- 用策略进行采样
while not done:
...
with torch.no_grad():
action, _, _ = policy.sample() # 采集的数据是不需要梯度的
- 计算重要性
ratio = (cur_policy_log_prob - old_policy_log_prob).exp()
5.3.4 从PPO到DPO(直接偏好优化)
DPO,direct preference optimization
在DPO中,reward model是隐式的,secretly a reward model
- 收集人类反馈 collect human/ai feedback to learn p(yw > yl)
- RLHF的目标中有3个model(actor model / ref model / reward model)

- reward hacking,在给定奖励机制下,个体通过非预期的方式最大化奖励的行为。
5.3.5 PPO与GRPO
去掉Value model(Critic model),无需额外的价值函数

5.4 A3C(Asynchronous Advantage Actor-Critic)
和A2C一样,每个worker独立和环境交互,得到梯度。但是不一样的是,每个worker单独更新global network,因此是异步的。
5.5 SAC=DDPG+随机性策略+最大熵+双Q网络
SAC,soft actor-critic,是DDPG的改进版,主要是为了解决DDPG的
- 采用随机性策略,提高探索能力
- 引入最大熵框架,鼓励探索
- 引入双Q网络,抑制过估计问题。其中是Q网络有2个,目标Q网络有2个。
因此,SAC包含3类网络5个网络:
- actor x 1
- critic(Q网络)x 2
- 目标Q网络 x 2
目标是 回报+熵
之前的强化学习算法是最大化回报,SAC引入了最大熵框架,在目标中加入了熵。
目标 = max E [ r + alpha * h ]
其中r是回报,h是熵,alpha时温度系数。
如果把之前最大化预期回报,找出最优动作理解为硬,那么当前的目标就更软——因为不再追求最优动作,而是坚固选择较好的动作,并保持较好的探索性。
熵h的计算方式为
h = - 积分 pi(a|s) * log ( pi(a|s) ) da
只有每个a(动作)的分布尽可能均衡,熵才会尽可能大。
6 Sparse Reward
agent在绝大部分action之后都没有奖励,只有部分action才能获得奖励。比如在寻宝游戏中,只有找到宝藏之后才能获得奖励,中间步骤没有奖励。这样导致可能学不到东西。
6.1 reward shaping
想办法design一些reward,是自行设计的,而不是环境反馈的。
比如对战游戏中,被敌人杀死,会从游戏环境得到-100的reward,让模型自己学需要学很久。那么可以自行设计一个掉血的reward,掉一滴得到-1的reward,捡到补给包得到+1的reward,这样模型就知道要自我保护。
6.2 curiosity
引入一个新模块:intrinsic curiosity module,输入(st, at, st+1),输出ri奖励
ri = diff(st+1, st+1_hat)
st+1_hat = predict(st, at)
这个模块鼓励产生与众不同的st+1,也就是鼓励冒险。所以模型会特别想看没看过的环境。
但是这样会导致模型会关注一些没有意义的少见的环境,比如游戏画面里树叶飘动的场景。这样会导致agent一直在树下看树叶飘。
因此,需要对场景进行过滤,把不重要的场景剔除。
ri = diff(useful_st+1, useful_st+1_hat)
useful_st+1_hat = predict(useful_st, at)
useful_st = find_useful_features(st)
useful_st+1 = find_useful_features(st+1)
6.3 curriculum learning
curriculum 课程
通过安排学习过程从简到难,从而帮助模型学习。
这个方法也出现在RNN中,RNN先回归短序列,在学习回归长序列,被验证效果会更好。
- Given a goal state sg
- sample some states s1 close to sg
- delete s1 whose reward is too large (already learned) or too small (too difficult to learn)
- sample s2 close to s1
6.4 Hierarchical RL
层次RL,将agents分成不同的层次,从上到下完成上一层的需求
将RL分成不同层次的agent,上一层agent提出要求,下一层的agents提出更细化的要求,然后最下面的agents执行。
if the lower agent cannot achieve the goal, the upper agent would get penalty.
7 逆强化学习
先学习reward function,再学习策略。
- 通过expert demonstration,使用IRL反推reward function
- 通过学习到的reward function,使用RL训练得到actor
IRL训练得到的reward function比较简单,但是依然可以得出复杂的策略。就像《三体》中的黑暗森里法则,三条就能够决定宇宙中高等智慧生物的生存方法。
7.1 具体步骤
- expert玩游戏得到轨迹tao_hat
- actor玩游戏得到轨迹tao
- 优化reward function,使得reward(tao_hat) > reward(tao)。The expert is always the best.
- 根据reward function优化actor的策略
一般IRL所需要的demonstration并不需要很多
8 机器人与强化学习
8.1 PPO样本效率不够,但是安全
PPO是目前ChatGPT使用的强化学习策略,是主流算法。但是PPO是on-policy的,虽然可以使用重要性采样对非当前策略的轨迹进行学习,但总体没有off-poilicy的样本效率高。在机器人数据量并不足的背景下,并不是最优选择。
但是PPO会对梯度进行clip,所以策略不会在训练过程中出现突变,是更安全的选择。
8.2 DDPG训练不稳定,不开源
DDPG是专门面向连续动作空间的off-policy算法,采用确定性的动作输出方法。但是DDPG训练不够稳定,且未开源,没有人能复现Deepmind的结果。
8.3 SAC好
SAC训练稳定,探索能力强(随机性策略+最大熵),off-policy,样本效率高。而且开源。
1745

被折叠的 条评论
为什么被折叠?



