Shortcuts

DI的Hello World

决策智能是人工智能领域中最重要的方向。 其一般形式是使用一个代理来处理来自环境的信息,给出合理的反馈和响应,并使环境的状态按照设计者的期望发生变化。 例如,自动驾驶汽车将从环境中接收有关路况的信息,并给出实时的自动驾驶决策,使车辆驶向设定的目的地。

我们首先使用“lunarlander”环境来介绍DI-engine中的代理以及它如何与环境交互。 在这个模拟环境中,代理需要将lunarlander安全平稳地降落到指定区域并避免坠毁。

../_images/lunarlander.gif

让代理运行

代理是一个可以自由与环境交互的对象,本质上是一个接受输入并反馈输出的数学模型。 其模型由模型结构和一组模型参数组成。 通常,我们会将模型写入文件进行保存,或从该文件中读取模型进行部署。 这里我们提供了一个使用DQN算法通过DI-engine框架训练的代理模型: final.pth.tar 只需使用以下代码即可让代理运行,记得将函数中的模型地址(“ckpt_path=’./final.pth.tar’”)替换为本地保存的模型文件路径,例如“’~/Download/final.pth.tar’”:

import gym # Load the gym library, which is used to standardize the reinforcement learning environment
import torch # Load the PyTorch library for loading the Tensor model and defining the computing network
from easydict import EasyDict # Load EasyDict for instantiating configuration files
from ding.config import compile_config # Load configuration related components in DI-engine config module
from ding.envs import DingEnvWrapper # Load environment related components in DI-engine env module
from ding.policy import DQNPolicy, single_env_forward_wrapper # Load policy-related components in DI-engine policy module
from ding.model import DQN # Load model related components in DI-engine model module
from dizoo.box2d.lunarlander.config.lunarlander_dqn_config import main_config, create_config # Load DI-zoo lunarlander environment and DQN algorithm related configurations


def main(main_config: EasyDict, create_config: EasyDict, ckpt_path: str):
    main_config.exp_name = 'lunarlander_dqn_deploy' # Set the name of the experiment to be run in this deployment, which is the name of the project folder to be created
    cfg = compile_config(main_config, create_cfg=create_config, auto=True) # Compile and generate all configurations
    env = DingEnvWrapper(gym.make(cfg.env.env_id), EasyDict(env_wrapper='default')) # Add the DI-engine environment decorator upon the gym's environment instance
    env.enable_save_replay(replay_path='./lunarlander_dqn_deploy/video') # Enable the video recording of the environment and set the video saving folder
    model = DQN(**cfg.policy.model) # Import model configuration, instantiate DQN model
    state_dict = torch.load(ckpt_path, map_location='cpu') # Load model parameters from file
    model.load_state_dict(state_dict['model']) # Load model parameters into the model
    policy = DQNPolicy(cfg.policy, model=model).eval_mode # Import policy configuration, import model, instantiate DQN policy, and turn to evaluation mode
    forward_fn = single_env_forward_wrapper(policy.forward) # Use the strategy decorator of the simple environment to decorate the decision method of the DQN strategy
    obs = env.reset() # Reset the initialization environment to get the initial observations
    returns = 0. # Initialize total reward
    while True: # Let the agent's strategy and environment interact cyclically until the end
        action = forward_fn(obs) # According to the observed state, make a decision and generate action
        obs, rew, done, info = env.step(action) # Execute actions, interact with the environment, get the next observation state, the reward of this interaction, the signal of whether to end, and other information
        returns += rew # Cumulative reward return
        if done:
            break
    print(f'Deploy is finished, final epsiode return is: {returns}')

if __name__ == "__main__":
    main(main_config=main_config, create_config=create_config, ckpt_path='./final.pth.tar')

如代码所示,可以通过使用torch.load获取模型的PyTorch对象参数。 然后可以使用load_state_dict将模型参数加载到DI-engine的DQN模型中,以重建模型。 接着将DQN模型加载到DQN策略中,并使用评估模式的forward_fn函数使代理为环境状态obs生成反馈动作。 代理的动作将与环境进行一次交互,生成下一时刻的环境状态obs、此次交互的奖励rew、环境是否结束的信号done以及其他信息info。

注意

环境状态通常是一组向量或张量。奖励通常是一个实数值。环境是否结束的信号是一个布尔变量,是或否。其他信息是环境创建者希望传递的附加消息,可以是任何格式。

奖励值将始终累积为此任务中代理的总分。

注意

您可以在日志中查看已部署代理的总分,并在实验文件夹中查看回放视频。

../_images/evaluator_info.png

为了更好地评估代理

在强化学习的各种情境中,代理的初始状态并不总是完全相同。 代理的性能可能会随着不同的初始状态而波动。 例如,在“lunarlander”环境中,月球表面每次都是不同的。

因此,我们需要设置多个环境并运行更多的评估测试,以便更好地评分。 DI-engine 设计了环境管理器 env_manager 来实现这一点,我们可以通过以下稍微复杂一些的代码来完成:

import os
import gym
import torch
from tensorboardX import SummaryWriter
from easydict import EasyDict

from ding.config import compile_config
from ding.worker import BaseLearner, SampleSerialCollector, InteractionSerialEvaluator, AdvancedReplayBuffer
from ding.envs import BaseEnvManager, DingEnvWrapper
from ding.policy import DQNPolicy
from ding.model import DQN
from ding.utils import set_pkg_seed
from ding.rl_utils import get_epsilon_greedy_fn
from dizoo.box2d.lunarlander.config.lunarlander_dqn_config import main_config, create_config

# Get DI-engine form env class
def wrapped_cartpole_env():
    return DingEnvWrapper(
        gym.make(main_config['env']['env_id']),
        EasyDict(env_wrapper='default'),
    )


def main(cfg, seed=0):
    cfg['exp_name'] = 'lunarlander_dqn_eval'
    cfg = compile_config(
        cfg,
        BaseEnvManager,
        DQNPolicy,
        BaseLearner,
        SampleSerialCollector,
        InteractionSerialEvaluator,
        AdvancedReplayBuffer,
        save_cfg=True
    )
    cfg.policy.load_path = './final.pth.tar'

    # build multiple environments and use env_manager to manage them
    evaluator_env_num = cfg.env.evaluator_env_num
    evaluator_env = BaseEnvManager(env_fn=[wrapped_cartpole_env for _ in range(evaluator_env_num)], cfg=cfg.env.manager)

    # switch save replay interface
    # evaluator_env.enable_save_replay(cfg.env.replay_path)
    evaluator_env.enable_save_replay(replay_path='./lunarlander_dqn_eval/video')

    # Set random seed for all package and instance
    evaluator_env.seed(seed, dynamic_seed=False)
    set_pkg_seed(seed, use_cuda=cfg.policy.cuda)

    # Set up RL Policy
    model = DQN(**cfg.policy.model)
    policy = DQNPolicy(cfg.policy, model=model)
    policy.eval_mode.load_state_dict(torch.load(cfg.policy.load_path, map_location='cpu'))

    # Evaluate
    tb_logger = SummaryWriter(os.path.join('./{}/log/'.format(cfg.exp_name), 'serial'))
    evaluator = InteractionSerialEvaluator(
        cfg.policy.eval.evaluator, evaluator_env, policy.eval_mode, tb_logger, exp_name=cfg.exp_name
    )
    evaluator.eval()

if __name__ == "__main__":
    main(main_config)

注意

在并行评估多个环境时,DI-engine 的环境管理器还会计算平均、最大和最小奖励,以及与某些算法相关的其他指标。

从零开始训练更强的代理

使用DI-engine运行以下代码以获取上述测试中的代理模型。 尝试自己生成一个代理模型,也许它会更强:

import gym
from ditk import logging
from ding.model import DQN
from ding.policy import DQNPolicy
from ding.envs import DingEnvWrapper, BaseEnvManagerV2, SubprocessEnvManagerV2
from ding.data import DequeBuffer
from ding.config import compile_config
from ding.framework import task, ding_init
from ding.framework.context import OnlineRLContext
from ding.framework.middleware import OffPolicyLearner, StepCollector, interaction_evaluator, data_pusher, \
    eps_greedy_handler, CkptSaver, online_logger, nstep_reward_enhancer
from ding.utils import set_pkg_seed
from dizoo.box2d.lunarlander.config.lunarlander_dqn_config import main_config, create_config

def main():
    logging.getLogger().setLevel(logging.INFO)
    cfg = compile_config(main_config, create_cfg=create_config, auto=True)
    ding_init(cfg)
    with task.start(async_mode=False, ctx=OnlineRLContext()):
        collector_env = SubprocessEnvManagerV2(
            env_fn=[lambda: DingEnvWrapper(gym.make(cfg.env.env_id)) for _ in range(cfg.env.collector_env_num)],
            cfg=cfg.env.manager
        )
        evaluator_env = SubprocessEnvManagerV2(
            env_fn=[lambda: DingEnvWrapper(gym.make(cfg.env.env_id)) for _ in range(cfg.env.evaluator_env_num)],
            cfg=cfg.env.manager
        )

        set_pkg_seed(cfg.seed, use_cuda=cfg.policy.cuda)

        model = DQN(**cfg.policy.model)
        buffer_ = DequeBuffer(size=cfg.policy.other.replay_buffer.replay_buffer_size)
        policy = DQNPolicy(cfg.policy, model=model)

        task.use(interaction_evaluator(cfg, policy.eval_mode, evaluator_env))
        task.use(eps_greedy_handler(cfg))
        task.use(StepCollector(cfg, policy.collect_mode, collector_env))
        task.use(nstep_reward_enhancer(cfg))
        task.use(data_pusher(cfg, buffer_))
        task.use(OffPolicyLearner(cfg, policy.learn_mode, buffer_))
        task.use(online_logger(train_show_freq=10))
        task.use(CkptSaver(policy, cfg.exp_name, train_freq=100))
        task.run()

if __name__ == "__main__":
    main()

注意

上述代码在Intel i5-10210U 1.6GHz CPU且没有GPU设备的情况下,大约需要10分钟训练到默认终止点。 如果你希望训练时间更短,可以尝试更简单的Cartpole环境。

注意

DI-engine 集成了 tensorboard 组件,用于记录训练过程中的关键信息。你可以在训练期间打开它,这样你就可以看到实时更新的信息,例如评估器记录的平均总奖励值等。

干得好!到目前为止,你已经完成了DI-engine的Hello World任务,使用了提供的代码和模型,并学习了强化学习代理如何与环境交互。 请继续阅读本文档,第一个强化学习程序,以了解如何在DI-engine中构建RL管道。