24/11/12 算法笔记<强化学习> Policy Gradient策略梯度

gradient的核心就是每次更新前要重新收集,每个阶段的actor是不一样的.

策略梯度算法的核心思想:

  1. 策略表示:首先,策略梯度方法需要一个策略,该策略能够根据当前的状态选择一个动作。这个策略通常由一个参数化的函数表示,例如一个神经网络。

  2. 梯度上升:算法通过梯度上升方法来优化策略的参数,使得期望回报最大化。梯度上升的方向是梯度的反方向,因为我们要最大化回报。

  3. 采样:在策略梯度方法中,智能体(Agent)会与环境交互,根据当前策略采样一系列的状态-动作对。

  4. 计算梯度:对于采样得到的数据,算法会计算策略参数相对于期望回报的梯度。这个梯度可以通过蒙特卡洛方法或者时间差分学习(Temporal Difference Learning, TD)来估计。

  5. 参数更新:最后,算法根据计算出的梯度来更新策略的参数。

策略梯度算法的关键步骤:

  1. 初始化:选择一个初始策略参数(通常是随机的),并初始化一些必要的变量。

  2. 交互:智能体根据当前策略与环境交互,收集状态-动作-奖励的样本。

  3. 计算回报:对于每个采样的样本,计算其回报。在策略梯度中,这通常是通过折扣回报来完成的。

  4. 估计梯度:对于每个样本,估计策略参数相对于该样本回报的梯度。

  5. 更新策略:使用梯度上升方法更新策略参数。

  6. 重复:重复步骤2-5,直到策略收敛或达到一定的迭代次数。

θ是Policy Gradient中模型的参数,给定一组模型参数它去玩n次游戏,一整把游戏的所有state、action和reward我们统称为τ 。τ 作为训练资料被收集起来训练一次模型,参数被update之后,再次去玩游戏,收集数据,之后更新模型。直至模型收敛为止。

如果先不考虑R ( τ^n ) 将每一个state都输入到network里面,整个训练过程就可以被视作是分类问题。这个式子,在 的情况下,采取 会得到高分,所以我们希望出现这个情况的概率越大越好。

而乘上R ( τ^n ) 的话,其实就是将得到的Reward当作是一个系数,放大得到高分Reward的τ 的概率。所以其实整个Policy Gradient并不是模型端有什么新的改进,甚至可以用之前常见的分类网络来做这个事情,它是一个强化学习的训练思路。

我们来看一下它的代码

import torch
import torch.nn as nn
import torch.optim as optim #优化器
import torch.distributions as dist #分布模块
import numpy as np

# 定义策略网络
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 = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return torch.softmax(x, dim=-1)

# 定义策略梯度算法
class PolicyGradient:
    def __init__(self, state_dim, hidden_dim, action_dim, learning_rate, gamma, device):
        self.policy_net = PolicyNet(state_dim, hidden_dim, action_dim).to(device)
        self.optimizer = optim.Adam(self.policy_net.parameters(), lr=learning_rate)
        self.gamma = gamma
        self.device = device
    
    def take_action(self, state):
        state = torch.tensor([state], dtype=torch.float).to(self.device)
        probs = self.policy_net(state)
        action_dist = dist.Categorical(probs)
        action = action_dist.sample()
        return action.item()
    
    def update(self, transition_dict):
        states = torch.tensor(transition_dict['states'], dtype=torch.float).to(self.device)
        actions = torch.tensor(transition_dict['actions'], dtype=torch.int).to(self.device)
        rewards = torch.tensor(transition_dict['rewards'], dtype=torch.float).to(self.device)
        
        # 计算折扣回报
        G = 0
        returns = []
        for r in rewards[::-1]:
            G = r + self.gamma * G
            returns.insert(0, G)
        
        returns = torch.tensor(returns).to(self.device)
        
        # 梯度上升
        self.optimizer.zero_grad()
        for i in range(len(states)):
            state = states[i]
            action = actions[i]
            log_prob = torch.log(self.policy_net(state)[action])
            loss = -log_prob * returns[i]
            loss.backward()
        self.optimizer.step()

# 主函数
def main():
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    state_dim = 4  # 状态空间维度
    hidden_dim = 128  # 隐藏层维度
    action_dim = 2  # 动作空间维度
    learning_rate = 0.01  # 学习率
    gamma = 0.99  # 折扣因子
    num_episodes = 1000  # 训练回合数
    
    agent = PolicyGradient(state_dim, hidden_dim, action_dim, learning_rate, gamma, device)
    
    for episode in range(num_episodes):
        state = env.reset()
        done = False
        rewards = []
        states = []
        actions = []
        
        while not done:
            action = agent.take_action(state)
            next_state, reward, done, _ = env.step(action)
            rewards.append(reward)
            states.append(state)
            actions.append(action)
            state = next_state
        
        # 将回合数据打包成字典
        transition_dict = {
            'states': states,
            'actions': actions,
            'rewards': rewards
        }
        
        # 更新策略
        agent.update(transition_dict)

if __name__ == "__main__":
    main()

我们来分析每段代码

1.定义策略网络

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 = torch.relu(self.fc1(x)) #这行代码将输入数据 x 通过第一个全连接层 fc1,然后应用ReLU激活函数。ReLU函数可以增加非线性,并且有助于解决梯度消失问题。

        x = self.fc2(x) #这行代码将经过ReLU激活的输出作为第二个全连接层 fc2 的输入。

        return torch.softmax(x, dim=-1)

