Python-DQN代码阅读(8)

1.代码

1.1 代码总括

# 初始化变量
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

1.2 代码分解

1.2.1 action = np.random.choice(np.arange(len(action_probs)), p=action_probs)

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 变量,作为智能体在当前时刻的动作选择。选中的动作会用于后续的环境交互和经验存储。

1.2.2 env.render()

env.render()

调用环境的 render() 方法,将当前环境状态渲染到屏幕上,以便可视化。

  • 注意,在实际训练过程中,由于渲染操作可能会消耗较多的计算资源,通常会在训练时禁用渲染以提高训练效率,仅在需要可视化时才会启用渲染。

1.2.3 next_state_img, reward, done, info = env.step(VALID_ACTIONS[action])

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 包含了其他与环境相关的信息。

1.2.4 info_ale_lives = int(info['ale.lives'])

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' 进行命名。

1.2.5 next_state_img = state_processor.process(sess, next_state_img)

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 变量,供后续使用。

1.2.6 next_state = np.zeros((84, 84, 4), dtype=np.uint8)

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 的四个通道,实现滑动窗口的效果。具体操作如下:

  1. 创建一个全零数组 next_state,形状为 (84, 84, 4),数据类型为 np.uint8,表示每个像素的取值范围在 0 到 255 之间。

  2. 将当前状态 state 中的通道 1 到 3 的数据赋值给 next_state 中的通道 0 到 2,相当于将通道 1 到 3 的数据往前滑动了一位。

  3. next_state_img(从环境中获取的下一状态的图像数据)赋值给 next_state 中的通道 3,作为滑动窗口后的最新状态。

这样,next_state 中的四个通道分别表示当前状态和前三个状态的图像数据,实现了滑动窗口的效果,用于构建状态序列。

1.2.7 episode_rewards += reward

episode_rewards += reward

将当前时间步的奖励 reward 累加到 episode_rewards 变量中,用于记录当前回合的总奖励。

1.2.8 time_steps += 1

time_steps += 1

time_steps 变量的值递增1,用于记录当前回合中已经经过的时间步数。

1.2.9 reward = np.sign(reward)

reward = np.sign(reward)

这行代码将原始的奖励值 reward 转换为其符号的值,即将正数映射为 1,将负数映射为 -1,将零映射为 0。这种处理常用于强化学习中,旨在将奖励值标准化为固定的取值范围,使得算法在处理不同任务时具有一定的一致性。在这段代码中,通过 np.sign() 函数来实现奖励值的符号映射操作。

你可能感兴趣的:(Python,深度强化学习,TensorFlow,python,深度学习,强化学习,深度强化学习,人工智能)