网络上关于强化学习的资料很多,但是针对双足机器人运动控制的强化学习的入门资料很少,所以打算将自己的理解汇总成一个博客系列。

关于深度强化学习

行走对于普通人来说是小事一桩,但是对机器人来说绝非易事。双足机器人是一个高维、非线性的复杂系统,在相对容易地环境中(如平坦地面行走)已有像 线性倒立摆模型 等成熟的计算规划机器人的运动轨迹,再使用逆运动学等方法计算关节角度等控制参数,从而驱动机器类人行走。

但是在各种复杂环境(如崎岖路面、外部扰动、机器人协作等)下令机器人走起来仍然困难重重,比如突然踹机器人一脚、脚底打滑或者腿瘸了,简单的模型无法理解这些变化,深度网络恰好可以帮助机器人理解这些复杂环境,其中 深度强化学习 受到越来越多的关注。

在强化学习中环境通常被规范为马尔可夫决策过程,机器人需要根据当前环境的状态采取最佳的动作,以获得最高的回合奖励值。超级玛丽一类的强化学习环境中,角色在每个 Step 要采取前进、后退、跳、发射子弹等离散的动作。但双足行走机器人要在每个 Step 控制每个关节的角度或者扭矩等值驱动自身运动,所以输出的动作值为连续的浮点数,即连续运动控制

连续动作控制环境的训练要比离散动作控制环境要更为困难,就算使用目前市面上配置最高的家用 CPU 和 GPU,对于训练像双足机器人行走、运动等复杂的连续运动控制环境,仍需要好几天的时间才能收敛。在 Alexirpan 的博文中,他总结了深度强化学习一些问题:

  1. 样本利用率非常低;
  2. 最终表现不够好,经常比不过基于模型的方法;
  3. 好的奖励函数难以设计;
  4. 难以平衡“探索”和“利用”, 以致算法陷入局部极小;
  5. 对环境的过拟合;
  6. 灾难性的不稳定性;

这些问题的存在,在看论文或者算法过程中,常常陷入局部细节当。OpenAI spinningup 博客 提供了解决方案,学习 DRL 需要:

  • 从了解和利用现有的强化学习算法为起点,不要陷入局部细节;
  • 在最简单的环境试验算法的有效性,快速迭代;
  • 当试验成功后,再应用到复杂的环境中去;

所以在后面内容中使用经典的 CartPole 环境作为演示。

环境安装

目前 baselinesstable-baselines3RLlib 等强化学习库都内置了主流的强化学习算法,这里使用 RLlib 作为演示。

参考 Running RLlib 安装步骤。

pip install 'ray[rllib]'
pip install PyBullet
pip install gym

CartPole 连续运动控制

倒立摆小车 Cartpole 通常作为 DRL 算法的入门环境,但如下实验代码所示,在 Gym 内置环境 CartPoleBulletEnv-v1 下是离散的动作空间,策略只能根据环境状态让小车向左、向右移动

import gym
env = gym.make('CartPoleBulletEnv-v1')
print(env.observation_space)
print(env.action_space)

# Box(-3.4028234663852886e+38, 3.4028234663852886e+38, (4,), float32)
# Discrete(2)

但是在 Pybullet 环境中,可以找到倒立摆小车的连续运动空间的试验环境 CartPoleContinuousBulletEnv-v0

import gym
import pybullet_envs
env = gym.make('CartPoleContinuousBulletEnv-v0')
print(env.observation_space)
print(env.action_space)

# Box(-3.4028234663852886e+38, 3.4028234663852886e+38, (4,), float32)
# Box(-10.0, 10.0, (1,), float32)

训练代码

训练代码如下,根据运行环境的配置,相应调节 num_workersnum_gpus等参数。训练结果默认保存在 ~/ray_results 目录下。

import gym
import pybullet_envs
import ray
from ray import tune
from ray.rllib.agents.ppo import PPOTrainer
from ray.tune.registry import register_env

ray.shutdown()
ray.init(ignore_reinit_error=True)

ENV = 'CartPoleContinuousBulletEnv-v0'
def make_env(env_config):
    import pybullet_envs
    return gym.make(ENV)
register_env(ENV, make_env)
TARGET_REWARD = 199
TRAINER = PPOTrainer

config_train = {
        "env": ENV,
        "num_workers": 1,
        "num_gpus": 0,
        "monitor": True,
        "evaluation_num_episodes": 50,
    }

analysis = tune.run(
    TRAINER,
    stop={"episode_reward_mean": TARGET_REWARD},
    config=config_train,
    checkpoint_at_end=True
)

使用 Tune 运行 RLlib 的 TRAINER,可以比较方便的管理实验和可视化。tune.run() 返回了 ExperimentAnalysis 类,可用于保存结果和加载 checkpoint。

加载训练好的模型

agent_test = PPOTrainer(config=config_train, env=ENV)
agent_test.restore('path/to/checkpoint/file')

测试回放

# instantiate env class
env = gym.make(ENV)

# run until episode ends
episode_reward = 0
done = False
obs = env.reset()
while not done:
    action = agent_test.compute_action(obs)
    obs, reward, done, info = env.step(action)
    episode_reward += reward

print(episode_reward)

# >> 200.0

学习曲线

%matplotlib inline
import pandas
df = pandas.read_csv('/your/path/to/progress.csv')
df.plot(kind='line', x='timesteps_total', y='episode_reward_mean', figsize=(6, 4))

结语

博客大致记录了下 rllib 在连续的 Pybullet 仿真环境下的使用流程,后续将记录下如何使用 Pybullet 内的连续控制的强化学习环境。