【问题标题】:ValueError: Unknown layer: FunctionalValueError:未知层:功能
【发布时间】:2020-11-14 00:41:07
【问题描述】:

我在 colab 中制作了一个 CNN,并在每个 epoch 保存了模型。我导出了 h5 文件,现在正尝试在一些测试图像上运行模型。这是主要错误:

ValueError: Unknown layer: Functional

这是我用来运行模型并在每个时期保存的代码:

epochs = 50

callbacks = [
    tf.keras.callbacks.TensorBoard(log_dir='./logs'),
    keras.callbacks.ModelCheckpoint("save_at_{epoch}.h5"),
]
model.compile(
    optimizer=keras.optimizers.Adam(1e-3),
    loss="binary_crossentropy",
    metrics=["accuracy"],
)
model.fit(
    train_ds, epochs=epochs, callbacks=callbacks, validation_data=val_ds,
)

模型运行后,我只是在本地从 colab 侧边栏下载了 h5 文件。我从本地磁盘重新上传了文件,这是我尝试加载模型的方式:

# load and evaluate a saved model
from tensorflow.keras.models import load_model

# load model#
loaded_model = load_model('save_at_47.h5')
loaded_model.layers[0].input_shape

这是完整的回溯:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-6af7396280fa> in <module>()
      3 
      4 # load model#
----> 5 loaded_model = load_model('save_at_47.h5')
      6 loaded_model.layers[0].input_shape

5 frames
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/saving/save.py in load_model(filepath, custom_objects, compile)
    182     if (h5py is not None and (
    183         isinstance(filepath, h5py.File) or h5py.is_hdf5(filepath))):
--> 184       return hdf5_format.load_model_from_hdf5(filepath, custom_objects, compile)
    185 
    186     if sys.version_info >= (3, 4) and isinstance(filepath, pathlib.Path):

/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/saving/hdf5_format.py in load_model_from_hdf5(filepath, custom_objects, compile)
    176     model_config = json.loads(model_config.decode('utf-8'))
    177     model = model_config_lib.model_from_config(model_config,
--> 178                                                custom_objects=custom_objects)
    179 
    180     # set weights

/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/saving/model_config.py in model_from_config(config, custom_objects)
     53                     '`Sequential.from_config(config)`?')
     54   from tensorflow.python.keras.layers import deserialize  # pylint: disable=g-import-not-at-top
---> 55   return deserialize(config, custom_objects=custom_objects)
     56 
     57 

/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/layers/serialization.py in deserialize(config, custom_objects)
    107       module_objects=globs,
    108       custom_objects=custom_objects,
--> 109       printable_module_name='layer')

/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/utils/generic_utils.py in deserialize_keras_object(identifier, module_objects, custom_objects, printable_module_name)
    360     config = identifier
    361     (cls, cls_config) = class_and_config_for_serialized_keras_object(
--> 362         config, module_objects, custom_objects, printable_module_name)
    363 
    364     if hasattr(cls, 'from_config'):

/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/utils/generic_utils.py in class_and_config_for_serialized_keras_object(config, module_objects, custom_objects, printable_module_name)
    319   cls = get_registered_object(class_name, custom_objects, module_objects)
    320   if cls is None:
--> 321     raise ValueError('Unknown ' + printable_module_name + ': ' + class_name)
    322 
    323   cls_config = config['config']

ValueError: Unknown layer: Functional

似乎有几个类似的questions herehere。更改导入方法还没有帮助,尝试制作一些 kind of custom 对象也没有奏效。

【问题讨论】:

  • 能否提供您用于保存模型的代码?
  • 当然,我更新了问题以显示我如何将模型保存到磁盘。谢谢
  • 为什么不自己从头开始重建模型并从h5 文件中加载权重(model.load_weights('save_at_47.h5'))?
  • 在你的错误中这个层被称为功能是什么?它是您制作的自定义图层吗?
  • 简单易行。只需运行包含模型定义和编译的单元格,然后将权重加载到我在上面告诉您的这个裸露的空模型中。

