10.2.2 强化学习
强化学习是一种机器学习方法,其核心思想是通过代理程序与环境的交互学习最优行为策略,以最大化累积奖励。在强化学习中,代理程序通过观察环境的状态,并选择动作来影响环境,从而学习如何在面对不同状态时做出最优的决策。和强化学习相关的关键概念包括:
- 环境与代理:环境提供反馈,告知代理其当前状态和执行动作后的奖励,代理则根据这些信息来调整其行为策略。
- 奖励信号:奖励信号是代理学习的关键反馈,它指示了每个动作在给定状态下的优劣程度。代理的目标是通过最大化累积奖励来学习最优策略。
- 策略:策略定义了代理在给定状态下选择动作的方式。它可以是确定性的(如基于最大化预期奖励的策略)或随机性的(如根据概率分布选择动作)。
- 值函数:值函数评估了状态或动作的好坏程度。状态值函数(V函数)预测从某状态开始,代理在未来能获得的预期累积奖励;动作值函数(Q函数)则预测在某状态执行某动作后的累积奖励。
常见的强化学习算法包括:
- Q-learning:基于动作值函数的迭代更新,适用于离散状态和动作空间。
- Deep Q Network (DQN):结合深度神经网络和Q-learning,处理高维状态空间和连续动作空间。
- Policy Gradient Methods:直接优化策略参数,适用于连续动作空间和高维状态空间。
- Actor-Critic:结合策略梯度和动作值函数的方法,平衡探索和利用。
- 探索与利用:在学习过程中,代理需要在探索新动作和利用已知最佳动作之间取得平衡。常见的方法包括ε-greedy策略和探索函数(如UCB算法)来鼓励探索未知动作,以改善长期性能。
强化学习在自动驾驶中具有重要的应用,主要体现在以下几个方面:
- 路径规划与决策:自动驾驶车辆需要根据当前路况和环境状态做出实时的路径规划和决策。强化学习可以帮助车辆学习最优的驾驶策略,以最大化安全性、效率和乘客舒适度。例如,通过与环境交互学习在不同路况下如何选择速度、车道和转弯动作。
- 交通流优化:强化学习可以应用于优化交通流,例如通过智能信号灯控制系统。代理程序学习在不同时间点和路口如何调整信号灯,以最大化道路的通行效率和减少交通拥堵。
- 自动驾驶策略改进:自动驾驶系统需要不断优化其策略,以适应复杂的交通情况和路况变化。强化学习可以在实时反馈的基础上进行决策学习,从而提高车辆在各种驾驶情景下的表现。
- 无人车训练:在虚拟或仿真环境中,强化学习被广泛用于训练无人驾驶汽车。代理程序通过与模拟环境的交互来学习驾驶技能,包括避障、遵守交通规则、停车等,从而提高在现实世界中的表现。
- 决策系统的应用:强化学习可以被用来开发复杂的决策系统,这些系统需要处理多变的道路条件、车辆行为和乘客需求。通过在真实道路或仿真环境中不断优化学习,可以实现更加智能化和安全的自动驾驶体验。
总体来说,强化学习为自动驾驶系统提供了一种灵活和高效的方法,能够在动态和复杂的环境中进行学习和优化,从而改善驾驶决策的精度和适应性。请看下面的例子,功能是使用强化学习中的Q-learning算法来解决出租车游戏问题,具体说明如下所示。
1. 问题定义
- 出租车问题:在这个环境中,有4个不同的地点,每个地点用不同的字母标记。任务是从一个地点接乘客,然后将他送到另一个地点。
- 得分机制:成功送达乘客得+20分,每个时间步失去1分。
- 惩罚:非法接乘客或送乘客会扣10分。
2. 环境定义
在本实例中提供了如下所示的三种环境:
- Taxi-v3
- FrozenLake-v1
- CliffWalking-v0
默认环境是Taxi-v3。
实例10-2:解决出租车接送乘客问题(源码路径:codes\10\taxi-q-learning.ipynb)
实例文件taxi-q-learning.ipynb的具体实现流程如下所示
(1)定义函数setup_environment,目的是设置并初始化一个强化学习环境。它接收一个参数 env_name,这个参数指定了要使用的特定环境名称。代码首先导入了 gym 库,这是一个广泛使用的开源库,用于开发和比较强化学习算法。
def setup_environment(env_name):
import gym
env = gym.make(env_name).env
env.reset() # reset environment to a new, random state
env.render()
print("Action Space {}".format(env.action_space))
print("State Space {}".format(env.observation_space))
return env
(2)配置环境变量以适应无图形界面的运行环境,并初始化一个强化学习环境,准备进行进一步的操作或训练。
import os
os.environ["SDL_VIDEODRIVER"] = "dummy"
environment_names=["Taxi-v3","FrozenLake-v1","CliffWalking-v0"]
env=setup_environment(environment_names[0])
env.render()
上述代码的实现流程如下:
- 首先导入了 os 模块,用于操作操作系统的功能,包括环境变量。然后,它设置了环境变量 SDL_VIDEODRIVER 的值为 "dummy",这通常用于禁用图形界面输出,使得程序可以在没有图形显示支持的系统上运行,例如服务器或在后台运行的脚本。
- 接下来,定义了一个名为 environment_names 的列表,其中包含了三个可用的强化学习环境名称:"Taxi-v3"、"FrozenLake-v1" 和 "CliffWalking-v0"。
- 之后,调用之前定义的 setup_environment 函数,并传入 environment_names 列表中的第一个元素 environment_names[0],即 "Taxi-v3" 作为参数,来初始化和设置这个环境。
- 最后,调用 env.render() 方法来渲染初始化后的环境。由于之前设置了 SDL_VIDEODRIVER 为 "dummy",这里的 render 调用可能不会显示任何图形界面,除非环境支持无头模式(headless mode)或者 render 方法被重写以适应无图形界面的输出。
(3)定义函数 random_action_to_end,它接收一个环境对象 env 作为参数。函数random_action_to_end的目的是在一个强化学习环境中执行随机动作,直到达到目标状态或结束条件。在这个过程中,它记录了执行的步数、因非法操作而产生的惩罚次数,并将每个步骤的状态、动作和奖励信息保存到一个列表中,用于后续可能的动画展示或分析。
def random_action_to_end(env):
epochs = 0
penalties, reward = 0, 0
frames = [] # 用于动画的帧列表
done = False
while not done:
# 自动选择一个随机动作
action = env.action_space.sample()
state, reward, done, info = env.step(action)
if reward == -10:
penalties += 1
# 将每个渲染的帧放入字典以用于动画
frames.append({
'frame': env.render(mode='ansi'),
'state': state,
'action': action,
'reward': reward
})
epochs += 1
print("Timesteps taken: {}".format(epochs))
print("Penalties incurred: {}".format(penalties))
return frames
(4)定义函数print_frames,其功能是用于展示由 random_action_to_end 函数收集的一系列动画帧。函数print_frames接收一个名为 frames 的列表作为参数,这个列表包含了之前记录的每个步骤的渲染帧、状态、动作和奖励信息。
def print_frames(frames):
from IPython.display import clear_output
from time import sleep
for i, frame in enumerate(frames):
clear_output(wait=True)
#print(frame['frame'].getvalue())
print(frame['frame'])
print(f"Timestep: {i + 1}")
print(f"State: {frame['state']}")
print(f"Action: {frame['action']}")
print(f"Reward: {frame['reward']}")
sleep(.1)
(5)调用了之前定义函数random_action_to_end,并将结果赋值给变量 frames。这个调用没有提供任何参数,这意味着它将使用 random_action_to_end 函数中定义的默认环境进行操作。函数执行完成后,frames 变量将包含一个列表,其中记录了从环境开始到结束的所有步骤的详细信息,包括每个步骤的渲染帧、状态、采取的动作以及获得的奖励。
frames=random_action_to_end(env)
执行后会输出:
Timesteps taken: 9695
Penalties incurred: 3078
(6)调用函数print_frames,将之前通过 random_action_to_end(env) 函数获得的 frames 列表作为参数传递给它。函数print_frames的目的是将这些帧信息以一种动画的形式展示出来,每帧展示后会有短暂的延迟,以便观察者可以看到智能体在环境中的每一步行动及其结果。
print_frames(frames)
执行后会输出:
+---------+
|R: | : :G|
| : | : : |
| : : : : |
| | : | : |
|Y| : |B: |
+---------+
(Dropoff)
Timestep: 9695
State: 0
Action: 5
Reward: 20
(7)定义函数train_the_agent,用于使用Q-learning算法训练强化学习智能体。函数train_the_agent接收环境 env 和几个超参数:学习率 alpha,折扣因子 gamma,探索率 epsilon,训练步数 training_steps,衰减步数 decay_steps,以及一个布尔值 decay 来控制是否启用超参数的衰减。
import random
from IPython.display import clear_output
import numpy as np
def train_the_agent(env, alpha, gamma, epsilon, training_steps, decay_steps, decay=False):
q_table = np.zeros([env.observation_space.n, env.action_space.n])
alpha_decay=1e-4
gamma_decay=1e-4
epsilon_decay=1e-4
learning_epochs=[]
learning_penalties=[]
for i in range(1, training_steps):
state = env.reset()
epochs, penalties, reward = 0, 0, 0
done = False
# 当启用衰减并且步数是衰减步数的倍数时,减少alpha、gamma和epsilon的值
if decay and not i % decay_steps:
alpha -= alpha_decay
gamma -= gamma_decay
epsilon -= epsilon_decay
while not done:
# 如果随机数小于epsilon,则探索动作空间
if random.uniform(0, 1) < epsilon:
action = env.action_space.sample() # 探索动作空间
else:
# 利用已学习到的值
action = np.argmax(q_table[state])
next_state, reward, done, info = env.step(action)
# 旧的Q值
old_value = q_table[state, action]
# 下一个状态的最大Q值
next_max = np.max(q_table[next_state])
# 计算新的Q值
new_value = (1 - alpha) * old_value + alpha * (reward + gamma * next_max)
# 更新Q表
q_table[state, action] = new_value
# 如果奖励是-10,表示非法操作,增加惩罚计数
if reward == -10:
penalties += 1
state = next_state
epochs += 1
# 每100个训练步骤清除一次输出并打印当前训练周期
if i % 100 == 0:
clear_output(wait=True)
print(f"Episode: {i}")
learning_epochs.append(epochs)
learning_penalties.append(penalties)
print("Training finished.\n")
return q_table, learning_epochs, learning_penalties
在上述代码中,函数train_the_agent的实现流程如下所示:
- 初始化一个Q表,用于存储“状态-动作”对的值。
- 设置超参数衰减的初始值。
- 循环执行训练步数,每个训练周期(或称为“episode”)开始时重置环境状态。
- 在每个周期中,根据当前的 epsilon 值决定是采取随机动作进行探索,还是选择当前状态下价值最高的动作进行利用。
- 使用Q学习更新规则更新Q表中的值。
- 如果执行了非法操作(即奖励为 -10),则增加惩罚计数。
- 记录每个周期的步数和惩罚次数。
- 每100个周期清除输出并打印当前周期编号,以便观察训练进度。
- 训练结束后,打印完成信息,并返回Q表以及记录的训练周期数和惩罚次数。
(8)调用函数train_the_agent来训练一个强化学习智能体,使用Q-learning算法,并将训练过程中的超参数和设置传递给函数。各个参数的具体说明如下:
- env 是要训练智能体的环境。
- alpha=0.1 是学习率,决定了新信息对Q值的影响程度。
- gamma=0.6 是折扣因子,表示未来奖励相对于当前奖励的重要性。
- epsilon=0.1 是初始探索率,决定了智能体在训练初期探索未知动作的频率。
- decay_steps=10000 指定了衰减步数,即每过这么多步,超参数会衰减一次。
- training_steps=100001 表示训练总共进行的步数或周期数。
- decay=True 表示启用超参数的衰减。
q_table,learning_epochs,learning_penalties=train_the_agent(env,alpha=0.1,gamma=0.6,epsilon=0.1,decay_steps=10000,training_steps=100001,decay=True)
执行函数train_the_agent后会返回三个值:
- q_table 是训练完成后的Q表,包含了所有状态-动作对的估计值。
- learning_epochs 是一个列表,记录了每个训练周期的步数。
- learning_penalties 是一个列表,记录了每个训练周期中智能体因非法操作而受到的惩罚次数。
执行后会输出:
Episode: 100000
Training finished.
(9)定义函数evaluate,其功能是评估已经训练好的Q学习智能体的性能。函数接收两个参数:q_table2 是训练完成后的Q表,episodes 是要评估的周期(或称为“episode”)数量。
def evaluate(q_table2, episodes):
total_epochs, total_penalties = 0, 0
for _ in range(episodes):
# 选择随机初始状态
state = env.reset()
epochs, penalties, reward = 0, 0, 0
done = False
frames = []
while not done:
action = np.argmax(q_table2[state])
# print(action)
state, reward, done, info = env.step(action)
# 将每个渲染的帧放入列表以用于动画
frames.append({
'frame': env.render(mode='ansi'),
'state': state,
'action': action,
'reward': reward
}
)
if reward == -10:
penalties += 1
epochs += 1
total_penalties += penalties
total_epochs += epochs
print_frames(frames)
print(f"Results after {episodes} episodes:")
print(f"Average timesteps per episode: {total_epochs / episodes}")
print(f"Average penalties per episode: {total_penalties / episodes}")
return total_epochs, total_penalties
在上述代码中,函数evaluate的实现流程如下所示:
- 初始化总步数 total_epochs 和总惩罚数 total_penalties。
- 循环 episodes 次,每次开始一个新的评估周期。
- 在每个周期中,从环境中重置状态到随机初始状态。
- 使用 q_table2 中的Q值选择最佳动作,并执行该动作。
- 记录每个周期的步数、惩罚数和渲染的帧,用于后续的动画展示。
- 如果执行了非法操作(即奖励为 -10),则增加惩罚计数。
- 在所有周期结束后,使用 print_frames 函数展示动画帧。
- 打印评估结果,包括每个周期的平均步数和平均惩罚数。
- 返回总步数和总惩罚数。
(10)调用函数evaluate,功能是评估之前通过 train_the_agent 函数训练得到的智能体的性能。函数evaluate使用训练完成后的 Q 表 q_table 作为评估的基础,并指定了评估周期 episodes 为 100。
total_epochs,total_penalties=evaluate(q_table2=q_table,episodes=100)
执行这行代码后将得到智能体在 100 个周期内的整体表现,包括它在环境中的效率(步数)和遵守规则的情况(惩罚次数)。执行后会输出:
+---------+
|R: | : :G|
| : | : : |
| : : : : |
| | : | : |
|Y| : |B: |
+---------+
(Dropoff)
Timestep: 11
State: 410
Action: 5
Reward: 20
Results after 100 episodes:
Average timesteps per episode: 13.31
Average penalties per episode: 0.0
(11)下面这段代码实现了一个网格搜索算法,用于找到强化学习智能体训练中的最佳超参数组合。代码中定义了三个超参数的候选值:学习率 alpha、折扣因子 gamma 和探索率 epsilon。然后,代码遍历所有可能的超参数组合,使用函数train_the_agent训练智能体,并记录每个组合的训练周期数和惩罚次数。
import pandas as pd
alpha = [0.1, 0.3, 0.5, 0.9]
gamma = [0.3, 0.6, 0.8, 0.9]
epsilon = [0.3, 0.6, 0.8, 0.9]
best_alpha, best_gamma, best_epsilon = 0, 0, 0
mini_penalties = 999999999999999999
mini_epochs = 9999999999999999
parameters = {
"Alpha": [],
"Gamma": [],
"Epsilon": [],
"Evaluation Total Penalties": [],
"Evaluation Total Epochs": [],
}
for ep in epsilon:
for al in alpha:
for gm in gamma:
returned_q_table, returned_learning_epochs, returned_learning_penalties = train_the_agent(
env=env, alpha=al, gamma=gm, epsilon=ep, decay_steps=10000, training_steps=10000, decay=False
)
# 评估Q表的性能
# total_epochs, total_penalties = evaluate(q_table2=returned_q_table, episodes=100)
# 记录超参数和评估结果
parameters['Alpha'].append(al)
parameters['Gamma'].append(gm)
parameters['Epsilon'].append(ep)
parameters['Evaluation Total Penalties'].append(total_penalties) # 此处应为returned_learning_penalties
parameters['Evaluation Total Epochs'].append(total_epochs) # 此处应为returned_learning_epochs
# 如果找到更少的惩罚次数,则更新最佳超参数
if returned_learning_penalties <= mini_penalties:
mini_penalties = returned_learning_penalties
best_alpha = al
best_gamma = gm
best_epsilon = ep
# 如果找到更少的训练周期数,则更新最佳超参数
if returned_learning_epochs <= mini_epochs:
mini_epochs = returned_learning_epochs
best_alpha = al
best_gamma = gm
best_epsilon = ep
parameters = pd.DataFrame(parameters)
print(parameters)
print(best_alpha, best_gamma, best_epsilon)
上述代码的实现流程如下:
- 初始化超参数候选值列表和用于记录结果的字典 parameters。
- 使用三重循环遍历所有超参数的组合。
- 对于每种组合,训练智能体并获取训练后的Q表、训练周期数和惩罚次数。
- 将超参数组合和对应的评估结果添加到 parameters 字典中。
- 检查并更新找到的最佳超参数组合,即在最少惩罚次数或最少训练周期数的情况下的组合。
- 将 parameters 字典转换为 pandas 的 DataFrame,以便于查看和分析。
- 打印出所有超参数组合的评估结果和找到的最佳超参数组合,执行后会输出:
Episode: 9900
Training finished.
Alpha Gamma Epsilon Evaluation Total Penalties Evaluation Total Epochs
0 0.1 0.3 0.3 0 1331
1 0.1 0.6 0.3 0 9999999999999999
2 0.1 0.8 0.3 0 9999999999999999
3 0.1 0.9 0.3 0 9999999999999999
4 0.3 0.3 0.3 0 9999999999999999
.. ... ... ... ... ...
59 0.5 0.9 0.9 0 9999999999999999
60 0.9 0.3 0.9 0 9999999999999999
61 0.9 0.6 0.9 0 9999999999999999
62 0.9 0.8 0.9 0 9999999999999999
63 0.9 0.9 0.9 0 9999999999999999
[64 rows x 5 columns]
0.9 0.9 0.9
(12)parameters 是一个字典,用于存储不同超参数组合的训练结果。
parameters
执行后会输出:
Alpha Gamma Epsilon Evaluation Total Penalties Evaluation Total Epochs
0 0.1 0.3 0.3 0 1331
1 0.1 0.6 0.3 0 9999999999999999
2 0.1 0.8 0.3 0 9999999999999999
3 0.1 0.9 0.3 0 9999999999999999
4 0.3 0.3 0.3 0 9999999999999999
... ... ... ... ... ...
59 0.5 0.9 0.9 0 9999999999999999
60 0.9 0.3 0.9 0 9999999999999999
61 0.9 0.6 0.9 0 9999999999999999
62 0.9 0.8 0.9 0 9999999999999999
63 0.9 0.9 0.9 0 9999999999999999
64 rows × 5 columns
(13)下面的代码使用之前通过网格搜索得到的最优超参数来训练智能体。在这个例子中,将最优超参数被假定为:
- alpha(学习率)为 0.9
- gamma(折扣因子)为 0.9
- epsilon(初始探索率)为 0.9
另外,在代码中还指定了以下训练参数:
- training_steps(训练步数)为 100000
- decay_steps(衰减步数)为 10000
- decay(是否启用衰减)为 True,表示在训练过程中将逐渐降低超参数。
best_q_table,learning_epochs,learning_penalties=train_the_agent(env,0.9,0.9,0.9,training_steps=100000,decay_steps=10000,decay=True)
函数 train_the_agent 将使用这些参数训练智能体,并返回训练过程中生成的 Q 表 best_q_table,以及记录训练周期数的 learning_epochs 和记录惩罚次数的 learning_penalties。执行后会输出:
Episode: 99900
Training finished.
(14)使用库matplotlib 和库 seaborn 可视化通过 Q-learning算法训练智能体过程中收集的数据。具体来说,绘制了两个线图,分别表示训练周期数(learning_epochs)和惩罚次数(learning_penalties)随训练步数的变化情况。
import matplotlib.pyplot as plt
import seaborn as sns
bins=list(range(0,100000,2000))
np_learning_epochs=np.array(learning_epochs)
np_learning_penalties=np.array(learning_penalties)
sns.lineplot(x=bins, y=np_learning_epochs[bins],label='Learning epochs')
sns.lineplot(x=bins, y=np_learning_penalties[bins],label='Learning penalties')
plt.show()
执行效果如图10-2所示,通过这些可视化图表,可以直观地观察智能体在训练过程中的表现,比如随着训练的进行,训练周期数是否减少(表示策略越来越有效),以及惩罚次数是否降低(表示智能体遵守规则的能力提高)。
图10-2 训练过程可视化图
(15)下面这段代码实现了对训练好的智能体在一定数量的训练周期(episodes)上的表现进行评估和可视化操作,通过可视化训练周期中的行为和统计分析来理解智能体的策略效果。
total_epochs, total_penalties = 0, 0
episodes = 500
for episode in range(episodes):
state = env.reset()
epochs, penalties, reward = 0, 0, 0
done = False
frames=[]
while not done:
action = np.argmax(best_q_table[state])
state, reward, done, info = env.step(action)
# Put each rendered frame into dict for animation
frames.append({
'frame': env.render(mode='ansi'),
'state': state,
'action': action,
'reward': reward
}
)
if reward == -10:
penalties += 1
epochs += 1
total_penalties += penalties
total_epochs += epochs
clear_output(wait=False)
print_frames(frames=frames)
print(f"Episode {episode}")
print(f"Results after {episodes} episodes:")
print(f"Average timesteps per episode: {total_epochs / episodes}")
print(f"Average penalties per episode: {total_penalties / episodes}")
上述代码的实现流程如下所示:
- 初始化总步数 total_epochs 和总惩罚数 total_penalties。
- 设置要评估的训练周期数量 episodes。
- 通过循环执行每个训练周期,在每个周期中进行如下操作:
- 重置环境到初始状态。
- 初始化周期内的步数 epochs、惩罚数 penalties 和奖励 reward。
- 使用最佳 Q 表 best_q_table 来选择动作,这里 np.argmax(best_q_table[state]) 根据当前状态从 Q 表中选择最佳动作。
- 执行动作并获取新的状态、奖励、完成标志和附加信息。
- 收集渲染的帧用于动画展示,并在每个周期结束后使用 print_frames 函数展示这些帧。
- 如果获得的奖励是 -10,表示发生了非法操作,增加惩罚计数。
- 更新步数计数器。
- 在每个周期结束后,清除之前的输出(clear_output(wait=False)),打印当前周期的动画帧和周期编号。
- 所有周期结束后,打印平均步数和平均惩罚数,这些统计信息提供了智能体在整个评估过程中性能的量化指标。执行后会输出:
+---------+
|R: | : :G|
| : | : : |
| : : : : |
| | : | : |
|Y| : |B: |
+---------+
(Dropoff)
Timestep: 12
State: 0
Action: 5
Reward: 20
Episode 499
Results after 500 episodes:
Average timesteps per episode: 13.132
Average penalties per episode: 0.0
到此为止,整个项目介绍完毕。这个项目是一个典型的强化学习应用,主要通过Q学习算法来训练一个智能体在特定环境中执行任务。以下是对整个项目的总结:
- 环境设置:项目开始于创建和配置强化学习环境,例如Taxi-v3、FrozenLake-v1或CliffWalking-v0,其中Taxi-v3是默认环境。
- 问题定义:在Taxi环境中,智能体的任务是接送乘客,从起始点到目的地,同时避免非法操作,以最大化累积奖励。
- 算法选择:选用Q学习算法,这是一种模型无关的强化学习算法,通过学习状态-动作对的价值函数来选择最佳动作。
- 超参数调优:通过网格搜索方法对学习率(alpha)、折扣因子(gamma)和探索率(epsilon)进行调优,以找到最优的超参数组合。
- 训练过程:使用确定的超参数,训练智能体直到收敛。训练过程中,智能体通过与环境交互学习最优策略。
- 性能评估:训练完成后,评估智能体的性能,记录训练周期数和因非法操作导致的惩罚次数。
- 结果可视化:使用图表展示训练过程中的学习和评估结果,如训练周期数和惩罚次数随时间的变化。
- 最佳策略确定:基于性能评估的结果,确定最佳超参数,并使用这些参数重新训练智能体以获得最佳策略。
- 动画展示:通过收集和展示训练周期中的帧,可视化智能体的行为,以便于分析其决策过程。
- 项目总结:最后,通过统计分析和可视化结果,对智能体的学习过程和策略效果进行总结。
整个项目展示了强化学习工作流程的标准步骤,从问题定义到环境设置,再到算法实现、超参数调优、训练、评估和结果可视化,最终实现智能体在复杂环境中的高效学习与决策。
标签:0.9,learning,训练,penalties,决策,epochs,智能,算法,env From: https://blog.csdn.net/asd343442/article/details/140818182