下面是关于智能体训练的过程
四、定义训练
import copy
def train(cfg, env, agent):
''' 训练
'''
print("开始训练!")
rewards = [] # 记录所有回合的奖励
steps = []
best_ep_reward = 0 # 记录最大回合奖励
output_agent = None # 用于储存表现最好的智能体
for i_ep in range(cfg.train_eps):
ep_reward = 0 # 记录一回合内的奖励
ep_step = 0
state = env.reset() # 重置环境,返回初始状态
for _ in range(cfg.max_steps):
ep_step += 1
action = agent.sample_action(state) # 选择动作
next_state, reward, done, _ = env.step(action) # 更新环境,返回transition
agent.memory.push((state, action, agent.log_probs, reward, done)) # 保存transition
state = next_state # 更新下一个状态
agent.update() # 更新智能体
ep_reward += reward # 累加奖励
if done:
break
if (i_ep + 1) % cfg.eval_per_episode == 0:
sum_eval_reward = 0
for _ in range(cfg.eval_eps):
eval_ep_reward = 0
state = env.reset()
for _ in range(cfg.max_steps):
action = agent.predict_action(state) # 选择动作
next_state, reward, done, _ = env.step(action) # 更新环境,返回transition
state = next_state # 更新下一个状态
eval_ep_reward += reward # 累加奖励
if done:
break
sum_eval_reward += eval_ep_reward
mean_eval_reward = sum_eval_reward / cfg.eval_eps
if mean_eval_reward >= best_ep_reward:
best_ep_reward = mean_eval_reward
output_agent = copy.deepcopy(agent)
print(
f"回合:{i_ep + 1}/{cfg.train_eps},奖励:{ep_reward:.2f},评估奖励:{mean_eval_reward:.2f},最佳评估奖励:{best_ep_reward:.2f},更新模型!")
else:
print(
f"回合:{i_ep + 1}/{cfg.train_eps},奖励:{ep_reward:.2f},评估奖励:{mean_eval_reward:.2f},最佳评估奖励:{best_ep_reward:.2f}")
steps.append(ep_step)
rewards.append(ep_reward)
print("完成训练!")
env.close()
return output_agent, {'rewards': rewards}
def test(cfg, env, agent):
print("开始测试!")
rewards = [] # 记录所有回合的奖励
steps = []
for i_ep in range(cfg.test_eps):
ep_reward = 0 # 记录一回合内的奖励
ep_step = 0
state = env.reset() # 重置环境,返回初始状态
for _ in range(cfg.max_steps):
ep_step += 1
action = agent.predict_action(state) # 选择动作
next_state, reward, done, _ = env.step(action) # 更新环境,返回transition
state = next_state # 更新下一个状态
ep_reward += reward # 累加奖励
if done:
break
steps.append(ep_step)
rewards.append(ep_reward)
print(f"回合:{i_ep + 1}/{cfg.test_eps},奖励:{ep_reward:.2f}")
print("完成测试")
env.close()
return {'rewards': rewards}
可以看出,该代码也是分为了两部分,一部分是训练,另一部分是测试,只不过训练的步骤更为完善。
1.训练部分
这段代码是一个训练循环。rewards = [] 和 steps = []:初始化两个空列表,用于记录每个回合(ep)的奖励和步数。初始化变量 best_ep_reward 为 0,用于记录最大回合奖励;output_agent 初始化为 None,用于存储表现最好的智能体。
最外面那个循环是让一回合一回合的运行,然后每个回合里面还有很多步数,所以下面又有一个循环for _ in range(cfg.max_steps):,每个步数里面都是:根据当前状态选择动作—用env.step(action)让智能体动作与环境交互,并返回下一个状态、奖励、是否结束等信息—保存上一步返回的信息—更新状态、更新智能体参数—计算这个回合的累加奖励。
然后这句话:(i_ep+1)%cfg.eval_per_episode == 0:是设定每过几个回合(cfg.eval_per_episode)就要进行评估,也就是看看现在的智能体咋样,评估流程与上面的一样,只不过要算一下所有回合的总奖励(sum_eval_reward)。之后计算每回合平均奖励。然后拿去与当前最好回合奖励去比较,谁更好用谁。
记录每回合的步数和奖励到 steps 和 rewards 列表中。最后打印训练完成消息,关闭环境,返回最优的智能体和奖励数据。
2.测试部分
rewards = [] 和 steps = []:初始化两个空列表,用于记录每个回合的奖励和步数。
for i_ep in range(cfg.test_eps)::开始测试循环,循环次数由配置参数 cfg.test_eps 决定。
ep_reward = 0 和 ep_step = 0:初始化变量 ep_reward 和 ep_step,用于记录每个回合内的奖励和步数。state = env.reset():重置环境,获取初始状态。
内部循环:通过循环根据当前状态选择动作、执行动作并更新状态,直到回合结束。
在每一步中,记录奖励、更新状态,并累加奖励。
记录步数和奖励到 steps 和 rewards 列表中。打印测试完成消息,关闭环境,返回奖励数据。这段代码实现了一个简单的测试函数,用于对训练好的智能体在环境中进行测试,记录测试过程中的奖励信息并返回。
注意:
(1)训练时,前面的第一次训练在选择动作时用的是agent.sample_action,而评估的时候用的是agent.predict_action,两者区别就是,前者会进行探索,而后者不会。因为sample_action里面会有关于梯度的计算,而另一个没有,有梯度计算就意味着会进行策略更新,而策略更新中是有探索部分的,所以可以简单理解为选择了sample_action,就是里面会进行探索,进而更新策略。predict_action通常用于在评估阶段直接根据当前的策略网络预测最优的动作,而不会涉及到梯度计算和策略更新,因此通常不包含额外的探索行为。