Cartpole:强化学习的“Hello World”






3.26/5 (9投票s)
在本文中,您将能够启动并运行,并且将完成您的第一个强化学习项目。
欢迎阅读一系列关于强化学习的文章的第一篇。强化学习是一个强大的工具,可以帮助机器学习算法取得积极成果,从自动驾驶汽车到股票交易。在本系列中,我们将使用强化学习来教会一个神经网络如何掌握一款类似“打砖块”的游戏。
假设您对机器学习有一定的了解。这并非严格必需,但我不会在这里深入解释底层概念,例如神经网络。我还假设您对 Python 3 有一些经验,并且知道如何管理您的虚拟环境和添加包。
强化学习简介
首先,一些定义
- 环境 – 学习发生的场所,例如太空侵略者游戏或机械臂
- 观测 – 对环境状态的某种测量(可能带有噪声或不完整)
- 奖励 – 环境授予您的奖金或惩罚,例如您射击太空侵略者得分
- 智能体 – 一个实体,它对其环境进行观测,在其中采取行动,并根据这些行动获得奖励
- 策略 – 告诉智能体如何行动的规则
有了以上词汇表,我们可以说强化学习就是训练一个策略,使智能体能够通过在其环境中采取最优行动来最大化其奖励。请注意,“什么都不做”通常是可用的行动之一。
通常,我们希望使用一个框架来整合所有必需的组件,并简化运行实验的任务。一些流行的 RL 框架是 Garage、Dopamine 和 RLlib。我们将使用 RLlib。
运行代码
在本文结束时,您应该能够启动并运行,并且已经完成了您的第一个强化学习项目。
您可以选择几种不同的选项来运行您的代码
- 在本地机器上运行。 如果您已经设置好了 Python 环境,这可能是一个不错的选择,尤其是如果它带有 GPU。即使没有,像 Anaconda 这样的工具也可以大大简化设置过程。一些训练会话将耗时很长(几小时到几天),并且会占用您机器的资源。如果您运行的是 Windows,则必须使用 WSL2 运行代码,因为 RLib 对 Windows 的原生支持仍在进行中。这是值得的——RLib 是强化学习的最佳工具。
- 在远程计算机上运行。 您需要为此付费;然而,随着各种供应商按小时收费,这不一定很贵。这种方法为您提供了很大的灵活性,可以选择所需的 CPU 核心和 GPU 数量。
- 在托管的 Jupyter Notebook 中运行。 托管的 Notebook 由虚拟机支持(因此您可以安装额外的软件),可选配 GPU。其中一些服务是免费的,尽管这些通常有有限的允许运行时间,这对于训练简单的模型来说已经足够了。选项包括 Google Colab、Paperspace Gradient Notebooks 和 Azure Notebooks。
我们将使用 Ray 项目的 RLlib 框架。要在没有 GUI 的系统上录制训练进度的视频,您可以安装一个虚拟显示器。我在远程 Linux 终端和托管的 Notebook 中都使用了以下命令(在后者中,每行以感叹号开头)
# install xvfb, a virtual X server
apt-get install -y xvfb x11-utils
pip install pyvirtualdisplay==0.2.* PyOpenGL==3.1.* PyOpenGL-accelerate==3.1.*
然后,在 Python 文件/Notebook 中
import pyvirtualdisplay
_display = pyvirtualdisplay.Display(visible=False, size=(1400, 900))
_ = _display.start()
训练 Cartpole 环境
我们将使用 OpenAI Gym 提供学习环境。其中第一个是 Cartpole。这个环境包含一个平衡垂直杆的轮式推车。推杆不稳定,容易倒下。智能体可以根据杆的状态观测来移动推车,并根据推杆保持不倒的时间长度获得奖励。
我们将使用的整体框架是 Ray/RLlib。安装它(例如,使用 pip install ray[rllib]==0.8.5 或通过 Anaconda)将包含其依赖项,包括 OpenAI Gym。
对于每个新环境,也许最好的做法是启动它并看一看。如果您运行的是带有图形显示的环境,您可以直接“玩”环境
import gym
from gym.utils.play import play
env = gym.make("CartPole-v0")
play(env, zoom=4)
我们将直接开始训练一个智能体来解决这个环境。我们将在下一篇文章中再深入探讨细节。
import ray
from ray import tune
from ray.rllib.agents.dqn import DQNTrainer
ray.shutdown()
ray.init(
include_webui=False,
ignore_reinit_error=True,
object_store_memory=8 * 1024 * 1024 * 1024 # 8GB limit … feel free to increase this if you can
)
ENV = 'CartPole-v0'
TARGET_REWARD = 195
TRAINER = DQNTrainer
tune.run(
TRAINER,
stop={"episode_reward_mean": TARGET_REWARD}, # stop as soon as we "solve" the environment
config={
"env": ENV,
"num_workers": 0, # run in a single process
"num_gpus": 0,
"monitor": True, # store stats and videos periodically
"evaluation_num_episodes": 25, # every 25 episodes instead of the default 10
}
)
您应该会看到很多输出。每批的最后一行显示状态,包括获得的平均奖励。我们将继续训练,直到此奖励达到环境的目标 195。进度不是线性的,因此奖励可能会令人恼火地接近目标,然后又回落。要有耐心;它应该很快就能达到。在我的电脑上花了不到 15 分钟。
195?恭喜!您现在已经训练了您的第一个强化学习模型!
我们告诉 Ray 存储进度的快照,它会将这些快照放在您主目录内的 ray_results
中。您应该会看到许多 mp4 视频。如果您在托管的 Notebook 中运行,请参阅下一节;否则,您可以跳过它。
在远程 Notebook 中检索视频
视频文件应该已经创建,但没有简单的方法可以查看它们。我写了一些辅助代码来解决这个问题
from base64 import b64encode
from pathlib import Path
from typing import List
# this will depend on which provider you are using; the correct version is
# probably what you get if you append /ray/results/ to the output from !pwd
OUT_PATH = Path('/root/ray_results/')
def latest_experiment() -> Path:
""" Get the path of the results directory of the most recent training run. """
experiment_dirs = []
for algorithm in OUT_PATH.iterdir():
if not algorithm.is_dir():
continue
for experiment in algorithm.iterdir():
if not experiment.is_dir():
continue
experiment_dirs.append((experiment.stat().st_mtime, experiment))
return max(experiment_dirs)[1]
def latest_videos() -> List[Path]:
# because the ISO timestamp is in the name, the last alphabetically is the latest
return list(sorted(latest_experiment().glob('*.mp4')))
def render_mp4(videopath: Path) -> str:
mp4 = open(videopath, 'rb').read()
base64_encoded_mp4 = b64encode(mp4).decode()
return f'<p>{videopath.name}</p><video width=400 controls>
<source src="data:video/mp4;base64,{base64_encoded_mp4}" type="video/mp4"></video>'
将此添加到 Notebook 单元格应该可以渲染最近的视频。
from IPython.display import HTML
html = render_mp4(latest_videos()[-1])
HTML(html)
检查结果
如果您播放最近的视频,代表训练结束,它应该看起来像这样
在下一篇文章中,我们将看到幕后发生了什么,以及有哪些选项可用于更改学习。
历史
- 2020年6月25日:初始版本