快捷搜索:  as

如何使用50行Python代码实现AI的动作平衡

本文将为大年夜家展示若何经由过程 Numpy 库和 50行 Python 代码,应用标准的 OpenAI Gym平台创建智能体 (agent),请教会机械处置惩罚推车杆问题 (cart pole problem) ,维持平衡。

推车杆问题 (cart pole problem) ,大年夜家可以类比似乎在手指尖上垂直平衡铅笔一样,必要经由过程阁下推动来平衡车顶部的杆,这是个异常具有寻衅性的问题!

本日,我们不过多的评论争论强化进修的根基理论,盼望大年夜家鄙人面的编译器里,赓续考试测验,体会这个项目。一开始,大年夜家只必要点击“Start”,开始设置设置设备摆设摆设必要的情况即可。

快速入门强化进修 (RL)

假如你是机械进修或强化进修领域的新人,先懂得一下下面的一些根基常识和术语,为后面做铺垫。假如你已经掌握了根基常识,那可以跳过这部分内容。

强化进修

强化进修旨在教会我们的智能体 (算法或机械) 履行特定的义务或动作,而无需显式地奉告它该若何做。想象一个婴儿在随机抬动自己的腿,当站立起来时就给予他一个奖励。同样地,智能体的目标是在其生命周内最大年夜化奖励值,而奖励取决于特定的义务。比如宝宝站立这个例子,站马上给予奖励记为1,否则记为0。

AlphaGo 便是一个范例的强化进修智能编制子,教会智能体若何玩游戏并最大年夜化其奖励 (即赢得游戏)。而在本文中就将创建一个智能体,教它若何经由过程阁下推动推车来办理推车上的杆平衡问题。

状态

状态即当前游戏的样子,平日用数字来表示。在乒乓球比赛中,它可能是每个球拍与x、y坐标轴的垂直位置或者是乒乓球的速率。在推车杆的环境下,这里的状态由4个数字组成:即推车的位置,推车的速率,杆的位置 (作为角度) 和杆的角速率。这4个数字作为向量 (或数组) 供给给智能体,这异常紧张:将状态作为一组数字意味着智能体能够对它进行一些数学运算,以便抉择若何根据状态来采取什么行动。

策略

策略是一种可以处置惩罚游戏状态的函数 (例如棋盘的位置或者推车和杆的位置), 并输出智能体在该位置应该采取的动作 (例如移动或将推车推到左边)。在智能体采取响应的操作后,游戏将以下一个状态更新,此时将再次根据其输入策略做出决策,这个历程不停持续到游戏达到某个终止前提时停止。策略同样是个异常关键的身分,由于它反应了是智能体背后的决策能力,这也是我们所必要卖力斟酌的。

点积 (dot product)

两个数组 (向量) 之间的点积可以简单理解为,将第一个数组的每个元素乘以第二个数组的对应元素,并将它们整个加在一路。假设想要谋略数组 A 和 B 的点积,形如 A[0]*B[0]+A[1]*B[1] ......随后将应用此运算结果再乘以一个状态 (同样是一个向量) 和一个策略值 (同样也是一个向量)。这部分内容将鄙人一节具体先容。

拟订策略

为了办理推车游戏,我们盼望所设计的机械进修策略能够赢得游戏或最大年夜化游戏奖励。对付智能体而言,这里将接管4维数组所表示策略,每一维代表每个组成的紧张性 (推车的位置,杆位等四个组成)。随后,再将点积的结果与策略、状态向量进行处置惩罚并输出终极的结果。根据结果的正负值抉择是向左照样向右推动推车。这听起来可能有点抽象,下面就经由过程一个详细的例子,来看看全部历程将发生什么。

假设推车在游戏中静止地处在中心位置,当杆向右倾斜时车也将向右倾斜,如下图这样:

所对应的的状态如下图所示:

此时的状态向量为 [0, 0, 0.2, 0.05]。直不雅地说,现在我们想要将推车推向右侧,并将杆拉直。这里经由过程练习中获得了一个很好的策略,即 [-0.116, 0.332, 0.207,  0.352]。将上面的状态向量与策略向量进行点积处置惩罚,假如获得的结果为正,则将推车向右推动;反之则向左推动。

显然,这里的输出是个正数,这意味着在这种策略下智能体将推车向右推动,这也恰是我们想要的结果。那么,该若何获得这个策略向量呢,以便智能体能够朝着我们盼望的偏向推动?或者说假如随机选择一个策略,那么智能体又该若何行动呢?

开始编辑

在该项目主页 repl.it 上弹出一个 Python 实例。repl.it容许用户快速启动大年夜量不合编程情况的云实例情况并在强大年夜云编译器 (IDE) 中编辑代码,这个强大年夜的 IDE 能在任何地方造访,如下图所示。

安装所需的包

安装这个项目所需的两个软件包:numpy 用于赞助数值谋略,而 OpenAI Gym 则作为智能体的模拟器。如下图所示,只需在编辑器左侧的包搜索对象中输入 gym 和 numpy,然后单击加号按钮即可安装这两个包。

