欢迎转载,转载请注明出处——知乎专栏“机器学习与控制论”。
“稀疏奖赏”(sparse reward)是强化学习应用中的经典难题。尤其是强化学习控制任务中,为了处理处理它,我打赌不少人都深受“奖赏塑形”等奖赏工程的折磨。
今天分享的这篇文献“Hindsight Experience Replay”(HER)正是提出一种
极其简单巧妙且易实现的方法试图摆脱奖赏工程。现在,HER和模仿学习已经几乎成了机器人学习控制的标配。(OpenAI的geek们也是挺有趣的,取名和寡姐的电影一样,电影也是讲人工智能。)
知乎上有过相关内容,这里从控制的角度梳理思路和使用心得,
附以简单的代码实现。
先放使用心得,后续经验还会更新:
(1)状态(state)设计需要满足文中两点前提
(2)尤其适合多目标(multi goal)任务,单目标任务很可能收益有限
(3)有些情况可能奖赏塑形效果更好、更简单
(4)主要思想并非与奖赏塑形不兼容,HER+奖赏塑形可能也有效果
(5)每个episode不要太长(本质是采样产生新goal的区间不要太长)
1.背景
强化学习(RL)直接应用,尤其应用于机器人学,往往需要精心地“奖赏塑形”(reward shaping),从而引导策略进行优化。
奖赏塑形思想倒是不难,如下面这个任务"pushing",推动方块到红点(目标)的位置。若是只是最后达到红点才给奖赏(即二元奖赏,binary reward),那大多数时候都得不到奖励。所以,可能的奖赏塑形方式是以方块到红点的距离平方的负数为奖赏函数。
简单任务还好,但是遇到复杂任务,就既要求有RL知识又要有领域知识,设计起来非常不容易,甚至有论文在奖赏中设计了5个带权项[1]。此外,许多时候,我们更关心最后的结果,而不关心、也不太好判断中间可能的情况。
个人经验是,如果奖赏中有多个权,往往还要防止Agent进行cheating的情况,而且许多时候,我们更关心最后的结果,而
不关心、也不太清楚中间可能的情况。因此,我们需要简单的奖赏设计,比如说,最好就是原来RL朴素的二元奖赏(达到目标则有,否则无)。
怎么做呢?从错误中学习。拿足球射门举例,如果你一次射门射偏到了球门右边,朴素的RL算法可能认为这就是没有奖赏,学到很少。而人的话却可以从这次失败中知道,这个射偏的落点,是我站在现在这个位置,用这样的脚法能射达的。夸张点说,如果门右挪一点就好了。
这种思想更有效的场景是控制、规划中常见的多目标任务,其中RL的建模方式叫做
universal policy,最早来源于Universal Value Function Approximators[2](UVFA),此时输入给Agent的不仅仅有状态,还有当前任务指定的目标(二者进行concatenate操作)。比如下面的情况,Agent被要求射第3个门,但是若射偏到了第2个门,虽然没达到当前目标,但是达到了“射中第2个门”的目标!这就是所谓的hindsight(后见之明),所以这个经验完全可以复用起来,采样效率就增大了,而且可能可以用二元奖赏。
HER的思想就是如此,回放每个episode,用新的目标(如已经达到的状态)去替换掉经验中原本想要去达到的目标。HER的适用范围也就很明显了,凡是off-policy的RL算法都可以配合适用,如DDPG和DQN等。
2.任务
翻转硬币(toy example):
n个硬币,每个硬币正面为1反面为0,n个硬币序列为状态。动作是翻转n个中的一个。目标是翻到某种状态。
机械臂(gripper) pushing, sliding, picke-and-place:
多目标任务:目标红点位置是随机放置的。
单目标任务:目标位置固定。
3.方案
前提假设:(1)对于一个目标g和一个状态s,必须能够计算得到该s是否能达到g。为什么呢?
因为HER要用s和g来计算(二元)奖赏。这个要求一般都能满足,因为goal这个维度的物理量一般都会在状态中。例如机器臂pushing任务中,目标是红点的位置——以坐标的形式给出,那机械臂手指(fingrer)的实时坐标也是会纳入到状态中的,所以能计算是否满足。
公式化如下:每一个目标
,对应一个函数
,Agent的目标就是达到某个状态使得该函数等于1. 例如,该函数可以是
,这种情况是状态正好等于目标的时候才为1,否则为0. 又例如
,这时候f只与s中的一维有关。
(2)对于一个状态s,必须要能作为一个goal。理由是HER中需要将失败的state作为新goal用于经验回放。这个也一般可以满足。
公式化表述如下:对于一个状态s有一个对应的映射
拿上面这个二维坐标x,y举例,m可以是
.
重要元素:(1)状态
对象仿真在Mujoco中的物理引擎实现,状态包括机械臂各个关节和速度,以及所有对象的位置、旋转和速度。
(2)目标
物体应该到达的位置,有一定的tolerance,比如
是三维坐标
,此时
.
(3)奖赏
主要使用二元奖赏。后面也对比了塑形后的奖赏。
(4)观测
策略的输入是gripper的绝对位置,目标和物体的相对(gripper的)位置以及相对距离。Q函数的输入额外添加了gripper和fingers的线速度以及物体的相对线速度和角速度。(限制policy是为了在物理机械臂上部署比较容易?)
(5)动作
4维,其中三维是gripper下一时间步的位置。最后一维是两个finger之间的距离。
(6)HER采样得到新目标的策略
采样数目K是超参数。
final:取后1个state作为新目标
future:回放该回合中,从现在开始K个随机状态作为新目标
episode:回放该回合中K个随机状态作为新目标
random:回放至今为止K个随机状态作为新目标
算法:算法非常之简洁,标准RL版本是一层episode次数循环内嵌一层step次数循环。但是这里内部有三次循环,第一次照常,第二次是重点,对于刚刚得到每一个三元组(s,a,s'),除了原始的goal拼接到state再存到buffer里,还用新goal进行改造,也放进去,
这样做的意思就很直观了,动态 是不变的,可以复用,只是goal变了而已。这样,buffer里样本实际上增加了(新goal数目)倍。前提假设用到的部分在图中进行了标注。
实现的时候,个人认为把原始的reward计算以及第三个内循环optimize部分放回原来的位置(第一部分)可能会更好,每走一步更新一次,方便与baseline进行比较。
基线:四个基线,DDPG、DDPG+count-based exploration、DDPG+HER(“final”策略)和DDPG+HER(verison from Sec. 4.5,“future”策略)。
注意,它们都是用的二元奖赏,包括前两者。
4.结果与讨论
(1)多目标
结果是加入HER的版本更好,其中“future”策略又更好。
注意到,每个episode只有50步,意味着采样产生新goal的区间最多是50,实验中发现这个数字大小很影响结果,不能太大,否则新goal和旧state仍然差很大,还是得到失败奖赏。
(2)单目标
单目标的情况居然也是有效果的,但DDPG+HER的优势显然不如多目标时候优势大,甚至sliding中不加HER更好。作者没有解释为什么有效果,直观的想是
神经网络的泛化性能起了作用。另外,就variance(阴影)而言,DDPG更大,也可以推测出HER确实提高采样效率,有效样本数较多,结果较为稳定。
(3)采样新目标的策略
纵轴上面是最高成功率,下面是平均,横轴是采样数目。整体来说符合直觉,random稍差,其余三者future稍好。final只取一个,所以是平的。采样数目上来看,
4个到8个一般都还不错,过多变差的原因解释是正常样本比例降低了。
(4)HER与奖赏塑形比较
多目标任务,奖赏塑形采用目标与物体坐标的距离平方的相反数。DDPG和HER都失败了,文中认为结果与之前工作[2]结论一致:如果不采用demonstration,奖赏函数会比较复杂。
失败的原因可能是:
1)塑形后的奖赏与成功的条件不一致。
2)塑形的奖赏惩罚了不正确的动作阻碍了探索(比如往反方向探索)。这可能使得Agent在没能按照准确操纵物体的情况下,不再去触碰物体。
文中谈到
也许存在一个设计好的塑形后的reward会相当好,但是可能设计很麻烦,需要领域知识。所以他们坚信二元奖赏很重要,简单胜过复杂。
5.代码
HER实现非常简单,这里介绍关键部分,全部代码请见github,定期更新代码,欢迎star :-)
简单起见,这里采用的环境是OpenAI gym中的pendulum,单目标任务。
state/observation一共有三维:
,
表示离垂直的角度。
action是转矩,goal是[1.0,0,0],即垂直位置稳定不动。
# PART II hindsight replay
for i, transition in enumerate(episode_cache):
new_goals = generate_goals(i, episode_cache, args.HER_sample_num)
for new_goal in new_goals:
reward = calcu_reward(new_goal, state, action)
state, action, new_state = gene_new_sas(new_goal, transition)
ram.add(state, action, reward, new_state)
除了将正常的rewad计算放在了第一次循环以外,和伪代码一样。主要涉及到goal的函数,计算奖赏,拼接新gaol三个函数。
新goal的产生采用“future”策略,限定了采样的范围是从第i步开始,最多50步。
def generate_goals(i, episode_cache, sample_num, sample_range = 200):
'''
Input: current steps, current episode transition's cache, sample number
Return: new goals sets
notice here only "future" sample policy
'''
end = (i+sample_range) if i+sample_range < len(episode_cache) else len(episode_cache)
epi_to_go = episode_cache[i:end]
if len(epi_to_go) < sample_num:
sample_trans = epi_to_go
else:
sample_trans = random.sample(epi_to_go, sample_num)
return [np.array(trans[3][:3]) for trans in sample_trans]
两种计算奖赏的方式,shaping用的是差的平方的相反数,her表示二元奖赏。里面的tolerance参数其实也很敏感,所以还是得调,不过比起奖赏塑形的n个带权term调起来还是轻松很多。
def calcu_reward(new_goal, state, action, mode='her'):
# direcly use observation as goal
if mode == 'shaping':
# shaping reward
goal_cos, goal_sin, goal_thdot = new_goal[0], new_goal[1], new_goal[2]
cos_th, sin_th, thdot = state[0], state[1], state[2]
costs = (goal_cos - cos_th)**2 + (goal_sin - sin_th)**2 + 0.1*(goal_thdot-thdot)**2
reward = -costs
elif mode == 'her':
# binary reward, no theta now
tolerance = 0.5
goal_cos, goal_sin, goal_thdot = new_goal[0], new_goal[1], new_goal[2]
cos_th, sin_th, thdot = state[0], state[1], state[2]
costs = (goal_cos - cos_th)**2 + (goal_sin - sin_th)**2 + 0.1*(goal_thdot-thdot)**2
reward = 0 if costs < tolerance else -1
return reward
最后就是简单的拼接新goal得到新的s,s'
def gene_new_sas(new_goals, transition):
state, new_state = transition[0][:3], transition[3][:3]
action = transition[1]
state = np.concatenate((state, new_goals))
new_state = np.concatenate((new_state, new_goals))
return state, action, new_state
进行了一些实验得到的小结:
1)该任务用gym中自带的奖赏函数已经是塑形之后的,效果很不错。
2)HER+塑形奖赏也可以取得很好的效果
3)超参数选择:采样goal样本4好于8,tolerance为0.5较好,这两个参数很敏感
参考
- ^https://arxiv.org/abs/1704.03073
- ^abhttp://proceedings.mlr.press/v37/schaul15.pdf