标签: python tensorflow keras


【解决方案1】:

从头开始重建网络:

image_size = (212, 212)
batch_size = 32

data_augmentation = keras.Sequential(
    [
        layers.experimental.preprocessing.RandomFlip("horizontal_and_vertical"),
        layers.experimental.preprocessing.RandomRotation(0.8),
    ]
)


def make_model(input_shape, num_classes):
    inputs = keras.Input(shape=input_shape)
    # Image augmentation block
    x = data_augmentation(inputs)

    # Entry block
    x = layers.experimental.preprocessing.Rescaling(1.0 / 255)(x)
    x = layers.Conv2D(32, 3, strides=2, padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.Activation("relu")(x)

    x = layers.Conv2D(64, 3, padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.Activation("relu")(x)

    previous_block_activation = x  # Set aside residual

    for size in [128, 256, 512, 728]:
        x = layers.Activation("relu")(x)
        x = layers.SeparableConv2D(size, 3, padding="same")(x)
        x = layers.BatchNormalization()(x)

        x = layers.Activation("relu")(x)
        x = layers.SeparableConv2D(size, 3, padding="same")(x)
        x = layers.BatchNormalization()(x)

        x = layers.MaxPooling2D(3, strides=2, padding="same")(x)

        # Project residual
        residual = layers.Conv2D(size, 1, strides=2, padding="same")(
            previous_block_activation
        )
        x = layers.add([x, residual])  # Add back residual
        previous_block_activation = x  # Set aside next residual

    x = layers.SeparableConv2D(1024, 3, padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.Activation("relu")(x)

    x = layers.GlobalAveragePooling2D()(x)
    if num_classes == 2:
        activation = "sigmoid"
        units = 1
    else:
        activation = "softmax"
        units = num_classes

    x = layers.Dropout(0.5)(x)
    outputs = layers.Dense(units, activation=activation)(x)
    return keras.Model(inputs, outputs)


model = make_model(input_shape=image_size + (3,), num_classes=2)
keras.utils.plot_model(model, show_shapes=False)

加载权重:

model.load_weights('save_at_47.h5')

并对图像进行预测:

# Running inference on new data
img = keras.preprocessing.image.load_img(
    "le_image.jpg", target_size=image_size
)
img_array = keras.preprocessing.image.img_to_array(img)
img_array = tf.expand_dims(img_array, 0)  # Create batch axis

predictions = model.predict(img_array)
score = predictions[0]
print(
    "This image is %.2f percent negative and %.2f percent positive."
    % (100 * (1 - score), 100 * score)
)

【讨论】:

  • 这是 Colab 特有的吗?我遇到了同样的错误。
  • 你救了我的命! ;P
  • @LobstaBoy 该解决方案未完全连接。您抱怨 load_model('save_at_47.h5') 无法正常工作,并且在回答中您建议改用 load_weights。那么,如果我想让load_model 正常工作怎么办?解决方案是什么?
  • @VM_AI 似乎存在某种版本兼容性问题,需要来回切换版本才能加载模型,这似乎比将权重加载到模型中更痛苦。我什至不确定为什么它一开始就给我这个错误,因为我正在将模型保存并加载到同一个 colab 环境中。
  • @LobstaBoy 我认为加载权重也是有缺陷的,因为当您使用model.load_weights(filename) 加载权重并重新训练模型时,错误应该从最近检查点的错误开始。相反,它从您从第一个 epoch 得到的错误开始。我仍在寻找有关如何正确保存和加载权重/模型的解决方案。
【解决方案2】:

我在使用 tf 2.3.0 时遇到了同样的问题,我降级到 tf 2.2.0 并且它工作了

【讨论】:

  • 我正在使用 CoLab 和 tf,所以我可以在每次打开工作区时降级版本,但一段时间后可能会很麻烦。不过很高兴知道,谢谢!
【解决方案3】:

在 colab 上使用 tf 2.3 训练模型并在我的本地机器上使用 tf 2.2 加载模型时,我遇到了同样的问题。解决方案是使用以下命令升级 TensorFlow:

pip3 install --upgrade tensorflow

【讨论】:

    【解决方案4】:

    这个错误的解决方法很简单,例如。原因是您已经在 Tensorflow 的“2.3.0”版本和 Keras 的“2.4.3”版本(在 Colab 或本地)上训练了模型。现在您正在通过另一个版本的 Keras 和 TensorFlow 访问保存的模型(.h5)。它会给你错误。解决方案是使用升级版本重新训练模型或将 TF&Keras 降级到与训练模型相同的版本。

    【讨论】:

    • 如果你不介意我问,你怎么知道错误发生在这个特定的 '2.3.0' 版本上?
    • “功能”层是 2.3.0 版新增的吗?
    【解决方案5】:

    这里的讨论为我省去了一些麻烦!对于类似情况,我分享了一个不同的解决方案,其中模型序列化是使用模型结构 (yaml) 和 h5 权重文件手动完成的(而不是通过 fit 方法)。在这种情况下,只需编辑 yaml 文件就足以使序列化模型适应较旧的 tensorflow 版本。

    在我的例子中,我生成了这样的模型

        model_config = { "class_name": "Model",
                         "config":model.get_config()
                         }
    
        with open(os.path.join(dump_model_dir, "model_config.yaml"), "w") as file:
            file.write(model.to_yaml())
    
        model.save_weights(os.path.join(dump_model_dir, "model_weights.hdf5"))
    

    在 TF2.2 和 2.3 中执行此操作会发现 yaml 文件中的微小变化。仅具有 Conv2D 层的模型结构的两个版本的差异如下所示。手动或使用 sed 修复很简单:

    需要将 class_name: Functional 更改为 class_name: Model 并删除 Conv2D 和其他 Conv 层中新的配置 groups: 1。为了保持一致性,我最后还更改了 keras 版本。显然,这仅在相关模型的组参数具有默认值1 时才有效。如果您不为模型使用 yaml 而使用 json 文件,则应该应用类似的解决方案。

    *** model_config_tf22.yaml  2021-01-07 15:00:03.042791215 +0100
    --- model_config_tf23.yaml  2021-01-07 14:59:56.426791386 +0100
    ***************
    *** 1,5 ****
      backend: tensorflow
    ! class_name: Model
      config:
        input_layers:
        - - input_1
    --- 1,5 ----
      backend: tensorflow
    ! class_name: Functional
      config:
        input_layers:
        - - input_1
    ***************
    *** 34,39 ****
    --- 34,40 ----
            - 1
            dtype: float32
            filters: 128
    +       groups: 1
            kernel_constraint: null
            kernel_initializer:
              class_name: RandomUniform
    ***************
    *** 343,346 ****
        - - Conv2D_5_37
          - 0
          - 0
    ! keras_version: 2.3.0-tf
    --- 351,354 ----
        - - Conv2D_5_37
          - 0
          - 0
    ! keras_version: 2.4.0
    

    【讨论】:

    • 您在哪里进行了这些更改?在定义 Keras 模型的 Python 代码中?
    • 不,如果这不够清楚,我很抱歉。对于使用 yaml 或 json 格式的模型结构文件和权重文件完成序列化的情况,此解决方案解决了与原始问题相同的问题。我编辑了解决方案,希望能澄清这一点。
    • 非常感谢,你帮了我很多
    【解决方案6】:

    如果您使用较旧的 TF(在我的情况下为 2.1.0)并尝试解压由较新的 TF(例如 2.4.1)打包的 h5 文件并遇到此错误,则以下技巧可能很有用。

    your_model = tf.keras.models.load_model(
        path_to_h5,
        custom_objects={'Functional':tf.keras.models.Model})
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-23
      • 2021-02-22
      • 1970-01-01
      • 2020-11-18
      相关资源
      最近更新 更多