如何修复 TF-Agents 中 policy_state 和 policy_state_spec 之间的类型错误?
How to fix a TypeError between policy_state and policy_state_spec in TF-Agents?
我正在开发一个 PPO 代理,它使用 TF-Agents 玩(好吧,应该)Doom。作为代理的输入,我试图给它一堆 4 张图像。我的完整代码在下面link:
https://colab.research.google.com/drive/1chrlrLVR_rwAeIZhL01LYkpXsusyFyq_?usp=sharing
不幸的是,我的代码无法编译。它 returns 下面显示的行中的类型错误(在 Google Colaboratory 中是 运行)。
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-10-d1571cbbda6b> in <module>()
8 t_step = tf_env.reset()
9 while (episode_steps <= max_steps_per_episode or (not t_step.is_last())):
---> 10 policy_step = agent.policy.action(t_step)
11 t_step = tf_env.step(policy_step.action)
12 episode_steps += 1
5 frames
/usr/local/lib/python3.7/dist-packages/tf_agents/utils/nest_utils.py in assert_same_structure(nest1, nest2, check_types, expand_composites, message)
112 str2 = tf.nest.map_structure(
113 lambda _: _DOT, nest2, expand_composites=expand_composites)
--> 114 raise exception('{}:\n {}\nvs.\n {}'.format(message, str1, str2))
115
116
TypeError: policy_state and policy_state_spec structures do not match:
()
vs.
{'actor_network_state': ListWrapper([., .])}
关于这个错误的事情是,对于我在 TF-Agents 文档中读到的内容,用户不应该对 policy_state 做任何事情,因为它是根据代理的网络自动生成的.
这是我发现的一个类似错误,但似乎并没有解决我的问题,尽管它暗示了我尝试过的解决方案之一:
看完上面的问题和答案后,我意识到我是在承诺 observation_spec 这样的:
self._observation_spec = array_spec.BoundedArraySpec(shape=(4, 160, 260, 3), dtype=np.float32, minimum=0, maximum=1, name='screen_observation')
但我传递的是 4 个 np.arrays 的列表,形状 = (160, 260, 3):
self._stacked_frames = []
for _ in range(4):
new_frame = np.zeros((160, 260, 3), dtype=np.float32)
self._stacked_frames.append(new_frame)
我这样做是因为我认为我的数据的“形状”不会改变,因为列表的元素数量始终与 observation_spec 的第一个维度相同。列表更容易删除过去的帧并添加新的帧,如下所示:
def stack_frames(self):
#This gets the current frame of the game
new_frame = self.preprocess_frame()
if self._game.is_new_episode():
for frame in range(4):
self._stacked_frames.append(new_frame)
#This pop was meant to clear an empty frames that was already in the list
self._stacked_frames.pop(0)
else:
self._stacked_frames.append(new_frame)
self._stacked_frames.pop(0)
return self._stacked_frames
我之前只尝试过 np.arrays,但无法删除过去的帧并添加新帧。可能我做的不对,但我觉得self._stacked_frames天生就和观察规范一样的形状,不能简单地删除或添加新数组。
self._stacked_frames = np.zeros((4, 160, 260, 3), dtype=np.float32)
def stack_frames(self):
new_frame = self.preprocess_frame()
if self._game.is_new_episode():
for frame in range(4):
#This delete was meant to clear an empty frames that was already in the list
self._stacked_frames = np.delete(self._stacked_frames, 0, 0)
#I tried "np.concatenate((self._stacked_frames, new_frame))" as well
self._stacked_frames = np.vstack((self._stacked_frames, new_frame))
else:
self._stacked_frames = np.delete(self._stacked_frames, 0, 0)
#I tried "np.concatenate((self._stacked_frames, new_frame))" as well
self._stacked_frames = np.vstack((self._stacked_frames, new_frame))
return self._stacked_frames
这里的这个方法没有用。就像我说的,可能我做错了。我看到了解决这种僵局的三种方法:
- 我将 observation_spec 声明为四个帧的列表,每个帧声明为 np.array(160, 260, 3);
- 我像以前一样声明了 observation_spec,但是以正确的方式从 self._stacked_frames 中删除和添加帧(不确定是否可能,因为 self._stacked_frames 将被声明为 np.array(4, 160, 260, 3) 我不确定它会变成 np.array(3, 160, 260, 3) 还是 np.array(5, 160, 260, 3 ), 在回到 np.array(4, 160, 260, 3);
之前
- 我仍然像以前一样声明 observation_spec,但我不删除或添加框架。我做了一个循环,将第二帧(在第二个槽中进入 stack_frames 函数)复制到第一个槽中,将第三帧复制到第二个槽中,将第四帧复制到第三个槽中,最后,新帧进入第四个插槽。举例如下:
self._stacked_frames Slot: 1 | 2 | 3 | 4
Game image inside self._stacked_frames: A | B | C | D
New game image: E
New game image's positions (step 1): B | B | C | D
New game image's positions (step 2): B | C | C | D
New game image's positions (step 3): B | C | D | D
New game image's positions (step 4): B | C | D | E
New self._stacked_frames: B | C | D | E
最后一个似乎是解决我的问题的最可靠方法,考虑到我对它的看法是正确的。我试过了,但 TypeError 仍然存在。我这样试过:
self._stacked_frames = np.zeros((self._frame_stack_size, 160, 260, 3), dtype=np.float32)
然后:
def stack_frames(self):
new_frame = self.preprocess_frame()
if self._game.is_new_episode():
for frame in range(self._frame_stack_size):
self._stacked_frames[frame] = new_frame
else:
for frame in range((self._frame_stack_size) - 1):
self._stacked_frames[frame] = self._stacked_frames[frame + 1]
self._stacked_frames[self._frame_stack_size - 1] = new_frame
return self._stacked_frames
那么两个问题:
- 考虑到我对所提供的 TypeError 的看法是正确的,三种修复方法中哪一种是最好的?那么我尝试解决第三种可能性的方法有什么问题吗?
- 考虑到我对 TypeError 的看法可能不正确,那么这个错误是关于什么的?
我遇到了同样的问题,那是在调用 policy.action(time_step)
时。 Action 采用可选参数 policy_state,默认情况下为“()”。
我通过调用
解决了这个问题
policy.action(time_step, policy.get_initial_state(batch_size=BATCH_SIZE))
我刚开始使用 TF-Agents,所以,我希望这不会产生一些不良影响。
我正在开发一个 PPO 代理,它使用 TF-Agents 玩(好吧,应该)Doom。作为代理的输入,我试图给它一堆 4 张图像。我的完整代码在下面link: https://colab.research.google.com/drive/1chrlrLVR_rwAeIZhL01LYkpXsusyFyq_?usp=sharing
不幸的是,我的代码无法编译。它 returns 下面显示的行中的类型错误(在 Google Colaboratory 中是 运行)。
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-10-d1571cbbda6b> in <module>()
8 t_step = tf_env.reset()
9 while (episode_steps <= max_steps_per_episode or (not t_step.is_last())):
---> 10 policy_step = agent.policy.action(t_step)
11 t_step = tf_env.step(policy_step.action)
12 episode_steps += 1
5 frames
/usr/local/lib/python3.7/dist-packages/tf_agents/utils/nest_utils.py in assert_same_structure(nest1, nest2, check_types, expand_composites, message)
112 str2 = tf.nest.map_structure(
113 lambda _: _DOT, nest2, expand_composites=expand_composites)
--> 114 raise exception('{}:\n {}\nvs.\n {}'.format(message, str1, str2))
115
116
TypeError: policy_state and policy_state_spec structures do not match:
()
vs.
{'actor_network_state': ListWrapper([., .])}
关于这个错误的事情是,对于我在 TF-Agents 文档中读到的内容,用户不应该对 policy_state 做任何事情,因为它是根据代理的网络自动生成的.
这是我发现的一个类似错误,但似乎并没有解决我的问题,尽管它暗示了我尝试过的解决方案之一:
看完上面的问题和答案后,我意识到我是在承诺 observation_spec 这样的:
self._observation_spec = array_spec.BoundedArraySpec(shape=(4, 160, 260, 3), dtype=np.float32, minimum=0, maximum=1, name='screen_observation')
但我传递的是 4 个 np.arrays 的列表,形状 = (160, 260, 3):
self._stacked_frames = []
for _ in range(4):
new_frame = np.zeros((160, 260, 3), dtype=np.float32)
self._stacked_frames.append(new_frame)
我这样做是因为我认为我的数据的“形状”不会改变,因为列表的元素数量始终与 observation_spec 的第一个维度相同。列表更容易删除过去的帧并添加新的帧,如下所示:
def stack_frames(self):
#This gets the current frame of the game
new_frame = self.preprocess_frame()
if self._game.is_new_episode():
for frame in range(4):
self._stacked_frames.append(new_frame)
#This pop was meant to clear an empty frames that was already in the list
self._stacked_frames.pop(0)
else:
self._stacked_frames.append(new_frame)
self._stacked_frames.pop(0)
return self._stacked_frames
我之前只尝试过 np.arrays,但无法删除过去的帧并添加新帧。可能我做的不对,但我觉得self._stacked_frames天生就和观察规范一样的形状,不能简单地删除或添加新数组。
self._stacked_frames = np.zeros((4, 160, 260, 3), dtype=np.float32)
def stack_frames(self):
new_frame = self.preprocess_frame()
if self._game.is_new_episode():
for frame in range(4):
#This delete was meant to clear an empty frames that was already in the list
self._stacked_frames = np.delete(self._stacked_frames, 0, 0)
#I tried "np.concatenate((self._stacked_frames, new_frame))" as well
self._stacked_frames = np.vstack((self._stacked_frames, new_frame))
else:
self._stacked_frames = np.delete(self._stacked_frames, 0, 0)
#I tried "np.concatenate((self._stacked_frames, new_frame))" as well
self._stacked_frames = np.vstack((self._stacked_frames, new_frame))
return self._stacked_frames
这里的这个方法没有用。就像我说的,可能我做错了。我看到了解决这种僵局的三种方法:
- 我将 observation_spec 声明为四个帧的列表,每个帧声明为 np.array(160, 260, 3);
- 我像以前一样声明了 observation_spec,但是以正确的方式从 self._stacked_frames 中删除和添加帧(不确定是否可能,因为 self._stacked_frames 将被声明为 np.array(4, 160, 260, 3) 我不确定它会变成 np.array(3, 160, 260, 3) 还是 np.array(5, 160, 260, 3 ), 在回到 np.array(4, 160, 260, 3); 之前
- 我仍然像以前一样声明 observation_spec,但我不删除或添加框架。我做了一个循环,将第二帧(在第二个槽中进入 stack_frames 函数)复制到第一个槽中,将第三帧复制到第二个槽中,将第四帧复制到第三个槽中,最后,新帧进入第四个插槽。举例如下:
self._stacked_frames Slot: 1 | 2 | 3 | 4
Game image inside self._stacked_frames: A | B | C | D
New game image: E
New game image's positions (step 1): B | B | C | D
New game image's positions (step 2): B | C | C | D
New game image's positions (step 3): B | C | D | D
New game image's positions (step 4): B | C | D | E
New self._stacked_frames: B | C | D | E
最后一个似乎是解决我的问题的最可靠方法,考虑到我对它的看法是正确的。我试过了,但 TypeError 仍然存在。我这样试过:
self._stacked_frames = np.zeros((self._frame_stack_size, 160, 260, 3), dtype=np.float32)
然后:
def stack_frames(self):
new_frame = self.preprocess_frame()
if self._game.is_new_episode():
for frame in range(self._frame_stack_size):
self._stacked_frames[frame] = new_frame
else:
for frame in range((self._frame_stack_size) - 1):
self._stacked_frames[frame] = self._stacked_frames[frame + 1]
self._stacked_frames[self._frame_stack_size - 1] = new_frame
return self._stacked_frames
那么两个问题:
- 考虑到我对所提供的 TypeError 的看法是正确的,三种修复方法中哪一种是最好的?那么我尝试解决第三种可能性的方法有什么问题吗?
- 考虑到我对 TypeError 的看法可能不正确,那么这个错误是关于什么的?
我遇到了同样的问题,那是在调用 policy.action(time_step)
时。 Action 采用可选参数 policy_state,默认情况下为“()”。
我通过调用
解决了这个问题policy.action(time_step, policy.get_initial_state(batch_size=BATCH_SIZE))
我刚开始使用 TF-Agents,所以,我希望这不会产生一些不良影响。