tf2.0 Keras:使用 RNN 的自定义张量流代码时无法保存权重

Posted

技术标签:

【中文标题】tf2.0 Keras:使用 RNN 的自定义张量流代码时无法保存权重【英文标题】:tf2.0 Keras: unable to save weights when using custom tensorflow code for RNN 【发布时间】:2019-12-21 18:47:35 【问题描述】:

我正在使用 Keras API 在 tf2 中编写一个 Encoder-Recurrent Decoder 模型。在解码阶段,我想将一些自定义函数应用于模型输出。但是,一旦我开始将 tensorflow 代码“嵌入”到我的功能性 Keras 模型中,我就无法再保存权重了 - 而是出现了 ValueError 异常:

ValueError: Unable to create group (name already exists)

模型可以被训练并且损失正在减少,正如我所期望的那样。唯一的问题是事后存储权重。

整个错误信息:

ValueError                                Traceback (most recent call last)
<ipython-input-4-5edae36ba5fe> in <module>()
     57 model.compile(loss='MSE', optimizer='adam')
     58 
---> 59 model.save_weights('/tmp/dummy.h5')
     60 print('saved')

2 frames
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/network.py in save_weights(self, filepath, overwrite, save_format)
   1310     if save_format == 'h5':
   1311       with h5py.File(filepath, 'w') as f:
-> 1312         saving.save_weights_to_hdf5_group(f, self.layers)
   1313     else:
   1314       if context.executing_eagerly():

/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/saving/hdf5_format.py in save_weights_to_hdf5_group(f, layers)
    617 
    618   for layer in layers:
--> 619     g = f.create_group(layer.name)
    620     weights = _legacy_weights(layer)
    621     weight_values = K.batch_get_value(weights)

/usr/local/lib/python3.6/dist-packages/h5py/_hl/group.py in create_group(self, name, track_order)
     58             name, lcpl = self._e(name, lcpl=True)
     59             gcpl = Group._gcpl_crt_order if track_order else None
---> 60             gid = h5g.create(self.id, name, lcpl=lcpl, gcpl=gcpl)
     61             return Group(gid)
     62 

h5py/_objects.pyx in h5py._objects.with_phil.wrapper()

h5py/_objects.pyx in h5py._objects.with_phil.wrapper()

h5py/h5g.pyx in h5py.h5g.create()

ValueError: Unable to create group (name already exists)

到目前为止我尝试过的事情:

tf 1.14.0 也会出现错误 在有问题的代码部分周围添加named_scope 也无济于事:with tf.name_scope('something' + str(step)): 明确命名tf.reshape 操作没有帮助:outputs = tf.reshape(..., name='custom_reshape1_' + str(step)) 该错误可以在 Google Colab 中重现 这不是权重文件的问题,因为我在运行代码之前删除了所有数据。此外,在删除有问题的 tensorflow 代码时,该代码可以正常工作
import tensorflow as tf
print('version=', tf.__version__)
import numpy as np

keras = tf.keras # pylint: disable=no-member
KL = keras.layers
KM = keras.models
K = keras.backend
KR = keras.regularizers
# GRU = tf.compat.v1.keras.layers.CuDNNGRU
GRU = KL.GRU

n_in = 20
n_out = 10
dim = 128
hidden_units = 1024

encoder_inputs = KL.Input(shape=(n_in, dim))
encoder = GRU(hidden_units,
              return_state=True)
_, state_h = encoder(encoder_inputs)

decoder_gru = GRU(hidden_units,
                  return_sequences=True,
                  return_state=True)
decoder_dense = KL.Dense(dim)

last_pose = KL.Lambda(lambda a: a[:, -1, :],
                      output_shape=(None, dim))(encoder_inputs)
last_pose = KL.Reshape((1, dim))(last_pose)


all_outputs = []
inputs = last_pose
for step in range(n_out):
  outputs, state_h = decoder_gru(inputs, initial_state=state_h)
  outputs = decoder_dense(outputs)

  # ~~~~~~~~~~~~~~~~~~~~~~~~ comment out to "fix" issue
  # -- problem cause (start)
  n_batch = tf.shape(outputs)[0]
  outputs = tf.reshape(outputs, (n_batch * 32, 4))
  # ... custom function stuff
  outputs = tf.reshape(outputs, (n_batch, 1, 32*4))
  # -- problem cause (end)
  # ~~~~~~~~~~~~~~~~~~~~~~~~

  all_outputs.append(outputs)
  inputs = outputs

