【PPO】近端策略优化【Clip版本,离散动作】

本博客代码参考了《动手学强化学习-PPO》

PPO算法是在Actor-Critic的基础上进行训练目标的调整。其改进的地方在于对每次参数更新进行了限制。

PPO 是 TRPO 的一种改进算法,它在实现上简化了 TRPO 中的复杂计算,并且它在实验中的性能大多数情况下会比 TRPO 更好,因此目前常被用作一种常用的基准算法。需要注意的是,TRPO 和 PPO 都属于在线策略学习算法,即使优化目标中包含重要性采样的过程,但其只是用到了上一轮策略的数据,而不是过去所有策略的数据。



PPO

策略网络定义

import torch.nn as nn
import torch.nn.functional as F

class PolicyNet(nn.Module):
	def __init__(self, state_dim, hidden_dim, action_dim):
		super(PolicyNet, self).__init__()
		self.fc1 = nn.Linear(state_dim, hidden_dim)
		self.fc2 = nn.Linear(hidden_dim, action_dim)

	def forward(self,x):
		x = F.relu(self.fc1(x))
		return F.softmax(self.fc2(x),dim=1)

可以看到PPO算法中的策略网络输出的是对应的动作概率,从最后一行代码中可以识别出F.softmax(self.fc2(x),dim=1)

价值网络定义

import torch.nn as nn
import torch.nn.functional as F

class ValueNet(nn.Module):
	def __init__(self, state_dim, hidden_dim):
		super(ValueNet, self).__init__()
		self.fc1 = nn.Linear(state_dim, hidden_dim)
		self.fc2 = nn.Linear(hidden_dim, 1)

	def forward(self,x):
		x = F.relu(self.fc1(x))
		return self.fc2(x)

PPO算法与Actor-Critic算法一样,其价值网络仅用来进行价值估计。所以其最后的输出的维度是一维,从self.fc2 = nn.Linear(hidden_dim, 1)可以看出

PPO算法整体结构

class PPO:
	def __init__(self, state_dim, hidden_dim, action_dim,actor_lr, critic_lr, gamma, lmbda, epochs, eps, device):
		self.actor = PolicyNet(state_dim, hidden_dim, action_dim)
		self.critic = ValueNet(state_dim, hidden_dim)
		self.actor_optimizer = torch.optim.Adam(lr = actor_lr)
		self.critic_optimizer = torch.optim.Adam(lr = critic_lr)
		self.device = device
		self.eps = eps
		self.lmbda = lmbda
		self.epochs

	def take_action(state):
		state = torch.tensor([state].dtype=torch.float).to(self.device)
		probs = self.actor(state)
		action_dist = torch.distributions.Categorical(x)
		action = action_dist.sample()
		return action.item()

	def update(self,transition_dict):
		states = torch.tensor(transition_dict['satats'],dtype=torch.float).to(self.device)
		actions torch.tensor(transition_dict['actions']).view(-1,1).to(self.device)
		rewards = torch.tensor(transition_dict['rewards'],dtype=torch.float).view(-1,1).to(self.device)
		next_states = torch.tensor(transition_dict['next_states'],dtype=torch.float).to(self.device)
		dones = torch.tensor[transition_dict['dones'],dtype=torch.float).view(-1,1).to(self.device)

		# 计算td target
		td_target = rewards + self.gamma*self.critic(next_states)
		td_delta = td_target - self.critic(states)
		advantages = rf_utils(self.gamma, self.lmbda, td_delta.cpu()).to(self.device))
		old_log_probs = torch.log(self.actor(states).gather(1,actions)).detach() # 参数更新之后,就不是当前策略的函数了,所以要进行detach()进行梯度截断
		for _ in range(self.epochs):
			log_probs = torch.log(self.actor(states).gather(1,actions))
			ratio = torch.exp(log_probs - old_log_probs)
			surr1 = ratio*advantages
			surr2 = torch.clamp(ratio, 1 -self.eps, 1+self.eps)*advantages
			actor_loss = torch.mean(-torch.min(surr1, surr2))
			critic_loss = torch.mean(torch.mse_loss(self.critic(states), td_target.detach()))
			self.criti_optimizer.zero_grad()
			self.actor_optimizer.zero_grad()
			actor_loss.backward()
			critic_loss.backward()
			self.critic_optimizer.step()
			self.actor_optimizer.step()
		

参数更新

PPO算法相比于Actor-Critic在参数更新部分有两个重要的调整:1. 近端策略优化; 2. 重要性采样

截断

PPO 的另一种形式 PPO-截断(PPO-Clip)更加直接,它在目标函数中进行限制,以保证新的参数和旧的参数的差距不会太大,即:
arg ⁡ max ⁡ θ E s ∼ ν E a ∼ π θ k ( ⋅ ∣ s ) [ min ⁡ ( π θ ( a ∣ s ) π θ k ( a ∣ s ) A π θ k ( s , a ) , clip ⁡ ( π θ ( a ∣ s ) π θ k ( a ∣ s ) , 1 − ϵ , 1 + ϵ ) A π θ k ( s , a ) ) ] \arg\max_{\theta}\mathbb{E}_{s\sim\nu}\mathbb{E}_{a\sim\pi_{\theta_{k}}(\cdot|s)}\left[\min\left(\frac{\pi_{\theta}(a|s)}{\pi_{\theta_{k}}(a|s)}A^{\pi_{\theta_{k}}}(s,a),\operatorname{clip}\left(\frac{\pi_{\theta}(a|s)}{\pi_{\theta_{k}}(a|s)},1-\epsilon,1+\epsilon\right)A^{\pi_{\theta_{k}}}(s,a)\right)\right] argmaxθEsνEaπθk(s)[min(πθk(as)πθ(as)Aπθk(s,a),clip(πθk(as)πθ(as),1ϵ,1+ϵ)Aπθk(s,a))]
其中 clip ⁡ ( x , l , r ) : = max ⁡ ( min ⁡ ( x , r ) , l ) \operatorname{clip}(x,l,r):=\max(\min(x,r),l) clip(x,l,r):=max(min(x,r),l) ,即把 x \text{x} x 限制在 [ l , r ] [l,r] [l,r] 内。上式中是一个超参数,表示进行截断(clip)的范围。

如果 A π θ k ( s , a ) > 0 A^{\pi_{\theta_{k}}}(s,a)>0 Aπθk(s,a)>0,说明这个动作的价值高于平均,最大化这个式子会增大 π θ ( a ∣ s ) π θ k ( a ∣ s ) \frac{\pi_{\theta}(a|s)}{\pi_{\theta_{k}}(a|s)} πθk(as)πθ(as),但不会让其超过 1 + ϵ 1+\epsilon 1+ϵ。反之,如果 A π θ k ( s , a ) < 0 A^{\pi_{\theta_{k}}}(s,a)<0 Aπθk(s,a)<0,最大化这个式子会减小 π θ ( a ∣ s ) π θ k ( a ∣ s ) \frac{\pi_{\theta}(a|s)}{\pi_{\theta_{k}}(a|s)} πθk(as)πθ(as) ,但不会让其超过$1-\epsilon $。如下图所示

在这里插入图片描述
代码surr2 = torch,clamp(ratio, 1- self.eps, 1+ self.eps)*advantages 和 代码actor_loss = torch.mean(- torch.min(surr1, surr2))提现了截断的思想

重要性采样

PPO中使用了重要性采样,从而一定程度上缓解了样本使用效率低的问题,提高了单次样本参与模型参数训练的次数。重要性采样的公式推导,与蒙特卡洛的近似分布有关。尽管重要性采样允许PPO算法使用单轮样本进行多次训练,但是PPO算法更偏向于 on-policy参考博客
代码ratio = torch.exp(log_probs - old_log_probs)其中的ratio就是重要性采样因子,通过该因子,从而调整出新策论与旧策略的分布差异。

在线训练

