1.基于策略的算法
1.1基于价值的算法(如DQN)的缺点:
1.无法表示连续动作,DQN需要对某个状态下的每个动作打分,因此它们只能处理离散动作空间的问题,无法表示连续动作空间的问题。
2.高方差:基于价值的方法通常都是通过采样的方式来估计价值函数,这样会导致估计的方差很高,从而影响算法的收敛性。
3.探索与利用的平衡问题。虽然可以通过 ϵ-greedy 策略等方式来实现一定程度的随机策略,但是实际上这种方式并不是很理想,因为它并不能很好地平衡探索与利用的关系。
1.2策略梯度算法
这被称作迹,智能体不断与环境交互,从s0做出动作a0,然后会到状态s1,再做出动作a1.....直到状态终止。
.
代表在s0状态下做出a0动作的概率。因此形成一个迹的概率可以被表述为:
我们应该如何去判断某个策略的好坏呢?可以用通过它选出的迹的累计回报的期望来估计。
设初始状态下取每一条迹的概率(实际上加起来为1)以及这条迹上智能体收到的累计回报的和,因为是一个概率乘积相加的形式,可以写成期望形式:
现在我们需要求梯度再通过梯度下降来使得这个价值期望更大,这样取得的策略就更好,求得的梯度经过一系列的数学推导可以写成这种形式: 写成这种形式有什么好处呢?
因为分离出了一个,这是对迹的积分,根据概率论的公式,分离出一个就可以写成期望的形式了:
(是在st状态下取动作at的概率,log外面的累加放里面就是累乘了)。分离出期望的形式后我们就可以对很多的迹进行采样(大数定律)来求梯度的期望了。经典的REINFORCE算法就是对N个迹进行采样,再对梯度进行取平均。
DQN是对每个动作进行打分,决策的时候取最大分数的动作,更新网络的目的是为了让打分更精准,但是在优化打分的过程很容易出现一步错步步错,也就是高方差。与DQN不同,基于策略的方法机器直接改变自己的决策,优化网络的目的是为了让策略更好,这样不会出现打分的误差,而且机器可以结合自己的经验去探索。
1.3确定性策略和随机性策略
确定性策略:在给定状态下,确定性策略总是输出同一个动作。这意味着如果你两次处于同样的状态,策略会两次推荐同样的动作。典型算法:DDPG,TD3。
它们都是基于actor-critic框架的。需要注意的是这里Actor的action-dim和DQN中的action-dim不同:
这里针对的是连续动作空间,输出的是一个特定的动作,action-dim代表动作的维度,他的网络更新是往critic的打分更大的方向走的。
DQN应用的是离散动作空间,action-dim代表所有可取动作的数量,这个向量每个动作维度的值代表对应动作的q值,选取动作是在q值最大的里面选的。
这是TD3和DDPG的Actor网络框架:
class Actor(nn.Module):
def __init__(self, state_dim, action_dim, max_action):
super(Actor, self).__init__()
self.l1 = nn.Linear(state_dim, 256)
self.l2 = nn.Linear(256, 256)
self.l3 = nn.Linear(256, action_dim)#action_dim代表动作的维度
self.max_action = max_action
def forward(self, state):
a = F.relu(self.l1(state))
a = F.relu(self.l2(a))
return self.max_action * torch.tanh(self.l3(a))#tanh输出[-1,1]的值进行归一化
这是DQN的网络框架,用于对比:
class MLP(nn.Module):
def __init__(self,state_dim,action_dim,hidden_dim=128):
super(MLP,self).__init__()
self.fc1=nn.Linear(state_dim,hidden_dim)
self.fc2=nn.Linear(hidden_dim,hidden_dim)
self.fc3=nn.Linear(hidden_dim,action_dim)#action_dim是动作的数量,不是维度
def forward(self,x):
x=F.relu(self.fc1(x))
x=F.relu(self.fc2(x))
return self.fc3(x)
随机性策略:在给定状态下,随机性策略输出一个动作的概率分布。这意味着即使在同样的状态下,策略可能推荐不同的动作。典型算法:PPO,REINFORCE
如何应用随机性策略呢?可以通过softmax层来输出一个概率分布,也可以通过神经网络直接输出各个动作的概率。
2.A2C&&A3C
2.1Actor-critic
Actor-Critic结合了值函数方法和策略梯度方法的优点。在这种框架中,"Actor"负责根据当前的策略选择动作,而"Critic"评估所采取动作的价值。Critic通过TD误差(Temporal Difference Error)给出价值函数的更新信号(更新价值函数方式各有不同,但目的都是为了让打分更精准),而Actor则根据Critic的反馈来优化其策略。这种结构允许连续学习和策略改进,适用于复杂的环境和连续的动作空间。
根据上面策略梯度的推导,策略的更新可以这样表述
,更新的依据是为了让critic打分更大。(s和a都作为critic的输入,一般是将s和a的向量并联了一下)
2.2A2C(Advantage Actor-Critic)
比起Actor-Critic算法,它使用了优势函数(Advantage function)来替代Critic部分中的值函数,优势函数用于评估一个动作相对于平均动作的优势程度。Q值实际上可以分解为两部分,即Q(s,a)=A(s,a)+V(s)。其中A(s,a)即为优势函数,评价的是在给定状态下当前选定动作相较于其他动作的好坏,它可以通过采样数据计算得出。这种做法其实和 Duelling DQN 算法很像
Duelling DQN 是把中间层分成了价值层和优势层最后求和得到q:
而A2C算法的核心就在于让critic学习而不再是学习Q(s,a)。
下面是A2C的网络框架,注意critic返回的是,而且actor输出的不再是最大q值的动作,而是一个动作的概率分布。
class ActorCritic(nn.Module):
''' A2C网络模型,包含一个Actor和Critic
'''
def __init__(self, input_dim, output_dim, hidden_dim):
super(ActorCritic, self).__init__()
self.critic = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, 1)
)
self.actor = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, output_dim),
nn.Softmax(dim=1),
)
def forward(self, x):
value = self.critic(x)
probs = self.actor(x)
return probs, value # 返回动作概率分布和价值
那这里的Q(s,a)是如何确定的呢?通过一个轨迹reward的采样学习:
A2C解决了高方差的问题,但是稳定性差,样本效率低,而且超参数敏感(强化学习算法的通病),还有较大提升空间。
2.3A3C(Asynchronous Advantage Actor-Critic)
A2C相当于使用一个全局网络,通过与环境的交互进行连续更新。而改进后的算法A3C引入了多个并行进程,每个进程都拥有独立的网络和环境,使它们可以并行地与环境交互。每个进程定期将自身的参数同步到全局网络中,从而提高了训练效率。这种训练模式是一种常见的多进程训练方式,不仅适用于A2C算法,还可以应用于其他算法,包括基于价值的算法。这样的改进有助于充分利用计算资源,加速学习过程,但是对计算资源的消耗更大。