创建根基情况

这里首先将刚安装的两个依附包导入到 main.py 脚本中并设置一个新的 gym情况。随后定义一个名为 play 的函数,该函数将被付与一个情况和一个策略向量,在情况中履行策略向量并返回分数以及每个光阴步的游戏不雅测值。着末,将经由过程分数上下来反应策略的效果短长,以及在单次游戏中策略的体现。如斯,就可以测试不合的策略,查看他们在游戏中的体现!

import gymimport numpy as npenv = gym.make('CartPole-v1')

下面从函数定义开始,将游戏重置为开始状态,如下所示。

def play(env, policy): observation = env.reset()

接着初始化一些变量,用来跟踪游戏是否达到终止前提,策略得分以及游戏中每个步骤的不雅测值,如下所示。

done = False score = 0  observations = []

现在,只必要一些光阴步来开始游戏,直到 gym 提示游戏停止为止。

for _ in range(5000): observations += [observation.tolist()] # Record the observations for normalization and replay if done: # If the simulation was over last iteration, exit loop break # Pick an action according to the policy matrix outcome = np.dot(policy, observation) action = 1 if outcome > 0 else 0 # Make the action, record reward observation, reward, done, info = env.step(action) score += reward  return score, observations

如下,这部分的代码主如果用于开始游戏并记录结果,而与策略相关的代码便是这两行:

outcome = np.dot(policy, observation) action = 1 if outcome > 0 else 0

在这里所做的只是对策略向量和状态 (不雅测) 数组之间进行点积运算,就像在之前具编制子中所展现的那样。随后根据结果的正负,选择1或0 (向左或右) 的动作。到这里为止,main.py 脚本如下所示:

import gymimport numpy as npenv = gym.make('CartPole-v1')def play(env, policy): observation = env.reset() done = False score = 0 observations = [] for _ in range(5000): observations += [observation.tolist()] # Record the observations for normalization and replay if done: # If the simulation was over last iteration, exit loop break # Pick an action according to the policy matrix outcome = np.dot(policy, observation) action = 1 if outcome > 0 else 0 # Make the action, record reward observation, reward, done, info = env.step(action) score += reward return score, observations

下面开始探求该游戏的最优策略!

第一次游戏

现在已经有了一个函数,用来反应策略的短长。是以,接下来要做的事开始拟订一些策略,并查看他们的体现若何。假如一开始你想考试测验一些随机的策略,那么这些策略的结果将会如何呢?这里应用 numpy 来随机天生一些的策略,这些策略都是4维数组或1x4矩阵,即选择4个0到1之间的数字作为游戏的策略,如下所示。

policy = np.random.rand(1,4)

有了这些策略以及上面所创建的情况,下面就可以开始游戏并得到策略分数:

score, observations = play(env, policy)print('Policy Score', score)

只需点击运行即可开始游戏,它将输出每个策略所对应的得分,如下所示。

着末,所有的策略得到的最高得分为500,在这里随机天生的策略可能并不能获得太好的结果,而且经由过程随机天生的要领,很难解释智能体是若何进行游戏的。下一步将先容若何选择并设置游戏的策略,来查看智能体的游戏体现。

察看我们的智能体

这里应用 Flask 来设置轻量级办事器,以便可以在浏览器中查看智能体的体现。 Flask 是一个轻量级的 Python HTTP 办事器框架,可以为 HTML UI 和数据供给办事。因为衬着和 HTTP 办事器背后的细节对智能体的练习并不紧张,在这里只是简单先容下。首先必要将 Flask 安装为 Python 包,就像上面安装 gym 和 numpy 包一样,如下所示。

接下来,在脚本的底部创建一个 flask 办事器,它将在 /data 端点上公开游戏的每个帧的记录,并在 / 上托管 UI,如下所示。

from flask import Flaskimport jsonapp = Flask(__name__, static_folder='.')@app.route("/data")def data(): return json.dumps(observations)@app.route('/')def root(): return app.send_static_file('./index.html')app.run(host='0.0.0.0', port='3000')

此外,还必要添加两个文件:一个是项目的空缺 Python 文件,这是 repl.it 用于检测 repl 是处于评估模式照样项目模式的关键。这里只需应用新文件按钮添加空缺的 Python 脚本即可。随后,还必要创建一个将承载衬着 UI 的 index.html 文件。在此不必要深入懂得这部分的内容,只需将此 index.html 上传到 repl.it 项目即可。

好了,现在的项目目录应该像这样,如下所示:

有了这两个新文件,当运行 repl 时它将回放所选择的游戏策略,便于我们探求一个最优的策略。

策略搜索

在第一次游戏中只是经由过程 numpy 为智能体随机天生一些策略并开始游戏。那么,若何选择一些游戏策略,并在游戏停止时只保留那个结果最好的策略呢?在这里,拟订游戏时并不光是天生一个策略,而是经由过程编写一个轮回来天生一些策略,跟踪每个策略的履行环境并在着末保存最佳的策略。