层这样分布的好处包括:

  • 简单性:这个网络结构非常简单,易于实现和理解。
  • 灵活性:通过调整 hidden_dim 的大小,可以灵活地控制网络的容量。
  • 非线性:ReLU激活函数引入非线性,使得网络可以学习复杂的状态-动作映射关系。
  • 概率输出:softmax输出使得网络可以直接预测每个动作的概率,这对于强化学习中的决策过程非常有用。
  • 适用于多种任务:这种结构不仅适用于强化学习,也可以用于其他需要预测概率分布的任务。

2.定义策略梯度算法类

class PolicyGradient:
    def __init__(self, state_dim, hidden_dim, action_dim, learning_rate, gamma, device):
        #策略网络
        self.policy_net = PolicyNet(state_dim, hidden_dim, action_dim).to(device)
        self.optimizer = optim.Adam(self.policy_net.parameters(), lr=learning_rate)
        self.gamma = gamma
        self.device = device

这个类初始化策略梯度算法,包括策略网络、优化器、折扣因子和设备(CPU或GPU)。优化器使用Adam算法,这是一种常用的梯度下降优化器。

什么叫策略网络?

策略网络(Policy Network)是强化学习(Reinforcement Learning, RL)中的一个概念,它是一种用于决策的神经网络,其目的是学习一个策略(policy),这个策略能够根据当前的环境状态(state)来选择一个最优的动作(action)。在强化学习中,策略网络通常被用来近似或学习一个策略函数,这个函数将状态映射到动作的概率分布。

3.策略网络采样动作

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

这个方法根据当前策略网络和给定的状态,采样一个动作。它首先将状态转换为张量,然后通过策略网络获取动作的概率分布,接着使用这个分布来采样一个动作。

4.更新策略网络

    def update(self, transition_dict):
        states = torch.tensor(transition_dict['states'], dtype=torch.float).to(self.device)
        actions = torch.tensor(transition_dict['actions'], dtype=torch.int).to(self.device)
        rewards = torch.tensor(transition_dict['rewards'], dtype=torch.float).to(self.device)
        
        # 计算折扣回报
        G = 0
        returns = []
        for r in rewards[::-1]:
            G = r + self.gamma * G
            returns.insert(0, G)
        
        returns = torch.tensor(returns).to(self.device)
        
        # 梯度上升
        self.optimizer.zero_grad()
        for i in range(len(states)):
            state = states[i]
            action = actions[i]
            log_prob = torch.log(self.policy_net(state)[action])
            loss = -log_prob * returns[i]
            loss.backward()
        self.optimizer.step()

这个方法用于更新策略网络。它首先将转换数据转换为张量,然后计算折扣回报。接着,它使用梯度上升来更新策略网络的参数。对于每个样本,它计算策略网络输出的对数概率和回报的乘积,然后进行反向传播。

5.主函数

def main():
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    state_dim = 4  # 状态空间维度
    hidden_dim = 128  # 隐藏层维度
    action_dim = 2  # 动作空间维度
    learning_rate = 0.01  # 学习率
    gamma = 0.99  # 折扣因子
    num_episodes = 1000  # 训练回合数
    
    agent = PolicyGradient(state_dim, hidden_dim, action_dim, learning_rate, gamma, device)
    
    for episode in range(num_episodes):
        state = env.reset()
        done = False
        rewards = []
        states = []
        actions = []
        
        while not done:
            action = agent.take_action(state)
            next_state, reward, done, _ = env.step(action)
            rewards.append(reward)
            states.append(state)
            actions.append(action)
            state = next_state
        
        # 将回合数据打包成字典
        transition_dict = {
            'states': states,
            'actions': actions,
            'rewards': rewards
        }
        
        # 更新策略
        agent.update(transition_dict)

if __name__ == "__main__":
    main()

主函数设置了一些超参数,包括状态空间维度、隐藏层维度、动作空间维度、学习率、折扣因子和训练回合数。然后,它创建了一个策略梯度算法的实例,并开始训练过程。在每个回合中,智能体与环境交互,收集状态、动作和奖励的数据,然后使用这些数据来更新策略网络。

缺点:

  1. 高方差: 策略梯度方法通常具有高方差,这意味着学习过程可能会非常不稳定,导致策略性能的大幅波动。

  2. 探索与利用的权衡: 虽然策略梯度方法内置了探索机制,但在实践中,找到合适的探索与利用平衡可能很困难,特别是在早期训练阶段。

  3. 计算成本: 策略梯度方法可能需要大量的采样来估计梯度,这可能导致高计算成本,尤其是在复杂的环境中。

  4. 对策略表示的敏感性: 策略梯度方法的性能可能对策略表示的选择非常敏感,包括网络架构、激活函数和参数初始化等。

  5. 难以处理稀疏奖励: 在稀疏奖励的环境中,策略梯度方法可能会遇到挑战,因为智能体可能需要很长时间才能学会将动作与奖励联系起来。

  6. 策略崩溃: 在某些情况下,策略梯度方法可能会遇到策略崩溃的问题,即策略在更新过程中突然变得非常糟糕,这通常是由于梯度估计的不准确或策略更新步长过大。

  7. 难以调试和分析: 由于策略梯度方法的复杂性,调试和分析学习过程可能非常困难,特别是当策略表现不佳时。

上一篇:磁盘的物理组成(Linux网络服务器 15)


下一篇:【LeetCode】【算法】581. 最短无序连续子数组-解题思路