NotImplementedError:在 `__init__` 中有参数的层必须覆盖 `get_config`
Posted
技术标签:
【中文标题】NotImplementedError:在 `__init__` 中有参数的层必须覆盖 `get_config`【英文标题】:NotImplementedError: Layers with arguments in `__init__` must override `get_config` 【发布时间】:2020-02-28 21:47:51 【问题描述】:我正在尝试使用 model.save()
保存我的 TensorFlow 模型,但是 - 我收到了这个错误。
此处提供模型摘要: Model Summary
变压器模型的代码:
def transformer(vocab_size, num_layers, units, d_model, num_heads, dropout, name="transformer"):
inputs = tf.keras.Input(shape=(None,), name="inputs")
dec_inputs = tf.keras.Input(shape=(None,), name="dec_inputs")
enc_padding_mask = tf.keras.layers.Lambda(
create_padding_mask, output_shape=(1, 1, None),
name='enc_padding_mask')(inputs)
# mask the future tokens for decoder inputs at the 1st attention block
look_ahead_mask = tf.keras.layers.Lambda(
create_look_ahead_mask,
output_shape=(1, None, None),
name='look_ahead_mask')(dec_inputs)
# mask the encoder outputs for the 2nd attention block
dec_padding_mask = tf.keras.layers.Lambda(
create_padding_mask, output_shape=(1, 1, None),
name='dec_padding_mask')(inputs)
enc_outputs = encoder(
vocab_size=vocab_size,
num_layers=num_layers,
units=units,
d_model=d_model,
num_heads=num_heads,
dropout=dropout,
)(inputs=[inputs, enc_padding_mask])
dec_outputs = decoder(
vocab_size=vocab_size,
num_layers=num_layers,
units=units,
d_model=d_model,
num_heads=num_heads,
dropout=dropout,
)(inputs=[dec_inputs, enc_outputs, look_ahead_mask, dec_padding_mask])
outputs = tf.keras.layers.Dense(units=vocab_size, name="outputs")(dec_outputs)
return tf.keras.Model(inputs=[inputs, dec_inputs], outputs=outputs, name=name)
我不明白为什么它会给出这个错误,因为模型训练得非常好。 任何帮助将不胜感激。
我的保存代码供参考:
print("Saving the model.")
saveloc = "C:/tmp/solar.h5"
model.save(saveloc)
print("Model saved to: " + saveloc + " succesfully.")
【问题讨论】:
我认为这已经随着 tensorflow 2.2.0 改变了......所以现在你不会遇到这个错误 【参考方案1】:这不是错误,这是一项功能。
此错误让您知道 TF 无法保存您的模型,因为它无法加载它。
具体来说,它将无法重新实例化您的自定义 Layer
类:encoder
和 decoder
。
要解决这个问题,只需根据您添加的新参数覆盖他们的 get_config
方法即可。
层配置是包含层配置的 Python 字典(可序列化)。稍后可以从此配置中重新实例化同一层(没有经过训练的权重)。
例如,如果您的 encoder
类看起来像这样:
class encoder(tf.keras.layers.Layer):
def __init__(
self,
vocab_size, num_layers, units, d_model, num_heads, dropout,
**kwargs,
):
super().__init__(**kwargs)
self.vocab_size = vocab_size
self.num_layers = num_layers
self.units = units
self.d_model = d_model
self.num_heads = num_heads
self.dropout = dropout
# Other methods etc.
那么你只需要重写这个方法:
def get_config(self):
config = super().get_config().copy()
config.update(
'vocab_size': self.vocab_size,
'num_layers': self.num_layers,
'units': self.units,
'd_model': self.d_model,
'num_heads': self.num_heads,
'dropout': self.dropout,
)
return config
当 TF 看到这一点时(对于两个类),您将能够保存模型。
因为现在加载模型时,TF 将能够从配置中重新实例化同一层。
Layer.from_config
的source code 可能会更好地了解它的工作原理:
@classmethod
def from_config(cls, config):
return cls(**config)
【讨论】:
我会试试这个。这不应该默认使用类构造中的参数来完成吗? 这个可以已经完成了,但是考虑不是所有参数都需要保存的情况,只需要它们的导数就足够了。例如x_train
的mean
和std
。在这种情况下,该层可以接受x_train
或(mean, std)
来构造。在构建模型时,您将使用x_train
并保存self.mean, self.std
,然后仅保存mean, std
到config
以重新实例化,而不使用整个x_train
。
我没有很好地理解它。有什么资料可以阅读更多有关它的信息吗?另外,为什么我们要重写编码器层而不是编码器本身?另外,如果编码器层是一个函数而不是一个类呢?
@Mee 1. 是的:tensorflow.org/guide/keras/… 2. 因为序列化模型的标准部件已经开箱即用。但是对于像 Encoder 和 Decoder 这样的自定义层,你需要定义它。 3. 我不确定,您可能想将此作为一个单独的问题提出。但是为什么不把你函数的逻辑放到一个 Layer 子类中呢?
感谢您的回复。我确实把它放在了一个单独的问题中。请你检查一下好吗? ***.com/questions/59796343/…【参考方案2】:
我认为简单的解决方案是为 gpu tensorflow-gpu==2.4.2 安装 tensorflow==2.4.2 ,我遇到了这个问题并调试了一整天,但没有解决。最后我安装了旧的稳定版本,错误消失了
【讨论】:
【参考方案3】:这个问题是由于在 keras 和 tf.keras 库之间混合导入导致的,不支持。
在任何地方使用 tf.keras.models 或 usr keras.models
您不应该在这些库之间混合导入,因为它不起作用并会产生各种奇怪的错误消息。这些错误会随着 keras 和 tensorflow 的版本而变化。
【讨论】:
即使我的问题与 OP 不完全相同,我也得到了完全相同的错误。约翰的回答对我来说很神奇,当我写的时候让我的 VSCode 自动导入 Dropout:model.add(Dropout())。它导入它: from tensorflow.python.keras.layers.core import Dropout 并因此产生上述错误。正确的导入是: from tensorflow.keras.layers import Dropout【参考方案4】:我建议您尝试以下方法:
model = tf.keras.Model(...)
model.save_weights("some_path")
...
model.load_weights("some_path")
【讨论】:
以上是关于NotImplementedError:在 `__init__` 中有参数的层必须覆盖 `get_config`的主要内容,如果未能解决你的问题,请参考以下文章
PyTorch NotImplementedError 转发
NotImplementedError:无法将符号张量 (lstm_4/strided_slice:0) 转换为 numpy 数组
Python之美[从菜鸟到高手]--NotImplemented小析
无法将符号张量 (lstm_15/strided_slice:0) 转换为 numpy 数组