强化学习其实并没有那么古老。当我在2000年中期开始的时候,它和现在有很大的不同。当时全世界只有少数几个实验室专注于强化学习。几乎没有人在行业内使用RL,RL的实际成功也仅限于少数应用。强化学习可以比任何人类更好地倒飞直升机。RL方法可以打败世界上最优秀的西洋双陆棋选手,并能很好地安排电梯的运行。但是RL并不是让机器人做有用的事情的最好方法,而且Q-learning 的智能体可以比人更好地玩电子游戏的想法几乎是不可想象的。但我们还是抱有希望。希望是因为我们认为强化学习是向人工智能迈进的最佳途径。RL的承诺几乎是令人陶醉的,一个学习agent可以通过简单地尝试事情并看看会发生什么来弄清楚世界如何运作。
毕竟,这就是我们认为人和动物所做的事情。那么为什么不在计算机中模拟一下呢。如果我们能做到这一点,那么它将在几乎所有的应用中发挥作用,作为一个很好的副作用,我们可能也会学到很多关于我们自己的思想是如何工作的。你可能会问,监督学习、无监督学习和强化学习之间有什么区别?区别很简单。在监督学习中,我们假设学习者可以获得给出正确答案的标签示例。在强化学习中,奖励给了代理一些关于其最近行动的好坏的想法。你可以认为监督学习需要一个老师,通过告诉你正确答案来帮助你。另一方面,奖励就像有一个人可以识别出好的行为是什么样的,但不能告诉你具体怎么做。无监督学习听起来好像可以有关联,但其实有一个非常不同的目标。无监督学习是关于提取数据中的底层结构。它是关于数据表示的。它可以用来构建表征,使监督或RL系统更好。事实上,正如你在本课程后面看到的那样,来自监督学习和无监督学习的技术都可以在RL中使用,以帮助泛化。
在RL中,我们专注于学习的问题,同时与一个不断变化的世界进行交互。我们不希望我们的代理简单地计算出一个好的行为,然后以开环的方式执行该行为。我们期望我们的代理会把事情做错,在他们走的过程中完善他们的理解。这个世界不是一个静态的地方。我们会受伤,天气会改变,我们会遇到新的情况,我们的目标也会改变。一个能立即整合其最新经验的代理应该做得很好,特别是与那些试图完美记忆世界如何运作的代理相比。在线学习的想法是非常强大的,是RL的一个定义特征。我们引入概念的方式是由这个事实决定的。例如,我们先介绍了强盗和探索的概念,之后再从监督学习中获取概念。如果你有机器学习的背景,这可能会让你觉得很落后。但你会看到,难的是在线学习,而不仅仅是从数据中学习。适应在线环境需要一个新的视角。如今,强化学习领域感觉正在飞速变化。几乎每周都有关于新的算法发展和基准领域最先进性能的改进的帖子。搜索公司、在线零售商和硬件制造商都在探索RL解决方案,用于日常运营。他们坚信,在线学习将使他们更有效率,节省资金,并使人类处于危险的境地。我从来没有想到,会有公司专门研究和应用强化学习。这真的是相当惊人。
不过,越是变化快的事物,越是要注重基础。RL中的一些理念最早可以追溯到巴甫洛夫和他的口水狗。拿几乎任何一个现代RL系统来仔细观察。它是建立在比本专业早一二十年的思想和算法之上的。例如,DQN的核心是结合了Qlearning、神经网络和经验回放。然而,要想从这些系统中获得良好的性能,需要进行重大创新。我们绝不会贬低这项工作的重要性。事实上,我们希望你能来理解这些复杂的放大学习系统。
在强化学习中,agent通过与世界的互动产生自己的训练数据。代理必须通过试错来学习自己行动的后果,而不是被告知正确的行动。在第一个模块中,我们将研究强化学习的这个评价方面。我们将专注于一个名为 "强盗 "的简化环境中的决策问题。在这段视频中,我们将使用k-bandit 来形式化不确定性下的决策问题,我们将使用这个匪徒问题来描述基本概念和强化学习,如奖励、时间步长和价值。
想象一下,在一项医学试验中,一位医生想测量三种不同治疗的效果。每当病人来到办公室,医生就会随机开出一种治疗方法。然后,医生会对病人进行监测,观察他们的健康状况是否有变化。一段时间后,医生注意到一种疗法似乎比其他疗法效果更好。医生现在必须决定是坚持使用效果最好的治疗方法还是继续进行随机研究。
如果医生只开一种疗法,那么他们就不能再收集其他两种疗法的数据。也许其他治疗方法中的一种其实更好,只是由于偶然性而显得更差。
如果其他两种治疗方法更差,那么继续研究就会危及其他患者的健康。这个医学试验是不确定性下决策的典范。这个医学试验的例子是一个k-armed bandit问题的案例。在k-armed bandit问题中,我们有一个agent,他在k个不同的行动中进行选择,并根据他选择的行动获得奖励。在医疗试验中,agent的角色是由医生扮演的。
医生必须在三种不同的行动中选择,开出蓝色、红色或黄色的治疗方案。每一种治疗都是一种行动。选择该治疗会产生一些未知的回报。最后,治疗后病人的福利是医生获得的奖励。为了让医生决定哪个行动是最好的,我们必须定义采取每个行动的价值。我们把这些值称为行动值或行动值函数。我们可以通过概率的语言使这个定义更加精确。我们将选择行动的价值定义为我们在采取坏行动时获得的预期报酬。
对了,如果你没有见过点等符号,它的简单意思是定义为。所以我们可以理解为q星的a被定义为R_t的期望值,给定我们选择了行动A,对于每一个可能的行动一到k,这个条件期望值被定义为所有可能的奖励的和。在这个和里面,我们已经把可能的奖赏乘以观察到这个奖赏的概率。这可以扩展到连续奖励的情况下,将求和换成积分。agent的目标是最大化预期奖励。如果代理选择了具有最高值的行动,它就实现了这个目标。我们把这个过程称为argmax,也就是使我们的函数q星最大化的参数。为了更好地理解q星,让我们回到我们的医疗试验例子。之前,我们说奖励可以是病人接受治疗后的福利。但在这个例子中,我们用一些更容易测量的东西,也许是接受治疗后的血压变化。每一种治疗可能会按照不同的概率分布产生奖赏。也许一个是伯努利分布,一个是二项分布,一个是均匀分布。
Q星是每个action的分布的平均值。你可以很容易地计算出伯努利分布的期望值。简单地将失败的概率乘以失败时的奖励,再加上成功的概率,乘以成功时的奖励。这只是基本的统计学。在不确定性下做决策的例子有很多。比如我们已经讨论过的医疗试验的例子。其他例子还包括内容推荐,比如看什么电影,或者听什么歌。即使是在餐厅点菜,你也不能确定你喜欢什么,但你会做出最好的选择。为什么我们要先考虑匪问题?因为在出现问题和算法设计选择的时候,最好在最简单的环境下考虑问题和算法设计选择。例如,在匪徒和强化学习中,奖励最大化和估计值都是重要的子问题。在这个视频中,我们向你介绍了强盗问题。我们展示了不确定性下的决策是如何通过k臂匪徒问题来形式化的。在匪徒问题中,我们已经看到了强化学习背后的基本思想;行动、奖励和价值函数。(action,reward,value functions)
还记得我们的医生在进行医学试验吗?如果这位医生已经知道每一种治疗的长期结果,会发生什么?选择合适的治疗方法将是小事一桩。不幸的是,情况往往不是这样。通常情况下,医生会进行许多试验来了解每种治疗方法。每天,医生可以利用之前收集的所有数据来估计他们认为哪种治疗方法是最好的。让我们来学习一下这可能是如何工作的。今天,我们将讨论一种估计作用值的方法,称为样本平均法sample average method。我们将使用这种方法来计算我们的医疗试验例子中每个治疗的价值。然后,我们将描述贪婪的行动选择。最后,我们将介绍强化学习中的exploration-exploitation 困境。
在开始之前,我们先回顾一下动作值的定义。选择一个动作Q星的价值是指采取该动作后得到的预期报酬。Q星并不为agent所知,就像医生不知道每次治疗的效果一样。相反,我们需要找到一种方法来估计它。估计Q星的一种方法是计算样本平均数。我们只需记录每个行动的总奖励,然后除以该行动被选择的次数。
为了直观地理解样本平均估计值,我们来看一个行动,行动A,行动A的估计值是采取行动A时观察到的奖励总和除以行动A被采取的总次数。我们使用t减1,因为时间t的值是基于时间t之前采取的行动。另外,如果行动A还没有被采取,我们将值设置为一些默认值,比如零。让我们回到我们的医疗试验例子。医生必须决定在三种可能的治疗方法中开出哪一种。如果病人的病情好转,医生就会记录一个奖励。否则,医生记录的奖励为零。假设我们知道Q星,但我们的医生不知道。
医生按时间步骤一给第一个病人治疗P,病人报告感觉好了。医生记录该治疗的奖励为1,并更新估计值。到目前为止只有一个数据点,所以治疗P的估计值是1。第二个病人到来。医生再次随机开出治疗P。失败了,医生记录并奖励0,并将治疗P的价值估计值更新为0.5。
由于我们定义初始估计值为零,所以其他行动的估计值仍然为零。让我们把时间快进一点。在每个治疗方法被尝试了几次之后,我们可以从观察到的数据中计算出估计值。随着医生观察更多的病人,估计值就会接近真实的行动值。在现实中,我们的医生不会随机给病人分配治疗方法。相反,他们可能会分配他们目前认为最好的治疗方法。我们称这种选择行动的方法为贪婪行动(greedy)。
贪婪的行动是当前估计值最大的行动。选择贪婪的行动意味着代理正在利用其当前的知识。它正试图获得它现在能得到的最大回报。我们可以通过取估计值的argmax来计算贪婪的行动。另外,agnet可以选择非贪婪行动来探索。代理会牺牲眼前的报酬,希望获得更多关于其他行动的信息。代理人不能同时选择探索和利用。这是强化学习的基本问题之一。探索-开发的困境。我们将在接下来的视频中更多地讨论这个问题。就这样吧。在这个视频中,我们介绍了估计动作值的样本平均法,我们将贪婪的动作定义为具有最大值估计的动作。下次再见。
想象一下,你维护了一个网站,每天的点击量达到数百万。你可以将其框定为一个 k-armed bandit问题。估计值对应着每个广告产生的总金额,而你的目标是显示能产生最多钱的广告。如何在不存储数百万次点击的数据的情况下,保持你的价值估计值的更新?在本视频结束时,您将能够:描述如何以增量方式估计行动值,识别增量更新规则如何成为更通用学习规则的一个实例,并描述通用学习规则如何用于非稳态问题。
样本平均法可以用递归的方式编写。通过这样做,我们可以避免存储所有之前的数据。让我们看看这是如何工作的。要做到这一点,我们要从和中提取当前的奖励。现在,总和只到之前的奖励。我们用之前的价值估计来写下我们的下一个价值估计。为此,我们将当前的和值乘以N减1。通过乘法和除法,我们实际上是在乘以一。圆圈一词你应该很熟悉。这只是我们对Q_n的定义,即当前值估计。我们可以把这个公式再简化一下。我们对Q_n进行分布,得到这个形式。最后,我们从总和中抽出 nQ_n,然后在 n 上乘以 1。现在,我们有了一个用于估计值的增量更新规则。
这个方程的形式在整个课程中会出现很多次。让我们定义其中的一些术语。
估计值的误差(error)是旧估计值和新目标之间的差值。向新目标迈进一步,就会产生一个新的估计,减少我们的误差。这里,新的报酬就是我们的目标。步长的大小由我们的步长参数和旧估计的误差决定。我们现在有了一个增量更新估计的一般规则。步长可以是一个n的函数,产生一个从0到1的数字。
在样本平均的特殊情况下,步长等于1大于n。如果在某些条件下,其中一种治疗方法更有效呢?具体来说,我们假设治疗方法B在冬季更有效。这就是一个非稳态土匪问题的例子。这些问题就像我们之前讨论过的强盗问题一样,只是奖励的分布会随着时间的变化而变化。医生不知道这种变化,但希望适应这种变化。一种选择是使用固定的步长大小。如果Alpha_n是恒定的,比如0.1,那么最近的奖励比旧的奖励对估计的影响更大。
这张图显示了最近的奖励与T时间步数前的奖励的权重。随着时间的推移,权重以指数的形式减弱。当我们在X轴上向右移动时,我们的时间就会越往后走。看到为什么这是真的,我们再来看看增量更新方程。我们先把Alpha分布并重新排列。我们可以把下一个值写成奖励和上一个值的加权和。注意递归形式。我们可以把Q_n的定义代入这个方程,我们就可以得到这个。然后我们可以将1减去Alpha,得到一个方程式,显示R_n和R_n减一的关系。我们可以进一步展开这个递推关系。我们不断地用它的定义替换Q,直到我们一直回到初始值Q_1。最后,我们来清理一下这个长方程。
我们把它写成我们的初始值Q加上随着时间推移的奖励的加权和。这个等式告诉我们什么呢?它将我们当前的估计值,Q_n加一与Q一,以及所有观察到的奖励联系起来。第一项告诉我们,Q_1的贡献随着时间的推移呈指数级递减。第二项告诉我们,时间越往后的奖励对总和的贡献越小。综上所述,我们可以看到,随着数据越来越多,我们初始化Q的影响也会归零。最近的奖励对我们当前的估计贡献最大。
在这个视频中,我们推导出了样本平均法的增量更新。我们将增量更新规则概括为一种形式,将在整个课程中重新审视。最后,我们讨论了一个恒定的步长大小如何帮助解决非稳态匪徒问题。
想象一下,你今晚要和朋友出去吃饭。当你到了餐厅,你将不得不决定点什么。你以前去过几次,你总是点同样的东西。所以你知道,如果你再点一次,你会很高兴。不过其他很多项目看起来都很好吃。你如何决定什么时候再点同样的好菜,或者尝试新的东西?在本视频结束时,你将能够定义探索-开发-权衡,你将能够定义Epsilon-Greedy,这是一种简单的方法来平衡探索和开发。在讨论权衡之前,我们先来谈谈什么时候我们会想要探索,什么时候会想要利用。探索可以让代理提高他对每个行动的认识。希望能带来长期的利益。通过提高估计行动值的准确性,代理人可以在未来做出更明智的决策。下面是一个探索性行为的例子。
假设这些盘子中的每一个都代表了你最喜欢的餐厅的一顿饭,而你正试图选择点哪一顿饭。
a的Q是选择该餐的估计值。a的N是你挑选该餐的次数,a的q星是每餐的价值。
每次去这家餐厅,你都会严格按照制度,以Round Robin的方式选择每一餐。也许某顿饭有时做得特别好。所以你点了它就会得到很高的奖励。一段时间后,你就会找到最适合点的饭菜。剥削则是利用代理人当前的估计值。它选择贪婪的行动,试图获得最多的奖励。
但通过对估计值的贪婪,可能并不能真正获得最多的回报。让我们来看看纯粹的贪婪行动选择是如何导致次优行为的。想象一下,agent喜欢第一餐。agent获得了正向的奖励,使得该餐的价值更高。其他行动的估计值为零。所以贪婪的行动总是一样的,选择第一顿饭。这意味着代理从来没有看到过其他膳食的任何样本。其他两个动作的估计值仍然与真实值相差甚远,这意味着代理从未发现最佳动作。这就自然而然地引入了探索-开发的困境。我们如何选择何时探索,何时利用?当我们探索时,我们会得到更准确的价值估计。当我们开发时,我们可能会得到更多的回报。然而,我们不能选择同时做这两件事。在探索和开发之间选择的一个非常简单的方法是随机选择。我们可以选择在大部分时间内进行探索,而探索的机会很小。例如,我们可以掷一个骰子。如果它落在一个上,那么我们就会探索。否则,我们会选择贪婪的行动。我们称这种方法为Epsilon-Greedy。其中epsilon指的是选择探索的概率。
在这种情况下,epsilon将等于1大于6。我们可以用下面的方式来写Epsilon-Greedy。我们在时间步长t上选择的行动,是概率为1减去epsilon的贪婪行动,或者是概率为epsilon的随机行动。我们可以在课本上的10臂测试台上证明Epsilon-Greedy动作选择的有效性。10臂横幅问题在这里有10个动作,沿X轴显示。在Y轴上,我们将显示奖励的分布。每个奖励都是从正态分布中抽样出来的,有一些均值q星的a和方差1。每一个q星的a都是从平均数为0,方差为1的正态分布中抽取的。每次我们运行10-arm Testbed时,q星将从正态分布中重新抽取。
请注意这个实验有多少随机性。q星是从正态分布中随机抽取的。奖励是根据q星随机抽样的,行动是在探索步骤上随机进行的。为了公平地比较不同的算法选择,我们需要进行许多独立的运行。让我们来看看10-arm Testbed中一个Epsilon-Greedy代理的单次运行。对于这个agent,我们设置epsilon等于0.1。时间步长在X轴上。Y轴是该时间步长上收到的奖励。
请注意这条曲线是多么的嘈杂,有几个尖锐的峰值。我们看到这些峰值的中心有轻微的上升趋势。但是在这种噪声量下,很难做出任何结论。如果我们用不同的随机种子运行另一个代理,我们会得到另一条有噪音的曲线,并进行第三次运行。对于每一个时间步,我们可以取这三个奖励的平均值,我们在该时间步上看到的每一个奖励。这将产生一条单线,代表这三次运行中每一次得到的平均奖励。例如,当我们取20次这样的运行并平均奖励时会发生什么。请注意,曲线上的尖峰已经不那么明显了。如果我们取100次运行并将它们平均在一起,我们会看到曲线的形状更加清晰。
在探索和开发之间选择一个很简单的方法就是随机选择。我们可以在大部分时间里选择开发,探索的几率很小。
对于每一个时间步,我们可以取这三个奖励的平均值,我们在该时间步上看到的每一个奖励。这将产生一条单线,代表这三次运行中每一次得到的平均奖励。例如,当我们取20次这样的运行并平均奖励时会发生什么。请注意,曲线上的尖峰已经不那么明显了。如果我们取100次运行并将它们平均在一起,我们会看到曲线的形状更加清晰。前200步的奖励有明显的增加,用2000次运行来做,我们就能清楚地看到这种方法的表现。这个结果说明的是,这种行为方式在可能的随机结果中获得了这么多的期望奖励。在整个这个专项中,我们使用了许多独立运行的平均性能来进行科学的比较。如果不使用平均数这样的汇总统计,就很难在算法之间进行公平的比较。在这个例子中,随机种子是这个Epsilon-Greedy智能体运行之间唯一的区别,然而性能看起来却大不相同。
我们要比较不同的Epsilon-Greedy代理。让我们先研究一下每个算法获得的平均奖励。时间步长显示在X轴上。Y轴上是2000次运行的平均奖励。这里是epsilon等于零时的性能。当epsilon为零时,代理不执行任何探索步骤,只执行贪婪的步骤。这是epsilon等于0.01时的性能。注意,平均奖励随着时间的推移不断提高。这种方法在1%的时间里进行探索,最终收敛到99.1%的时间里采取最优行动。epsilon等于0.1的代理比其他方法平均更早获得更多的奖励。但它在300步后就趋于平缓。在这个讲座中,我们讨论了探索和开发之间的权衡。我们还讨论了Epsilon-Greedy,这是一种平衡探索和开发的简单方法。稍后,我们将讨论更复杂的探索和开发之间的选择方法。
我们已经讨论了一些平衡探索和开发的方法。因为我们是从采样的奖励中估计我们的行动值,所以我们估计的准确性存在固有的不确定性。我们探索降低这种不确定性,以便我们在未来做出更好的决策。在这个视频中,我们将讨论另一种选择行动的方法,以平衡探索和开发,称为UCB。在本视频结束时,您将了解上置信度约束行动选择如何利用估计中的不确定性来推动探索。回忆一下我们之前讨论过的Epsilon-greedy动作选择方法。这种方法在时间上使用探索性动作的epsilon百分比。
探索性动作是统一选择的。我们还能做得更好吗?如果我们的价值估计中有一个不确定性的概念,我们就有可能以一种更智能的方式选择行动。什么叫估计中的不确定性?这里a的Q代表了我们当前对行动A的估计,这些括号代表了A的Q星周围的置信区间,它们表示我们确信行动A的价值就在这个区域的某个地方。例如,我们相信它可能在这里或这里。左边的括号叫做下界,右边的是上界。中间的区域就是置信区间,代表我们的不确定性。如果这个区域非常小,我们非常确定行动A的值接近我们的估计值。如果这个区域很大,我们不确定动作A的值是否接近或估计值。
在UCB中,我们遵循面对不确定性时的乐观原则。简单来说,就是如果我们对某件事情不确定,我们应该乐观地认为它是好的。比如说我们有这三个具有相关不确定性的行动,我们的代理不知道哪个是最好的。所以它乐观地选择了上界最高的行动。这是有意义的,因为要么它确实有最高的价值,我们得到了很好的回报,要么通过采取它,我们可以了解到一个我们最不了解的动作,比如幻灯片上的例子。让我们让算法再选一个动作。这次Q2的上置信度边界最高,因为它的估计值最高,尽管区间很小。
我们可以使用上置信边界来选择行动,使用下面的公式;我们将选择估计值最高的行动加上我们的上置信边界探索项。上界项可以分成三个部分,我们将在下一张幻灯片中看到。C参数作为用户指定的参数,控制探索量。我们在这里可以清楚地看到UCB是如何将勘探和开发结合起来的。和中的第一项代表开发部分,第二项代表探索部分。我们来看几个探索项的例子。假设到目前为止,我们已经走了10000步。想象一下,我们已经选择了5000次行动A。这里的不确定性项将是常数C的0.043倍,如果相反,我们只选择了行动A 100次,不确定性项将大10倍。
大概是说选择时间少,重复次数多的价值高。
让我们使用10臂测试台来研究上置信度约束动作选择的性能。我们将使用与之前相同的设置。这些动作的Q星值是正态分布,平均数为0,标准差为1。奖励是从平均Q星的单变量正态分布中抽样得到的。和之前一样,我们将对2000次独立运行进行平均。为了在10臂床问题上比较UCB和Epsilon-greedy,我们说C等于2为UCB,所以Epsilon-greedy的epsilon等于0.1。在这里我们看到,UCB在大约100倍步后,平均获得的回报比Epsilon-greedy更大。最初,UCB探索更多的是为了系统地减少不确定性。UCB的探索随着时间的推移而减少,而Epsilon-greedy则在10%的时间内继续采取随机行动。在这个视频中,我们讨论了上置信度约束行动选择,它利用价值估计的不确定性来平衡探索和开发。
你好,我叫John Langford,我想给大家讲讲用于真实世界强化学习的情境匪徒。它源于我十多年来一直在做的一个长期项目,导致很多真实世界的部署,总的来说,情境匪徒是现在现实世界中强化学习的部署方式。我们先说说为什么要考虑现实世界的问题。一般来说,强化的方式往往与现实世界不同。通常来说,现在强化学习是和模拟器一起工作的。模拟器提供观测值,然后学习算法有一个策略,它选择一个动作。然后模拟器进行处理并返回奖励。例如,当你为一个游戏玩法做强化学习时,就会发生这种情况。现在,当你想把这个应用到现实世界的时候,就会有一个真正的问题,就是这些东西如何对齐。所以,例如,当一个观察来自真实世界时,它是否像来自模拟器的观察?通常情况下,它有各种不同的方式。当根据观察采取的行动时,它是否相同?通常情况下,因为观察的性质不同,导致即使给定相同的政策,也会有不同的行动。那么,从现实世界中得到的回报和在模拟器中得到的回报相似吗?不,答案是否定的。它是不相似的。所以,鉴于此,有一个分歧。模拟器和现实之间是有差距的。所以,虽然你可以尝试在模拟器中学习,但在模拟器中所学到的知识在实际应用中的适用性是不明确的,在很多情况下,甚至可能是不可能的。那么,既然基于模拟器的强化学习(这是很多强化学习的地方)和基于真实世界的强化学习之间有差距,那么如何进行真实世界的强化学习呢?我认为关键的答案是优先级的转变。所以你要转变你的优先级来支持真实世界的强化学习应用。所以举个例子,Temporal Credit Assignment,换句话说,我们看了比赛,对强化学习来说真的很重要。但也许它的重要性要低一些。也许在不同观察中的泛化更重要。在模拟器中,强化学习算法很容易控制环境。你可以说一步一步请向前走。但在现实世界中,通常环境会控制你。这是一个基本的进口,就你的接口需要在现实世界中工作。在模拟器中,计算效率是关键的限制性问题,因为你有尽可能多的样本,你可以计算。但在真实世界中,统计效率是更大的关注点,因为你只有真实世界给你的样本,所以你必须使用这些样本来实现最大的影响。在基于模拟器的强化学习中,我们必须要考虑状态的问题。好吧,状态是做出决策所必需的基本信息。但在现实世界中,往往你有一些非常复杂的观察结果,它可能有更多的信息,是做出决策所必需的。如果你有一个百万像素的相机,也许你不需要所有这些像素来做决策,也许在做决策的时候,在其他方面区分所有这些不同可能的像素设置作为状态是很重要的。当你在现实世界中的时候,突然之间,能够关闭政策评估变得很重要。所以在上下文匪,我一会儿会讲到,有一些算法只是做学习,算法做学习,但也作为副产品产生了它的候选者,你可以用它做一个政策评估。自然,这些政策评估支持的算法只是在实际应用中的首选。另一个区别必须要和你关心的政策来区分。在模拟器中,也许你运行了很长时间,并保存了你关心的最后一个策略。但是在现实世界中,你收集的每一个数据点都会涉及到与世界的一些交互,你希望这种方式的性能非常好。所以你真正关心的是整个策略的轨迹,策略的顺序,因为你在现实世界中学习。让我们想想个性化的新闻。这是强化学习在现实世界中一个非常自然的应用。也许你有一组可能的新闻文章,这些文章是今天感兴趣的。一些音乐来到一个网站。你想选择一些他们可能感兴趣的新闻文章。然后你会得到一些反馈,他们是否真的阅读了这篇文章。所以这是一个非常自然的强化学习结构,这个其实更简单的是它的情境强盗结构。那么想一想什么是情境强盗?在情境强盗中发生的是,你观察到一些特征。也许是用户的地理位置。也许是基于用户过去的行为方式的一些特征。也许是可能的行动的特征,这也是可用的。基于此,你选择一个行动,然后你会得到一些奖励。你的目标是在设定中最大化奖励。案例运河,这听起来像是全强化学习,而且在很大程度上是这样的。但是有一个严重的警告,就是我们想象中没有学分分配问题。所以展示给你的新闻文章并不会影响我对新闻文章进行解释时的行为方式。这个历史其实是很近的。在过去的十年里,世界发生了很大的变化的东西。所以在2007年的时候,有了第一个上下文强盗算法,叫Epoch Greedy,本质上是Epsilon Greedy的一个版本,根据你知道的多少来改变Epsilon的交易。我们迅速发现有一个更早的论文,EXP4算法,它在某种意义上统计上更有效率。但它在计算上却糟糕得可怕。2010年,我们有了第一个个性化新闻的应用,在现实世界中进行了部署,当时我在雅虎研究。2011年,我们有了纪元贪婪式学习和EXP4式学习的第一次联姻,实现了如果本质上有计算统计效率。2014年,我们有了一个更好的算法,我们想出了一个更好的算法,其实你今天可以用,然后2016年,我们创建了第一个版本的决策服务,这是一个通用的服务云服务,你可以用它来创建自己的情境匪学习者。二千零九十,最终形成了一个强化学习服务产品,Azure认知服务个性化器。基于该服务,你可以去个性化你的网站或其布局或许多其他东西。这是一个通用的服务。你可以输入任意的功能,选择一个动作,然后坐任意的词与它学习。基于这个系统,我们其实有2019年的年度AI系统。所以我没有足够的时间在这里详细介绍。但如果你对情境匪夷所思的更多细节感兴趣的话,2018年有一个教程出来[听不清],我建议你看一看。如果你对个性化服务感兴趣,可以在这个网址上找到,然后如果你应该需要个性化服务背后的算法和上下文强盗算法的内部实现,窝窝团已经成为大量不同的上下文强盗算法的资源库。谢谢你。
将Exploitation定义为:代理采取它目前认为最好的行动,希望它能产生最大的回报,而Exploration是考虑到重复次数,和迭代的时间希望在长时间下有好的结果。
带入一下递归公式,Target是Rn,Qn是estimate
(注:其中的RL-Glue提供了一个标准界面,使您可以将强化学习[wikipedia.com]agent,environment和实验程序连接在一起,即使它们以不同的语言编写也是如此。 要使用RL-Glue,请先安装RL-Glue Core,然后安装编解码器(在左侧导航栏中列出),以使您选择的语言能够相互对话。核心项目和所有编解码器都跨平台兼容,并且可以在Unix,Linux,Mac和Microsoft Windows(有时在Cygwin下)上运行。)
任务 :Bandits and Exploration/Exploitation
Section 0: Preliminaries
# Import necessary libraries
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm
import time
from rlglue.rl_glue import RLGlue
import main_agent
import ten_arm_env
import test_env
在上面的单元格中,我们导入了本次作业所需的库。我们在整个课程中都会使用numpy,偶尔也会提供一些提示,告诉我们在numpy中应该使用哪些方法。除此之外,我们主要使用vanilla python,偶尔也会使用其他库,比如matplotlib来做图。
你可能已经注意到,我们导入了 ten_arm_env。这就是教材2.3节中介绍的10-armed Testbed。我们在整个笔记本中都使用这个来测试我们的强盗特工。它有10条手臂,这是代理可以采取的行动。拉动一个手臂会从一个具有单位方差的高斯分布中产生一个随机奖励。对于每个动作,在每次运行开始时,从正态分布中随机抽取该动作的期望值。如果你对10臂测试台不熟悉,请在继续之前先复习一下课本上的内容。
我们想要创建一个agent,它将找到具有最高预期报酬的行动。一个代理可以操作的方式是总是根据代理当前的估计选择具有最高价值的行动。这被称为贪婪的代理,因为它贪婪地选择它认为价值最高的行动。让我们看看在这种情况下会发生什么。
首先我们要实现argmax函数,它接收一个动作值的列表,并返回一个具有最高值的动作。为什么我们要实现自己的函数,而不是使用numpy使用的argmax函数呢?Numpy 的 argmax 函数会返回最高值的第一个实例。我们不希望发生这种情况,因为在平局的情况下,它会使代理偏向于选择一个特定的动作。相反,我们希望随机地打破最高值之间的平局。所以我们要实现我们自己的argmax函数。你可能想看看np.random.choice来从一个值的列表中随机选择。
我们举个例子理解一下将第一个函数的返回值设置成ties而不是np.random.choice(ties),观察一下ties的内容。
test_array = [0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
np.argmax(test_array) # 8
argmax(test_array) # [8]
test_array = [1, 0, 0, 1]
np.argmax(test_array) # 0
argmax(test_array) # [0, 3] 因此choice后随机出现0或者3
参考一下这个博客
#numpy.random.choice(a, size=None, replace=True, p=None)
从数组a(只要是ndarray都可以,但必须是一维的)中随机抽取数字,并组成指定大小(size)的数组
replace:True表示可以取相同数字,False表示不可以取相同数字
数组p:与数组a相对应,表示取数组a中每个元素的概率,默认为选取每个元素的概率相同。
# -----------
# Graded Cell
# -----------
def argmax(q_values):
"""
读取q_values的列表,并返回值最高的项目的索引。
返回值: int - q_values中最高值的索引。
"""
top_value = float("-inf")
ties = []
top_value = max(q_values)
for i in range(len(q_values)):
# 如果q_values中的一个值大于最高值,则更新到最上面并将ties重置为零。
# 如果一个值等于最大值,则将索引加到ties上。
# 返回从ties中随机的选择之
if q_values[i] == top_value:
ties.append(i)
raise NotImplementedError()
return np.random.choice(ties)
现在我们介绍一下你将实现的RL-Glue代理的第一部分。这里我们将创建一个GreedyAgent,并实现agent_step方法。这个方法在每次代理采取步骤时都会被调用。该方法必须返回代理选择的动作。这个方法还可以确保代理的估计根据它从环境中得到的信号进行更新。
# -----------
# Graded Cell
# -----------
class GreedyAgent(main_agent.Agent):
def agent_step(self, reward, observation):
"""
让智能体一步到位。它输入的是奖励和观察并
返回智能体在该时间步选择的动作。
定义:
reward -- float, 智能体在采取最后一次行动后从环境中获得的reward。
observation -- float, 智能体所处的观察状态.不要担心这个,因为在以后的课程中才会用到它。
返回:
current_action -- int, 智能体在当前时间步选择的行动。
"""
### 有用的类变量 ###
# self.q_values : 一个数组,包含智能体认为Arm的每个值是什么。
# self.arm_count : 一个数组,包含每个Arm被拉动的次数。
# self.last_action : 智能体在上一个时间步骤所采取的行动。
#######################
self.arm_count[self.last_action] += 1
self.q_values[self.last_action] = self.q_values[self.last_action] + (1.0 / self.arm_count[self.last_action]) * (reward - self.q_values[self.last_action])
# 更新Q值 提示:请看课本2.4节的算法。
# 递增self.arm_count中的计数器,从上一个时间步骤开始计算。
# 使用self.arm_count更新步长大小。
# 更新self.q_values为上一个时间步骤的动作。
current_action = argmax(self.q_values)
self.last_action = current_action
# YOUR CODE HERE
raise NotImplementedError()
# current action = ? # 使用上面创建的argmax函数
# YOUR CODE HERE
raise NotImplementedError()
return current_action
让我们把结果可视化。这里,我们使用RL-Glue运行一个实验来测试我们的代理。现在,我们将设置实验代码;在未来的课程中,我们将指导您运行实验,以便您可以创建自己的实验。
# ---------------
# Discussion Cell
# ---------------
num_runs = 200 # 运行实验的次数
num_steps = 1000 # 智能体每只arm的拉动次数
env = ten_arm_env.Environment # 设置测试的环境
agent = GreedyAgent # 设置想用的智能体
agent_info = {"num_actions": 10} # 把它所需要的信息传给智能体,看看这里有多少个arm。
env_info = {} # 把环境所需的信息传递给它。在这种情况下,什么都不需要。
all_averages = []
average_best = 0
for run in tqdm(range(num_runs)): # tqdm是创建下面的进度条的。
np.random.seed(run)
rl_glue = RLGlue(env, agent) # 使用我们上面选择的环境和智能体创建一个新的RLGlue实验。
rl_glue.rl_init(agent_info, env_info) # 初始化智能体和环境所需要的东西传递给RLGlue。
rl_glue.rl_start() # 启动环境
average_best += np.max(rl_glue.environment.arms)
scores = [0]
averages = []
for i in range(num_steps):
reward, _, action, _ = rl_glue.rl_step() # 环境和智能体采取一步并返回相应的reward和action
scores.append(scores[-1] + reward)
averages.append(scores[-1] / (i + 1))
all_averages.append(averages)
plt.figure(figsize=(15, 5), dpi= 80, facecolor='w', edgecolor='k')
plt.plot([average_best / num_runs for _ in range(num_steps)], linestyle="--")
plt.plot(np.mean(all_averages, axis=0))
plt.legend(["Best Possible", "Greedy"])
plt.title("Average Reward of Greedy Agent")
plt.xlabel("Steps")
plt.ylabel("Average reward")
plt.show()
greedy_scores = np.mean(all_averages, axis=0)
我们了解到智能体的另一种运作方式,它并不总是采取贪婪的行动。相反,有时它会采取探索性行动。它这样做是为了能够找出真正的最佳行动是什么。如果我们总是选择我们认为当前的最佳行动是什么,我们可能会错过采取真正的最佳行动,因为我们还没有探索足够的时间来寻找这个最佳行动。
下面实现一个epsilongreedy代理。提示:我们实现的是课本2.4节的算法。你可能想使用上面的greedy代码,看看np.random.random,以及np.random.randint,来帮助你选择随机行动。
# -----------
# Graded Cell
# -----------
class EpsilonGreedyAgent(main_agent.Agent):
def agent_step(self, reward, observation):
"""
让智能体一步到位。它输入的是奖励和观察并
返回智能体在该时间步选择的动作。
定义:
reward -- float, 智能体在采取最后一次行动后从环境中获得的reward。
observation -- float, 智能体所处的观察状态.不要担心这个,因为在以后的课程中才会用到它。
返回:
current_action -- int, 智能体在当前时间步选择的行动。
"""
### 有用的类变量 ###
# self.q_values : 一个数组,包含智能体认为Arm的每个值是什么。
# self.arm_count : 一个数组,包含每个Arm被拉动的次数。
# self.last_action : 智能体在上一个时间步骤所采取的行动。
# 比上一次多了这个变量
# self.epsilon : epsilon贪婪智能体探索的概率(范围在0和1之间)
#######################
# Update Q values - 和之前一样
# YOUR CODE HERE
self.arm_count[self.last_action] += 1
self.q_values[self.last_action] = self.q_values[self.last_action] + (1.0 / self.arm_count[self.last_action]) * (reward - self.q_values[self.last_action])
# 使用贪婪的epsilon选择行动。
# 在0和1之间随机选择一个数字,看它是否小于self.epsilon。
# (提示:看np.random.random())。如果是,就把current_action设置为一个随机动作。
# 否则就像上面那样贪婪地选择current_action。
# YOUR CODE HERE
_ = np.random.random()
current_action = argmax(self.q_values) if _ >= self.epsilon else np.random.randint(0,len(self.q_values))
self.last_action = current_action
return current_action
# ---------------
# Discussion Cell
# ---------------
# Plot Epsilon greedy results and greedy results
num_runs = 200
num_steps = 1000
epsilon = 0.1
agent = EpsilonGreedyAgent
env = ten_arm_env.Environment
agent_info = {"num_actions": 10, "epsilon": epsilon}
env_info = {}
all_averages = []
for run in tqdm(range(num_runs)):
np.random.seed(run)
rl_glue = RLGlue(env, agent)
rl_glue.rl_init(agent_info, env_info)
rl_glue.rl_start()
scores = [0]
averages = []
for i in range(num_steps):
reward, _, action, _ = rl_glue.rl_step() # The environment and agent take a step and return
# the reward, and action taken.
scores.append(scores[-1] + reward)
averages.append(scores[-1] / (i + 1))
all_averages.append(averages)
plt.figure(figsize=(15, 5), dpi= 80, facecolor='w', edgecolor='k')
plt.plot([1.55 for _ in range(num_steps)], linestyle="--")
plt.plot(greedy_scores)
plt.title("Average Reward of Greedy Agent vs. E-Greedy Agent")
plt.plot(np.mean(all_averages, axis=0))
plt.legend(("Best Possible", "Greedy", "Epsilon: 0.1"))
plt.xlabel("Steps")
plt.ylabel("Average reward")
plt.show()
注意epsilon-greedy代理的性能要好得多。因为我们偶尔会选择一个随机动作,所以我们能够找到更好的长期策略。通过在我们的价值估算准确之前采取贪婪的行动,我们就有可能采取次优行动。
您是否注意到我们平均进行了200多次run?我们为什么要这样做? 为了获得一些更好的理解,让我们看一下同一智能体两次单独运行的结果。
# ---------------
# Discussion Cell
# ---------------
# Plot runs of e-greedy agent
agent = EpsilonGreedyAgent
env = ten_arm_env.Environment
agent_info = {"num_actions": 10, "epsilon": 0.1}
env_info = {}
all_averages = []
plt.figure(figsize=(15, 5), dpi= 80, facecolor='w', edgecolor='k')
num_steps = 1000
for run in (0, 1):
np.random.seed(run) # Here we set the seed so that we can compare two different runs
averages = []
rl_glue = RLGlue(env, agent)
rl_glue.rl_init(agent_info, env_info)
rl_glue.rl_start()
scores = [0]
for i in range(num_steps):
reward, state, action, is_terminal = rl_glue.rl_step()
scores.append(scores[-1] + reward)
averages.append(scores[-1] / (i + 1))
plt.plot(averages)
plt.title("Comparing two independent runs")
plt.xlabel("Steps")
plt.ylabel("Average reward")
plt.show()
请注意,两次运行有何不同?但是,如果这是完全相同的算法,为什么在这两次运行中它的行为会有所不同? 答案是,这是由于环境和智能体中的随机性引起的。根据智能体随机开始执行的操作或随机选择进行探索的时间,智能体可以更改运行结果。即使智能体选择相同的动作,也会从高斯随机抽取来自环境的奖励。智能体可能会很幸运,并且会尽早看到较大的奖励以获得最佳操作,因此可以更快地确定最佳操作。或者,它可能会变得不走运,并且会在早期看到最佳行动的较小回报,因此需要更长的时间才能意识到这实际上是最佳行动。 具体来说,让我们看看针对不同种子进行了几次探索性操作。
# ---------------
# Discussion Cell
# ---------------
print("Random Seed 1")
np.random.seed(1)
for _ in range(15):
if np.random.random() < 0.1:
print("Exploratory Action")
print()
print()
print("Random Seed 2")
np.random.seed(2)
for _ in range(15):
if np.random.random() < 0.1:
print("Exploratory Action")
对于第一个种子,我们将进行15次中的三次探索性操作,但是对于第二个种子,我们将仅进行一次探索性操作。这可能会严重影响我们智能体的性能,因为探索的数量已发生重大变化。为了比较算法,因此我们报告了多次运行的平均性能。我们这样做是为了确保我们不会像在讲座中解释的那样简单地报告由于随机性导致的结果。相反,我们希望获得具有统计意义的结果。在本课程中,我们将不使用统计显着性检验。相反,因为我们可以使用仿真器进行实验,所以我们使用了更简单的策略来进行大量运行,并确保置信区间不会重叠。
我们能做得比0.1的epsilon更好吗?让我们尝试几种不同的epsilon值,看看它们的表现如何。我们尝试关键性能参数的不同设置,以了解代理在不同条件下的表现。
下面我们运行一个实验,在这个实验中,我们扫过epsilon的不同值。
# ---------------
# Discussion Cell
# ---------------
# Experiment code for different e-greedy
epsilons = [0.0, 0.01, 0.1, 0.4]
plt.figure(figsize=(15, 5), dpi= 80, facecolor='w', edgecolor='k')
plt.plot([1.55 for _ in range(num_steps)], linestyle="--")
n_q_values = []
n_averages = []
n_best_actions = []
num_runs = 200
for epsilon in epsilons:
all_averages = []
for run in tqdm(range(num_runs)):
agent = EpsilonGreedyAgent
agent_info = {"num_actions": 10, "epsilon": epsilon}
env_info = {"random_seed": run}
rl_glue = RLGlue(env, agent)
rl_glue.rl_init(agent_info, env_info)
rl_glue.rl_start()
best_arm = np.argmax(rl_glue.environment.arms)
scores = [0]
averages = []
best_action_chosen = []
for i in range(num_steps):
reward, state, action, is_terminal = rl_glue.rl_step()
scores.append(scores[-1] + reward)
averages.append(scores[-1] / (i + 1))
if action == best_arm:
best_action_chosen.append(1)
else:
best_action_chosen.append(0)
if epsilon == 0.1 and run == 0:
n_q_values.append(np.copy(rl_glue.agent.q_values))
if epsilon == 0.1:
n_averages.append(averages)
n_best_actions.append(best_action_chosen)
all_averages.append(averages)
plt.plot(np.mean(all_averages, axis=0))
plt.legend(["Best Possible"] + epsilons)
plt.xlabel("Steps")
plt.ylabel("Average reward")
plt.show()
为什么0.1的表现比0.01好?因为0.01探索的还不够,在指定时间内没有完成最佳点的探索。
如果探索有帮助,为什么0.4的表现比0.0(贪婪的代理)差? 因为0.4探索的太多,导致了他采取了很多次最佳点,长期来看效果变差。
在本任务的第1节中,我们根据动作选择次数对步长进行了随时间衰减。步长大小为1/N(A),其中N(A)是动作A被选择的次数。这和计算样本平均值是一样的。我们也可以将步长设置为一个常数,比如0.1。这样做会有什么效果呢?又是用常数法好还是用样本平均法好呢?
为了研究这个问题,我们先创建一个新的智能体,它的步长大小为常数。这将与上面创建的智能体几乎相同。您将使用相同的代码来选择epsilongreedy动作。您将更改更新,使其具有恒定的步长,而不是使用1/N(A)更新。
# -----------
# Graded Cell
# -----------
class EpsilonGreedyAgentConstantStepsize(main_agent.Agent):
def agent_step(self, reward, observation):
"""
让智能体一步到位。它输入的是奖励和观察并
返回智能体在该时间步选择的动作。
定义:
reward -- float, 智能体在采取最后一次行动后从环境中获得的reward。
observation -- float, 智能体所处的观察状态.不要担心这个,因为在以后的课程中才会用到它。
返回:
current_action -- int, 智能体在当前时间步选择的行动。
"""
### 有用的类变量 ###
# self.q_values : 一个数组,包含智能体认为Arm的每个值是什么。
# self.arm_count : 一个数组,包含每个Arm被拉动的次数。
# self.last_action : 智能体在上一个时间步骤所采取的行动
# self.epsilon : epsilon贪婪智能体探索的概率(范围在0和1之间)
# 比上一次多了这个变量
# self.step_size : 一个浮点数,是当前智能体的步长大小。
#######################
# Update Q values - 和之前一样
# YOUR CODE HERE
self.arm_count[self.last_action] += 1
self.q_values[self.last_action] = self.q_values[self.last_action] + self.step_size * (reward - self.q_values[self.last_action])
# 使用贪婪的epsilon选择行动。
# 在0和1之间随机选择一个数字,看它是否小于self.epsilon。
# (提示:看np.random.random())。如果是,就把current_action设置为一个随机动作。
# 否则就像上面那样贪婪地选择current_action。
# YOUR CODE HERE
_ = np.random.random()
current_action = argmax(self.q_values) if _ >= self.epsilon else np.random.randint(0,len(self.q_values))
self.last_action = current_action
return current_action
# ---------------
# Discussion Cell
# ---------------
# Experiment code for different step sizes
step_sizes = [0.01, 0.1, 0.5, 1.0, '1/N(A)']
epsilon = 0.1
num_steps = 1000
num_runs = 200
fig, ax = plt.subplots(figsize=(15, 5), dpi= 80, facecolor='w', edgecolor='k')
q_values = {step_size: [] for step_size in step_sizes}
true_values = {step_size: None for step_size in step_sizes}
best_actions = {step_size: [] for step_size in step_sizes}
for step_size in step_sizes:
all_averages = []
for run in tqdm(range(num_runs)):
np.random.seed(run)
agent = EpsilonGreedyAgentConstantStepsize if step_size != '1/N(A)' else EpsilonGreedyAgent
agent_info = {"num_actions": 10, "epsilon": epsilon, "step_size": step_size, "initial_value": 0.0}
env_info = {}
rl_glue = RLGlue(env, agent)
rl_glue.rl_init(agent_info, env_info)
rl_glue.rl_start()
best_arm = np.argmax(rl_glue.environment.arms)
scores = [0]
averages = []
if run == 0:
true_values[step_size] = np.copy(rl_glue.environment.arms)
best_action_chosen = []
for i in range(num_steps):
reward, state, action, is_terminal = rl_glue.rl_step()
scores.append(scores[-1] + reward)
averages.append(scores[-1] / (i + 1))
if action == best_arm:
best_action_chosen.append(1)
else:
best_action_chosen.append(0)
if run == 0:
q_values[step_size].append(np.copy(rl_glue.agent.q_values))
best_actions[step_size].append(best_action_chosen)
ax.plot(np.mean(best_actions[step_size], axis=0))
plt.legend(step_sizes)
plt.title("% Best Arm Pulled")
plt.xlabel("Steps")
plt.ylabel("% Best Arm Pulled")
vals = ax.get_yticks()
ax.set_yticklabels(['{:,.2%}'.format(x) for x in vals])
plt.show()
首先注意,我们现在绘制的是采取最佳行动的时间,而不是平均奖励。为了更好地理解一个智能体的性能,衡量具体的行为可能是有用的,不仅仅是积累了多少奖励。这个衡量标准表明代理的行为有多接近最优。
看起来,似乎1/N(A)的表现比其他的要好,因为它达到了一个解决方案,在那里它最频繁地采取最佳行动。现在为什么会这样呢?为什么步长为0.5的步长一开始表现较好,但最后表现较差?为什么步长为0.01的步长表现如此糟糕?
下面让我们来进一步研究一下这个问题。让我们来绘制每个代理对真实值的跟踪情况,其中每个代理有不同的步长大小方法。这里不需要输入任何代码,只要跟着做就可以了。
# lock
# ---------------
# Discussion Cell
# ---------------
largest = 0
num_steps = 1000
for step_size in step_sizes:
plt.figure(figsize=(15, 5), dpi= 80, facecolor='w', edgecolor='k')
largest = np.argmax(true_values[step_size])
plt.plot([true_values[step_size][largest] for _ in range(num_steps)], linestyle="--")
plt.title("Step Size: {}".format(step_size))
plt.plot(np.array(q_values[step_size])[:, largest])
plt.legend(["True Expected Value", "Estimated Value"])
plt.xlabel("Steps")
plt.ylabel("Value")
plt.show()
0.01
0.1
0.5
1.0
1/NA
这些图有助于澄清不同步长大小之间的性能差异。0.01的步长大小使得智能体对最佳行动的价值估计更新幅度很小,以至于无法接近实际价值。步长大小为0.5和1.0的步长都能很快接近真实值,但非常容易受到奖励的随机性影响。更新对最近的奖励过度修正,所以在真实值附近摇摆。这意味着在很多步数上,拉动最佳手臂的动作可能看起来比实际情况更糟糕。步幅大小为0.1的步幅更新到真实值的速度相当快,而且不会像0.5和1.0那样围绕真实值广泛摆动。这也是0.1表现相当好的原因之一。最后我们看看为什么1/N(A)表现良好。早期当步长还相当高的时候,它很快就会移动到真实的期望值,但随着它被拉得越多,它的步长就越小,这使得它不太容易受到奖励的随机性影响。
这是否意味着1/N(A)总是最好的?什么时候可能不是呢?一个可能不那么有效的环境是在非稳态问题中。你在课程中学习了非稳态性。非稳态意味着环境可能会随着时间的推移而改变。这可能表现为环境随着时间的推移不断变化,也可能表现为环境的突然变化。
我们来看看奖励分布的突然变化是如何影响1/N(A)这样的步长大小的。这次我们会将环境运行2000步,1000步后我们会随机改变所有arm的期望值。我们比较两个智能体,都是使用epsilongreedy,epsilon=0.1。其中一个使用0.1的恒定步长,另一个使用1/N(A)的步长,随着时间的推移而减小。
# ---------------
# Discussion Cell
# ---------------
epsilon = 0.1
num_steps = 2000
num_runs = 200
step_size = 0.1
plt.figure(figsize=(15, 5), dpi= 80, facecolor='w', edgecolor='k')
plt.plot([1.55 for _ in range(num_steps)], linestyle="--")
for agent in [EpsilonGreedyAgent, EpsilonGreedyAgentConstantStepsize]:
all_averages = []
for run in tqdm(range(num_runs)):
agent_info = {"num_actions": 10, "epsilon": epsilon, "step_size": step_size}
np.random.seed(run)
rl_glue = RLGlue(env, agent)
rl_glue.rl_init(agent_info, env_info)
rl_glue.rl_start()
scores = [0]
averages = []
for i in range(num_steps):
reward, state, action, is_terminal = rl_glue.rl_step()
scores.append(scores[-1] + reward)
averages.append(scores[-1] / (i + 1))
if i == 1000:
rl_glue.environment.arms = np.random.randn(10)
all_averages.append(averages)
plt.plot(np.mean(all_averages, axis=0))
plt.legend(["Best Possible", "1/N(A)", "0.1"])
plt.xlabel("Steps")
plt.ylabel("Average reward")
plt.show()
现在,步长为1/N(A)的代理在开始时表现较好,但当环境发生变化时,表现就更差了! 发生了什么?
想一想1000步后的步长会是多少。假设最佳动作被选择500次。这意味着该动作的步长是1/500或0.002。在每一步,当我们更新动作的值和值要移动的时候,只有0.002*误差。这是一个非常微小的调整,它需要很长的时间才能达到真实值。
然而,步长为0.1的代理将始终以误差的1/10的方向更新。这意味着平均而言,它需要10步才能将其值更新到样本平均值。
这些都是我们在强化学习中必须考虑的权衡类型。
更大的步长大小可以使我们更快地走向真实值,但会使我们的估计值在预期值附近摇摆。一个步长大小随着时间的推移而减小,可以收敛到接近预期值,而不会出现振荡。另一方面,这样一个递减的步长不能适应环境的变化。非稳态性—以及相关的部分可观察性概念—是强化学习问题和在线学习时的常见特征。
也就是说
步长大,更快到真实值,但会在预期值摇摆,新环境后也能很快到达比较好的结果。。
步长随着时间减小(1/NA),可以收敛且无震荡,但不能适应环境的变化。
机器人有很多可以选择的行为,根据他的状态可以选择搜索等待还是去充电。
嗨,我是迈克尔・利特曼。我是布朗大学的计算机科学教授。我被要求发言 关于奖励假说。奖赏假说的基本思想在这句名言中得到了说明,给一个人一条鱼,他就能吃一天,教一个人钓鱼,他就能吃一辈子。给一个人一条鱼的味道,他就会想办法钓鱼,即使细节变了,他也会想办法钓鱼。好吧,也许这不是什么名言,但不是我的人转发了,也算是吧。总之,关于创造智能行为,有三种思路。第一种,授人以鱼,就是老式的人工智能。如果我们想让一台机器变得聪明,我们就给它编程,让它拥有我们想要的行为。但随着新问题的出现,机器就无法适应新的环境。这就需要我们一直在那里提供新的程序。第二种,授人以鱼,就是监督学习。如果我们想让机器变得聪明,我们提供训练例子,机器就会自己写程序来匹配这些例子。它就会学习,所以只要我们有办法提供训练例子,我们的机器就能自己写程序,这就是进步。但是情况会有变化,我的意思是我们大部分人没有机会天天吃鱼,也没有机会天天捞饭。第三个,给一个人吃鱼的味道,这就是强化学习。就是我们不必指定实现目标的机制。我们只需将目标编码,机器就可以设计自己的策略来实现它。我的意思是,如今,你不一定要抓到三文鱼才能吃到三文鱼,有超市,有海鲜连锁餐厅。如果一切都失败了,还有加油站的寿司,所以这就是高层次的想法。但假设本身呢?现在,我很确定我是从里奇-萨顿那里得到的,但我听说里奇-萨顿把它归于我。所以,如果我要告诉你,我想了解一下这个词的历史会是个好主意。谷歌趋势是一个很棒的服务,它提供了一个术语在历史上使用频率的信息。所以当我问它关于奖励假说的时候,它说没有骰子。搜索奖励假说强化学习有3580个结果,所以这也算是个东西。在结果的前几页,我找到了几个例子,Muhammad Ashraf的一篇博文说,所有的目标都可以用预期累积奖励的最大化来描述。
David Silver在他的入门强化学习课程中使用了同样的短语,但他用S来拼写最大化,因为他是英国人。
里奇-萨顿有一篇博客文章叫奖励假说,在那里,他的说法有点不同。他说,我们所说的目标和目的可以很好地被认为是一个接收到的标量信号的累积总和的期望值的最大化,即奖励。这个版本强调了它超越了目标和奖励是一个标量的事实,但是总体来说,精神和我找到的其他版本是非常一致的。
好吧,那我的版本呢?所以我搜索了我的档案,我没有得到任何点击。然后我看到在同一篇文章里 Then I saw in that same essay 里奇说我把它叫做强化学习假说 that Rich said that I call it the reinforcement learning hypothesis. 所以这就解释了为什么我找不到它 So that explains why I wasn’t finding it. With the right term in hand, I was able to dig up this slide from a talk that I gave in the early 2000s, 有了正确的术语,我从2000年初的一次演讲中挖出了这张幻灯片, and it says intelligent behavior arises from the actions of an individual seeking to maximize its received reward signals in a complex and changing world. 它说智能行为产生于个体在复杂多变的世界中寻求最大化接收奖励信号的行为。同样,它和其他的很相似。我忽略了说累积和标量,但我确实对比了奖励这一概念的简单性和现实世界的复杂性。我还指出了这个想法的含义。所以,如果你相信这个假说,就说明有两个主要的研究分支需要解决。第一是要弄清楚奖励代理应该优化什么,第二是要设计算法来最大化它。大家对第一条已经给予了很多关注,我重点说说第二条。我们如何定义奖励?好吧,为什么这还难呢?但有时候并不是,股市上的强化学习代理可能只需要给货币奖励就可以优化。买入动作需要花费美元,卖出动作产生美元,取舍很容易。有一个共同的货币,[笑]字面意思。这张图是我的一些学生制作的基于强化学习的太阳能板。移动电机重新定位需要耗费能量,而阳光照射在面板上也会带来能量,所以同样,有一种共同的货币。但如果我们设计一个强化学习代理来控制恒温器,奖励是什么?开暖气或空调会耗费能源,但不开暖气或空调会导致居住者的不适,所以没有共同的货币。我想我们可以把两者都换算成美元,但这不是很自然。你愿意支付多少钱来让温度更接近你的舒适区?好吧,我们通常定义了一些不适的成本单位,但设定一个精确的数值可能很棘手。我们可以用奖励来表达一个目标的想法。一种方法是定义一种状态,目标实现了就有加一奖励,其他都是0奖励,这有时被称为目标奖励编码。另一种是在目标没有实现的情况下,每走一步就给代理一个-1的惩罚。一旦目标实现了,就没有成本了,这就是行动惩罚表示。在这两种情况下,只要达到目标就能实现最优行为,所以这很好。但它们导致在代理人在途中应该做什么方面存在微妙的差异。第一种并没有真正鼓励代理以任何紧迫感去达到目标。而第二种如果有一些小概率的卡住,永远达不到目标,就会遇到严重的问题。而这两种方案都会导致对于真正长视野的目标出现大问题。想象一下,我们想鼓励一个代理人获得诺贝尔奖。嗯,想想看,这将会阻碍计算机科学研究,因为CS领域没有诺贝尔奖。但我的意思是,我们会给代理一个在瑞典获得荣誉的奖励,否则就给0,这真的非常粗暴。一些中间的奖励,比如科考成绩好的奖励+0.0001,或者获得终身教职的奖励+0.001,对于帮助代理人指明正确的方向,会有很大的作用。所以,即使我们接受奖励假说,仍然需要努力定义正确的奖励。鱼的口号提供了三种不同的行为可能来自的地方,我们可以用同样的方法来谈论奖励可能来自的地方。计算机科学家爱计算机科学家爱递归。
编程是定义学习代理的奖励的最常见方式。一个人坐下来,做将行为目标转化为奖励值的工作。这可以通过编写一个接收状态并输出奖励的程序一劳永逸地完成。最近的一些研究着眼于指定任务的特殊语言,比如时空逻辑。这些语言可能是有用的中间格式,对人来说有点容易写,但对机器来说也有点容易解释。奖励也可以由人在飞行中交付。最近的研究集中在当奖励的来源是人时,强化学习算法需要如何改变。人的行为与奖励函数不同,他们倾向于根据代理的学习方式等改变他们给予的奖励。标准的强化学习算法不能很好地响应这种非稳定的奖励。我们也可以通过例子来指定奖励,这可能意味着代理学习复制一个人给予的奖励,但这种方法的一个非常有趣的版本是逆强化学习。在逆强化学习中,训练者展示了一个所需行为的例子,学习者就会找出训练者一定是在最大化什么奖励,才使得这个行为成为最优。所以,强化学习是从奖励到行为,而逆强化学习则是从行为到奖励。一旦确定了这些奖励,就可以在其他环境中实现最大化,从而实现环境之间强大的泛化。奖励也可以通过优化过程间接得出,如果有一些高层次的行为,我们可以为其创建一个分数,优化方法可以搜索鼓励该行为的奖励。所以回到前面诺贝尔奖的例子,想象一下,创建多个代理追求这个目标,而不是单一的代理。这样我们就可以评估,不仅仅是行为的结果是得了奖,而是用奖励来鼓励这个行为。可以说,这就是活的代理是如何获得奖励函数的,强化学习代理如果有好的奖励函数和一个好的算法来最大化这些函数,他们就能生存下来。这些代理将奖励函数顺势传递给他们的后代。更广义的说,这是一个元强化学习的例子,在进化层面的学习,在个体层面创造了更好的学习方式。我个人认为,奖励假说非常强大,对于设计最先进的代理非常有用,它是一个伟大的工作假说,帮助我们取得了一些优秀的成果。但我要提醒你不要把它看得太字面,当假说的作用过期时,我们应该开放地拒绝这个假说。首先,它们是一些行为的例子,似乎在做一些不是最大化奖励的事情。例如,如何在这个框架中捕捉风险规避行为并不是很明显。风险规避行为包括选择可能不是平均最好的行动,但例如,最大限度地减少最坏情况结果的机会。另一方面,如果你能通过干预奖赏流来放大负面结果来捕捉这种行为,那将以正确的方式转变行为。
当我们想要的行为不是一直做最好的事情,而是在某种平衡下做一堆事情的时候呢?比如想象一个纯粹的奖励最大化的音乐推荐系统,它应该找出你最喜欢的歌曲,然后一直为你播放,这不是我们想要的。虽然也许有办法扩大状态空间,如果最近播放过一首歌,那么播放这首歌的奖励就会缩减。这有点像动物从喝水中获得很多价值的想法,但只有在它口渴的情况下。如果它刚喝了一杯,马上再喝的奖励就很低。所以也许奖励可以处理这些情况。嗯,我觉得还有一个观点值得考虑,就是追求现有的奖励是否符合人类的高级行为。有的人一心一意追求自己的明确目标,但我们并不清楚判断这种人是否好相处。正如道德哲学家可能指出的那样,我们应该追求的目标对我们来说并不是立竿见影的。随着年龄的增长,我们对做出好的决定的意义有了更多的了解,一代又一代的学者一直在研究成为一个好的道德人的意义。其中一部分是更好地理解我们的行为对环境的影响,以及对彼此的影响,这只是强化学习。但其中一部分是阐明更深层次的目的感。我们只是在确定已经埋藏在脑海中的奖励功能的细节,还是真正为自己创造更好的目标?我不知道,但与此同时,我们应该考虑这样一种可能性,即最大化奖励可能只是对智能代理动机的一种极好的近似。
学会区分这两种类型的任务。
参考总结,伽马为0时候只考虑Rt+1时候的Reward比较短视。
案例1:想象你是一个视觉系统。当你刚开机一天的时候,一幅幅图像涌入你的相机。你可以看到很多东西,但不是所有的东西。你看不到被遮挡的物体,当然也看不到你身后的物体。在看到第一个场景后,你是否能获得环境的马尔科夫状态?
案例2:想象一下,视觉系统从来没有正常工作过:它总是返回同样的静态想象,永远如此。那么,你是否能获得马尔科夫状态?(
不正确。因为在第一个图像之前没有历史,所以第一个状态具有马尔科夫属性。马尔科夫属性并不意味着状态表示法告诉了所有有用的信息,只是说它没有忘记任何有用的信息。
摄像机坏掉的情况是不同的,但我们同样具有马尔可夫属性。所有可能的未来都是一样的(都是白色的),所以为了预测它们,不需要记住任何东西。
我是安德鲁-巴托,我想介绍一下里奇-萨顿,他是我的第一个学生,我们一起工作了很多年。我们俩都很惊讶,我想 作为应用程序 [听不清]的外延 那早期的工作。和丰富的,是一个惊人的专注执着,人的天才,我认为和花式。我让他很尴尬。很多伦敦的核心思想,我真的欠一个巨大的数量,以丰富的,所以这是丰富的。
好吧,我觉得我已经学会了 一个巨大的量 从你身上,安迪。你刚刚被必不可少的 使我们的工作 学术的和相关的 现代和旧的。我觉得巨大的基础 由所有的事情我已经学会了 作为你的学生在这些年。我想说的是,我们在写那本教科书的地方,主要做的事情是我们重新发现了强化领域。我想说,我想说我们发现了它,但我知道你会对此有反应,因为太阳底下没有什么新东西,你曾经告诉我。很好,如果你真的发现了什么, 如果你真的发现了什么,你读,有什么错 与重新发现旧的东西, 你应该拥抱。如果你重新发现了轮子,就像你说的,我们应该把它叫做轮子。也许有更好的方法。也许有更好的方法,但我确实觉得我们重新发现了强化。我们唤醒了它,因为它会在收集上增加落差,我们澄清了它是什么,它与监督学习有什么不同。这算是我对强化学习的起源故事的定性。这是一个很明显的想法,马文-明斯基在1960或59年就知道了。它是如此的明显,每个人都知道它,但后来它变得被监督学习所掩盖,直到,埃里克-洛夫特开始敲人们的门,并说,“嘿,这是被忽视的东西。” 而且是真实的,也是重要的,并责成我们把它弄明白。事实上,农田克拉克在数字计算机上进行的第一个神经网络模拟是在1954年。是一个强化学习系统。在他们的第二篇论文中,Clark和Farley在一年后,是同样的系统,但他们关注的是泛化。当然,它背离了根区。在那之后,你的感知器和撤回霍夫是错误纠正。即使,他们使用的一些词是试错,但他们真的有效。成了监督。是的,也有例外,但是就像我们刚才说的,明斯基,在管理员的情况下,论文和他的步骤论文,是充满了预测,电视一样的东西,当然学分分配问题。然后他在普林斯顿的论文,有一个强化学习的物理网络,那学习通过迷宫。我想明斯基对它失去了兴趣,原因有很多,也可能是对它感到尴尬。我不知道,但那是一个强化学习系统。安迪,典型的你自己,你说的是历史上其他人做的事情,但也许典型的我,我想把它带回我们做的事情,因为我认为我们确实做了一些事情。
我几乎没有做什么,但我们认识到,我们只是站起来说,"这是一个事情。“这是一件事,还没有被调查 它值得调查。” 我们写了关于联想搜索网络的论文,而且只是真正简单的想法,并提出了这样的主张:这是不可能完成的。联想和试错的结合。我想就像你说的,我当时认为,搜索到一些有效的东西,然后你就会记住,把搜索和记忆结合起来。这就是强化的本质,然后奇怪的是一直错了。我发现了一些相关的东西。Mentalization,那个问题[听不清]他是我在马萨诸塞大学的同事,有一段时间。
唐纳德-米奇,谈到了mentalization这是一个,RL是一个记忆的搜索。你做了一些操作,然后你记住了结果,下次你要做。你去查,而不是重新计算,这样可以节省很多时间等等。从某种意义上说,我们的RL在根本上就是记忆性的上下文敏感搜索。Pople stone,其实在他的一篇论文的最后,这个50号,我忘记了日期,但是谈到了插值器,比如说用多项式代替Lookup table去查一些泛化的东西。比如说神经网络就是这么做的。所以我们没有–我们发现了。我们没有发明记忆,而是通过对它的新用途。我不知道人们是否在用强化学习者的方式进行记忆搜索。在这里他有这样一个想法,就是用分布式的方式。由寻金组件组成的寻金系统。他还有一个想法,就是你所谓的泛化强化,这些单元中的一个单元可以被各种信号强化,而不仅仅是我们的二进制信号。我记得的方式,必不可少的,我知道我在列,所以它像一个洞察力,但它是这样的对一个没有洞察力。我们有一天决定,好吧,也许只是目标寻求单位的事情。也许这是个有趣的想法,都是自己的想法。如果不把目标寻求系统做出来胆大妄为的拥护者,也没有一个通用的强化,会只是有一个专门的奖励信号。我们只是研究那个Learning,也许就是这个东西。也许这就是需要研究的东西。像。对我来说,这是补救措施一样,也许只是。这就像一个致命的水平和花哨的东西,或者你在混淆的东西之外。就目前而言,有一点要说明,我认为这就是强化学习。就是专注于一个学习系统,其实要做试错的东西,并且记住它,要专门的奖励信号。
backup 后援 增援 可以理解成update
正确,加入说有一个policy pi1 在某些状态下表现的很好,然而policy pi2在其他状态下表现的好。我们把这两种policy结合后变成一个pi3,始终选额任意一个选择操作pi1和pi2 在当前状态下的最高值,在每一个状态下,pi3必然大于等于pi1和pi2。因此,我们永远不会遇到这样一种情况:在一种状态下做好工作需要牺牲另一种状态下的价值。因此,总是存在一些在每个州都最好的政策。当然,这只是一个非正式的论据,但实际上有严格的证据表明,必须始终存在至少一个最优的确定性策略。
贝尔曼最优方程实际上是一个方程组,每个状态都有一个方程组,所以如果有N个状态,那么在N个未知数中就有N个方程。如果环境的动态是已知的,那么原则上可以用各种非线性方程系统求解方法中的任何一种来求解这个方程系统的最优价值函数。所有的最优政策都具有相同的最优状态值函数
在奖励信号中加入一个常数可以使较长的情节变得更有优势(取决于常数是正数还是负数)。因此在好像是PPO算法还是啥用了归一化的方法避免了这种情况。
由于任务是持续进行的,所以智能体将积累相同数量的额外奖励,与它的行为无关。
function test = rewards(gama)
gama=0;
char str;
V1=1/(1-gama^2);
V2=2*gama/(1-gama^2);
if V1 > V2 str='V1 is larger'
else if V1 == V2 str='V1 is equal to V2'
else str ='V2 is larger'
end
end
end
贝尔曼最优方程实际上是一个方程组,每个状态都有一个方程组,所以如果有N个状态,那么在N个未知数中就有N个方程。如果环境的动态是已知的,那么原则上可以用各种非线性方程系统求解方法中的任何一种来求解这个方程系统的最优价值函数。所有的最优政策都具有相同的最优状态值函数。
假设有一个政策1在某些状态表现良好,而政策2在其他状态表现良好。我们可以将这些政策组合成第三个政策3,它总是根据政策1和政策2中的哪一个在当前状态下的价值最高来选择行动,3在每个状态下的价值必然大于或等于这两个政策!所以我们永远不会出现在一个状态下做得好需要牺牲另一个状态下的价值的情况。所以,我们永远不会出现在一种状态下做得好就需要牺牲另一种状态下的价值的情况。正因为如此,总是存在着某种政策在每个状态下都是最好的。当然,这只是一个非正式的论证,但事实上,有一个严格的证明表明,至少总是存在一个最优的确定性deterministic政策。
如果我们有每个状态-行动对的预期回报,我们就可以计算出任何政策下的预期回报。前面的policy从pi到b
例如,想象一个有一个状态和两个行动的马尔科夫决策过程。如果两个行动得到的Reward相同,那么任何政策都是最优政策。
successor后续的
这一章的东西很多,需要再消化一遍。
首先我们学习了Value Fuction 和Q Functions
然后学习了贝尔曼方程。贝尔曼最优方程实际上是一个方程组,每个状态都有一个方程组,所以如果有N个状态,那么在N个未知数中就有N个方程。如果环境的动态是已知的,那么原则上可以用各种非线性方程系统求解方法中的任何一种来求解这个方程系统的最优价值函数。所有的最优政策都具有相同的最优状态值函数。
然后学习了最佳政策和最佳的价值函数,他们都是在所有的政策下最大化价值函数(state value或者是 action-value)
当我们知道最佳的价值函数的时候,我们就解决了MDP问题
最佳政策是什么,有一个政策比其他情况都好,并且实现了在这种政策下的最佳价值函数,最佳政策并不是唯一的,想象一个有一个状态和两个行动的马尔科夫决策过程。如果两个行动得到的Reward相同,那么任何政策都是最优政策。
在寻找最优政策的时候,如果q是最大的,那么pi取1,就可以化简了。
异步方法可以将更新的重点放在更相关的状态上,而对不太相关的状态更新的频率较低。如果状态空间非常大,异步方法可能还能获得很好的性能,而即使只是同步扫描一次状态空间也可能是难以解决的。
异步方法可以将更新的重点放在更相关的状态上,而对不太相关的状态更新的频率较低。如果状态空间非常大,异步方法可能还能获得很好的性能,而即使只是同步扫描一次状态空间也可能是难以解决的。
Assignment 2: Optimal Policies with Dynamic Programming
numpy: 用Python进行科学计算的基本包
tools:包含一个环境和一个绘图函数的模块。包含一个环境和一个绘图函数的模块。
%matplotlib inline
import numpy as np
import tools
import grader
在市议会的停车MDP中,状态为非负整数,表示有多少停车位被占用,行动为非负整数,指定路边停车的价格,奖励是描述城市对这种情况的偏好的实际值,时间则以小时为单位进行离散化。
正如预期的那样,收取高价很可能在一小时内减少占用率,而收取低价则可能增加占用率。
现在,让我们考虑一个有三个停车位和三个价格点的环境。请注意,一个有三个停车位的环境实际上有四种状态–零、一个、两个或三个车位都可能被占用。
# ---------------
# Discussion Cell
# ---------------
num_spaces = 3
num_prices = 3
env = tools.ParkingWorld(num_spaces, num_prices)
V = np.zeros(num_spaces + 1)
pi = np.ones((num_spaces + 1, num_prices)) / num_prices
价值函数是一个一维数组,其中第i个条目给出了被占用的空间的值。
看一下V是什么
V
array([0., 0., 0., 0.])
再看一下pi是什么
pi
array([[0.33333333, 0.33333333, 0.33333333],
[0.33333333, 0.33333333, 0.33333333],
[0.33333333, 0.33333333, 0.33333333],
[0.33333333, 0.33333333, 0.33333333]])
我们可以将策略policy表示为一个二维数组,其中(,)-个条目给出了在状态中采取行动的概率。
pi[0] = [0.75, 0.11, 0.14]
for s, pi_s in enumerate(pi):
for a, p in enumerate(pi_s):
print(f'pi(A={a}|S={s}) = {p.round(2)} ', end='')
print()
pi(A=0|S=0) = 0.75 pi(A=1|S=0) = 0.11 pi(A=2|S=0) = 0.14
pi(A=0|S=1) = 0.33 pi(A=1|S=1) = 0.33 pi(A=2|S=1) = 0.33
pi(A=0|S=2) = 0.33 pi(A=1|S=2) = 0.33 pi(A=2|S=2) = 0.33
pi(A=0|S=3) = 0.33 pi(A=1|S=3) = 0.33 pi(A=2|S=3) = 0.33
理解一下这个enumerate ,是先从行开始
for s, pi_s in enumerate(pi):
print(s)
print("next is pi_s")
print(pi_s)
print("")
0
next is pi_s
[0.75 0.11 0.14]
1
next is pi_s
[0.33333333 0.33333333 0.33333333]
2
next is pi_s
[0.33333333 0.33333333 0.33333333]
3
next is pi_s
[0.33333333 0.33333333 0.33333333]
for s, pi_s in enumerate(pi):
for a, p in enumerate(pi_s):
print(a)
print("next is p")
print(p)
print("")
0
next is p
0.75
1
next is p
0.11
2
next is p
0.14
0
next is p
0.3333333333333333
1
next is p
0.3333333333333333
2
next is p
0.3333333333333333
0
next is p
0.3333333333333333
1
next is p
0.3333333333333333
2
next is p
0.3333333333333333
0
next is p
0.3333333333333333
1
next is p
0.3333333333333333
2
next is p
0.3333333333333333
用两次enumerate就实现了遍历所有的情况,其中i是状态(state),j是动作(action)
V[0] = 1
tools.plot(V, pi)
我们可以通过工具模块中的绘图功能将值函数和策略可视化。在左边,价值函数以柱状图的形式显示。状态0的预期收益率为1,而其他状态的预期收益率为0。在右边,策略显示在一个二维网格上。每个垂直条带给出了标注状态下的政策。在状态零中,行动零是最暗的,因为智能体的政策使这个选择的概率最高。在其他状态下,智能体的政策是等概率的,所以垂直条带的颜色是统一的。
你可以把状态空间和行动集作为环境的属性来访问。
env.S # [0, 1, 2, 3]
env.A # [0, 1, 2]
你需要使用环境中的transitions方法来完成这个任务。该方法接收一个状态和一个动作,并返回一个二维数组,其中(,0)处的条目是由当前状态过渡到状态的奖励,(,1)处的条目是在当前状态和动作的情况下过渡到状态的条件概率。
state = 3
action = 1
transitions = env.transitions(state, action)
transitions
array([[1. , 0.12390437],
[2. , 0.15133714],
[3. , 0.1848436 ],
[2. , 0.53991488]])
for sp, (r, p) in enumerate(transitions):
print(f'p(S\'={sp}, R={r} | S={state}, A={action}) = {p.round(2)}')
p(S'=0, R=1.0 | S=3, A=1) = 0.12
p(S'=1, R=2.0 | S=3, A=1) = 0.15
p(S'=2, R=3.0 | S=3, A=1) = 0.18
p(S'=3, R=2.0 | S=3, A=1) = 0.54
你现在可以开始任务了! 首先,市政府希望你对现有定价方案的质量进行评估。政策评估的工作原理是将Bellman方程中的 反复应用于工作的价值函数,作为更新规则,如下图所示。
这种更新可以 "原地 "进行(即更新规则依次应用于每个状态),也可以用 "双阵列 "进行(即更新规则同时应用于每个状态)。两个版本都会收敛到,但原地版本通常收敛得更快。在本次作业中,我们将像教材第4章的伪代码一样,实现所有更新规则的就地化。
我们已经写好了课本第4.1章中描述的策略评估算法的大纲。剩下的就是填写bellman_update函数来完成算法了。
# lock
def evaluate_policy(env, V, pi, gamma, theta):
delta = float('inf')
while delta > theta:
delta = 0
for s in env.S:
v = V[s]
bellman_update(env, V, pi, s, gamma)
delta = max(delta, abs(v - V[s]))
return V
# -----------
# Graded Cell
# -----------
def bellman_update(env, V, pi, s, gamma):
"""Mutate ``V`` according to the Bellman update equation."""
# YOUR CODE HERE
v = 0
for a in env.A:
transitions = env.transitions(s, a)
for s_, (r, p) in enumerate(transitions):
v += pi[s][a] * p * (r + gamma * V[s_])
V[s] = v
# lock
tools.plot(V, city_policy)
观察到价值函数与市议会的偏好有质的相似–随着停车位的使用越多,价值函数单调地增加,直到没有停车位了,在这种情况下,价值函数就会降低。由于相对简单的奖励函数(当很多但不是所有的停车位都被占用时,就会累积更多的奖励,而当很少或所有的停车位都被占用时,就会累积较少的奖励)和高度随机的动态函数(每个状态在每个时间步长都有正的概率达到),大多数政策的价值函数将在质量上类似于这个图。
然而,根据政策的智能性,该图的比例会有所不同。换句话说,更好的政策会增加每个状态下的预期收益,而不是改变各个状态的相对可取性。直观地讲,可以通过使一个较不理想的状态停留在较不理想的状态的可能性降低来增加其价值。同样,可以通过使一个较理想的状态更有可能保持在一个较理想的状态中来增加它的价值。也就是说,**好的政策是指在理想状态下花费更多时间,在不理想状态下花费更少时间的政策。**正如我们在本次作业中会看到的那样,这种稳态分布是通过在低占用率状态下将价格定得很低(这样占用率就会增加),而在占用率高时将价格定得很高(这样就可以避免完全占用)来实现的。
现在,市议会希望你使用政策迭代来计算一个更有效的政策。政策迭代的工作原理是交替评估现有政策和使政策对现有价值函数产生贪婪。我们在教材4.3章中写了一个政策迭代算法的大纲。我们将利用你在第1节中完成的策略评价算法。剩下的工作就是填写q_greedify_policy函数,使其修改在处的策略对处的q值贪婪,完成策略改进算法。
def improve_policy(env, V, pi, gamma):
policy_stable = True
for s in env.S:
old = pi[s].copy()
q_greedify_policy(env, V, pi, s, gamma)
if not np.array_equal(pi[s], old):
policy_stable = False
return pi, policy_stable
def policy_iteration(env, gamma, theta):
V = np.zeros(len(env.S))
pi = np.ones((len(env.S), len(env.A))) / len(env.A)
policy_stable = False
while not policy_stable:
V = evaluate_policy(env, V, pi, gamma, theta)
pi, policy_stable = improve_policy(env, V, pi, gamma)
return V, pi
# -----------
# Graded Cell
# -----------
def q_greedify_policy(env, V, pi, s, gamma):
"""Mutate ``pi`` to be greedy with respect to the q-values induced by ``V``."""
q = np.zeros_like(env.A, dtype=float) #because this is an array of float
for a in env.A:
transitions = env.transitions(s, a)
for s_, (r, p) in enumerate(transitions):
q[a] += p * (r + gamma * V[s_])
greed_actions = np.argwhere(q == np.amax(q))
for a in env.A:
if a in greed_actions:
pi[s, a] = 1 / len(greed_actions)
else:
pi[s, a] = 0
raise NotImplementedError()
env = tools.ParkingWorld(num_spaces=10, num_prices=4)
gamma = 0.9
theta = 0.1
V, pi = policy_iteration(env, gamma, theta)
tools.plot(V, pi)
价值迭代的工作原理是,将 Bellman最优方程∗ 迭代应用于工作价值函数,作为更新规则,如下图所示.本市也听说过价值迭代,希望你能实现它。
我们已经写好了教材第4.4章中介绍的价值迭代算法的大纲。剩下的就是填写bellman_optimality_update函数来完成价值迭代算法。
def value_iteration(env, gamma, theta):
V = np.zeros(len(env.S))
while True:
delta = 0
for s in env.S:
v = V[s]
bellman_optimality_update(env, V, s, gamma)
delta = max(delta, abs(v - V[s]))
if delta < theta:
break
pi = np.ones((len(env.S), len(env.A))) / len(env.A)
for s in env.S:
q_greedify_policy(env, V, pi, s, gamma)
return V, pi
# -----------
# Graded Cell
# -----------
def bellman_optimality_update(env, V, s, gamma):
vmax = - float('inf')#starting from negative infinity
for a in env.A:
transitions = env.transitions(s, a)
v = 0
for s_, (r, p) in enumerate(transitions):
v += p * (r + gamma * V[s_])
vmax = max(v, vmax)
V[s] = vmax
env = tools.ParkingWorld(num_spaces=10, num_prices=4)
gamma = 0.9
theta = 0.1
V, pi = value_iteration(env, gamma, theta)
tools.plot(V, pi)
在上面的值迭代算法中,在值函数收敛之前,不会显式地维护一个策略。下面,我们写了一个行为相同的价值迭代算法,它可以维护更新的策略。以这种形式写出价值迭代,使其与策略迭代的关系更加明显。策略迭代在做完全贪婪化和完全评价之间交替进行。另一方面,价值迭代在做局部贪婪化和局部评价之间交替进行。
def value_iteration2(env, gamma, theta):
V = np.zeros(len(env.S))
pi = np.ones((len(env.S), len(env.A))) / len(env.A)
while True:
delta = 0
for s in env.S:
v = V[s]
q_greedify_policy(env, V, pi, s, gamma)
bellman_update(env, V, pi, s, gamma)
delta = max(delta, abs(v - V[s]))
if delta < theta:
break
return V, pi
env = tools.ParkingWorld(num_spaces=10, num_prices=4)
gamma = 0.9
theta = 0.1
V, pi = value_iteration2(env, gamma, theta)
tools.plot(V, pi)
参考
1.Dynamic Programming
什么是动态规划,动态是处理序列或者带有时间成分的问题,规划是优化一个问题,比如线性规划,动态规划一般是用来处理复杂的问题,它通过将问题划分为子问题,然后把子问题的解组合在一起,比如你想从A走到B,可以将问题分成从A到AB之间的重点C,以及C到B两个子问题。
动态规划的性质,最优化子结构,问题的最优解可以被分解到子问题当中,子问题重叠,子问题重复出现,子问题的解可以被存储和重复利用。
MDP过程满足上述两个性质,贝尔曼方程可以被递归分解,值函数存储和重复李用
动态规划在MDP过程的应用。动态规划要求我们知道MDP的全部知识,尤其是环境,也就是说知道转移概率以及奖励;动态规划是解决MDP中的规划(planning)问题,因为有MDP的全部指示;具体而言可以做prediction问题,给定MDP全部知识加上策略,求解策略的值函数v_pi (s),也可以做control问题,给定MDP全部知识,求解最优策略以及最优值函数。
2.Iterative Policy Evaluation
给定一个策略,我们如何获得对应的值函数v_pi (s),这里给出的方法是不断迭代Bellman期望方程
3.Policy Iteration
包括Evaluate和Improve
4.Value Iteration
最优化原则:
一个最优的策略可以被分解成两个部分:
一个当前情况(s)下的最优动作
在后续状态(s’)下沿着最优策略继续进行
最优性定理: