【问题标题】:Keras Model for Siamese Network not Learning and always predicting the same ouput暹罗网络的 Keras 模型不学习并且总是预测相同的输出
【发布时间】:2020-04-14 00:15:10
【问题描述】:

我正在尝试使用 Keras 训练 Siamese 神经网络,目的是识别 2 张图像是否属于同一类。我的数据被打乱了,正例和负例的数量相等。我的模型没有学习任何东西,它总是预测相同的输出。我每次都得到相同的损失、验证准确性和验证损失。

Training Output

def convert(row):
    return imread(row)

def contrastive_loss(y_true, y_pred):
    margin = 1
    square_pred = K.square(y_pred)
    margin_square = K.square(K.maximum(margin - y_pred, 0))
    return K.mean(y_true * square_pred + (1 - y_true) * margin_square)

def SiameseNetwork(input_shape):
    top_input = Input(input_shape)

    bottom_input = Input(input_shape)

    # Network
    model = Sequential()
    model.add(Conv2D(96,(7,7),activation='relu',input_shape=input_shape))
    model.add(MaxPooling2D())
    model.add(Conv2D(256,(5,5),activation='relu',input_shape=input_shape))
    model.add(MaxPooling2D())
    model.add(Conv2D(256,(5,5),activation='relu',input_shape=input_shape))
    model.add(MaxPooling2D())
    model.add(Flatten())
    model.add(Dense(4096,activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(1024,activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(512,activation='relu'))
    model.add(Dropout(0.5))

    encoded_top = model(top_input)
    encoded_bottom = model(bottom_input)

    L1_layer = Lambda(lambda tensors:K.abs(tensors[0] - tensors[1]))    
    L1_distance = L1_layer([encoded_top, encoded_bottom])

    prediction = Dense(1,activation='sigmoid')(L1_distance)
    siamesenet = Model(inputs=[top_input,bottom_input],outputs=prediction)
    return siamesenet

data = pd.read_csv('shuffleddata.csv')
print('Converting X1....')

X1 = [convert(x) for x in data['X1']]

print('Converting X2....')

X2 = [convert(x) for x in data['X2']]

print('Converting Y.....')
Y = [0 if data['Y'][i] == 'Negative' else 1 for i in range(len(data['Y']))]

input_shape = (53,121,3,)
model = SiameseNetwork(input_shape)
model.compile(loss=contrastive_loss,optimizer='sgd',metrics=['accuracy'])
print(model.summary())
model.fit(X1,Y,batch_size=32,epochs=20,shuffle=True,validation_split = 0.2)
model.save('Siamese.h5')

【问题讨论】:

  • 您是否尝试过使用较小的步长(甚至是不同的优化器)?您是否尝试过对数据集的一小部分进行过拟合?
  • 是的,我尝试过使用更小的步长以及不同的优化器和损失函数。我也尝试过拟合小数据,但模型没有学到任何东西。您能否检查一下我输入的方式是否正确?
  • 嗯嗯,你调用L1_distance的层我猜应该是连体网络的2个输出之间的距离,但这里是一个错误图。您需要计算平均 l1 差异,例如:Lambda(lambda tensors: K.mean(K.abs(tensors[0] - tensors[1])))。我也很惊讶你在这层之后有一个致密层。输出不应该只是距离吗?
  • 我已经尝试使用您的 L1 距离版本,并且还删除了密集层,但它没有工作,顺便说一下,我需要给定的 2 个图像有多相似的概率,它们之间没有任何距离图片
  • 当然有道理。我只是认为这可能更简单,您可以删除 Dense 层并在对比损失中使用 sigmoid,但我已经看到您使用的实现,我知道您想坚持下去。

标签: python tensorflow keras neural-network


【解决方案1】:

为了社区的利益,在本节中提及此问题的解决方案(即使它出现在评论部分)。

由于模型与其他标准数据集配合良好,解决方案是使用更多数据。模型没有在学习,因为它用于训练的数据较少。

【讨论】:

  • 感谢您的回答。但我认为 Siamese 旨在处理少量数据并提供良好的结果。据我所知,它用于需要很少量数据的一些镜头学习。那么数据是如何成为问题的呢?我在 AT&T 数据集上训练时遇到了同样的问题,它有 40 个人的 400 张图像。我使用 Pytorch 用这些数据训练了一个模型,该模型正在学习并给了我很好的结果。当我使用 keras 模型在同一数据集上进行训练时,它没有学到任何东西。你知道吗?
【解决方案2】:

模型在 cmets 和 Tensorflow Support 的回答中提到的更多数据工作正常。稍微调整模型也很有效。将第 2 和第 3 卷积层中的过滤器数量从 256 更改为 64 会大量减少可训练参数的数量,因此模型开始学习。

【讨论】:

    【解决方案3】:

    我想在这里提一些可能对其他人有用的事情:

    1) 数据分层/随机抽样

    当您使用validation_split 时,Keras 使用最后 x% 的数据作为验证数据。这意味着如果数据按类排序,例如因为“pairs”或“tripletts”是按顺序生成的,所以验证数据将仅来自最后 x% 数据中包含的类(或类)。在这种情况下,验证集将毫无用处。因此必须对输入数据进行混洗,以确保验证集包含来自每个类别的随机样本。

    validation_split 的文档说:

    在 0 和 1 之间浮动。要用作训练数据的分数 验证数据。该模型将区分这部分 训练数据,不会对其进行训练,并将评估损失和 每个时期结束时有关此数据的任何模型指标。这 验证数据是从 x 和 y 数据中的最后一个样本中选择的 提供,在洗牌之前

    2) 优化器的选择

    model.compile() 中选择optimizer='sgd' 可能不是最好的方法,因为sgd 可能会陷入局部最小值等。Adam (see docs) 似乎是一个不错的选择,因为它.. .

    [...] 结合了 [...] AdaGrad 处理稀疏的优点 梯度,以及 RMSProp 处理非平稳的能力 目标。

    根据Kingma and Ba(2014 年,第 10 页)。

    from keras.optimizers import Adam
    ...
    model.compile(loss=contrastive_loss, optimizer=keras.optimizers.Adam(lr=0.0001))
    

    3) 提前停止/学习率

    在训练期间使用early stoppingadjusting the learning rate 也可能对取得良好结果非常有用。所以模型可以训练直到没有更多成功(在这种情况下自动停止)。

    from keras.callbacks import EarlyStopping
    from keras.callbacks import ReduceLROnPlateau
    ...
    early_stopping = EarlyStopping(monitor='val_loss', patience=50, mode='auto', restore_best_weights=True)
    reduce_on_plateau = ReduceLROnPlateau(monitor="val_loss", factor=0.8, patience=15, cooldown=5, verbose=0)
    ...
    hist = model.fit([img_1, img_2], y, 
                validation_split=.2, 
                batch_size=128, 
                verbose=1, 
                epochs=9999,
                callbacks=[early_stopping])
    

    4) 内核初始化

    内核初始化(使用较小的 SD)也可能会有所帮助。

    # Layer 1
        seq.add(Conv2D(8, (5,5), input_shape=input_shape, 
            kernel_initializer=keras.initializers.TruncatedNormal(mean=0.0, stddev=0.01, seed=None), 
            data_format="channels_first"))
        seq.add(Activation('relu'))
        seq.add(MaxPooling2D(pool_size=(2, 2))) 
        seq.add(Dropout(0.1))
    

    5) 过拟合

    我注意到,与其使用 dropout 来对抗过度拟合,不如添加一些噪声会很有帮助。在这种情况下,只需在网络顶部添加一些 GaussianNoise

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-07
      • 2022-06-16
      • 1970-01-01
      • 2022-12-09
      • 2020-05-27
      • 2018-09-13
      • 2018-11-16
      相关资源
      最近更新 更多