# 初始化变量
time_to_fire = False
steps_in_this_life = 0
num_no_ops_this_life = np.random.randint(low=0, high=7)
ale_lives = info_ale_lives
# 根据时间步数和生命数判断是否需要执行新的游戏或新的生命
if time_steps == 0 or ale_lives != info_ale_lives:
steps_in_this_life = 0
num_no_ops_this_life = np.random.randint(low=0, high=7)
action_probs = [0.0, 1.0, 0.0, 0.0] # 执行 fire 动作
time_to_fire = True
if ale_lives != info_ale_lives:
ale_lives = info_ale_lives
else:
action_probs = policy(sess, state, epsilon) # 根据策略网络获取动作概率
# 根据生命数和时间步数判断是否执行无操作
steps_in_this_life += 1
if steps_in_this_life < num_no_ops_this_life and not time_to_fire:
action_probs = [1.0, 0.0, 0.0, 0.0] # 执行 no-op 动作
# 从动作概率分布中选择动作
action = np.random.choice(np.arange(len(action_probs)), p=action_probs)
# 渲染当前环境状态
env.render()
# 执行选择的动作并获取下一个时间步的状态、奖励、完成状态和其他信息
next_state_img, reward, done, info = env.step(VALID_ACTIONS[action])
# 获取当前生命数
info_ale_lives = int(info['ale.lives'])
# rewards = -1,0,+1 as done in the paper
# reward = np.sign(reward)
# 预处理下一个时间步的状态 注意state_processor有降维tf.squeeze()的过程
next_state_img = state_processor.process(sess, next_state_img)
# state is of size [84,84,4]; next_state_img is of size[84,84]
# next_state = np.append(state[:,:,1:], np.expand_dims(next_state, 2), axis=2)
# 创建新的状态,将预处理后的状态添加到状态序列的末尾
next_state = np.zeros((84, 84, 4), dtype=np.uint8)
next_state[:, :, 0] = state[:, :, 1]
next_state[:, :, 1] = state[:, :, 2]
next_state[:, :, 2] = state[:, :, 3]
next_state[:, :, 3] = next_state_img
# 累加当前时间步的奖励
episode_rewards += reward
# 更新时间步数
time_steps += 1
action = np.random.choice(np.arange(len(action_probs)), p=action_probs)
从概率分布 action_probs
中根据概率选择一个动作,将其索引赋值给 action
变量,表示当前时间步选择的动作。
这行代码使用 np.random.choice 函数根据动作概率分布 action_probs 来随机选择一个动作,并将选中的动作赋值给 action。
具体解释如下:
np.random.choice 函数用于从给定的一维数组中进行随机采样,并返回一个随机选中的元素。
np.arange(len(action_probs)) 生成了一个从 0 到 len(action_probs)-1 的整数数组,用于作为随机采样的候选动作。
p=action_probs 参数指定了每个候选动作的选择概率,即动作概率分布。
action 是从候选动作中随机选中的动作,作为智能体当前时刻的动作选择。
这段代码的作用是根据动作概率分布 action_probs 来随机选择一个动作,并将选中的动作赋值给 action 变量,作为智能体在当前时刻的动作选择。选中的动作会用于后续的环境交互和经验存储。
env.render()
调用环境的 render()
方法,将当前环境状态渲染到屏幕上,以便可视化。
next_state_img, reward, done, info = env.step(VALID_ACTIONS[action])
通过调用环境的 step()
方法,传入 action
变量作为当前时间步选择的动作,获取下一个时间步的状态 next_state_img
、奖励 reward
、完成状态 done
和其他信息 info
。
env.step(VALID_ACTIONS[action])
是在 OpenAI Gym 环境中执行动作 VALID_ACTIONS[action]
,并返回执行该动作后的下一个状态 next_state_img
,奖励值 reward
,结束标志 done
,以及其他环境信息 info
。这里的 VALID_ACTIONS[action]
是根据之前选择的动作索引 action
在动作空间 VALID_ACTIONS
中选取对应的动作。next_state_img
表示执行动作后的图像状态,reward
表示执行动作后获得的奖励值,done
表示环境是否结束,info
包含了其他与环境相关的信息。
info_ale_lives = int(info['ale.lives'])
从 info
字典中获取 'ale.lives' 键对应的值,表示当前生命中剩余的生命数,并将其转换为整数类型,赋值给 info_ale_lives
变量。
info['ale.lives']
是从环境信息 info
中获取当前游戏中剩余生命值的属性值。通过 int()
函数将其转换为整数类型,并赋值给 info_ale_lives
变量,用于后续的比较和判断。这里的 'ale.lives'
是一种常见的属性名称,可能是在使用 Atari 游戏环境时,环境信息中记录了游戏的生命值信息,并以 'ale.lives'
进行命名。
next_state_img = state_processor.process(sess, next_state_img)
通过调用 state_processor
对象的 process()
方法,将获取到的下一个时间步的状态 next_state_img
进行预处理。
这行代码调用了 state_processor.process() 方法,用于处理环境返回的下一步状态。
具体解释如下:
state_processor 是一个用于处理状态的对象,可能包含了对状态进行预处理或者特征提取的逻辑。
sess 是 TensorFlow 会话,用于执行 TensorFlow 计算图中的操作。
next_state_img 是从环境中获得的下一步状态,通过 env.step() 函数返回。
state_processor.process(sess, next_state_img) 是对下一步状态进行处理的方法,它接受 TensorFlow 会话和下一步状态作为输入,并返回处理后的状态。
处理后的状态会被赋值给 next_state_img 变量,供后续使用。
next_state = np.zeros((84, 84, 4), dtype=np.uint8)
next_state[:, :, 0] = state[:, :, 1]
next_state[:, :, 1] = state[:, :, 2]
next_state[:, :, 2] = state[:, :, 3]
next_state[:, :, 3] = next_state_img
这部分代码是为了更新状态 next_state
的四个通道,实现滑动窗口的效果。具体操作如下:
创建一个全零数组 next_state
,形状为 (84, 84, 4)
,数据类型为 np.uint8
,表示每个像素的取值范围在 0 到 255 之间。
将当前状态 state
中的通道 1 到 3 的数据赋值给 next_state
中的通道 0 到 2,相当于将通道 1 到 3 的数据往前滑动了一位。
将 next_state_img
(从环境中获取的下一状态的图像数据)赋值给 next_state
中的通道 3,作为滑动窗口后的最新状态。
这样,next_state
中的四个通道分别表示当前状态和前三个状态的图像数据,实现了滑动窗口的效果,用于构建状态序列。
episode_rewards += reward
将当前时间步的奖励 reward
累加到 episode_rewards
变量中,用于记录当前回合的总奖励。
time_steps += 1
将 time_steps
变量的值递增1,用于记录当前回合中已经经过的时间步数。
reward = np.sign(reward)
这行代码将原始的奖励值 reward
转换为其符号的值,即将正数映射为 1,将负数映射为 -1,将零映射为 0。这种处理常用于强化学习中,旨在将奖励值标准化为固定的取值范围,使得算法在处理不同任务时具有一定的一致性。在这段代码中,通过 np.sign()
函数来实现奖励值的符号映射操作。