Categorical 51 DQN

论文链接: https://proceedings.mlr.press/v70/bellemare17a.html

C51 算法(Categorical DQN)是 DQN 的一种变体, 它将分布式强化学习方法引入 DQN。 与仅为 Q 函数预测单个标量值(即未来回报的期望)不同, C51 会在一组离散的可能回报上预测概率分布, 使智能体不仅能够学习期望回报,还能够刻画回报的不确定性。

下表列出了 C51 算法的一些基本特征:

C51 的特征

是否具备

说明

同策略(On-policy)

评估策略与目标策略相同。

异策略(Off-policy)

评估策略与目标策略不同。

无模型(Model-free)

无须预先构建环境动力学模型。

基于模型(Model-based)

需要使用环境模型训练策略。

离散动作

可处理离散动作空间。

连续动作

可处理连续动作空间。

方法

DQN 存在的问题

在传统 DQN 中,目标是学习给定状态下每个动作对应的期望回报:

\[ Q(s, a) = \mathbb{E}[G_t | S_t=s, A_t=a], \]

其中,

\[ G_t = R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \dots = \sum^{\infty}_{k=0} {\gamma^k R_{t+k+1}} \]

C51 不再只学习一个标量 \(Q(s, a)\), 而是学习每个动作对应的完整回报分布,记为 \(Z(s, a)\)

C51 将可能的回报范围(例如从 -1 到 1)划分为固定数量的离散区间或支撑点, 这些离散支撑点被称为原子(atoms)。 对于每个原子,算法预测回报落在该原子上的概率。

因此,智能体可以同时根据期望回报及其不确定性进行决策。

类别分布表示

为了近似 \(Z(s, a)\),C51 在预先定义的取值范围 \([v_{min}, v_{max}]\) 内,使用由 \(N\) 个离散原子构成的类别分布来表示它。 这些原子定义为:

\[ z_i = v_{min} + i \cdot \Delta, \Delta = \frac{v_{max} - v_{min}}{N-1}, i=0, 1, \dots, N-1. \]

每个原子 \(z_i\) 都对应一个概率 \(p_i\),从而构成类别分布:

\[ P(Z(s,a)=z_i) = p_i, \sum_{i=0}^{N-1}{p_i}=1. \]

分布式 Bellman 方程

回报分布对应的 Bellman 方程为:

\[ Z(s, a) := R + \gamma Z(S', A'). \]

该方程表示,当前状态—动作对的回报分布由即时奖励 \(R\) 以及下一状态 \(S'\) 对应回报分布的折扣结果共同决定。

在实际计算中,为了保持表示的一致性, 下一状态的回报分布 \(Z(S', A')\) 会被投影回固定的原子集合 \(z_i\) 上。

算法

训练 C51 的完整算法如算法 1 所示。

../../../_images/pseucode-C51.png

备注

算法 1 能够以关于 N 的线性时间复杂度计算该投影。

在 XuanCe 中运行 C51

在 XuanCe 中运行 C51 之前,需要先准备一个 conda 环境,并按照 安装步骤安装 xuance

运行内置示例

完成安装后,可以打开 Python 控制台,并使用以下命令直接运行 C51:

import xuance
runner = xuance.get_runner(method='c51',
                           env='classic_control',  # 可选项:claasi_control、box2d、atari。
                           env_id='CartPole-v1',  # 可选项:CartPole-v1、LunarLander-v2、ALE/Breakout-v5 等。
                           is_test=False)
runner.run()  # 也可以使用 runner.benchmark()

使用自定义配置运行

如需使用不同配置运行 C51,可以新建一个 .yaml 文件,例如 my_config.yaml。 然后使用以下代码运行 C51:

import xuance as xp
runner = xp.get_runner(method='c51',
                       env='classic_control',  # 可选项:claasi_control、box2d、atari。
                       env_id='CartPole-v1',  # 可选项:CartPole-v1、LunarLander-v2、ALE/Breakout-v5 等。
                       config_path="my_config.yaml",  # 请确保 my_config.yaml 文件的路径正确。
                       is_test=False)
runner.run()  # 也可以使用 runner.benchmark()

如需进一步了解配置方法,请参阅 配置教程

在自定义环境中运行

如需在 XuanCe 尚未包含的自定义环境中运行 C51, 需要按照 新环境教程 中的步骤定义新环境。 然后,准备配置文件 c51_myenv.yaml

完成上述操作后,可以使用以下代码在自定义环境中运行 C51:

import argparse
from xuance.common import get_configs
from xuance.environment import REGISTRY_ENV
from xuance.environment import make_envs
from xuance.torch.agents import C51_Agent

configs_dict = get_configs(file_dir="c51_myenv.yaml")
configs = argparse.Namespace(**configs_dict)
REGISTRY_ENV[configs.env_name] = MyNewEnv

envs = make_envs(configs)  # 创建并行环境。
Agent = C51_Agent(config=configs, envs=envs)  # 创建一个来自 XuanCe 的 C51 智能体。
Agent.train(configs.running_steps // configs.parallels)  # 对模型进行多个步骤的训练。
Agent.save_model("final_train_model.pth")  # 将模型保存到 model_dir。
Agent.finish()  # 结束训练。

参考文献

@inproceedings{bellemare2017distributional,
  title={A distributional perspective on reinforcement learning},
  author={Bellemare, Marc G and Dabney, Will and Munos, R{\'e}mi},
  booktitle={International conference on machine learning},
  pages={449--458},
  year={2017},
  organization={PMLR}
}