如何在 Keras 中正确保存和加载中间模型?

数据挖掘 神经网络 喀拉斯 计算机视觉 图像识别 卷积神经网络
2022-02-18 03:19:35

我正在使用一个模型,该模型涉及 Keras 中模型的 3 个“嵌套”阶段。

从概念上讲,第一个是迁移学习 CNN 模型,例如 MobileNetV2。(模型 1)然后由一个由小型 DNN 组成的模型包装。(模型 2)最后在训练期间,这些都被一个模型包裹起来,该模型连接模型 2 的多个输出,计算损失,然后反向传播到模型 2 和未来的模型 1。(模型 3)

为了稍后进行推断,我只是想保存模型 1 和 2 的权重。由于某些版本的 Keras(我使用的是 2.2.2)中似乎存在错误并且还加载了权重,因此我遇到了多个问题更明确地似乎导致随机权重,因此无法正常工作。我没有尝试解决任何情况下出了什么问题,我只是想确定保存中间嵌套模型的最佳实践是什么。

def create_model_2(IN_DIM=(224, 224, 3), OUT_DIM=128):
    # First define the transfer learning model
    initial_img = Input(shape=(IN_DIM))

    black_box = MobileNetV2(include_top=False, input_shape=IN_DIM, weights="imagenet", pooling="avg")(initial_img)

    bb_model = Model(b_img, black_box)

    # freeze layers for transfer learning model
    for layer in bb_model.layers:
        layer.trainable = False

    #########################
    ###### TOWER BLOCK ######
    #########################

    img = Input(shape=(IN_DIM))

    x = bb_model(img)

    # add some layers to try to learn
    x = Dense(64, activation='relu', name='new_fc0')(x)

    x = Dense(OUT_DIM, activation='relu', name='new_fc1')(x)

    # L2 norm to project to unit sphere
    out = Lambda(lambda x: K.l2_normalize(x, axis=1), name='final_l2_norm')(x)

    _model_2 = Model(img, out)

    return _model_2

那么Model 3的结构:

IN_DIM = (224, 224, 3)  # mobilenetv2=(224, 224, 3) Iv3=(299, 299, 3)
OUT_DIM = 32 

model_2 = create_model_2(IN_DIM, OUT_DIM)

# then define images for triplets
anchor_img = Input(shape=IN_DIM)
pos_img = Input(shape=IN_DIM)
neg_img = Input(shape=IN_DIM)

# create three vectors representing the images
anchor_in = model_2(anchor_img)
positive_in = model_2(pos_img)
negative_in = model_2(neg_img)

# concatenate the vectors into one large vector for input into the triplet loss "processor"
merged_vector = concatenate([anchor_in, positive_in, negative_in], axis=-1)

# actually define the model:
model_3 = Model(inputs=[anchor_img, pos_img, neg_img], outputs=merged_vector)

该模型似乎可以正常运行和训练:

OPTIMIZER = SGD(lr=learning_rate, momentum=0.9)

final_model.compile(optimizer=OPTIMIZER, loss=triplet_loss, metrics=[avg_AP_dist, avg_AN_dist])

history = final_model.fit_generator(generator=training_generator,
                                    epochs=5,  # short for debugging
                                    use_multiprocessing=True,
                                    workers=4)

但是训练后保存模型还不清楚:

out_file = "../../models/{:}_epoch_{:}_weights.h5".format(MODEL_DESC, 5)
model_2.save_weights(out_file)  # save the actual Tower weights, discard the "booster" wrapper
print("Saved: {:}".format(out_file))

或者:

out_file = "../../models/{:}_epoch_{:}_weights.h5".format(MODEL_DESC, 5)
model_2.save(out_file)  # save the actual Tower weights, discard the "booster" wrapper
print("Saved: {:}".format(out_file))

或者是其他东西?

当前的故障模式似乎是,如果我尝试仅将权重加载到新实例化的 model_2 实例中,则会得到:

ValueError: axes don't match array

搜索结果可能与 Keras 中的错误有关。如果我保存模型(.save() 而不是 .save_weights() 那么它会毫无怨言地加载,但推理不稳定并且看起来很可怕/随机。)

