强化学习入门

强化学习入门

1 强化学习概念

1.0 模仿学习的困境

  1. 无法处理out of distribution的问题。模型学习的对象是专家,专家经验不会犯错。比如自动驾驶中车在拐弯的时候不会走歪,甚至撞墙。所以模型并不知道如果走歪了,会发生什么,以及怎么解决。Expert only samples limited observations.
  2. 因果混淆causal confusion。模仿学习建模的是相关性,而不是因果性。当输入的信息过于丰富时,模型可能无法判断什么才是导致某种行为的原因。比如模型过于依赖历史轨迹,导致捷径学习shortcut learning.
  3. 开环训练和闭环部署的gap太大。模仿学习是没有办法和环境做互动的,不会确切知道这种行为的结果Machine does not know the influence the result of each action。强化学习是可以和环境做互动的,可以影响环境,从而影响接下来的行为,举例:AlphaGo。闭环

1.1 MDP过程

MDP是强化学习的核心,分为如下5个部分:

  1. 状态state。基本要素。observation是观测到的信息,需要从中选取对于模型最重要的给到模型,那么筛选的结果就是state。比如自动驾驶中,observation是道路环境,但是可能包括无关的信息,比如路边树上有一只鸟,这就是要被筛选掉的东西。但是由于现在模型很强大,不一定要做这样的筛选,所以可以把observation=state
  2. 动作。基本要素
  3. 状态转移概率。注意,状态转移函数是状态转移概率在确定性下的特殊形式
  4. 奖励函数。没有奖励函数,就没有好动作和坏动作的区别
  5. 折扣因子。防止无限域的奖励发散。

episode是agent与环境进行的一轮完整的互动周期,比如一轮游戏。由多个steps组成。

1.2 策略迭代

强化学习的核心,是基于MDP过程,通过策略迭代,获取最优策略的过程。

其中,策略迭代分为策略评估策略改进的2个部分。

策略评估指的是给定一个状态,评估该状态的价值的过程。

策略改进指的是根据当前动作值函数,更新策略网络,使高价值的动作的概率更大的过程。

1.2.1 策略评估

在传统强化学习(使用表格法)时,计算状态/各个动作的价值,然后更新到表格中。

在深度强化学习中:

  1. Value-based 方法(如 DQN):使用神经网络作为值函数逼近器,直接输出 Q(s,a) 的估计值。
  2. Policy-based 方法(如 REINFORCE):通常不直接估计V,而是通过蒙特卡洛采样轨迹来估计回报 ,并以此作为 V的无偏估计。
  3. Actor-Critic 方法:引入一个辅助的Critic 网络来显式估计 ,用于指导策略更新。

1.2.2 策略改进

在传统强化学习(使用表格法)时,通过贪心算法,更新策略表,从而使高价值的动作的概率更大。

在深度强学习中,不显式构造新策略,而是通过梯度上升更新策略网络参数。

1.3 分类

是否理解环境

  1. 不理解环境 Model-free RL
    a. 必须根据真实世界的反馈进行调整
    b. 当前主流的算法,PPO / PG 等都是
  2. 理解环境 Model-based RL
    a. 可以根据模型推理未来变化,不必依赖当前世界的反馈
    b. Learning MPC / Deep MPC。核心思想是把传统MPC中的动力学模型替换成深度学习模型。通过模型(状态转移方程)对未来状态进行预测,选择cost最小的方案。

基于策略/价值

  1. 基于策略 Policy-based
    a. 直接输出每个策略的概率,更直接 learn an actor
    b. Policy gradients
  2. 基于价值 Value-based
    a. 输出每个动作的价值,价值指导策略更新,相当于Value间接影响策略 learn a critic
    b. Q learning / Sarsa
  3. 既基于策略 Policy-based,又基于价值 Value-based
    a. 同时拥有策略模块和价值模块,即actor-critic架构,比如PPO

单步/多步/回合更新

  1. 单步更新 step-by-step update
    a. 游戏每进行一步,就更新一次。一般有critic的单步更新,因为后续的奖励可以通过价值函数得到。
  2. 多步更新 n-step update
    a. 游戏每进行n步,更新一次
  3. 回合更新 episode update
    a. 游戏直到结束,才能更新一次

