Skip to content

9 策略梯度算法

  • 之前的算法基于价值,没有显式策略(策略就是选最大动作价值的动作)。下述 REINFORCE 方法基于策略.
  • 设 $pi_theta$ 是策略,处处可微,要学习的参数为 $theta$
  • 目标是最大化 : $$J(theta) = EE_(s_0) [V^(pi_theta) (s_0) ]$$
  • 设状态访问分布为 $nu^pi$(无穷步状态概率加权向量,见第三章),有:

    • 提示: $(log f)^prime = f^prime / f$
    • image.png
  • 另一证明:

蒙特卡洛 REINFORCE

  • 考虑用蒙特卡洛方法估计,对有限步的环境来说,依据上式有:

    • 其中 $T$ 为最大步数. 小括号内就是 $G_t$,下面第二张图中以 $psi_t$ 表示.
    • image.png
  • 训练步骤

    • image.png
  • 网络结构:
    • Input: 可微状态
    • Output: 离散动作的概率多项分布
    • 损失函数: 上述梯度更新公式(去掉微分符号)
class PolicyNet(torch.nn.Module):
    def __init__(self, state_dim, hidden_dim, action_dim):
        super(PolicyNet, self).__init__()
        self.fc1 = torch.nn.Linear(state_dim, hidden_dim)
        self.fc2 = torch.nn.Linear(hidden_dim, action_dim)

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

class REINFORCE:
    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)
        ...

    def take_action(self, state):  # 根据动作概率分布随机采样
        state = torch.tensor([state], dtype=torch.float).to(self.device)
        probs = self.policy_net(state)
        action_dist = torch.distributions.Categorical(probs)
        action = action_dist.sample() # 随机选一个
        return action.item()

    def update(self, transition_dict):
        reward_list = transition_dict['rewards']
        state_list = transition_dict['states']
        action_list = transition_dict['actions']

        G = 0
        self.optimizer.zero_grad()
        for i in reversed(range(len(reward_list))):  # 从最后一步算起
            reward = reward_list[i]
            state = torch.tensor([state_list[i]],
                                 dtype=torch.float).to(self.device)
            action = torch.tensor([action_list[i]]).view(-1, 1).to(self.device)
            log_prob = torch.log(self.policy_net(state).gather(1, action))
            G = self.gamma * G + reward
            loss = -log_prob * G  # 每一步的损失函数
            loss.backward()  # 反向传播计算梯度
        self.optimizer.step()  # 梯度下降

# 其他一样.
  • 考虑最优情况的正确性:若 $G_1 = 200, G_2 = -200$,则会学到使得 $p_1$ 尽可能大(取 -log 后尽可能小,损失尽可能小),$p_2$ 尽可能小(取 -log 后极大,损失极小)
    • softmax 应该能防止数值爆炸.

优化问题,神经网络和强化学习

...