# train!


智能体训练

函数库: TyReinforcementLearning

# 语法

result = train!(agent, env, trainOptions)

# 说明

result = train!(env, agent, trainOptions) 在指定的环境中训练强化学习智能体,使用 trainOptions 控制训练选项。在每个训练回合结束后,train 会更新在 agents 的策略(通常为表格或神经网络)参数,以最大化它们从环境中预期获得的长期奖励。当训练终止时,返回训练结果 result,agents 保持为智能体在最后一个训练回合结束时的状态。对于不同的强化学习智能体,其训练过程也不同,函数根据 agent 的种类自动选择相应的算法。

一般而言,train!在每一轮(episode)执行以下迭代步骤:

  1. 重置环境。

  2. 从环境中获取初始状态值 s。

  3. 计算初始动作 a = μ(s)。

  4. 将当前动作设置为初始动作,并将当前状态值设置为初始状态值。

  5. 当回合未完成或终止时:

    (1). 使用动作 a 步进环境,获取下一个观察值 s' 和奖励 r。

    (2). 从经验集(s,a,r,s' )中学习。

    (3). 计算下一个动作 a' = μ(s')。

    (4). 使用下一个动作更新当前动作(a ← a'),并使用下一个状态值更新当前状态值(s ← s' )。

    (5). 如果满足环境中定义的回合终止条件,则终止当前回合。

# 示例

QL 智能体训练

在悬崖行走(CliffWalking)的环境示例中配置 QL 智能体,并以相应的环境进行训练。

CliffWalking 是一个经典的强化学习环境,通常用于教学和研究强化学习算法的性能。这个环境的特点是一个方格世界,智能体需要在其中移动,并在不掉入悬崖的情况下尽可能快地到达目标位置。

CliffWalking 环境是一个矩形方格世界,由网格组成,其中包括起始点、目标点和悬崖区域。 悬崖区域是位于起始点和目标点之间的一行方格,代表了危险区域,如果智能体掉入悬崖,将会受到较大的惩罚。 代理程序可以在四个基本方向(上、下、左、右)中选择一个动作,以在方格世界中移动。 目标是让智能体尽可能快地从起始点到达目标点,但要避免掉入悬崖区域。

代理程序会受到奖励或惩罚,具体规则如下: 如果代理程序成功到达目标点,会获得正奖励,表示任务成功完成。 如果代理程序掉入悬崖,会受到较大的负奖励,以惩罚不安全的行动。 对于其他非终止状态,代理程序执行动作后会获得小的负奖励,以鼓励它尽快到达目标而不浪费时间。

状态空间:状态空间通常由方格世界中的每个方格组成,表示代理程序的位置。状态可以用坐标 1~48 来表示。

动作空间:动作空间由代理程序可选择的四个基本动作(上、下、左、右)组成,用于在方格世界中移动,表示为 1,2,3,4。

导入需要的包以及创建 CliffWalking 训练环境。

using TyReinforcementLearning
env = BuildEnv("CliffWalking-v0");

创建智能体所需的 Q 表格,表格的形式为(48,4),各行代表了环境的状态,各列代表了智能体的动作,值为需要学习的 Q(s,a),智能体在处于 s 状态下,选取 Q 最大的 a 进行下一步行动,以期获得更高的长期奖励。

models = rlQLModels(
    Qtable=zeros(StateDims(env), ActionDims(env))
)

创建智能体选项,将环境的状态与动作空间信息传入。

option = rlQLAgentOptions(
    stateNum=StateDims(env),
    actionNum=ActionDims(env)
);

创建 QL 智能体。

agent = rlQLAgent(models,option);

创建 train_options 来指定一些训练参数。对于这个示例,智能体最多训练 1000 个回合,每进行 1 步学习一次。

train_options = rlTrainOptions(
    max_episodes=1000,
    learning_interval=1,
    path=joinpath(pwd(),"result")
);

此时,就可以将智能体传入train!函数中,在 Cart Pole 的环境下进行训练并得到训练结果。

result = train!(agent, env, train_options)

训练结束后,可以在工作目录的 result 文件夹下得到智能体文件 agent0,该智能体是训练过程中 score 得分最高的一个。

调用plot_result函数可以绘制训练结果图像,将 steps_per_episode,rewards_per_episode ,test_scores_per_episode 三个变量随训练回合增加的变化曲线绘制出来。

plot_result(result, ["steps", "rewards", "test_scores"])

对于这个已经训练好的智能体,使用 get_action 来获取其对环境状态的动作反应。

state = Reset(env)[1]
action = get_action(agent, state)
1

将智能体给出的动作输入环境,即可实现智能体与环境的互动。

