深度强化学习(5)策略梯度定理 & REINFORCE算法


Q-learning、DQN 都是 基于价值(value-based)的方法,其中 Q-learning 是处理有限状态的算法,而 DQN 可以用来解决连续状态的问题。虽然DQN能够解决连续的状态的问题,但是却无法处理连续动作空间的动作决策。而在实际应用中,很多场景的动作都是连续的,如自动驾驶中,需要决策车辆的速度、加速度、油门刹车的角度等,在游戏AI中,需要决策角色的移动和攻击的方向、距离、预判敌人的位置等。

基于策略(policy-based)的策略梯度(Policy Gradiant)方法不需要学习值函数,它直接构造当前状态 s s s、神经网络参数 θ \theta θ到动作 a a a的策略 π θ \pi_{\theta} πθ,输出当前状态下执行各种动作的概率值:
π θ ( s , a ) = P [ a ∣ s , θ ] \pi_{\theta}(s,a)=\Bbb P[a|s,\theta] πθ(s,a)=P[as,θ]
策略梯度方法执行的是非确定性策略。

非确定性策略:在每种状态下,执行的动作是随机的,可以按照概率值选择动作(如Softmax输出执行每个动作的概率)。

确定性策略:在某种状态下,要执行的动作是唯一且确定的。

5.1 策略梯度优化

基于Policy的强化学习是一个最优化问题,给定策略 π θ ( s , a ) \pi_{\theta}(s,a) πθ(s,a)以及神经网络参数 θ \theta θ,找到最优的 θ \theta θ使得目标函数 J ( θ ) J(\theta) J(θ)最大化。

目标函数 J ( θ ) J(\theta) J(θ)的构造

在回合制的环境中,存在起始和终止状态,需要计算从起始状态 s 1 s_1 s1起,执行策略 π θ \pi_{\theta} πθ所得的累积回报的数学期望,表示为:
J 1 ( θ ) = E [ ∑ t = 1 + ∞ γ t r t ∣ s 0 , π θ ] J_1(\theta)=\Bbb E[\sum^{+\infty}_{t=1}\gamma^tr_t|s_0,\pi_{\theta}] J1(θ)=E[t=1+γtrts0,πθ]
其中,折扣因子 γ ∈ [ 0 , 1 ] \gamma\in[0,1] γ[0,1] r t r_t rt为立即回报。
而在现实中应用较多持续运行的环境中,并不存在起始和终止状态,因此利用平均奖励目标函数计算各个时刻回报值的均值,表示为:
J a v g ( θ ) = ∑ s d π θ ( s ) ∑ a π θ ( s , a ) R s a J_{\rm{avg}}(\theta)=\sum_sd^{\pi_{\theta}}(s)\sum_a\pi_{\theta}(s,a)R^a_s Javg(θ)=sdπθ(s)aπθ(s,a)Rsa
其中, d π θ ( s ) d^{\pi_{\theta}}(s) dπθ(s)表示状态的平稳分布,也即状态 s s s的出现概率; R s a R^a_s Rsa表示在状态 s s s下执行动作 a a a时的立即回报的数学期望; ∑ a π θ ( s , a ) R s a \sum_a\pi_{\theta}(s,a)R^a_s aπθ(s,a)Rsa表示在状态 s s s下,执行所有动作时的立即回报的均值。

优化神经网络参数 θ \theta θ

梯度下降法

给定神经网络映射函数 ϕ θ \phi_{\theta} ϕθ θ \theta θ是神经网络参数, x x x是一个训练样本, y y y是对应的样本标签,给定损失函数 L ( ⋅ ) \mathcal L(\cdot) L(),一个常规的优化目标为:
min ⁡ L ( ϕ θ ( x ) , y ) \min\mathcal L(\phi_{\theta}(x),y) minL(ϕθ(x),y)
ϕ θ ( x ) \phi_{\theta}(x) ϕθ(x)为预测值, y y y为目标值。梯度下降的目标是最小化预测值和目标值之间的差距。
在这里插入图片描述
梯度: g = ∇ θ L ( ϕ θ ( x ) , y ) g=\nabla_{\theta}\mathcal L(\phi_{\theta}(x),y) g=θL(ϕθ(x),y)