On-policy / off-policy

按照agent学习与交互的环境是否是同一个区分。The agent learned and the agent interacting with the environment is the same one

  1. 是同一个/近似是同一个 = on-policy。比如Policy gradient是同一个,PPO是近似同一个。 on-policy的特点是运行一步/多步/一个回合,就更新一次,问题是和环境互动是很花时间的,所以效率不是很高。
  2. 不是同一个 = off-policy,就像agent在旁边看另一个环境。比如Q learning / Deep Q network
    a. 策略theta’固定,重复采样。通过theta’的数据去更新theta,由于两者分布不一样,所以需要乘以对应的权重。
    在这里插入图片描述
    b. 为了避免策略theta‘和theta差太多,在损失函数中加入正则项,计算theta’和theta的KL散度,保证两者的分布不要相差太大。
    在这里插入图片描述

随机性策略/确定性策略

随机性策略指的是:输出动作的概率分布,最终动作需要根据概率进行采样。比如PG,PPO,SAC

确定性策略指的是:输出的就是动作本身,没有概率。比如DPG,DDPG

在强化学习的发展过程中,经历了随机性 -> 确定性 -> 随机性的螺旋上升过程。

  1. 在1990-2000,基础的随机性策略就被提出,比如PG,但是无法解决连续动作空间问题,因为对于高维连续动作空间,想要采样到正确的值非常难。
  2. 在2014年,出现了DPG,用确定性策略输出连续动作,改良后的DDPG依然饱受训练不稳定,探索能力差,难复现的困扰。
  3. 在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)采样轨迹回报,直接优化策略函数,通过梯度下降法最大化累计回报。

优势:没有使用价值函数,所以避免了价值函数估计的偏差和方差。

问题:

  1. 方差大。由于奖励方差大,环境随机性,策略随机性(策略采样得到)导致。方差大导致:
    a. 梯度更新方向/大小波动,训练不稳定。
    b. 低样本效率,需要大量轨迹才能获得准确的优化方向。
    c. 收敛缓慢,容易陷入震荡和局部最优。
  2. 步长难以确定。步长大了震荡,小了收敛慢

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网络的。

  1. 动作采样和奖励计算:采样多个用同一个输入状态和同一个策略网络,通过调整温度系数或调整随机种子,从而获得不同的输出,形成一组多个动作和奖励。
  2. 优势估计:对组内奖励进行归一化,得到相对优势(Relative Advantage),以缓解奖励尺度敏感问题。
  3. 策略更新:根据归一化后的优势,通过策略梯度算法更新策略网络参数,强化生成高优势动作的策略。

4 Value-based method

4.1 分类

基于价值函数的方法可以分为非深度学习的方法和深度学习的方法。

价值函数可以分为动作价值函数Q状态价值函数V

  1. 状态价值函数state value function V(s),输入环境s,输出预期收益。
  2. 动作价值函数Q(a),输入环境s和动作a,输出预期收益。V相当于Q的期望,或者说V是Q的加权平均

a. 预期收益和场景相关。比如星球大战游戏,很多敌人的话,critic会输出很大的值,因为如果杀掉它们可能拿很多分。

  1. 状态动作价值函数state-action value function Q(s,a),表征累积奖励的期望。输入环境s和对应的行为a,才能输出收益。反过来说,给定s,可以得到不同a的价值 Q。那么可以通过xx办法找到更好的策略(更好指的是V_pi’ >= V_pi),从而提升Q。
  2. 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. 解决训练不稳定的问题。如果只有1个Q网络,这个Q网络既负责y=r+maxQ_t+1,又要负责预测当前的Q,所以就像在打一个移动的靶,不方便学习。如果能固定目标Q,那么就会提升稳定性。