decoder_outputs = KL.Concatenate()(all_outputs)
decoder_outputs = KL.Reshape((n_out, dim))(decoder_outputs)
model = KM.Model(inputs=encoder_inputs,
                 outputs=decoder_outputs)

model = KM.Model(inputs=encoder_inputs, outputs=state_h)


model.compile(loss='MSE', optimizer='adam')

model.save_weights('/tmp/dummy.h5')
print('saved')

我不确定出了什么问题,我希望能够节省重量!该模型可以被训练并且它的损失正在减少,仅存储权重会导致问题。

【问题讨论】:

文件 /tmp/dummy.h5 是否已经存在?如果文件已存在,则保存模型可能会出现问题。在运行此代码之前尝试将其删除。 @MatiasValdenegro 感谢您的意见。在构建模型之前,我已经清除了所有创建的数据。我将更新“尝试过的东西”部分。另外:删除有问题的 tf 代码后,代码可以正常工作! 您是否尝试为所有 keras 图层添加名称?我知道这不是问题的核心,但它确实创建了一些名称范围(只是一种尝试)。 【参考方案1】:

看来tf.shape 电话是罪魁祸首。在没有它的情况下重新编写代码允许模型按预期存储。我仍然很好奇为什么会发生这种情况..

import tensorflow as tf
print('version=', tf.__version__)
import numpy as np

keras = tf.keras # pylint: disable=no-member
KL = keras.layers
KM = keras.models
K = keras.backend
KR = keras.regularizers
# GRU = tf.compat.v1.keras.layers.CuDNNGRU
GRU = KL.GRU

n_in = 20
n_out = 10
dim = 128
hidden_units = 1024

encoder_inputs = KL.Input(shape=(n_in, dim))
encoder = GRU(hidden_units,
              return_state=True)
_, state_h = encoder(encoder_inputs)

decoder_gru = GRU(hidden_units,
                  return_sequences=True,
                  return_state=True)
decoder_dense = KL.Dense(dim)

last_pose = KL.Lambda(lambda a: a[:, -1, :],
                      output_shape=(None, dim))(encoder_inputs)
last_pose = KL.Reshape((1, dim))(last_pose)


all_outputs = []
inputs = last_pose
for step in range(n_out):
  outputs, state_h = decoder_gru(inputs, initial_state=state_h)
  outputs = decoder_dense(outputs)

  # ~~~~~~~~~~~~~~~~~~~~~~~~ comment out to "fix" issue
  # -- problem cause (start)
  # n_batch = tf.shape(outputs)[0]
  outputs = tf.reshape(outputs, (-1, 4))
  # ... custom function stuff
  outputs = tf.reshape(outputs, (-1, 1, 32*4))
  # -- problem cause (end)
  # ~~~~~~~~~~~~~~~~~~~~~~~~

  all_outputs.append(outputs)
  inputs = outputs

decoder_outputs = KL.Concatenate()(all_outputs)
decoder_outputs = KL.Reshape((n_out, dim))(decoder_outputs)
model = KM.Model(inputs=encoder_inputs,
                 outputs=decoder_outputs)

model = KM.Model(inputs=encoder_inputs, outputs=state_h)


model.compile(loss='MSE', optimizer='adam')

model.save_weights('/tmp/dummy.h5')
print('saved')

【讨论】:

以上是关于tf2.0 Keras:使用 RNN 的自定义张量流代码时无法保存权重的主要内容,如果未能解决你的问题,请参考以下文章

什么是使用Keras的RNN Layer的return_state输出

访问在 TF 2.0 中未显式公开为层的 Keras 模型的中间张量

如何在 Keras 中为循环神经网络 (RNN) 使用嵌入层

如何在keras中包装张量流RNNCell?

使用 TF2.0 训练 RNN 的每次迭代逐渐增加内存使用量

keras 的指标返回啥值?标量还是张量?