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
我在观看 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