python - 具有两个预训练 ResNet 50 的连体神经网络 - 测试模型时的奇怪行为
问题描述
我使用 Keras lib 构建了连体神经网络。我的模型有两个形状为 (64,64,3) 的输入,两个预训练的 ResNet-50。损失函数是二元交叉熵。
该模型是基于本文的一个链接
在训练期间,我有非常好的 trait/val 准确度,大约 0.99/0.98,低损失 0.01/0.05。
但是当我测试我保存的模型时,我得到了不好的结果。该模型甚至无法识别两张相同的图片。
我还注意到奇怪的行为:epoch 数越多,结果越差。例如,比较两个相同的图像,经过10 个 epoch的训练模型 给出预测: “8.jpg”:0.5180479884147644但用100 个 epoch 训练的相同模型给出 “8.jpg”:5.579867080537926E-13 但是对于100 个 epoch,我有更好的训练结果。
我为 CNN 尝试了不同的模型:ResNet18,不同的输入形状,如(224,224,3)或(128,128,3)。
此外,我使用三合会不使用预训练模型,仅使用没有预训练权重的ResNet50/ResNet18。但是在测试真实模型时,我得到了同样糟糕的结果。
我的代码是
def create_base_model(image_shape, dropout_rate, suffix=''):
I1 = Input(shape=image_shape)
model = ResNet50(include_top=False, weights='imagenet', input_tensor=I1, pooling=None)
model.layers.pop()
model.outputs = [model.layers[-1].output]
model.layers[-1].outbound_nodes = []
for layer in model.layers:
layer.name = layer.name + str(suffix)
layer.trainable = False
flatten_name = 'flatten' + str(suffix)
x = model.output
x = Flatten(name=flatten_name)(x)
x = Dense(1024, activation='relu')(x)
x = Dropout(dropout_rate)(x)
x = Dense(512, activation='relu')(x)
x = Dropout(dropout_rate)(x)
return x, model.input
def create_siamese_model(image_shape, dropout_rate):
output_left, input_left = create_base_model(image_shape, dropout_rate)
output_right, input_right = create_base_model(image_shape, dropout_rate, suffix="_2")
L1_layer = Lambda(lambda tensors: tf.abs(tensors[0] - tensors[1]))
L1_distance = L1_layer([output_left, output_right])
L1_prediction = Dense(1, use_bias=True,
activation='sigmoid',
kernel_initializer=RandomNormal(mean=0.0, stddev=0.001),
name='weighted-average')(L1_distance)
prediction = Dropout(0.2)(L1_prediction)
siamese_model = Model(inputs=[input_left, input_right], outputs=prediction)
return siamese_model
siamese_model = create_siamese_model(image_shape=(64, 64, 3),
dropout_rate=0.2)
siamese_model.compile(loss='binary_crossentropy',
optimizer=Adam(lr=0.0001),
metrics=['binary_crossentropy', 'acc'])
siamese_model.fit_generator(train_gen,
steps_per_epoch=1000,
epochs=10,
verbose=1,
callbacks=[checkpoint, tensor_board_callback, lr_reducer, early_stopper, csv_logger],
validation_data=validation_data,
max_q_size=3)
siamese_model.save('siamese_model.h5')
# and the my prediction
siamese_net = load_model('siamese_model.h5', custom_objects={"tf": tf})
X_1 = [image, ] * len(markers)
batch = [markers, X_1]
result = siamese_net.predict_on_batch(batch)
# I've tried also to check identical images
markers = [image]
X_1 = [image, ] * len(markers)
batch = [markers, X_1]
result = siamese_net.predict_on_batch(batch)
我对我的预测方法有些怀疑。有人可以帮我找出预测有什么问题吗?
解决方案
你得到的是预期的。我不确定你的意思
我还注意到奇怪的行为:epoch 数越多,结果越差。
但是您显示的结果是有效的和预期的。让我们从模型输出的内容开始。您的模型输出是第一个和第二个输入之间的(标准化)距离。如果输入相似,那么距离应该接近于零。随着训练步数的增加,模型学习识别输入,即如果输入相似,模型学习输出接近零的值,如果输入不同,模型学习输出接近一的值。所以,
...经过 10 个 epoch 的训练模型给出预测:“8.jpg”:0.5180479884147644 但用 100 个 epoch 训练的相同模型给出“8.jpg”:5.579867080537926E-13 但是对于 100 个 epoch,我有更好的训练结果。
, 确认模型已经知道两个输入和输出是相似的5.579867080537926E-13 ~ 0
(大约接近 0)。
尽管模型表现良好,但我在模型定义中观察到一个问题:- 输出层是 dropout 层。Dropout 不是有效的输出层。您通过此设置所做的是,随机概率为 0.2,您将模型的输出设置为零。
假设目标变量为 1(两个输入不同),模型已经学会正确识别图像并在 dropout 层之前输出接近 1 的值。让我们进一步假设 dropout 层已决定将输出设置为零。所以模型输出将为零。尽管 dropout 层之前的层表现良好,但由于 dropout 层,它们会受到惩罚。如果这不是您要查找的内容,请删除最后一个 dropout 层。
L1_prediction = Dense(1, use_bias=True,
activation='sigmoid',
kernel_initializer=RandomNormal(mean=0.0, stddev=0.001),
name='weighted-average')(L1_distance)
siamese_model = Model(inputs=[input_left, input_right], outputs=L1_prediction)
但是,如果想要向模型添加噪声,有时需要这种行为。这与值为 1 时随机更改目标变量具有相同的效果。
推荐阅读
- amazon-web-services - 从经理那里检索一个秘密并在 ec2 cfn-init 中使用它
- android - 如何使我的应用程序可供 Play 商店中的用户使用
- vb.net - Visual Basic,使应用程序仅在特定文件夹中打开
- wpf - 在现有应用程序中设置自动化 ID
- python - 在将数据传递给插值例程之前存储数据
- kubernetes - 如何通过一个入口在裸机上使用多域
- backbone.js - 如何从自身调用布局以创建实例
- android - 使用 Android Jetpack Navigation 时如何禁用导航图标
- node.js - MongoDB 在 $group 上缺乏性能
- c# - 我需要编辑列表中的值,并存储用户输入