tf.Keras 具有子类 Layer 的子类模型为 save_weights() 生成 AttributeError

tf.Keras subclass Model having subclass Layer generate AttributeError for save_weights()

我在观看 F.Chollet youtube 视频“TensorFlow 内部:tf.Keras(第 1 部分)后尝试了这个。在这个 session 中,他讨论了如何通过子类化创建自定义层和模型。我运行 这个在 colab 上与:

try:
  # %tensorflow_version only exists in Colab.
  %tensorflow_version 2.x
except Exception:
  pass

import tensorflow as tf

from tensorflow import keras
from tensorflow.keras.models import Sequential, Model, load_model
from tensorflow.keras.layers import Layer

from tensorflow.keras.optimizers import Adam
from tensorflow.keras.losses import BinaryCrossentropy

我这样定义 "Linear" 层:

class Linear(Layer):

  def __init__(self, units=32, **kwargs):
    super(Linear, self).__init__(**kwargs)
    self.units = units 

  def build(self, input_shape):
    #print("build: input_shape = {}".format(input_shape))
    self.w = self.add_weight(shape=(input_shape[-1], self.units), initializer='random_normal', trainable=True)
    self.b = self.add_weight(shape=(self.units,), initializer='zeros', trainable=True)

  def call(self, inputs):
    return tf.matmul(inputs, self.w) + self.b

  def get_config(self):
    config = super(Linear, self).get_config()
    config.update({'units': self.units})

    return config

和 MLP 模型子类如下:

class MLP(Model):
  def __init__(self, **kwargs):
    super(MLP, self).__init__(**kwargs)
    self.linear = Linear(1)

  def call(self, inputs):
    return self.linear(inputs)

请注意,我已将 MLP 简化为只有 1 层而不是视频中的 3 层。

本人编译训练:

x_train = np.random.randn(1024, 64)
y_train = np.random.randint(0, 2, size=(1024, 1))
mlp = MLP()
mlp.compile(optimizer=Adam(), loss=BinaryCrossentropy(from_logits=True))
mlp.fit(x=x_train, y=y_train, epochs=10, verbose=0)
loss = mlp.evaluate(x=x_train, y=y_train, batch_size=1024, verbose=0)

然后保存权重:

mlp.save_weights('mlp', save_format='tf')

错误:

AttributeError                            Traceback (most recent call last)
<ipython-input-8-00c47f30bead> in <module>()
----> 1 mlp.save_weights('mlp', save_format='tf')
      2 
      3 # export_saved_model(mlp, 'mlp.h5')

8 frames
/tensorflow-2.0.0-rc0/python3.6/tensorflow_core/python/training/tracking/graph_view.py in _escape_local_name(name)
     55   # edges traversed to reach the variable, so we escape forward slashes in
     56   # names.
---> 57   return (name.replace(_ESCAPE_CHAR, _ESCAPE_CHAR + _ESCAPE_CHAR)
     58           .replace(r"/", _ESCAPE_CHAR + "S"))
     59 

AttributeError: 'NoneType' object has no attribute 'replace'

有没有我做错了什么?

Is there anything I did badly wrong?

不是真的。序列化权重时,未为其指定名称会导致崩溃。

改变

    self.w = self.add_weight(shape=(input_shape[-1], self.units), initializer='random_normal', trainable=True)
    self.b = self.add_weight(shape=(self.units,), initializer='zeros', trainable=True)

    self.w = self.add_weight(name='w',shape=(input_shape[-1], self.units), initializer='random_normal', trainable=True)
    self.b = self.add_weight(name='b',shape=(self.units,), initializer='zeros', trainable=True)

https://github.com/tensorflow/tensorflow/issues/26811#issuecomment-474255444