首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >连体模型不学习任何东西,总是将图像编码成一个零向量

连体模型不学习任何东西,总是将图像编码成一个零向量
EN

Stack Overflow用户
提问于 2019-06-06 21:18:00
回答 1查看 702关注 0票数 0

我正在尝试训练一个暹罗模型来预测两个图像中的单词是否相同。除了这个模型,还应该能够区分两个人的写作。这个问题类似于签名验证问题。

我的基础网络如下所示:

代码语言:javascript
复制
def create_base_network_signet(input_shape):
    '''Base Siamese Network'''

    seq = Sequential()
    seq.add(Conv2D(96, kernel_size=(7,7), strides=2, input_shape= input_shape, activation='relu'))
    seq.add(BatchNormalization())
    seq.add(ZeroPadding2D(padding=(2, 2)))

    seq.add(Conv2D(96, kernel_size=(7,7), strides=1, activation='relu'))
    seq.add(BatchNormalization())
    seq.add(MaxPooling2D(pool_size=(3, 3), strides=2))
    seq.add(ZeroPadding2D(padding=(1, 1)))

    seq.add(Conv2D(128, kernel_size=(5,5), strides=1, activation='relu'))
    seq.add(Conv2D(128, kernel_size=(5,5), strides=1, activation='relu'))
    seq.add(MaxPooling2D(pool_size=(3, 3), strides=2))
    seq.add(Dropout(0.3))
    seq.add(ZeroPadding2D(padding=(1, 1)))

    seq.add(Conv2D(384, kernel_size=(3,3), strides=1, activation='relu'))
    seq.add(Conv2D(256, kernel_size=(3,3), strides=1, activation='relu'))
    seq.add(BatchNormalization())
    seq.add(MaxPooling2D(pool_size=(3,3), strides=2))
    seq.add(Dropout(0.3))
    seq.add(ZeroPadding2D(padding=(1,1)))

    seq.add(Conv2D(128, kernel_size=(2,2), strides=1, activation='relu'))
    seq.add(Dropout(0.3))

    seq.add(Flatten(name='flatten'))
    seq.add(Dense(1024, W_regularizer=l2(0.0005), activation='relu', init='glorot_uniform'))
    seq.add(Dropout(0.4))

    seq.add(Dense(128, W_regularizer=l2(0.0005), activation='relu', init='glorot_uniform')) # softmax changed to relu

    return seq

最终模型(用于对比损失):

代码语言:javascript
复制
base_network = create_base_network_signet(input_shape)
input_a = Input(shape=(input_shape), name="first")
input_b = Input(shape=(input_shape), name="second")

processed_a = base_network(input_a)
processed_b = base_network(input_b)

distance = Lambda(euclidean_distance, output_shape=eucl_dist_output_shape)([processed_a, processed_b])

model = Model(input=[input_a, input_b], output=distance)

除了这个模型,我还尝试了其他更简单的模型作为基础模型。我也尝试过训练像VGG16和盗梦空间这样的模型作为基础模型。在训练所有这些模型时,我遇到了同样的问题。模型最终学习将输入图像编码为零的向量。

我尝试了三重损失和对比损失来训练模型。两者最终都有相同的预测零的问题。对比损失函数取自keras教程。并且三重损失被定义为:

代码语言:javascript
复制
def triplet_loss(y_true, y_pred, alpha = 0.5):
    anchor, positive, negative = y_pred[0], y_pred[1], y_pred[2]
    pos_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, positive)), axis=-1)
    neg_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, negative)), axis=-1)
    basic_loss = tf.add(tf.subtract(pos_dist, neg_dist), alpha)
    loss = tf.reduce_sum(tf.maximum(basic_loss, 0.0))

    return loss

我还想提一下,当我使用binary_crossentropy损失函数训练我的模型时。模型开始学习编码。但是,在准确率达到82%左右后,准确率停止提高,但损失继续减少。

这是在三重损失和对比损失的情况下输出编码的样子:

我的训练数据如下所示:

EN

回答 1

Stack Overflow用户

发布于 2019-06-07 18:45:33

我在我的一个使用triplet loss训练的暹罗网络中也遇到了同样的问题。对我来说,诀窍是从loss = tf.reduce_sum(tf.maximum(basic_loss, 0.0))行中删除tf.reduce_sum()部件。我的三元组损失代码的相关片段如下。

代码语言:javascript
复制
# distance between the anchor and the positive
pos_dist = K.sum(K.square(anchor-positive),axis=1)

# distance between the anchor and the negative
neg_dist = K.sum(K.square(anchor-negative),axis=1)

# compute loss
basic_loss = pos_dist-neg_dist+alpha
loss = K.maximum(basic_loss,0.0)

最后,在编译模型时,请执行以下操作。

model.compile(optimizer=Adam(), loss=triplet_loss)

我相信当triplet_loss作为loss时,keras在训练中会照顾到reduce_sum()的部分。

试试这个,看看是否有帮助。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56478458

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档