目标Q网络的更新方式:

  1. 每隔一段时间更新为当前的Q
  2. 采用滑动平均缓慢更新

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都使用旧策略的数据,但是区别是:

  1. DQN使用replay buffer存储旧策略,然后从buffer中提取一个batch来更新
  2. 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解决过估计

  1. DQN的Q存在过估计问题,常常高估会得到的reward。Q value is usually over-estimated.
  2. 所以选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.
  3. 其核心思想类似于行政和立法相互独立。Q’相当于提案,Q相当于执行。

在后续介绍的SAC算法中,SAC使用双Q网络,选择更小的价值作为最终价值,也是用来解决过估计问题的。

4.3.2 Prioritized Reply

  1. 传统DQN是从buffer中随机采样,对模型进行训练。问题是有些数据比较简单,有些数据比较难(TD error更大)
  2. TD error指的是Qt 和 rt + Qt+1的差
  3. prioitized reply的思想是TD error更大的数据,有更高的概率被采样到。

4.3.3 Noise Net

  1. 之前的加噪声方法是epsilon greedy,在输出动作的时候有epsilon的概率去采取随机行为。
  2. 但是epsilon greedy的方法并不真实 No real policy works in this way,因为这导致同样的state,输出动作不一样。
  3. 因此考虑在Q模型中加噪声,在一轮episode中保持不变。这样state一致时,agent输出的行为就是一样的了,能够explore in a consistent way

5 Actor-critic method

actor-critic可以分为确定性策略随机性策略

  1. 确定性策略指的是输入状态s,输出一个单一的动作a,没有随机性没有概率分布
  2. 随机性策略指的是输入状态s,输出概率分布。

5.0 actor-critic

来历:actor的前身是policy net,是基于回合更新的,而且是on-policy,学习效率低,且reward方差大,如果用value-based的critic,每步输出价值,那么就可以实现单步更新,且更稳定,两者互补的到actor-critic

在这里插入图片描述

5.0.1 缺点:收敛慢

2点原因导致:

  1. critic本身以蒙特卡洛或者TD error为真值目标,它们波动大,所以critic难收敛
  2. critic和actor互相制约,一起更难收敛。

5.0.2 优点:单步更新

因为每步都有critic的输出,因此可以更新。而不用等到回合结束再更新。

注意:actor-critic并不是动作空间无限的,actor可以是有限的,也可以是无限的。比如DDPG就是动作空间无限的。

5.1 actor相关

  1. 给定theta,让actor进行一次episode,会达到一个序列的观测s/行为a/奖励r。其中,奖励之和为R_theta
    在这里插入图片描述
  2. 因为模型输出的随机性和场景的随机性,R_theta并不是固定的,因此目标不是最大化R_theta,而是最大化R_theta的期望
  3. R_theta的期望是轨迹的概率==P(tao | theta)乘以该轨迹的奖励R(ta0)==之和。
  4. 穷举所有可能性是不现实的,因此可以采用同一个策略进行N次,N次的平均结果就是期望。
    在这里插入图片描述
  5. 采用梯度上升gradient ascent的方法,最大化期望奖励。但是在实现的时候,是最小化 -期望奖励
  6. 最小化 -期望奖励,需要对奖励对theta求偏导。因为R(tao)不含theta,所以可以当成常数。这也解释了为什么可以用RLHF,人类反馈的奖励是没有梯度的。

在这里插入图片描述

在这里插入图片描述

5.2 确定性策略Actor-Critic

确定性策略方法是为了解决随机性策略方法的效率低方差大的问题。

5.2.0 随机性策略方法的问题

  1. 效率低。在连续动作空间中,尤其是高维的连续动作空间中,正确的动作范围非常小,选中概率很低,需要大量采样才能碰到好动作。
  2. 方差大。就算探索到好动作,在下一次增大其概率后,依然有较大概率采样到坏动作,那样训练不稳定,方差大。

这个过程就像大海(高维连续动作空间)捞针(找到最优动作),就算知道了方向,也会去探索其他方向。

因此,考虑不输出动作概率,直接输出动作,并且让critic告诉actor动作的优化方向,即确定性策略。

确定性(deterministic)策略一般包含DPG,DDPG

5.2.1 DPG=Actor-Critic 框架+确定性策略+基于∇Q的梯度