谢谢你。

仍然得到以下回溯:

<snip>/src/notebooks/vectorizer.py in load_model()
     65 
     66     # load the weights
---> 67     loaded_model.load_weights(weights_path)
     68 
     69     print("Model ready")

/opt/conda/lib/python3.6/site-packages/keras/engine/network.py in load_weights(self, filepath, by_name, skip_mismatch, reshape)
   1164             else:
   1165                 saving.load_weights_from_hdf5_group(
-> 1166                     f, self.layers, reshape=reshape)
   1167 
   1168     def _updated_config(self):

/opt/conda/lib/python3.6/site-packages/keras/engine/saving.py in load_weights_from_hdf5_group(f, layers, reshape)
   1043                                                        original_keras_version,
   1044                                                        original_backend,
-> 1045                                                        reshape=reshape)
   1046         if len(weight_values) != len(symbolic_weights):
   1047             raise ValueError('Layer #' + str(k) +

/opt/conda/lib/python3.6/site-packages/keras/engine/saving.py in preprocess_weights_for_loading(layer, weights, original_keras_version, original_backend, reshape)
    680         weights = convert_nested_time_distributed(weights)
    681     elif layer.__class__.__name__ in ['Model', 'Sequential']:
--> 682         weights = convert_nested_model(weights)
    683 
    684     if original_keras_version == '1':

/opt/conda/lib/python3.6/site-packages/keras/engine/saving.py in convert_nested_model(weights)
    668                     weights=weights[:num_weights],
    669                     original_keras_version=original_keras_version,
--> 670                     original_backend=original_backend))
    671                 weights = weights[num_weights:]
    672         return new_weights

/opt/conda/lib/python3.6/site-packages/keras/engine/saving.py in preprocess_weights_for_loading(layer, weights, original_keras_version, original_backend, reshape)
    680         weights = convert_nested_time_distributed(weights)
    681     elif layer.__class__.__name__ in ['Model', 'Sequential']:
--> 682         weights = convert_nested_model(weights)
    683 
    684     if original_keras_version == '1':

/opt/conda/lib/python3.6/site-packages/keras/engine/saving.py in convert_nested_model(weights)
    656                     weights=weights[:num_weights],
    657                     original_keras_version=original_keras_version,
--> 658                     original_backend=original_backend))
    659                 weights = weights[num_weights:]
    660 

/opt/conda/lib/python3.6/site-packages/keras/engine/saving.py in preprocess_weights_for_loading(layer, weights, original_keras_version, original_backend, reshape)
    799             weights[0] = np.reshape(weights[0], layer_weights_shape)
    800         elif layer_weights_shape != weights[0].shape:
--> 801             weights[0] = np.transpose(weights[0], (3, 2, 0, 1))
    802             if layer.__class__.__name__ == 'ConvLSTM2D':
    803                 weights[1] = np.transpose(weights[1], (3, 2, 0, 1))

/opt/conda/lib/python3.6/site-packages/numpy/core/fromnumeric.py in transpose(a, axes)
    596 
    597     """
--> 598     return _wrapfunc(a, 'transpose', axes)
    599 
    600 

/opt/conda/lib/python3.6/site-packages/numpy/core/fromnumeric.py in _wrapfunc(obj, method, *args, **kwds)
     49 def _wrapfunc(obj, method, *args, **kwds):
     50     try:
---> 51         return getattr(obj, method)(*args, **kwds)
     52 
     53     # An AttributeError occurs if the object does not have

ValueError: axes don't match array
2个回答

尝试将模型保存为 JSON,并将权重保存为 HDF5 格式save_weights()

# save the model
model_json = model_2.to_json()
with open("model_2.json", "w") as j_file:
    j_file.write(model_json)

# save the weights
model.save_weights("model_2.h5")

稍后加载模型:

# load the model
j_file = open('model_2.json', 'r')
loaded_json_model = j_file.read()
j_file.close()
loaded_model = model_from_json(loaded_json_model)


# load the weights
loaded_model.load_weights("model_2.h5")

完成模型训练后:

final_model.save('model.h5')

要重新加载模型,只需使用:

from keras import load_model
model=load_model('model.h5')