def train_on_policy_agent(agent, env, num_episodes):
	return_list = []
	for i in range(10):
		with tqdm(total = int(num_episodes/10),desc='Iteration %d':% i) as pbar:
			for i_episode in range(int(episode/10)):
				state = env.reset()
				transition_dict = {'states':[],'actions':[],'next_state'=[],'rewards':[],'dones':[]}
				episode_return = 0
				done = False 
				while not done:
					action = agent.take_action(state)
					next_state,reward, done, _ = agent.take_action(state)
					transition_dict['states'].append(state)
					transition_dict['actions'].append(action)
					transition_dict['next_states'].append(next_state)
					transition_dict['rewards'].append(reward)
					transition_dict['dones'].append(done)
					state = next_state
					episode_return += reward
				return_list.append(episode_return)
				agent.update(transition_dict)
				if (i+i_episode)%10 == 0:
                    pbar.set_postfix({'episode': '%d' % (num_episodes/10 * i + i_episode+1), 'return': '%.3f' % np.mean(return_list[-10:])})
				bar.update(1)
	return return_list

由于PPOon-policy类型的强化学习,所以训练PPO参数需要使用在线策略学习方式,即每次与环境交互一轮之后,就要根据交互收集到的轨迹transition进行一次参数更新,体现在代码agent.update(transition_dict

一些概念

在这里插入图片描述

  • Q-learning、DQN 及 DQN 改进算法都是基于价值(value-based), 他们通过选择最大价值动作来与环境交互

  • Actor-Critic 结合了两者的特点,Reinforce 作为 Actor 部分, DQN 作为 Critic 部分,从而结合了两者的有点

  • Reinforce、Actor-Critic 通过 SARSA 样本数据进行训练,所以他们是 on-policy基于策略,也就是学习一个策略,从策略中进行动作概率分布抽样

  • REINFORCE 算法基于蒙特卡洛采样,只能在序列结束后进行更新, Actor-Critic 算法则可以在每一步之后都进行更新,并且不对任务的步数做限制。

  • TRPO 是在 Actor-Critic 的基础上加入了更新幅度限,也就是制信任区域(trust region),从而避免模型效果的震荡。

  • PPO 是 TRPO 的改良版, 基于 TRPO 的思想,但是 PPO算法实现更加简单,没有TRPO 的计算那么复杂和远算量那么大。

  • PPO 有两种形式,一是 PPO-惩罚,二是 PPO-截断,

  • PPO-截断总是比 PPO-惩罚表现得更好, 大量实验表明。

  • REINFORCE、Actor-Critic 以及两个改进算法——TRPO 和 PPO, 这类算法有一个共同的特点:它们都是在线策略算法,这意味着它们的样本效率(sample efficiency)比较低。

  • TRPO(trust region policy optimization,TRPO)。当策略网络是深度模型时,沿着策略梯度更新参数,很有可能由于步长太长,策略突然显著变差,进而影响训练效果。针对这个问题,考虑在更新时找到一块信任区域(trust region),在这个区域上更新策略时能够得到某种策略性能的安全性保证,这就是信任区域策略优化(trust region policy optimization,TRPO)算法的主要思想。TRPO 算法在 2015 年被提出,它在理论上能够保证策略学习的性能单调性,并在实际应用中取得了比策略梯度算法更好的效果。

  • Policy Base 与 Value Base

    • Policy-Base (基于策略) 通过环境,直接输出下一步要采取的各种动作的概率,然后根据概率采取行动,所以每种动作都有可能被选中,只是可能性不同。如,Policy Gradients等。
    • Value-Based RL(基于价值)
      输出所有动作的价值,根据最高价值来选择动作。如,Q learning 、DQN等。(对于不连续的动作,这两种方法都可行,但如果是连续的动作基于价值的方法是不能用的,我们只能用一个概率分布在连续动作中选择特定的动作)。
    • Actor-Critic (主要基于策略,价值作为辅助)
      结合这两种方法建立一种Actor-Critic的方法,基于概率会给出做出的动作,基于价值会对做出的动作进行评分,是二者的综合,但更偏向于策略模型领域。
  • on-policy 与 off-policy 的异同点。 无论是在线策略(on-policy)算法还是离线策略(off-policy)算法,都有一个共同点:智能体在训练过程中可以不断和环境交互,得到新的反馈数据。二者的区别主要在于在线策略算法会直接使用这些反馈数据,而离线策略算法会先将数据存入经验回放池中,需要时再采样

  • Model-Based和Model-Free 是关于如何对环境建模和学习的方法。Model-Based建立模型,Model-Free直接学习策略或价值函数。

  • Q-learning 与 Sarsa

    • 为什么 Q learning 能够使用Exprience replay 而 Sarsa 不能使用Exprience replay。 Q-learning的目标是求解“真正”的 Q ∗ ( s , a ) Q^{*}(s,a) Q(s,a) ,而Sarsa的目标则是求解 Q π ( s , a ) Q_\pi(s,a) Qπ(s,a) 。在Q-learning中,我们一般会采用experience replay技术,即准备一个数据库并不断把Agent新产生的 ( s , a , r , s ′ ) (s,a,r,s^{\prime}) (s,a,r,s) 数据集存入数据库中。我们每次会从数据库中随机抽取一个batch的数据集用以训练,这意味着每次训练时我们用到的数据集可能是Agent在很久以前产生的。但是,无论我们用到的数据是Agent在训练中的哪一个阶段产生的,数据都是服从环境分布的,所以它们当然都可以被用以训练。
    • Sarsa 类型为什么是 on-policy 在线策略学习。 在Sarsa中,情况则与Q-learning很不一样。对于 ( s , a , r , s ′ , a ′ ) (s,a,r,s',a') (s,a,r,s,a) 的训练数据集,我们不但要求 ( r , s ′ ) (r,s^{\prime}) (r,s) 应该服从环境分布,也要求 a ′ a^{\prime} a 必须服从 π \pi π 关于 s ′ s^{\prime} s 的条件分布。在训练中,Q表的内容会不断被改变,所以Agent产生数据的策略 也会不断被改变。这意味在Agent过去产生的 ( s , a , r , s ′ , a ′ ) (s,a,r,s',a') (s,a,r,s,a) 中, ( s ′ , a ′ ) (s^{\prime},a^{\prime}) (s,a) 可能不服从现在策略 π \pi π 对应的条件分布,因此Agent在过去产生的数据就不能用以现在的训练。 由于上述的原因,我们不能在Sarsa中采用experience replay。在训练中,设当前Agent产生数据的策略为 π \pi π 。我们可以一次性用Agent产生大量服从环境及 π \pi π 分布的数据,并用这些数据来进行训练。而训练过后,Q表的内容发生了变化,这意味着Agent产生数据的策略变成了与 π \pi π 不同的 π ′ \pi^{\prime} π 。这时,刚才那些服从环境与 π \pi π 分布的 ( s , a , r , s ′ , a ′ ) (s,a,r,s',a') (s,a,r,s,a) 数据就变得不再有价值,我们只能将其丢弃。接下来,我们就要让Agent用当前产生数据的策略 继续产生大量的数据,并进行下一步的训练。
  • off-line (离线学习)的应用场景。 在现实生活中的许多场景下,让尚未学习好的智能体和环境交互可能会导致危险发生,或是造成巨大损失。例如,在训练自动驾驶的规控智能体时,如果让智能体从零开始和真实环境进行交互,那么在训练的最初阶段,它操控的汽车无疑会横冲直撞,造成各种事故。再例如,在推荐系统中,用户的反馈往往比较滞后,统计智能体策略的回报需要很长时间。而如果策略存在问题,早期的用户体验不佳,就会导致用户流失等后果。因此,离线强化学习(offline reinforcement learning)的目标是,在智能体不和环境交互的情况下,仅从已经收集好的确定的数据集中,通过强化学习算法得到比较好的策略。

  • Reinforce 基于蒙特卡洛采样,只能在序列结束后进行更新,这同时也要求任务具有有限的步数,而 Actor-Critic 算法则可以在每一步之后都进行更新,并且不对任务的步数做限制。这是因为没有价值网络,所以他无法对当下状态的价值进行直接估计,只能通过蒙特卡洛采样进行逆向奖励累积。而Actor-Critic 由于有价值网络,所以可以直接通过计算前后状态和奖励的差值来计算时序误差。当然Actor-Critic也可以采用蒙特卡洛采样,不过这种方法需要更多的计算量


https://blog.csdn.net/qq_45889056/article/details/130297960
https://zhuanlan.zhihu.com/p/166412379
https://blog.csdn.net/qq_45889056/article/details/130297960

  • 10
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值