从 Keras 预训练网络进行图像检索的三元组模型

T.P*_*Poe 5 python conv-neural-network keras tensorflow

我想实现一个图像检索模型。该模型将使用三元组损失函数(与 facenet 或类似架构相同)进行训练。我的想法是使用来自 Keras 的预训练分类模型(例如 resnet50),并使其成为三重架构。这是我在 Keras 中的模型:

resnet_input = Input(shape=(224,224,3))
resnet_model = ResNet50(weights='imagenet', include_top = False, input_tensor=resnet_input)
net = resnet_model.output

net = Flatten(name='flatten')(net) 
net = Dense(512, activation='relu', name='embded')(net)
net = Lambda(l2Norm, output_shape=[512])(net)

base_model = Model(resnet_model.input, net, name='resnet_model')

input_shape=(224,224,3)
input_anchor = Input(shape=input_shape, name='input_anchor')
input_positive = Input(shape=input_shape, name='input_pos')
input_negative = Input(shape=input_shape, name='input_neg')

net_anchor = base_model(input_anchor)
net_positive = base_model(input_positive)
net_negative = base_model(input_negative)

positive_dist = Lambda(euclidean_distance, name='pos_dist')([net_anchor, net_positive])
negative_dist = Lambda(euclidean_distance, name='neg_dist')([net_anchor, net_negative])

stacked_dists = Lambda( 
            lambda vects: K.stack(vects, axis=1),
            name='stacked_dists'
)([positive_dist, negative_dist])

model = Model([input_anchor, input_positive, input_negative], stacked_dists, name='triple_siamese')

def triplet_loss(_, y_pred):
    margin = K.constant(1)
    return K.mean(K.maximum(K.constant(0), K.square(y_pred[0]) - K.square(y_pred[1]) + margin))

def accuracy(_, y_pred):
    return K.mean(y_pred[0] < y_pred[1])

def l2Norm(x):
    return  K.l2_normalize(x, axis=-1)

def euclidean_distance(vects):
    x, y = vects
    return K.sqrt(K.maximum(K.sum(K.square(x - y), axis=1, keepdims=True), K.epsilon()))
Run Code Online (Sandbox Code Playgroud)

该模型应该为每个图像预测一个特征向量。如果图像来自同一类,则这些向量之间的距离(在这种情况下为欧几里得)应该接近于零,如果不是,则接近于 1。

我已经尝试了不同的学习步骤、批量大小、损失函数中的不同边距、从原始 resnet 模型中选择不同的输出层、将不同的层添加到 resnet 的末尾、只训练新添加的层 vs 训练整个模型。我也尝试使用这个没有预训练权重的 resnet 模型,结果仍然相同,大约 0.5 准确度和 1.0 损失,无论我做什么。(输入图像以该模型预期的方式进行了预处理keras.applications.resnet50.preprocess_input

我没有进行任何可能导致收敛缓慢的硬负挖掘,但在这种情况下,0.5 的准确度(检查函数)仍然是随机预测。

所以我开始想也许我在这里错过了一些非常重要的东西(这是一个非常困难的架构)。所以,如果您在我的实现中发现错误或可疑之处,我会非常高兴。

T.P*_*Poe 3

如果有人有兴趣,重写

y_pred[0]y_pred[1]

y_pred[:,0,0]y_pred[:,1,0]

修复。

现在模型似乎正在训练(损失在减少,准确性在增加)。