实践小栈:从头开始强化学习
第一部分:定义环境,通过价值迭代寻找最优政策并引入Q学习
摘要
在本文中,我将介绍一个新项目,该项目试图通过在Python笔记本中完全定义和解决一个简单任务来帮助学习强化学习。本文将解释环境和基本方法,所有代码都在以下链接中发布。此外,我创建了一个“Meta”笔记本,可以轻松分叉,只包含定义的环境供其他人尝试、调整和应用自己的代码。
https://www.kaggle.com/osbornep/-reinforcement-learning-from-scratch-in-python
上下文
当我第一次开始学习强化学习时,我直接复制了在线指南和项目,但我有点困惑。 “为什么结果显示是这样?这个参数有什么作用?环境以这种方式起什么作用?”我开始问自己一些问题,直到我退后一步并从首先完全理解概率环境如何定义的基础知识开始,建立一个我可以在纸上解决的小例子,事情这才开始变得更有意义。但是,我发现很难找到不需要从外部源导入就应用我的知识的环境。
因此,我给自己设定了挑战:
我可以在Python笔记本中为任务环境完全自包含地定义并找到最优操作吗?
通过跟随我的工作,我希望其他人可以将此作为学习的一个基本出发点。
第1阶段:定义环境
任务
很简单,我想知道从一个房间的任何位置将一张纸放入垃圾箱(垃圾桶)的最佳方法。我可以选择把纸扔向任何方向的方式,也可以选择一次移动一步的方式。
虽然对于人类来说,通过视力判断垃圾箱的位置很容易,但是,对于计算机来说是需要学习大量的先验知识的。
这定义了这样的环境,其中成功投掷的概率是基于投掷纸张的方向和当前距离垃圾箱的距离来计算的。
例如,在下面的图像中,我们有三个标记为A、B和C的人。A和B都向正确的方向投掷,但是A比B更接近,因此着陆投射的概率更高。
C比B更接近,但是朝着完全错误的方向投掷,因此击中垃圾箱的概率非常低。C会朝这个方向扔,这可能看起来不合逻辑,但是,正如我们稍后将要展示的那样,算法必须首先尝试一系列方向来确定成功的位置,在这个过程中,并不会有垃圾箱在哪里的视觉指南给出。
任务环境示例
为了在python中创建环境,我们将图表转换为x和y值的二维维度,并使用轴承数学来计算抛出的角度。我们使用归一化的整数x和y值,因此它们必须以-10和10为界。
环境映射到二维空间
环境概率
成功投掷的概率与投掷的距离和方向有关。因此,我们需要计算两个指标:
- 当前位置到目标位置的距离
- 纸张投掷的角度与垃圾桶的真实方向之间的差异
距离测量
如上图所示,A的位置设定为(-5,-5)。这是他们当前的状态,他们与垃圾箱的距离可以使用欧几里德距离测量来计算:
对于最终计算,我们将其归一化并反转该值,以便高分表示该人更接近目标仓:
因为我们已经在(-10,10)之间修正了二维维度,所以该人最大可能距离是来自二进制位的sqrt {(100)+(100)} = sqrt {200}。因此,A的距离得分是:
方向测量
然后,A下了一个决定,他们移动还是选择一个方向。现在,让我们假设他们选择扔纸,第一次投掷是50度,第二次是从正北方向60度。A的箱子方向可以通过一个简单的三角学计算:
因此,第一次投掷与真实方向相差5度,第二次投掷是15度。
当我们认为好的投掷在实际方向的任一侧(即没有投掷错误的方向)45度时,我们可以使用以下方法来计算这个选择的方向有多好。任何超出45度范围的任何方向都会产生负值并映射到0的概率:
两者都相当接近,但他们的第一次投掷更有可能击中垃圾箱。
概率计算
因此,我们计算成功投掷的概率与这两个指标相关:
创建广义概率函数
虽然之前的计算相当简单,但在我们推广这些计算并开始考虑仓位或当前位置不固定时,需要考虑一些因素。
在我们之前的例子中,A是从垃圾箱西南方向投掷,因此角度是一个简单的计算,但如果我们应用相同的方式来说一个人在东北方,那么这将是不正确的。此外,因为垃圾箱可以放置在任何地方,我们需要首先找到人与此相关的位置,而不仅仅是原点,然后用于建立所需的角度计算。
这在下图中进行了总结,我们根据人与箱子的相对位置归纳了一个三角计算:
角度计算规则
考虑到这个图,我们创建了一个函数,该函数仅从相对于容器的给定位置计算投掷成功的概率。
然后,我们根据上图计算从人到垃圾箱的方位,并计算在+/- 45度窗口内限定的分数。最接近真实方向得分的投掷更高,而那些距离更远得分更少,超过45度(或小于-45度)的任何东西都为负,然后将其设置为零概率。
最后,整体概率与给定当前位置的距离和方向有关,如前所示。
注意:我选择了45度作为边界,但您可以选择更改此窗口,也可以手动缩放概率计算,以不同方式对方向测量距离进行加权。
我们重新计算前面的例子并得到了与预期相同的结果。
绘制每种状态的概率
现在我们有了这样一个函数,可以很容易地计算并绘制我们的二维网格中所有点的概率,以获得固定的投掷方向。
概率由我们在前一个函数中设置的角度定义,目前这个角是45度,但是如果需要可以减少或增加,结果也将相应地改变。我们也可以根据距离来调整概率。
例如,对于每个x / y位置,当纸张以180度方位(正南)抛出时的概率如下所示
所有投掷方向的动画情节
为了进一步证明这一点,我们可以迭代一些投掷方向并创建一个交互式动画。代码变得有点复杂,你总是可以简单地使用前面的代码块并手动更改“throw_direction”参数来探索不同的位置。然而,这有助于探索概率,它可以在Kaggle笔记本中找到。
第二阶段:寻找概率已知的环境的最优政策
基于模型的方法
我们的目标是通过投掷或沿给定方向移动来找到每种状态下的最佳行动。因为我们已经知道概率,所以我们实际上可以使用基于模型的方法,并首先演示它,并且可以使用值迭代通过以下公式实现:
值迭代更新规则
值迭代以任意函数V0开始,并使用以下等式使k + 1阶段的函数从k阶段的函数转到(https://artint.info/html/ArtInt_227.html)。
每个状态的初始价值
MOVE动作的计算相当简单,因为我已经确定了保证运动成功的概率(等于1)。因此,例如来自状态(-5,-5)的动作(1,1)的Q值等同于:
Q(( - 5,-5),MOVE(1,1))= 1 *(R(( - 5,-5),(1,1),( - 4,-4))+ gamma * V( -4,-4)))
目前,奖励也都是0,因此第一次计算的值比较简单:
Q(( - 5,-5),(1,1))= 1 *(0 + gamma * 0)= 0
移动操作的第一个Q更新
第一次更新中的所有移动操作都将以类似方式计算。成功抛出将值添加到系统中。因此,我们可以计算特定投掷动作的Q值。以前,我们发现投掷方向从(-5,-5)开始沿50度方向的概率等于0.444。此操作的Q值会相应更新:
Q(( - 5,-5),THROW(50))=
0.444 *(R(( - 5,-5),(50),bin)+ gamma * V(bin +)))+
(1-0.444)*(R(( - 5,-5),(50),bin)+ gamma * V(bin-)))
同样,奖励设置为0,垃圾箱的正值为1,而垃圾箱的负值为-1。因此我们有:
Q(( - 5,-5),THROW(50))=
0.444 *(0 + gamma * 1)+
(1-0.444)*(0 + gamma * 1)= 0.3552-0.4448 = -0.0896
很明显,尽管在第一次更新后移动并没有从初始值改变,但是由于距离和丢失概率,在50度处投掷情况会更糟。
一旦针对所有状态和动作计算每个Q(s,a),则将每个状态的值V(s)更新为该状态的最大Q值。该过程反复进行,直到结果收敛。
价值迭代更新程序
对于需要重复多少次没有设置限制,这取决于问题。因为我们的环境非常简单,它实际上只需要10次更新就可以收敛到最优策略。
价值迭代更新的收敛性
我们首先通过如下所示的一个简单的彩色散点展示基于投掷或移动的最佳动作。
最优政策图v1
改进最优政策的可视化
虽然图表显示了最佳动作是投掷还是移动,但它并没有告诉我们这些动作所处的方向所在。因此,我们将每个最优动作映射到一个u和v的向量,并使用它们创建一个quiver plot。
我们定义箭头的规模并使用它来定义标记u的水平分量。对于移动的动作,我们简单地将x方向上的移动乘以该因子,并且对于掷骰方向,我们向左或向右移动1个单位(在0或180度时没有水平移动,在90或270度时没有垂直移动) 。
然后使用水平分量来计算具有一些基本三角函数的垂直分量,用一些基本的三角法,再次考虑某些角度,这些角度会导致计算错误。
我们看到一些状态下有多项最佳行动。那些直接向北,向东,向西的东西可以在多个方向上移动,而状态(1,1),(1,-1),( - 1,-1)和(-1,1)可以向垃圾桶移动或朝向垃圾箱扔。
最后,我决定通过导出每个绘图并传入一个小动画来显示每个更新的最优策略的变化。
第3阶段:在概率隐藏的情况下,通过强化学习找到最佳策略
Q学习算法
我们现在将假设这个人不知道概率,因此需要经验来找到最佳动作。
首先,让我们尝试找到最佳动作,如果这个人一开始就固定一个位置,并且垃圾桶像以前一样固定在(0,0)。
我们将应用Q-学习初始化值为0的所有状态 - 动作对,并且使用更新规则:
Q学习更新规则
我们给算法一个选择,在任何方向投掷或移动到当前的任何位置。(有8个方向可以移动:北,东北,东等)。
当我们选择扔纸时,它将获得+1的正奖励或-1的负值,当然具体取决于它是否打到垃圾箱从而决定这一趴是否结束。
事实证明,机器需要通过一系列试验和错误尝试来确定箱子所在的位置,然后确定是选择先移动还是先从当前位置扔出来更好。
Q-学习伪码
首先,和以前一样,我们用任意值0初始化Q表。
目前,将位置的开头将固定为一个状态,我们还会对每集中的动作数量设置一个上限,这样它就不会没完没了地进行下去。
如果纸张被抛出,则这一集会自然结束,算法执行的动作由ε-贪婪算法选择过程下决定,在这个过程中,操作是随机选择的。为了在平衡移动或投掷动作之间的随机选择(因为只有8个移动动作,但是有360个投掷方向)我决定给算法移动或投掷50/50的机会,然后从这些操作中随机选择一个动作。
如前所述,随机移动动作不能超出房间的边界,并且一旦发现,我们根据所有可能的后续动作的最大Q(s',a)更新当前Q(s,a)。例如,如果我们从-9,-9移动到-8,-8,Q((-9,-9),(1,1))将根据Q的最大值更新((-8,-8) ),a)所有可能的行动,包括投掷行动。
如果算法抛出纸张,则计算此投掷的成功概率,并且我们模拟在这种情况下,它是成功的并且能获得正的终止奖励,或者是不成功并且接收负的终端奖励。
该算法继续更新每个状态 - 动作对的Q值,直到结果收敛。
我们将在下一篇文章中分析不同参数的影响,但现在简单介绍一些任意参数选择:
- num_episodes = 100
- alpha = 0.5
- gamma = 0.5
- epsilon = 0.2
- max_actions = 1000
- pos_terminal_reward = 1
- neg_terminal_reward = -1
使用这些参数运行算法10次,在-5,-5状态下产生以下“最佳”动作:
显然,这些并不是一致的,这表明这些行动实际上并不是最佳的。因此,我们需要考虑我们选择的参数如何影响输出以及可以采取哪些措施来改善结果。
结论
我们在Python中从头开始引入了一个环境,并找到了最优策略。此外,我已经开始介绍使用Q学习找到最优策略的方法。
我将在后续帖子中继续这一点,并通过改变参数来改进这些初始结果。现在,我希望这足以让你在这个例子中开始尝试自己的算法。