OpenAI 是由 Elon Musk 和 Sam Altman 创立的非营利性,开源人工智能(AI)研究公司,旨在构建通用 AI。 他们是由顶级行业领导者和顶尖公司赞助的。 OpenAI 具有 Gym 和 Universe 两种样式,我们可以使用它们模拟现实环境,构建强化学习(RL)算法,并在这些环境中测试我们的智能体。 TensorFlow 是 Google 的开源机器学习库,已广泛用于数值计算。 在接下来的章节中,我们将使用 OpenAI 和 TensorFlow 来构建和评估强大的 RL 算法。
在本章中,您将了解以下内容:
- 通过安装 Anaconda,Docker,OpenAI Gym 和 Universe 和 TensorFlow 设置机器
- 使用 OpenAI Gym 和 Universe 模拟环境
- 训练机器人走路
- 构建一个视频游戏机器人
- TensorFlow 的基本原理
- 使用 TensorBoard
安装 OpenAI 并不是一件容易的事。 要设置和运行系统,必须正确遵循一组步骤。 现在,让我们看看如何设置我们的机器并安装 OpenAI Gym 和 Universe。
本书中的所有示例均使用 Anaconda 版本的 Python。 Anaconda 是 Python 的开源发行版。 它被广泛用于科学计算和处理大量数据。 它提供了一个出色的包管理环境。 它提供对 Windows,macOS 和 Linux 的支持。 Anaconda 随附安装了 Python 以及用于科学计算的流行包,例如 NumPy,SciPy 等。
要下载 Anaconda,请访问这里,您将在此处看到用于下载用于不同平台的 Anaconda 的选项。
如果使用 Windows 或 Mac,则可以根据计算机架构直接下载图形安装程序,然后使用图形安装程序进行安装。
如果您使用的是 Linux,请按照以下步骤操作:
- 打开终端并输入以下内容以下载 Anaconda:
wget https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.sh
- 完成后,我们可以通过以下命令安装 Anaconda:
bash Anaconda3-5.0.1-Linux-x86_64.sh
成功安装 Anaconda 后,我们需要创建一个新的 Anaconda 环境,该环境基本上是一个虚拟环境。 虚拟环境有什么需求? 假设您正在使用 Aum 版本 1.14 的项目 A 和使用 NumPy 版本 1.13 的项目 B。 因此,要进行项目 B,您可以降级 NumPy 或重新安装 Anaconda。 在每个项目中,我们使用具有不同版本的不同库,这些库不适用于其他项目。 我们使用虚拟环境来代替降级或升级版本或为新项目每次重新安装 Anaconda。 这为当前项目创建了一个隔离的环境,因此每个项目可以具有自己的依赖,并且不会影响其他项目。 我们将使用以下命令创建这样的环境,并将我们的环境命名为universe
:
conda create --name universe python=3.6 anaconda
我们可以使用以下命令激活环境:
source activate universe
安装 Anaconda 之后,我们需要安装 Docker。 Docker 使将应用部署到生产变得容易。 假设您在具有 TensorFlow 和其他一些库的localhost
中构建了一个应用,并且要将应用部署到服务器中。 您将需要在服务器上安装所有这些依赖项。 但是使用 Docker,我们可以将应用及其依赖项打包在一起,这称为容器,并且我们可以在服务器上运行应用而无需在打包的 Docker 容器中使用任何外部依赖项。 OpenAI 不支持 Windows,因此要在 Windows 中安装 OpenAI,我们需要使用 Docker。 而且,大多数 OpenAI Universe 环境都需要 Docker 来模拟环境。 现在让我们看看如何安装 Docker。
要下载 Docker,请转至这里,您将在其中看到一个名为“Get Docker”的选项。 如果选择该选项,则将看到不同操作系统的选项。 如果使用 Windows 或 Mac,则可以下载 Docker 并直接使用图形安装程序进行安装。
如果您使用的是 Linux,请按照以下步骤操作:
打开您的终端并输入以下内容:
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
然后输入:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
然后输入:
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
最后,输入:
sudo apt-get update
sudo apt-get install docker-ce
我们需要成为 Docker 用户组的成员才能开始使用 Docker。 您可以通过以下命令加入 Docker 用户组:
sudo adduser $(whoami) docker
newgrp docker
groups
我们可以通过运行内置的hello-world
程序来测试 Docker 的安装:
sudo service docker start
sudo docker run hello-world
为了避免每次使用sudo
来使用 Docker,我们可以使用以下命令:
sudo groupadd docker
sudo usermod -aG docker $USER
sudo reboot
现在让我们看看如何安装 OpenAI Gym 和 Universe。 在此之前,我们需要安装几个依赖项。 首先,让我们使用以下命令激活刚刚创建的conda
环境:
source activate universe
然后,我们将安装以下依赖项:
sudo apt-get update
sudo apt-get install golang libcupti-dev libjpeg-turbo8-dev make tmux htop chromium-browser git cmake zlib1g-dev libjpeg-dev xvfb libav-tools xorg-dev python-opengl libboost-all-dev libsdl2-dev swig
conda install pip six libgcc swig
conda install opencv
在本书中,我们将使用gym
版本0.7.0
,因此您可以使用pip
直接安装gym
,如下所示:
pip install gym==0.7.0
或者,您可以克隆gym
存储库并通过以下命令安装最新版本:
cd ~
git clone https://github.com/openai/gym.git
cd gym
pip install -e '.[all]'
前面的命令将获取gym
存储库并以包的形式安装gym
,如以下屏幕截图所示:
在安装 Gym 时,您很可能会遇到以下任何错误。 如果出现这些错误,只需运行以下命令并尝试重新安装:
Failed building wheel for pachi-py
或Failed building wheel for pachi-py atari-py
:
sudo apt-get update
sudo apt-get install xvfb libav-tools xorg-dev libsdl2-dev swig cmake
Failed building wheel for mujoco-py
:
git clone https://github.com/openai/mujoco-py.git
cd mujoco-py
sudo apt-get update
sudo apt-get install libgl1-mesa-dev libgl1-mesa-glx libosmesa6-dev python3-pip python3-numpy python3-scipy
pip3 install -r requirements.txt
sudo python3 setup.py install
Error: command 'gcc' failed with exit status 1
:
sudo apt-get update
sudo apt-get install python-dev
sudo apt-get install libevent-dev
同样,我们可以通过获取universe
存储库并将universe
作为包安装来安装 OpenAI Universe:
cd ~
git clone https://github.com/openai/universe.git
cd universe
pip install -e .
以下屏幕快照显示了安装:
如前所述,Open AI Universe 需要 Docker,因为大多数 Universe 环境都在 Docker 容器中运行。
因此,让我们构建一个 Docker 镜像并将其命名为universe
:
docker build -t universe .
构建 Docker 镜像后,我们运行以下命令,该命令从 Docker 镜像启动容器:
docker run --privileged --rm -it -p 12345:12345 -p 5900:5900 -e DOCKER_NET_HOST=172.17.0.1 universe /bin/bash
借助 OpenAI Gym,我们可以模拟各种环境,并开发,评估和比较 RL 算法。 现在让我们了解如何使用 Gym。
让我们看看如何模拟基本的购物车杆环境:
- 首先,让我们导入库:
import gym
- 下一步是使用
make
函数创建一个仿真实例:
env = gym.make('CartPole-v0')
- 然后,我们应该使用
reset
方法初始化环境:
env.reset()
- 然后,我们可以循环执行一些时间步骤,并在每个步骤渲染环境:
for _ in range(1000):
env.render()
env.step(env.action_space.sample())
完整的代码如下:
import gym
env = gym.make('CartPole-v0')
env.reset()
for _ in range(1000):
env.render()
env.step(env.action_space.sample())
如果运行前面的程序,则可以看到输出,该输出显示了购物车杆环境:
OpenAI Gym 提供了许多模拟环境,用于训练,评估和构建我们的智能体。 我们可以通过检查其网站或输入以下内容来检查可用的环境,这些将列出可用的环境:
from gym import envs
print(envs.registry.all())
由于 Gym 提供了不同的有趣环境,因此让我们模拟一个赛车环境,如下所示:
import gym
env = gym.make('CarRacing-v0')
env.reset()
for _ in range(1000):
env.render()
env.step(env.action_space.sample())
您将获得如下输出:
现在,让我们学习如何使用 Gym 训练机器人走路以及一些基础知识。
该策略是当机器人向前移动时将获得X
点作为奖励,如果机器人无法移动,则会减少Y
点。 因此,机器人将在最大化奖励的情况下学习行走。
首先,我们将导入库,然后通过make
函数创建一个仿真实例。 Open AI Gym 提供了一个称为BipedalWalker-v2
的环境,用于在简单的地形中训练机器人智能体:
import gym
env = gym.make('BipedalWalker-v2')
然后,对于每个剧集(初始状态和最终状态之间的智能体程序-环境交互),我们将使用reset
方法初始化环境:
for episode in range(100):
observation = env.reset()
然后,我们将循环并渲染环境:
for i in range(10000):
env.render()
我们从环境的行动空间中抽样随机行动。 每个环境都有一个动作空间,其中包含所有可能的有效动作:
action = env.action_space.sample()
对于每个操作步骤,我们将记录observation
,reward
,done
和info
:
observation, reward, done, info = env.step(action)
observation
是代表观察环境的对象。 例如,机器人在地形中的状态。
reward
是上一动作获得的奖励。 例如,机器人成功前进所获得的奖励。
done
是布尔值; 如果为真,则表明该剧集已经完成(也就是说,机器人学会了行走或完全失败)。 剧集完成后,我们可以使用env.reset()
初始化下一个剧集的环境。
info
是可用于调试的信息。
当done
为true
时,我们打印该剧集采取的时间步长并中断当前剧集:
if done:
print("{} timesteps taken for the Episode".format(i+1))
break
完整的代码如下:
import gym
env = gym.make('BipedalWalker-v2')
for i_episode in range(100):
observation = env.reset()
for t in range(10000):
env.render()
print(observation)
action = env.action_space.sample()
observation, reward, done, info = env.step(action)
if done:
print("{} timesteps taken for the episode".format(t+1))
break
输出显示在以下屏幕截图中:
OpenAI Universe 提供了广泛的现实游戏环境。 它是 OpenAI Gym 的扩展。 它提供了在各种简单到实时复杂环境中训练和评估智能体的能力。 它可以无限制地访问许多游戏环境。
让我们学习如何构建一个可以玩赛车游戏的视频游戏机器人。 我们的目标是赛车必须前进,而不会卡在任何障碍物上或撞到其他赛车上。
首先,我们导入必要的库:
import gym
import universe # register universe environment
import random
然后,我们使用make
函数模拟赛车环境:
env = gym.make('flashgames.NeonRace-v0')
env.configure(remotes=1) #automatically creates a local docker container
让我们创建用于移动汽车的变量:
# Move left
left = [('KeyEvent', 'ArrowUp', True), ('KeyEvent', 'ArrowLeft', True),
('KeyEvent', 'ArrowRight', False)]
#Move right
right = [('KeyEvent', 'ArrowUp', True), ('KeyEvent', 'ArrowLeft', False),
('KeyEvent', 'ArrowRight', True)]
# Move forward
forward = [('KeyEvent', 'ArrowUp', True), ('KeyEvent', 'ArrowRight', False),
('KeyEvent', 'ArrowLeft', False), ('KeyEvent', 'n', True)]
我们将初始化一些其他变量:
# We use turn variable for deciding whether to turn or not
turn = 0
# We store all the rewards in rewards list
rewards = []
#we will use buffer as some threshold
buffer_size = 100
#we will initially set action as forward, which just move the car forward #without any turn
action = forward
现在,让我们的游戏智能体在无限循环中玩,该循环基于与环境的交互持续执行动作:
while True:
turn -= 1
# Let us say initially we take no turn and move forward.
# We will check value of turn, if it is less than 0
# then there is no necessity for turning and we just move forward.
if turn <= 0:
action = forward
turn = 0
然后,我们使用env.step()
一次性执行一项操作(暂时向前移动):
action_n = [action for ob in observation_n]
observation_n, reward_n, done_n, info = env.step(action_n)
对于每个时间步,我们将结果记录在observation_n
,reward_n
,done_n
和info
变量中:
observation _n
:汽车状态reward_n
:如果汽车成功前进但没有卡在障碍物上,则通过上一个动作获得奖励done_n
:这是一个布尔值; 如果游戏结束,它将设置为true
info_n
:用于调试目的
显然,智能体(汽车)无法在整个游戏中前进; 它需要转弯,避免障碍物,并且还会撞到其他车辆。 但是它必须确定是否应该转弯,如果需要转弯,则应朝哪个方向转弯。
首先,我们将计算到目前为止获得的奖励的平均值; 如果是0
,则很明显我们在前进时被卡在某处,我们需要转弯。 然后,我们需要转向哪个方向? 您是否还记得我们在第 1 章,“强化学习简介”中研究的策略函数。
关于同一概念,我们这里有两个策略:一个是左转,另一个是右转。 我们将在这里采取随机策略,并计算出奖励并加以改善。
我们将生成一个随机数,如果它小于0.5
,那么我们将获得一个右数,否则我们将得到一个左数。 稍后,我们将更新奖励,并根据奖励,了解哪个方向最佳:
if len(rewards) >= buffer_size:
mean = sum(rewards)/len(rewards)
if mean == 0:
turn = 20
if random.random() < 0.5:
action = right
else:
action = left
rewards = []
然后,对于每个剧集(例如游戏结束),我们使用env.render()
重新初始化环境(从头开始游戏):
env.render()
完整的代码如下:
import gym
import universe # register universe environment
import random
env = gym.make('flashgames.NeonRace-v0')
env.configure(remotes=1) # automatically creates a local docker container
observation_n = env.reset()
##Declare actions
#Move left
left = [('KeyEvent', 'ArrowUp', True), ('KeyEvent', 'ArrowLeft', True),
('KeyEvent', 'ArrowRight', False)]
#move right
right = [('KeyEvent', 'ArrowUp', True), ('KeyEvent', 'ArrowLeft', False),
('KeyEvent', 'ArrowRight', True)]
# Move forward
forward = [('KeyEvent', 'ArrowUp', True), ('KeyEvent', 'ArrowRight', False),
('KeyEvent', 'ArrowLeft', False), ('KeyEvent', 'n', True)]
#Determine whether to turn or not
turn = 0
#store rewards in a list
rewards = []
#use buffer as a threshold
buffer_size = 100
#initial action as forward
action = forward
while True:
turn -= 1
if turn <= 0:
action = forward
turn = 0
action_n = [action for ob in observation_n]
observation_n, reward_n, done_n, info = env.step(action_n)
rewards += [reward_n[0]]
if len(rewards) >= buffer_size:
mean = sum(rewards)/len(rewards)
if mean == 0:
turn = 20
if random.random() < 0.5:
action = right
else:
action = left
rewards = []
env.render()
如果运行该程序,则可以看到汽车如何学习运动而不会被卡住或撞到其他车辆:
TensorFlow 是 Google 的开源软件库,已广泛用于数值计算。 它被广泛用于构建深度学习模型,并且是机器学习的一个子集。 它使用可以在许多不同平台上共享和执行的数据流图。 张量只是多维数组,因此,当我们说 TensorFlow 时,它实际上是计算图中的多维数组(张量)的流。
安装 Anaconda 后,安装 TensorFlow 变得非常简单。 无论使用什么平台,都可以通过键入以下命令轻松安装 TensorFlow:
source activate universe
conda install -c conda-forge tensorflow
在安装 TensorFlow 之前,请不要忘记激活universe
环境。
我们可以通过简单地运行以下Hello World
程序来检查 TensorFlow 安装是否成功:
import tensorflow as tf
hello = tf.constant("Hello World")
sess = tf.Session()
print(sess.run(hello))
变量,常量和占位符是 TensorFlow 的基本元素。 但是,这三者之间总是存在混淆。 让我们逐一查看每个元素,并了解它们之间的区别。
变量是用于存储值的容器。 变量将用作计算图中其他几个操作的输入。 我们可以使用tf.Variable()
函数创建 TensorFlow 变量。 在下面的示例中,我们定义一个具有随机正态分布值的变量,并将其命名为weights
:
weights = tf.Variable(tf.random_normal([3, 2], stddev=0.1), name="weights")
但是,在定义变量后,我们需要使用tf.global_variables_initializer()
方法显式创建初始化操作,该方法将为变量分配资源。
常量与变量不同,不能更改其值。 常量是不可变的。 一旦为它们分配了值,就不能在整个过程中进行更改。 我们可以使用tf.constant()
函数创建常量:
x = tf.constant(13)
可以将占位符视为变量,在其中仅定义类型和大小而不会分配值。 占位符定义为无值。 占位符的值将在运行时输入。 占位符有一个可选参数shape
,它指定数据的维数。 如果shape
设置为None
,那么我们可以在运行时提供任意大小的数据。 可以使用tf.placeholder()
函数定义占位符:
x = tf.placeholder("float", shape=None)
简单来说,我们使用tf.Variable
存储数据,并使用tf.placeholder
馈送外部数据。
TensorFlow 中的所有内容都将表示为由节点和边组成的计算图,其中节点是数学运算(例如加法,乘法等),而边是张量。 拥有计算图非常有效地优化了资源,并且还促进了分布式计算。
假设我们有节点B
,其输入取决于节点A
的输出; 这种依赖关系称为直接依赖关系。
例如:
A = tf.multiply(8,5)
B = tf.multiply(A,1)
当节点B
的输入不依赖于节点A
时,称为间接依赖。
例如:
A = tf.multiply(8,5)
B = tf.multiply(4,3)
因此,如果我们能够理解这些依赖性,则可以在可用资源中分配独立的计算并减少计算时间。
每当我们导入 TensorFlow 时,都会自动创建一个默认图,并且我们创建的所有节点都将与该默认图关联。
计算图只会被定义; 为了执行计算图,我们使用 TensorFlow 会话:
sess = tf.Session()
我们可以使用tf.Session()
方法为我们的计算图创建会话,该方法将分配用于存储变量当前值的内存。 创建会话后,我们可以使用sess.run()
方法执行图。
为了在 TensorFlow 中运行任何内容,我们需要为实例启动 TensorFlow 会话; 请参考代码:
import tensorflow as tf
a = tf.multiply(2,3)
print(a)
它将打印一个 TensorFlow 对象而不是6
。 就像已经说过的,每当我们导入 TensorFlow 时,都会自动创建一个默认计算图,并且我们创建的所有节点a
都将附加到该图上。 为了执行图,我们需要初始化一个 TensorFlow 会话,如下所示:
#Import tensorflow
import tensorflow as tf
#Initialize variables
a = tf.multiply(2,3)
#create tensorflow session for executing the session
with tf.Session() as sess:
#run the session
print(sess.run(a))
前面的代码将显示6
。
TensorBoard 是 TensorFlow 的可视化工具,可用于可视化计算图。 它也可以用来绘制各种定量指标和一些中间计算的结果。 使用 TensorBoard,我们可以轻松地可视化复杂的模型,这对于调试和共享非常有用。
现在,让我们构建一个基本的计算图,并在 TensorBoard 中对其进行可视化。
首先,让我们导入库:
import tensorflow as tf
接下来,我们初始化变量:
a = tf.constant(5)
b = tf.constant(4)
c = tf.multiply(a,b)
d = tf.constant(2)
e = tf.constant(3)
f = tf.multiply(d,e)
g = tf.add(c,f)
现在,我们将创建一个 TensorFlow 会话。 我们将使用tf.summary.FileWriter()
将图的结果写入名为event
的文件中:
with tf.Session() as sess:
writer = tf.summary.FileWriter("output", sess.graph)
print(sess.run(g))
writer.close()
为了运行 TensorBoard,请转到您的终端,找到工作目录,然后键入tensorboard --logdir=output --port=6003
。
您可以看到如下所示的输出:
范围划分用于降低复杂性,并通过将相关节点分组在一起来帮助我们更好地理解模型。 例如,在前面的示例中,我们可以将图分为两个不同的组,称为计算和结果。 如果看前面的示例,可以看到节点a
至e
执行计算,而节点g
计算结果。 因此,我们可以使用范围将它们分开分组,以便于理解。 可以使用tf.name_scope()
函数创建作用域。
让我们通过Computation
使用tf.name_scope()
函数:
with tf.name_scope("Computation"):
a = tf.constant(5)
b = tf.constant(4)
c = tf.multiply(a,b)
d = tf.constant(2)
e = tf.constant(3)
f = tf.multiply(d,e)
让我们通过Result
使用tf.name_scope()
函数:
with tf.name_scope("Result"):
g = tf.add(c,f)
查看Computation
范围; 我们可以将其进一步分解为更多的部分。 我们可以创建一个范围为Part 1
并具有节点a
至c
的范围,并创建一个范围为Part 2
并具有节点d
至e
的范围,因为第 1 部分和第 2 部分彼此独立 :
with tf.name_scope("Computation"):
with tf.name_scope("Part1"):
a = tf.constant(5)
b = tf.constant(4)
c = tf.multiply(a,b)
with tf.name_scope("Part2"):
d = tf.constant(2)
e = tf.constant(3)
f = tf.multiply(d,e)
通过在 TensorBoard 中可视化它们可以更好地了解作用域。 完整的代码如下:
import tensorflow as tf
with tf.name_scope("Computation"):
with tf.name_scope("Part1"):
a = tf.constant(5)
b = tf.constant(4)
c = tf.multiply(a,b)
with tf.name_scope("Part2"):
d = tf.constant(2)
e = tf.constant(3)
f = tf.multiply(d,e)
with tf.name_scope("Result"):
g = tf.add(c,f)
with tf.Session() as sess:
writer = tf.summary.FileWriter("output", sess.graph)
print(sess.run(g))
writer.close()
如果查看下图,您可以轻松地了解范围如何通过将相似节点分组在一起来帮助我们降低理解的复杂性。 范围界定在处理复杂项目时被广泛使用,以更好地了解节点的功能和依赖项:
在本章中,我们学习了如何通过安装 Anaconda,Docker,OpenAI Gym,Universe 和 TensorFlow 来设置机器。 我们还学习了如何使用 OpenAI 创建模拟,以及如何训练智能体在 OpenAI 环境中学习。 然后,我们了解了 TensorFlow 的基础知识,然后在 TensorBoard 中可视化了图。
在下一章第 3 章,“马尔可夫决策过程和动态规划”中,我们将学习马尔可夫决策过程和动态规划以及如何使用值和策略迭代来解决冻湖问题。
问题列表如下:
- 为什么以及如何在 Anaconda 中创建新环境?
- 使用 Docker 有什么需要?
- 我们如何在 OpenAI Gym 中模拟环境?
- 我们如何检查 OpenAI Gym 中的所有可用环境?
- OpenAI Gym 和 Universe 是否相同? 如果没有,原因是什么?
- TensorFlow 变量和占位符有何区别?
- 什么是计算图?
- 为什么我们需要 TensorFlow 中的会话?
- TensorBoard 的目的是什么?我们如何启动它?
您可以进一步参考以下论文: