本文内容源自百度强化学习 7 日入门课程学习整理
感谢百度 PARL 团队李科浇老师的课程讲解
基于价值
基于策略
Value-based:先优化 Q 函数
Policy-based:输出动作的概率
π ( a 1 ∣ s , θ ) = p ( a 1 , s ) = 0.3 π ( a 2 ∣ s , θ ) = p ( a 2 , s ) = 0.5 π ( a 3 ∣ s , θ ) = p ( a 3 , s ) = 0.2 π(a_1|s,θ) = p(a_1,s)=0.3 \\ π(a_2|s,θ) = p(a_2,s)=0.5 \\ π(a_3|s,θ) = p(a_3,s)=0.2 π(a1∣s,θ)=p(a1,s)=0.3π(a2∣s,θ)=p(a2,s)=0.5π(a3∣s,θ)=p(a3,s)=0.2
softmax 的作用,就是把输出映射到 0~1 的区间内,并使得所有的输出相加等于 1,于是就可以等同于不同选择的概率了
计算方法:
当我们选择一个动作以后,其实并不知道动作的优劣,而只有最终游戏结束得到结果的时候,我们才能反推之前的动作优劣
优化策略的目的:让 “每一个” episode 的 “总的” reward 尽可能大
从初始状态出发,有不同的概率选择动作
然后状态发生变化(环境的随机性,会导致环境的变化也是个概率分布,即状态转移概率 p ( s ′ ∣ s , a ) p(s'|s,a) p(s′∣s,a))
在新的状态下,再通过不同概率选择动作
状态继续发生变化
不断地交互,直到完成一个 episode(一局游戏结束)
把这个 episode 中所有的连续的 s 变化 和 a 选择串起来,就是一个 episode 的轨迹 Trajectory
轨迹: τ = { s 1 , a 1 , s 2 , a 2 , . . . s T , a T } τ\ =\ \{s_1,a_1,s_2,a_2,...s_T,a_T\} τ = {s1,a1,s2,a2,...sT,aT}
轨迹的概率:
轨迹的总 reward:
我们和环境交互的轨迹可以有千千万万条,所以当我们跑了很多 episode ,获得许多轨迹后,我们可以获得 “期望回报”:
π θ ( a ∣ s ) π_θ(a|s) πθ(a∣s) 的期望回报:所有 episode 的平均回报
R θ ‾ = ∑ τ R ( τ ) p θ ( τ ) \overline{R_θ}\ =\ \sum_{τ}R(τ)p_θ(τ) Rθ = ∑τR(τ)pθ(τ)
策略 π θ ( a ∣ s ) π_θ(a|s) πθ(a∣s) 下的期望回报就可以用来评价我们的策略优劣
难点:
解决方法:取近似值
我们可以用期望回报 R θ ‾ \overline{R_θ} Rθ 来优化策略函数 π θ ( s , a ) π_θ(s,a) πθ(s,a)
在 DQN 中,我们的 loss 函数是来源于 目标 Q 和 预测 Q 之间的差别,我们希望优化过程是 预测 Q 不断逼近 目标 Q,降低 loss(越小越好)
所以在 DQN 中,目标 Q 担任的是一个正确的 label 指导
但是在 Policy 网络中,没有这样一个 正确的 label 指导
所以需要用到 R θ ‾ \overline{R_θ} Rθ
优化目标:
策略梯度:
def calc_reward_to_go(reward_list, gamma=1.0):
for i in range(len(reward_list) - 2, -1, -1):
# G_t = r_t + γ·r_t+1 + ... = r_t + γ·G_t+1
reward_list[i] += gamma * reward_list[i + 1] # Gt
return np.array(reward_list)
这里的代码就是把每一步的收益,转成每一步的未来总收益
连续的 step 之间未来总收益有相关性: G t = ∑ t = k + 1 T γ k − t − 1 r t = r t + γ G t + 1 G_t\ = \ \sum_{t=k+1}^Tγ^{k-t-1}r_t\ =\ r_t\ +\ γG_{t+1} Gt = ∑t=k+1Tγk−t−1rt = rt + γGt+1
所以在代码实现上,是从后往前计算,先计算 G T G_T GT,再计算 G T − 1 G_{T-1} GT−1,依次进行
假设实际执行的动作 a t a_t at 是 [0,1,0],计算得到的概率 π ( a ∣ s , θ ) π(a|s,θ) π(a∣s,θ) 是 [0.2,0.5,0.3],对每一个 action: L o s s = − G t ⋅ [ 0 , 1 , 0 ] ⋅ log [ 0.2 , 0.5 , 0.3 ] Loss = -G_t\ ·\ [0,1,0]\ ·\ \log[0.2,0.5,0.3] Loss=−Gt ⋅ [0,1,0] ⋅ log[0.2,0.5,0.3]
类比监督学习:
Policy Gradient 中:
def learn(self, obs, action, reward): # 输入的就是获得的轨迹,reward代表未来总收益
""" 用policy gradient 算法更新policy model
"""
act_prob = self.model(obs) # 获取输出动作概率(由神经网络预测得到)
# log_prob = layers.cross_entropy(act_prob, action) # 交叉熵
log_prob = layers.reduce_sum(
-1.0 * layers.log(act_prob) * layers.one_hot(
action, act_prob.shape[1]),
dim=1)
cost = log_prob * reward # 乘的是当前 action 的未来总收益
cost = layers.reduce_mean(cost) # 所有 step 要取均值
optimizer = fluid.optimizer.Adam(self.lr)
optimizer.minimize(cost)
return cost
分成了 model,algorithm,agent 三个类
比如在 Pong 的乒乓球游戏环境中:
# Pong 图片预处理
def preprocess(image):
""" 预处理 210x160x3 uint8 frame into 6400 (80x80) 1维 float vector """
image = image[35:195] # 裁剪
image = image[::2,::2,0] # 下采样,缩放2倍
image[image == 144] = 0 # 擦除背景 (background type 1)
image[image == 109] = 0 # 擦除背景 (background type 2)
image[image != 0] = 1 # 转为灰度图,除了黑色外其他都是白色
return image.astype(np.float).ravel()
当然我们也可以用 CNN 网络,但是对于简单图像的环境,其实也可以这样处理,就不用 CNN 网络了
因为有些游戏一个 episode 的时间很长,比如乒乓球游戏 Pong,一方拿到 21 分游戏才结束,所以整个过程有非常多的 step
所以要设计一个衰减因子,不需要考虑太长时间以后的收益,一般会设置为 0.99
另外需要对一个 episode 拿到的收益做 normalize,让我们获取的收益有正有负,基本在原点两侧均衡分布
通常这种归一化的做法是为了加速训练,对于 action 的快速收敛更有效果
# 根据一个episode的每个step的reward列表,计算每一个Step的Gt
def calc_reward_to_go(reward_list, gamma=0.99):
"""calculate discounted reward"""
reward_arr = np.array(reward_list)
for i in range(len(reward_arr) - 2, -1, -1):
# G_t = r_t + γ·r_t+1 + ... = r_t + γ·G_t+1
reward_arr[i] += gamma * reward_arr[i + 1]
# normalize episode rewards
reward_arr -= np.mean(reward_arr)
reward_arr /= np.std(reward_arr)
return reward_arr
强化学习算法 Policy Gradient 解决 CartPole 问题,代码逐条详解