如何使用 Keras 将输入和输出数据放入 Siamese Network?

Posted

技术标签:

【中文标题】如何使用 Keras 将输入和输出数据放入 Siamese Network?【英文标题】:How to fit input and output data into Siamese Network using Keras? 【发布时间】:2021-04-08 17:26:37 【问题描述】:

我正在尝试使用野外标注的人脸(Kaggle 中的 LFW 数据集)实现人脸识别连体网络。

训练数据图像对存储格式为:

ndarray[ndarray[image1,image2],ndarray[image1,image2]...] 等等。图像为 224*224 的 RGB 通道。

有 2200 个训练对,其中 1100 个匹配图像对和 1100 个不匹配图像对。此外,还有 1000 个测试对,其中 500 个匹配图像对和 500 个不匹配图像对。

我设计了具有 VGG-16 架构的 Siamese 网络。模型总结如下:

但是,当我尝试为数据拟合模型时,我收到此错误:

网络的代码是:

from keras.layers import Input,Lambda
from keras import backend as K
from keras.models import Model
from keras.regularizers import l2

IMG_SHAPE=(224,224,3)
BATCH_SIZE=16
EPOCHS=32

def return_siamese_net():

  left_input=Input(IMG_SHAPE)
  right_input=Input(IMG_SHAPE)

  model=Sequential(name="VGG-16")

  #First Layer

  model.add(Conv2D(filters=64,kernel_size=(3,3),activation='relu',padding='same',input_shape=IMG_SHAPE,kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(Conv2D(filters=64,kernel_size=(3,3),activation='relu',padding='same',kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))

  #Second Layer
  model.add(Conv2D(filters=128,kernel_size=(3,3),activation='relu',padding='same',kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(Conv2D(filters=128,kernel_size=(3,3),activation='relu',padding='same',kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))

  #Third Layer
  model.add(Conv2D(filters=256,kernel_size=(3,3),activation='relu',padding='same',kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(Conv2D(filters=256,kernel_size=(3,3),activation='relu',padding='same',kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(Conv2D(filters=256,kernel_size=(3,3),activation='relu',padding='same',kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))

  #Fourth Layer
  model.add(Conv2D(filters=512,kernel_size=(3,3),activation='relu',padding='same',kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(Conv2D(filters=512,kernel_size=(3,3),activation='relu',padding='same',kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(Conv2D(filters=512,kernel_size=(3,3),activation='relu',padding='same',kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))

  #Fifth Layer
  model.add(Conv2D(filters=512,kernel_size=(3,3),activation='relu',padding='same',kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(Conv2D(filters=512,kernel_size=(3,3),activation='relu',padding='same',kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(Conv2D(filters=512,kernel_size=(3,3),activation='relu',padding='same',kernel_initializer='glorot_uniform',kernel_regularizer=l2(1e-4)))
  model.add(MaxPooling2D(pool_size=(2,2),strides=(2,2)))

  #Sixth Layer
  model.add(Flatten())
  model.add(Dense(4096, activation='relu'))

  encoded_l=model(left_input)
  encoded_r=model(right_input)

  lambda_layer= Lambda(lambda tensors:K.abs(tensors[0]-tensors[1]))
  L1_distance = lambda_layer([encoded_l, encoded_r])
  prediction = Dense(1,activation='sigmoid')(L1_distance)
  siamese_net = Model(inputs=[left_input,right_input],outputs=prediction)
  
  return siamese_net


from keras.optimizers import SGD,RMSprop,Adam

optimizer=Adam(lr=0.01)
model.compile(loss='binary_crossentropy',metrics=['accuracy'],optimizer=optimizer)

在下面的 sn-p 中,train_nparr_pairs 有 2200 个匹配和不匹配的图像,而 test_nparr_pairs 有 1000 个匹配和不匹配的图像。 train_labels 和 test_labels 有 0 和 1 基于正对和负对。

history = model.fit([train_nparr_pairs[:, 0], train_nparr_pairs[:, 1]], train_labels,validation_data=([test_nparr_pairs[:, 0], test_nparr_pairs[:, 1]], test_labels),batch_size=BATCH_SIZE, epochs=EPOCHS)

这里有什么我遗漏的吗?

【问题讨论】:

【参考方案1】:

您没有提到制作正负对的代码。据我猜测,您的 make_pair 函数仅返回图像对和标签列表。您需要以 numpy 数组格式返回它们。

def make_pairs(images_val, labels_val):

    pairImages = []
    pairLabels = []
    # Your code for appending the pair of positive and negative images to the list
    
    # return a 2-tuple of our image pairs and labels
    return (np.array(pairImages), np.array(pairLabels))

【讨论】:

以上是关于如何使用 Keras 将输入和输出数据放入 Siamese Network?的主要内容,如果未能解决你的问题,请参考以下文章

使用张量流在 keras 中对损失函数的输入进行切片

如何在 Keras 中训练网络以适应不同的输出大小

Keras:SimpleRNN - 如何在每个时间步进入新输入(而不是使用输出)

如何在 tf.data.Dataset 对象上使用序列/生成器将部分数据放入内存?

深度学习高级,Keras多输入和混合数据实现回归模型

如何在keras tensorflow中将图像作为输入并获取另一个图像作为输出