DPG的actor直接输出动作a=μ(s),不输出概率分布。即确定性策略。

critic输出∇Q,而不是输出Q。
因为没有概率分布,所以无法计算log概率梯度,所以只能去获取信息:稍微改变动作,Q会变大还是变小,即∇Q。

  1. 输出Q可理解为:告诉actor要当前动作能获得多少回报;
  2. 输出∇Q可理解为:告诉actor要沿什么方向优化才可以。

DPG的优势:

  1. 高效。不会像随机性策略一样需要探索非常多的动作;
  2. 方差低。输出确定性的动作。

DPG的劣势:

  1. 训练不稳定。actor-critic架构,互相耦合,任意一方出错就会导致训练发散;
  2. 探索能力弱。无法像随机性策略一样探索不同的动作,需要额外加噪等方法;
  3. 容易陷入局部最优。一旦通过critic收敛到局部最优位置,很难跳出去。

注意:DPG只是一套理论框架,并不要求actor和critic是神经网络,也可以是线性模型等,只要可以进行函数逼近即可。这也为下一步D(deep)DPG的出现埋下伏笔。

5.2.2 DDPG=DPG+DQN技巧(经验回放,目标网络)

DDPG, deep deterministic policy gradient,将深度神经网络,和DQN的经验回放,目标网络技术引入。

  1. 引入DQN的经验回放,形成off-policy策略,提高样本利用效率;
  2. 引入DQN的目标Q网络,避免Q输出价值的方差过大,提高训练稳定性
  3. DQN只能处理离散动作空间,无法处理连续动作空间(比如油门刹车),DDPG能够处理连续动作空间。

DDPG的优势:

  1. 连续动作空间,继承于DPG
  2. 样本效率高,继承于DQN的经验回放
  3. 训练比DPG稳定一些,因为有目标Q网络

DDPG的劣势:

  1. 过估计。和DQN一样,因为总是在选取最大的Q(s,a),导致对最大值的高估,使模型学到错误的价值。
  2. 训练仍然不够稳定。
  3. 探索能力弱。输出确定性的动作,无法有效探索到其他可能。

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。
注意:

  1. 这样子可以省掉一个Q网络
  2. 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,提供一个优化方向,然后更新全局模型。就像火影忍者里的鸣人开影分身学螺旋丸。

需要注意的是:

  1. A2C可以并行,可以不并行。但是典型实现是并行,因为和环境交互很耗时,所以并行能够提高训练速度。
  2. 每个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(atst)πθ(atst)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的。

举例如下:

  1. 先定义策略网络
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
  1. 用策略进行采样
while not done:
	...
	with torch.no_grad():
		action, _, _ = policy.sample() # 采集的数据是不需要梯度的
	
  1. 计算重要性
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

  1. 收集人类反馈 collect human/ai feedback to learn p(yw > yl)
  2. RLHF的目标中有3个model(actor model / ref model / reward model)

在这里插入图片描述

  1. 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的

  1. 采用随机性策略,提高探索能力
  2. 引入最大熵框架,鼓励探索
  3. 引入双Q网络,抑制过估计问题。其中是Q网络有2个,目标Q网络有2个。

因此,SAC包含3类网络5个网络:

  1. actor x 1
  2. critic(Q网络)x 2
  3. 目标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先回归短序列,在学习回归长序列,被验证效果会更好。

  1. Given a goal state sg
  2. sample some states s1 close to sg
  3. delete s1 whose reward is too large (already learned) or too small (too difficult to learn)
  4. 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,再学习策略。

  1. 通过expert demonstration,使用IRL反推reward function
  2. 通过学习到的reward function,使用RL训练得到actor

IRL训练得到的reward function比较简单,但是依然可以得出复杂的策略。就像《三体》中的黑暗森里法则,三条就能够决定宇宙中高等智慧生物的生存方法。

7.1 具体步骤

  1. expert玩游戏得到轨迹tao_hat
  2. actor玩游戏得到轨迹tao
  3. 优化reward function,使得reward(tao_hat) > reward(tao)。The expert is always the best.
  4. 根据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,样本效率高。而且开源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值