强化学习系列--带基准线的REINFORCE算法

强化学习系列--带基准线的REINFORCE算法

介绍

在强化学习中,带基准线的REINFORCE算法是一种用于求解策略梯度的方法。REINFORCE算法(也称为蒙特卡洛策略梯度算法)可以用于训练能够从环境中学习的策略。带基准线的REINFORCE算法是对经典REINFORCE算法的改进,通过引入一个基准线来减小方差,加速学习的过程

REINFORCE算法通过采样轨迹并利用蒙特卡洛方法来估计策略梯度。该算法的目标是最大化期望回报,即最大化累积奖励的期望值。具体来说,REINFORCE算法使用以下更新规则来更新策略参数:

Δ θ = α ∑ t = 0 T ∇ θ log ⁡ ( π ( a t ∣ s t ) ) G t \Delta\theta = \alpha \sum_{t=0}^{T} \nabla\theta \log(\pi(a_t|s_t)) G_t Δθ=αt=0Tθlog(π(atst))Gt

其中, Δ θ \Delta\theta Δθ是策略参数的更新量, α \alpha α是学习率, ∇ θ \nabla\theta θ是对策略参数的梯度, π ( a t ∣ s t ) \pi(a_t|s_t) π(atst)是在状态 s t s_t st下选择动作 a t a_t at的概率, G t G_t Gt是从时间步 t t t开始的累积奖励。

带基准线的REINFORCE算法则在更新规则中引入了一个基准线 b ( s t ) b(s_t) b(st),用来减小方差。基准线可以是任何函数,通常选择一个与状态有关的函数,如状态值函数 V ( s t ) V(s_t) V(st)。更新规则变为:

Δ θ = α ∑ t = 0 T ∇ θ log ⁡ ( π ( a t ∣ s t ) ) ( G t − b ( s t ) ) \Delta\theta = \alpha \sum_{t=0}^{T} \nabla\theta \log(\pi(a_t|s_t)) (G_t - b(s_t)) Δθ=αt=0Tθlog(π(atst))(Gtb(st))

通过减去基准线的值,可以降低更新的方差,加速学习过程。基准线可以看作是估计的奖励期望的偏差,通过减去这个偏差,可以更准确地估计策略梯度。

带基准线的REINFORCE算法的步骤如下:

  1. 初始化策略参数 θ \theta θ和基准线 b ( s ) b(s) b(s)
  2. 与环境交互,采样轨迹,记录奖励和状态序列。
  3. 对于每个时间步 t t t,计算状态 s t s_t st下选择动作 a t a_t at的概率 π ( a t ∣ s t ) \pi(a_t|s_t) π(atst)和基准线 b ( s t ) b(s_t) b(st)的值。
  4. 计算策略梯度 ∇ θ log ⁡ ( π ( a t ∣ s t ) ) ( G t − b ( s t ) ) \nabla\theta \log(\pi(a_t|s_t)) (G_t - b(s_t)) θlog(π(atst))(Gtb(st))
  5. 更新策略参数 θ \theta θ θ = θ + α ∇ θ log ⁡ ( π ( a t ∣ s t ) ) ( G t − b ( s t ) ) \theta = \theta + \alpha \nabla\theta \log(\pi(a_t|s_t)) (G_t - b(s_t)) θ=θ+αθlog(π(atst))(Gtb(st))
  6. 重复步骤2-5,直到达到停止条件。

带基准线的REINFORCE算法通过减小方差来加速学习过程,提高了算法的稳定性和收敛性。选择合适的基准线函数对算法的表现有重要影响,通常需要通过实验来确定。

示例代码

下面是一个简单的Python代码实现带基准线的REINFORCE算法,其中包含了策略网络和基线网络:

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import gym

# 定义策略网络
class PolicyNetwork(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(PolicyNetwork, self).__init__()
        self.fc1 = nn.Linear(input_dim, 32)
        self.fc2 = nn.Linear(32, output_dim)

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

# 定义基线网络
class BaselineNetwork(nn.Module):
    def __init__(self, input_dim):
        super(BaselineNetwork, self).__init__()
        self.fc1 = nn.Linear(input_dim, 32)
        self.fc2 = nn.Linear(32, 1)

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

# 定义带基准线的REINFORCE算法
def reinforce(env, policy_net, baseline_net, num_episodes, gamma=0.99):
    optimizer_policy = optim.Adam(policy_net.parameters(), lr=0.01)
    optimizer_baseline = optim.Adam(baseline_net.parameters(), lr=0.01)

    for episode in range(num_episodes):
        state = env.reset()
        log_probs = []
        rewards = []

        while True:
            state_tensor = torch.FloatTensor(state)
            action_probs = policy_net(state_tensor)
            action_dist = torch.distributions.Categorical(action_probs)
            action = action_dist.sample()

            log_prob = action_dist.log_prob(action)
            log_probs.append(log_prob)

            next_state, reward, done, _ = env.step(action.item())
            rewards.append(reward)

            if done:
                break

            state = next_state

        returns = []
        cumulative_return = 0
        for r in reversed(rewards):
            cumulative_return = r + gamma * cumulative_return
            returns.insert(0, cumulative_return)

        returns = torch.FloatTensor(returns)
        log_probs = torch.stack(log_probs)

        # 计算基准线的值
        values = baseline_net(torch.FloatTensor(state))
        advantages = returns - values

        # 更新策略网络
        policy_loss = -(log_probs * advantages.detach()).mean()
        optimizer_policy.zero_grad()
        policy_loss.backward()
        optimizer_policy.step()

        # 更新基线网络
        baseline_loss = F.mse_loss(returns, values)
        optimizer_baseline.zero_grad()
        baseline_loss.backward()
        optimizer_baseline.step()

        if episode % 10 == 0:
            print(f"Episode {
      
      episode}: policy_loss = {
      
      policy_loss}, baseline_loss = {
      
      baseline_loss}")

# 创建环境和网络
env = gym.make('CartPole-v1')
input_dim = env.observation_space.shape[0]
output_dim = env.action_space.n

policy_net = PolicyNetwork(input_dim, output_dim)
baseline_net = BaselineNetwork(input_dim)

# 运行带基准线的REINFORCE算法
reinforce(env, policy_net, baseline_net, num_episodes=1000)

这段代码使用PyTorch实现了带基准线的REINFORCE算法,并应用于OpenAI Gym中的CartPole环境。首先定义了策略网络和基线网络的结构,然后在reinforce函数中进行算法的训练过程。在每个回合中,通过策略网络选择动作,并计算动作的概率和对数概率。同时,也记录下每个动作的奖励。当回合结束后,根据累积奖励计算优势函数,并使用优势函数更新策略网络和基线网络的参数。算法通过反复迭代多个回合来提高策略的性能。

猜你喜欢

转载自blog.csdn.net/qq_36892712/article/details/132503741