更新量: Δ θ = η ⋅ g \Delta\theta=\eta\cdot g Δθ=ηg

更新参数:
θ ← { θ − η ⋅ g 梯度下降法 θ + η ⋅ g 梯度上升法 \theta\larr \begin{cases} \theta-\eta\cdot g&梯度下降法\\ \theta+\eta\cdot g&梯度上升法 \end{cases} θ{θηgθ+ηg梯度下降法梯度上升法

在传统深度学习的训练中,最优目标 y y y已知,目的是最小化神经网络的输出 y ^ \hat y y^和目标输出 y y y之间的差距(即损失)。而强化学习的训练中,虽然环境能给出立即回报 r r r,但最优目标 y y y(即动作 a a a)是未知的,它需要最大化目标(奖赏)函数 J ( θ ) J(\theta) J(θ)。因此策略梯度法就需要通过梯度上升法来搜索目标函数 J ( θ ) J(\theta) J(θ)中局部最大值所对应的神经网络参数 θ \theta θ

计算策略梯度

定义策略梯度:
g = ∇ θ J ( θ ) = ( ∂ J ( θ ) ∂ θ 1 ⋮ ∂ J ( θ ) ∂ θ n ) g=\nabla_{\theta}J(\theta)= \begin{pmatrix} {\partial J(\theta)\over\partial\theta_1}\\ \vdots\\ {\partial J(\theta)\over\partial\theta_n} \end{pmatrix} g=θJ(θ)= θ1J(θ)θnJ(θ)
其中 J ( θ ) J(\theta) J(θ)使用平均奖励目标函数 J a v g ( θ ) = ∑ s d π θ ( s ) ∑ a π θ ( s , a ) R s a J_{\rm{avg}}(\theta)=\sum_sd^{\pi_{\theta}}(s)\sum_a\pi_{\theta}(s,a)R^a_s Javg(θ)=sdπθ(s)aπθ(s,a)Rsa,对于策略 π θ \pi_{\theta} πθ

  • π θ \pi_{\theta} πθ不可微时,利用有限差分法(一种求解微分方程数值解的近似方法,只要原理是对微分方程中的微分项直接进行差分近似),即:
    ∂ J ( θ ) ∂ θ k ≈ J ( θ + ϵ u k ) − J ( θ ) ϵ {\partial J(\theta)\over\partial\theta_k}\approx{J(\theta+\epsilon u_k)-J(\theta)\over\epsilon} θkJ(θ)ϵJ(θ+ϵuk)J(θ)
    式中 u k u_k uk表示为独热向量,仅第k维为1, ϵ \epsilon ϵ为加入的噪音。该方法简单但是有噪且低效,对任意策略 π θ \pi_{\theta} πθ都有效。

  • π θ \pi_{\theta} πθ可微时,利用似然比(Likeinhood Ratios),以上面的平均奖励目标函数 J a v g ( θ ) J_{\rm avg}(\theta) Javg(θ)为例,它的梯度为:
    ∇ θ J a v g ( θ ) = E π θ [ ∇ θ log ⁡ π θ ( s , a ) Q π θ ( s , a ) ] \nabla_{\theta}J_{\rm avg}(\theta)=\Bbb E_{\pi_{\theta}}[\nabla_{\theta}\log\pi_{\theta}(s,a)Q^{\pi_{\theta}}(s,a)] θJavg(θ)=Eπθ[θlogπθ(s,a)Qπθ(s,a)]
    上式即为策略梯度定理(Policy Gradient Theorem)。其中, ∇ θ log ⁡ π θ ( s , a ) \nabla_{\theta}\log\pi_{\theta}(s,a) θlogπθ(s,a)是score function,它指示 θ \theta θ向哪个方向调整能够获得较好的效果; r r r代表reward,在单步MDP中,算法执行一个时间步即停止,此时立即回报为 r = R s a r=R^a_s r=Rsa

    推导
    ∇ θ J a v g ( θ ) = ∑ s ∈ S d ( s ) ∑ a ∈ A ∇ θ π θ ( s , a ) R s a \nabla_{\theta}J_{\rm avg}(\theta)=\sum_{s\in S}d(s)\sum_{a\in A}\nabla_{\theta}\pi_{\theta}(s,a)R^a_s\\ θJavg(θ)=sSd(s)aAθπθ(s,a)Rsa

    利用恒等式 ∇ f = f ∇ log ⁡ f \nabla f=f\nabla\log f f=flogf进行转换:
    ∇ θ π θ ( s , a ) = π θ ( s , a ) ∇ θ π θ ( s , a ) π θ ( s , a ) = π θ ( s , a ) ∇ θ log ⁡ π θ ( s , a ) \begin{align} \nabla_{\theta}\pi_{\theta}(s,a)&=\pi_{\theta}(s,a){\nabla_{\theta}\pi_{\theta}(s,a)\over\pi_{\theta}(s,a)}\\ &=\pi_{\theta}(s,a)\nabla_{\theta}\log\pi_{\theta}(s,a) \end{align} θπθ(s,a)=πθ(s,a)πθ(s,a)θπθ(s,a)=πθ(s,a)θlogπθ(s,a)
    将该式带入上面式子,得:
    ∇ θ J a v g ( θ ) = ∑ s ∈ S d ( s ) ∑ a ∈ A π θ ( s , a ) ∇ θ log ⁡ π θ ( s , a ) R s a = E π θ [ ∇ θ log ⁡ π θ ( s , a ) r ] \begin{align} \nabla_{\theta}J_{\rm avg}(\theta)&=\sum_{s\in S}d(s)\sum_{a\in A}\pi_{\theta}(s,a)\nabla_{\theta}\log\pi_{\theta}(s,a)R^a_s\\ &=\Bbb E_{\pi_{\theta}}[\nabla_{\theta}\log\pi_{\theta}(s,a)r] \end{align} θJavg(θ)=sSd(s)aAπθ(s,a)θlogπθ(s,a)Rsa=Eπθ[θlogπθ(s,a)r]

    使用长期价值 Q π θ ( s , a ) Q^{\pi_{\theta}}(s,a) Qπθ(s,a)替代瞬时奖励 r r r,最后得:
    ∇ θ J a v g ( θ ) = E π θ [ ∇ θ log ⁡ π θ ( s , a ) Q π θ ( s , a ) ] \nabla_{\theta}J_{\rm avg}(\theta)=\Bbb E_{\pi_{\theta}}[\nabla_{\theta}\log\pi_{\theta}(s,a)Q^{\pi_{\theta}}(s,a)] θJavg(θ)=Eπθ[θlogπθ(s,a)Qπθ(s,a)]

蒙特卡洛策略梯度算法

计算策略梯度的公式中的 Q π θ ( s , a ) Q^{\pi_{\theta}}(s,a) Qπθ(s,a)可以采用蒙特卡洛方法来估计,该方法即REINFORCE算法,它的策略梯度为:
∇ θ J a v g ( θ ) = E π θ [ ∑ t = 0 T ( ∑ t ′ = t T γ t ′ − t r t ′ ) ∇ θ log ⁡ π θ ( s t , a t ) ] \nabla_{\theta}J_{\rm avg}(\theta)=\Bbb E_{\pi_{\theta}}[\sum^T_{t=0}(\sum^T_{t^{\prime}=t}\gamma^{t^{\prime}-t}r_{t^{\prime}})\nabla_{\theta}\log\pi_{\theta}(s_t,a_t)] θJavg(θ)=Eπθ[t=0T(t=tTγttrt)θlogπθ(st,at)]
其中, T T T是和环境交互的最大步数。

5.2 REINFORCE算法

算法流程:

  • 初始化策略参数 θ \theta θ
  • f o r for for序列 e = 1 → E   d o e=1\rarr E\space do e=1E do
    • 用当前策略 π θ \pi_{\theta} πθ采样轨迹 { s 1 , a 1 , r 1 , s 2 , a 2 , r 2 , … , s T , a T , r T } \{s_1,a_1,r_1,s_2,a_2,r_2,\dots,s_T,a_T,r_T\} {s1,a1,r1,s2,a2,r2,,sT,aT,rT}
    • 计算当前轨迹每个时刻 t t t往后的回报 ∑ t ′ = t T γ t ′ − t r t ′ \sum^T_{t^{\prime}=t}\gamma^{t^{\prime}-t}r_{t^{\prime}} t=tTγttrt,记为 ψ t \psi_t ψt
    • θ \theta θ进行更新: θ = θ + α ∑ t T ψ t ∇ θ log ⁡ π θ ( a t ∣ s t ) \theta=\theta+\alpha\sum^T_t\psi_t\nabla_{\theta}\log\pi_{\theta}(a_t|s_t) θ=θ+αtTψtθlogπθ(atst)
代码实现

定义策略网络

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)

REINFORCE算法

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)
        self.optimizer = torch.optim.Adam(self.policy_net.parameters(), 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 = 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()  # 梯度下降

实现

learning_rate = 1e-3
num_episodes = 1000
hidden_dim = 128
gamma = 0.98
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")

env_name = "CartPole-v0"
env = gym.make(env_name)
env.seed(0)
torch.manual_seed(0)
state_dim = env.observation_space.shape[0]
action_dim = env.action_space.n
agent = REINFORCE(state_dim, hidden_dim, action_dim, learning_rate, gamma, device)

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(num_episodes / 10)):
            episode_return = 0
            transition_dict = {
                'states': [],
                'actions': [],
                'next_states': [],
                'rewards': [],
                'dones': []
            }
            state = env.reset()
            done = False
            while not done:
                action = agent.take_action(state)
                next_state, reward, done, _ = env.step(action)
                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_episode + 1) % 10 == 0:
                pbar.set_postfix({
                    'episode':
                    '%d' % (num_episodes / 10 * i + i_episode + 1),
                    'return':
                    '%.3f' % np.mean(return_list[-10:])
                })
            pbar.update(1)
Iteration 0: 100%|██████████| 100/100 [00:04<00:00, 24.69it/s, episode=100, return=42.400]
Iteration 1: 100%|██████████| 100/100 [00:07<00:00, 13.01it/s, episode=200, return=47.700]
Iteration 2: 100%|██████████| 100/100 [00:14<00:00,  7.04it/s, episode=300, return=129.700]
Iteration 3: 100%|██████████| 100/100 [00:22<00:00,  4.50it/s, episode=400, return=167.600]
Iteration 4: 100%|██████████| 100/100 [00:25<00:00,  3.91it/s, episode=500, return=197.200]
Iteration 5: 100%|██████████| 100/100 [00:26<00:00,  3.83it/s, episode=600, return=180.100]
Iteration 6: 100%|██████████| 100/100 [00:26<00:00,  3.84it/s, episode=700, return=194.400]
Iteration 7: 100%|██████████| 100/100 [00:26<00:00,  3.76it/s, episode=800, return=186.600]
Iteration 8: 100%|██████████| 100/100 [00:22<00:00,  4.44it/s, episode=900, return=151.500]
Iteration 9: 100%|██████████| 100/100 [00:26<00:00,  3.78it/s, episode=1000, return=192.800]

在这里插入图片描述

def moving_average(a, window_size):
    cumulative_sum = np.cumsum(np.insert(a, 0, 0))
    middle = (cumulative_sum[window_size:] - cumulative_sum[:-window_size]) / window_size
    r = np.arange(1, window_size - 1, 2)
    begin = np.cumsum(a[:window_size - 1])[::2] / r
    end = (np.cumsum(a[:-window_size:-1])[::2] / r)[::-1]
    return np.concatenate((begin, middle, end))

mv_return = moving_average(return_list, 9)
plt.plot(episodes_list, mv_return)
plt.xlabel('Episodes')
plt.ylabel('Returns')
plt.title('REINFORCE on {}'.format(env_name))
plt.show()

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值