65.9K
CodeProject 正在变化。 阅读更多。
Home

Cartpole:强化学习的“Hello World”

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.26/5 (9投票s)

2020年6月25日

CPOL

5分钟阅读

viewsIcon

14344

在本文中,您将能够启动并运行,并且将完成您的第一个强化学习项目。

欢迎阅读一系列关于强化学习的文章的第一篇。强化学习是一个强大的工具,可以帮助机器学习算法取得积极成果,从自动驾驶汽车到股票交易。在本系列中,我们将使用强化学习来教会一个神经网络如何掌握一款类似“打砖块”的游戏。

假设您对机器学习有一定的了解。这并非严格必需,但我不会在这里深入解释底层概念,例如神经网络。我还假设您对 Python 3 有一些经验,并且知道如何管理您的虚拟环境和添加包。

强化学习简介

首先,一些定义

  • 环境 – 学习发生的场所,例如太空侵略者游戏或机械臂
  • 观测 – 对环境状态的某种测量(可能带有噪声或不完整)
  • 奖励 – 环境授予您的奖金或惩罚,例如您射击太空侵略者得分
  • 智能体 – 一个实体,它对其环境进行观测,在其中采取行动,并根据这些行动获得奖励
  • 策略 – 告诉智能体如何行动的规则

有了以上词汇表,我们可以说强化学习就是训练一个策略,使智能体能够通过在其环境中采取最优行动来最大化其奖励。请注意,“什么都不做”通常是可用的行动之一。

通常,我们希望使用一个框架来整合所有必需的组件,并简化运行实验的任务。一些流行的 RL 框架是 Garage、Dopamine 和 RLlib。我们将使用 RLlib。

运行代码

在本文结束时,您应该能够启动并运行,并且已经完成了您的第一个强化学习项目。

您可以选择几种不同的选项来运行您的代码

  1. 在本地机器上运行。 如果您已经设置好了 Python 环境,这可能是一个不错的选择,尤其是如果它带有 GPU。即使没有,像 Anaconda 这样的工具也可以大大简化设置过程。一些训练会话将耗时很长(几小时到几天),并且会占用您机器的资源。如果您运行的是 Windows,则必须使用 WSL2 运行代码,因为 RLib 对 Windows 的原生支持仍在进行中。这是值得的——RLib 是强化学习的最佳工具。
  2. 在远程计算机上运行。 您需要为此付费;然而,随着各种供应商按小时收费,这不一定很贵。这种方法为您提供了很大的灵活性,可以选择所需的 CPU 核心和 GPU 数量。
  3. 在托管的 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日:初始版本
© . All rights reserved.