state, reward, done, _, _ = Step(env, action)
(25, -1, false, false, Dict{Any, Any}("prob" => 1.0))

强化学习每次训练具有随机性,输出结果不会完全一致。

PG 智能体训练

在平衡杆小车(Cart Pole)的环境示例中配置 PG 智能体,并以相应的环境进行训练。

Cart Pole 即车杆游戏,游戏里面有一个小车,上有竖着一根杆子,每次重置后的初始状态会有所不同。小车需要左右移动来保持杆子竖直,为了保证游戏继续进行需要满足以下两个条件:

  • 杆子倾斜的角度 不能大于 15°
  • 小车移动的位置需保持在一定范围(中间到两边各 2.4 个单位长度)

环境中的状态值是一个包含小车的位置和速度,以及杆的角度位置和角速度的向量。动作是一个标量,有两个可能的元素(对小车施加-10 或 10 牛顿的力)。

导入需要的包以及创建 Cart Pole 训练环境。

using TyReinforcementLearning
env = BuildEnv("CartPole-v1");

创建 PG 智能体所需的神经网络模型,指定中间层神经元个数为 128。由于 Cart Pole 状态空间与动作空间均为离散,因此输入层神经元个数为环境状态的个数,输出层神经元为环境动作的个数。由于 PG 智能体采用概率的方法来确定动作,因此要在最后一层进行 soft_max 处理来获取概率值。

actor_net = BuildDefaultNet(128, StateSize(env)[1], ActionDims(env); soft=true)
models = rlPGModels(
    actorNet=actor_net
);

创建智能体选项,对于离散动作空间的问题,采用 epsilonGreedy 探索策略,并将环境的状态与动作空间信息传入。

option = rlPGAgentOptions(
    stateSize=StateSize(env),
    actionNum=ActionDims(env)
);

创建 PG 智能体。

agent = rlPGAgent(models,option);

创建 train_options 来指定一些训练参数。对于这个示例,智能体最多训练 1500 个回合,每进行 200 步学习一次。

train_options = rlTrainOptions(
    max_episodes=1500,
    learning_interval=200,
    path=joinpath(pwd(),"result")
)

此时,就可以将智能体传入train!函数中,在 Cart Pole 的环境下进行训练并得到训练结果。

result = train!(agent, env, train_options)

训练结束后,可以在工作目录的 result 文件夹下得到智能体文件 agent0,该智能体是训练过程中 score 得分最高的一个。

调用plot_result函数可以绘制训练结果图像,将 steps_per_episode,rewards_per_episode ,test_scores_per_episode 三个变量随训练回合增加的变化曲线绘制出来。

plot_result(result, ["steps", "rewards", "test_scores"])

对于这个已经训练好的智能体,使用 get_action 来获取其对 Cart Pole 环境状态的动作反应。

state = Reset(env)[1]
action = get_action(agent, state)
1

将智能体给出的动作输入环境,即可实现智能体与环境的互动。

state, reward, done, _, _ = Step(env, action)
(Float32[-0.045320075, -0.17840403, 0.044338264, 0.34655356], 1.0, false, false, Dict{Any, Any}())

强化学习每次训练具有随机性,输出结果不会完全一致。

# 输入参数

agent-智能体
结构体

需要训练的智能体,指定为强化学习智能体对象,例如rlQAgentrlDQNAgent

env-环境
环境对象

智能体训练的环境,指定为强化学习环境对象,通过BuildEnv函数创建或由用户自定义得到,也可以使用GridWorldrlMDPEnv对象作为环境。

trainOptions-训练选项
结构体

训练选项,指定为rlTrainOptions对象。

# 输出参数

result-训练结果
字典

训练结果,包含有以下内容:

名称 说明
TrainOptions 训练选项。
BestScore 最高分。
rewards_per_episode 每个回合的奖励,以向量形式返回。每个条目包含对应回合的奖励。
steps_per_episode 每个回合的步数,以向量形式返回。每个条目包含对应回合的步数。
test_scores_per_episode 每个回合的分数,以向量形式返回。每个条目包含对应回合的分数。(如果在 trainOptions 中指定 test=false,则该项等于 rewards_per_episode )。
average_rewards_per_episode 窗口期内的平均奖励,以向量形式返回。
average_steps_per_episode 窗口期内的平均步数,以向量形式返回。
average_test_scores_per_episode 窗口期内的平均分数,以向量形式返回。
total_agent_steps 训练中智能体的总步数,以向量形式返回。每个条目包含到达该回合之前的 steps_per_episode 条目的累积和。

# 另请参阅

rlQLAgent | rlSARSAAgent | rlDQNAgent | rldoubleDQNAgent | rlPGAgent | rlACAgent | rlDDPGAgent