起开创建一个名为 max 的元组,它将存储游戏历程所呈现的最佳策略得分、不雅测和策略数组,如下所示。

max = (0, [], [])

接下来将天生并评估10个策略,并将得分最大年夜值的策略保存。此外,这里还必要在 /data 端点返回最佳策略的重放,如下所示。

for _ in range(10): policy = np.random.rand(1,4) score, observations = play(env, policy) if score > max[0]: max = (score, observations, policy)print('Max Score', max[0])

此外,这个端点:

@app.route("/data")def data(): return json.dumps(observations)

应改为:

@app.route("/data")def data(): return json.dumps(max[1])

着末 main.py 脚本应像这样,如下图所示:

import gymimport numpy as npenv = gym.make('CartPole-v1')def play(env, policy): observation = env.reset() done = False score = 0 observations = [] for _ in range(5000): observations += [observation.tolist()] # Record the observations for normalization and replay if done: # If the simulation was over last iteration, exit loop break # Pick an action according to the policy matrix outcome = np.dot(policy, observation) action = 1 if outcome > 0 else 0 # Make the action, record reward observation, reward, done, info = env.step(action) score += reward return score, observationsmax = (0, [], [])for _ in range(10): policy = np.random.rand(1,4) score, observations = play(env, policy) if score > max[0]: max = (score, observations, policy)print('Max Score', max[0])from flask import Flaskimport jsonapp = Flask(__name__, static_folder='.')@app.route("/data")def data(): return json.dumps(max[1])@app.route('/')def root(): return app.send_static_file('./index.html')app.run(host='0.0.0.0', port='3000')

假如现在运行 repl,正常环境所获得的最大年夜分数应为500。假如没有的话,请再次考试测验运行 repl! 经由过程这种要领,能够完美地察看游戏策略是若何让杆达到平衡的!

若何加速?

(1)这里智能体达到平衡的速率并不敷块。回顾前面拟订策略时,首先只是在0到1范围内随机创建了策略数组,这正好是有效的。但假如这里智能体翻转大年夜于运算符所设定的那样,那么可能将看到劫难性的掉败结果。可以考试测验将 action> 0 if outcome>0 else 0 改为 action=1 if outcome<0 else 0。

效果彷佛并没有很显着,这可能是由于假如正好选择少于而不是大年夜于,那么可能永世也找不到办理游戏的策略。为了缓解这种环境,在实际操作时也应该天生一些带负数的策略。虽然这将使得搜索一个好策略的历程变得加倍艰苦 (由于包孕许多负的策略并不好),但所带来的好处是不再必要经由过程特定算法来匹配特定游戏。假如考试测验在 OpenAI gym 的其他情况中这样做,那么算法肯定会掉败。

要做到这一点,不能应用 policy = np.random.rand(1,4),必要将改为 policy = np.random.rand(1,4) -0.5。如斯,所天生的策略中每个数字都在-0.5到0.5之间,而不是0到1。然则因为这样做会使得最优策略的搜索历程变得艰苦,是以在上面的 for 轮回中,不要迭代10个策略,变动这部分的代码考试测验搜索100个策略 (for _ in range (100):)。当然,你也可以先考试测验迭代10次,看看用负的策略得到最优策略的艰苦性。

好了,现在的 main.py 脚本可参考

https://gist.github.com/MikeShi42/e1c5551bbf2cb2064da962ad8b198c1b

假如现在运行 repl,无论应用的是否大年夜于或小于,仍旧可以找到一个好的游戏策略。

(2)不仅如斯,纵然所天生的策略可能能够在一次游戏中获得最高分500的结果,那它能够在每次游戏中都有这样的体现呢?当天生100个策略并选择在单次运行中体现最佳的策略时,该策略可能只是单次最佳策略,或者它可能是一个异常糟糕的策略,只是正好在一次游戏中有异常好的机能。由于游戏本身具有随机性 (如肇端位置每次都不合),是以策略可以只是在一个肇端位置体现优越,而不是在其他位置。

是以,为了办理这个问题,必要评估一个策略在多次实验中的体现。现在就采取之前实验获得的最佳政策,查看它在100次游戏实验中的体现。在这里对最优策略进行100次游戏 (最大年夜索引值为2) 并记录每次的游戏得分。随后应用 numpy 谋略该策略的匀称分数并将其打印到终端。你可能会留意到,最佳的游戏策略实际上并不必然是最优秀的。

总结

好了,以上已经成功创建了一个能够异常有效地办理推车杆问题的 AI 智能体。当然它还有很大年夜的改进空间,这将是后续系列文章的一部分。此外,后续的事情还可以对一些问题展开钻研:

探求“真正的”最优策略 (即在100次自力游戏中体现优越)

优化最佳策略搜索所需的次数 (即样本效率问题)

选择精确搜索策略,而不是考试测验随机地选择。

在其他的情况中创建。

您可能还会对下面的文章感兴趣: