python - 具有两个预训练 ResNet 50 的连体神经网络 - 测试模型时出现奇怪的行为

标签 python tensorflow machine-learning keras neural-network

我使用 Keras lib 构建了暹罗神经网络。 我的模型有两个形状为 (64,64,3) 的输入,两个预训练的 ResNet-50。 损失函数为二元交叉熵。

模型基于这篇论文a link

在训练过程中,我具有非常好的特征/值准确度,约为 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)

我对我的预测方法有些怀疑。 有人可以帮我找出预测有什么问题吗?

最佳答案

您所得到的是预期的。我不确定你的意思

Also I noticed strange behavior: the greater the number of epochs the result is worse.

但是您显示的结果是有效且符合预期的。让我们从模型输出的内容开始。您的模型输出是第一个和第二个输入之间的(标准化)距离。如果输入相似,则距离应接近于零。随着训练步骤数量的增加,模型学习识别输入,即,如果输入相似,则模型学习输出接近于零的值,如果输入不同,则模型学习输出接近于 1 的值。所以,

... trained model with 10 epoch gives prediction: "8.jpg": 0.5180479884147644 but the same model trained with 100 epoch gives "8.jpg": 5.579867080537926E-13 However for 100 epoch I have better train results.

,确认模型已获知两个输入相似并输出 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 时随机更改目标变量具有相同的效果。

关于python - 具有两个预训练 ResNet 50 的连体神经网络 - 测试模型时出现奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56323567/

相关文章:

python - 删除文本文件中包含 python 中特定单词/字符串的整行

python - 在没有标准库的情况下嵌入 Python3

python - 如何在 tensorflow 中检查 GPU 是否存在而不生成警告

python-3.x - 如何使用 sklearn 中经过训练的 NB 分类器来预测电子邮件的标签?

python - 尝试实现交叉验证的核心学习模型时遇到问题吗?

python - 使用 Pandas 用另一列的值填充特定列中的空白行

python - (Python/Django) : How do I keep my production db in sync (scheme and data) and with dev pc db?

tensorflow:一级分类

python - 如何在 tensorboard 中显示 Tensorflow 2.0 中的 tf.data.Dataset.map 子图?

machine-learning - 用于文档分类、阈值检测的质心算法