Keras 加载预训练的权重。形状不匹配

数据挖掘 Python 喀拉斯 迁移学习
2022-03-11 04:06:38

我在使用 Keras 加载预训练的权重时遇到了一些问题。假设我有一个 keras 模型model,并且我的权重存储在my_weights.h5.

我尝试按如下方式加载我的重量:

model.load_weights("my_weights.h5", by_name=True)

但这给了我以下错误:

Layer #1 (named "conv2d_1"), weight <tf.Variable 'conv2d_1/kernel:0' shape=(3, 3, 32, 64) dtype=float32> has shape (3, 3, 32, 64), but the saved weight has shape (32, 3, 3, 3).

所以我试着看看我的重量和模型结构的形状是什么:

for layer in model_body.layers :
    print(layer.name+" : input ("+str(layer.input_shape)+") output ("+str(layer.output_shape)+")")

print("__")
with h5py.File(weights_filepath, 'r') as f:
    for k in f.keys():
        for l in f[k].keys():
            for m in f[k][l].keys():
                print(k+ " : " + m + " : " + str(f[k][l][m].shape))


conv2d_1 : input ((None, None, None, 32)) output ((None, None, None, 64))
__
conv2d_1 : kernel:0 : (3, 3, 3, 32)

(我只保留了错误中出现的图层)

通过看到这一点,我不明白为什么形状不匹配,以及(3, 3, 32, 64)错误中的形状来自哪里)。我错过了什么吗?

3个回答

trainable关于与属性https://datascience.stackexchange.com/a/84067/51317相关的问题 ,如果很难确定哪些权重设置为可训练,一种选择是尝试按名称加载权重像这样的东西(这并不涵盖所有场景):

def load_weights_by_name(model, path, verbose=False):
    import h5py
    def load_model_weights(cmodel, weights):
        for layer in cmodel.layers:
            print(layer.name)
            if hasattr(layer, 'layers'):
                load_model_weights(layer, weights[layer.name])
            else:
                for w in layer.weights:
                    _, name = w.name.split('/')
                    if verbose:
                        print(w.name)
                    try:
                        w.assign(weights[layer.name][name][()])
                    except:
                        w.assign(weights[layer.name][layer.name][name][()])

    with h5py.File(path, 'r') as f:
        load_model_weights(model, f)

不幸的是,问题的发生是因为在保存具有修改的可训练属性的模型时权重的顺序发生了变化;但是,在 keras 中按名称加载权重的功能在尝试将权重值与符号权重匹配时不会检查权重的顺序https://github.com/keras-team/keras/blob/98a762224578cf5e15be39fddf6917cf8efea6e0/keras /保存/hdf5_format.py#L782

我已经解决了如下问题。希望解决方案会有所帮助。

1.删​​除“by_name=True”

# -model.load_weights(weights_path, by_name=True)
model.load_weights(weights_path)

2.更改班级人数

当它抛出另一个抛出“ValueError:Shapes (1536, 1000) 和 (1536, 1001) 不兼容”时,我将 num_classes 从 1000 更改为 1001。然后它显示了正确的模型摘要。

# -num_classes = 1000
num_classes = 1001

我有一个类似的错误,非常困惑

ValueError: Shapes (32,) and (3, 3, 32, 64) are incompatible

我最终发现我修改了trainable模型的属性。(我在最后几层进行迁移学习,然后切换到训练完整模型。)@Supratim 检查摘要的建议让我知道,因为这显示了可训练参数的数量。

错误信息有点难以解读,因为我没想到会trainable改变任何形状。我想要吸取的教训是模型必须完全匹配。