微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何修复 TF-Agents 中 policy_state 和 policy_state_spec 之间的类型错误?

如何解决如何修复 TF-Agents 中 policy_state 和 policy_state_spec 之间的类型错误?

我正在开发一个 PPO 代理,它使用 TF-Agents 播放(嗯,应该)Doom。作为代理的输入,我试图给它一堆 4 张图像。我的完整代码在以下链接中: https://colab.research.google.com/drive/1chrlrLVR_rwAeIZhL01LYkpXsusyFyq_?usp=sharing

不幸的是,我的代码无法编译。它在下面显示的行中返回一个 TypeError(它正在 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,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 做任何事情,因为它是根据代理的网络自动生成的。

这是我发现的类似错误,但似乎没有解决我的问题,尽管它在尝试的解决方案之一中暗示了我: py_environment 'time_step' doesn't match 'time_step_spec'

在阅读上面的问题和答案后,我意识到我承诺的是这样的 Observation_spec:

self._observation_spec = array_spec.BoundedArraySpec(shape=(4,160,260,3),dtype=np.float32,minimum=0,maximum=1,name='screen_observation')

但是我传递的是一个包含 4 个形状为 (160,3) 的 np.arrays 的列表:

self._stacked_frames = []
for _ in range(4):
  new_frame = np.zeros((160,dtype=np.float32)
  self._stacked_frames.append(new_frame)

我这样做是因为我认为我的数据的“形状”不会改变,因为列表的元素数量总是与观察规范的第一维相同。列表更容易删除过去的帧并添加新的帧,如下所示:

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,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)
      #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)
    #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

这里的这种方法不起作用。就像我说的,可能我做错了。我看到了解决这种僵局的三种方法

  1. 我将observation_spec声明为一个包含四个帧的列表,每个帧声明为 np.array(160,3);
  2. 我像我一样声明了observation_spec,但是以正确的方式从 self._stacked_frames 中删除添加帧(不确定是否可能,因为 self._stacked_frames 将被声明为 np.array(4,3 ) 并且我不确定它可以变成 np.array(3,3) 或 np.array(5,3),然后再回到 np.array(4,3);
  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,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

那么两个问题:

  1. 考虑到我对 TypeError 的看法是正确的,修复它的三种方法中哪一种最好?那么我尝试解决第三种可能性的方式有什么问题吗?
  2. 考虑到我对 TypeError 的看法可能不对,那么这个错误是关于什么的?

解决方法

我在调用 policy.action(time_step) 时遇到了同样的问题。 Action 采用可选参数 policy_state,默认情况下为“()”。

我通过调用解决了这个问题

policy.action(time_step,policy.get_initial_state(batch_size=BATCH_SIZE))

我刚刚开始使用 TF-Agents,所以,我希望这不会产生一些不良影响。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。