zoukankan      html  css  js  c++  java
  • 使用暹罗{(Xiānluó),泰国的旧称 one-shot} 网络进行人脸识别

    什么是暹罗网络?

    暹罗网络是一种特殊类型的神经网络,是最简单、最常用的one-shot学习算法之一。

    one-shot学习是一种每类只从一个训练例子中学习的技术。

    暹罗网络主要用于在每个类中没有很多数据点的应用程序中。

    为什么要使用暹罗网络?

    例如,假设我们想为我们的组织建立一个人脸识别模型,大约有500人在我们的组织中工作。如果我们想用卷积神经网络(CNN)从零开始建立人脸识别模型,那么我们需要这500个人的很多图像来训练网络,以获得良好的准确度。但是很明显,我们不会为这500个人提供太多的图像,所以使用卷积神经网络(CNN)或任何深度学习算法来建立模型是不可行的,除非我们有足够的数据点。因此,在这种情况下,我们可以使用复杂的one-shot学习算法,比如暹罗网络,它可以从更少的数据点学习。

    暹罗网络是如何运作的?

    使用暹罗网络进行人脸识别

     

    但是暹罗网络是如何运作的呢?暹罗网络基本上由两个对称的神经网络组成,它们具有相同的权值和结构,并在最后使用一些能量函数E连接在一起。暹罗网络的目标是了解两个输入值是相似还是不相似。比如我们有两幅图像,X1和X2,我们想知道这两幅图像是相似还是不相似的。

    暹罗网络不仅用于人脸识别,而且还广泛用于我们没有很多数据点和任务的应用中,我们需要学习两个输入之间的相似性。暹罗网络的应用包括签名验证,类似问题检索,对象跟踪等。我们将在接下来的部分详细研究暹罗网络。

    暹罗网络的体系结构

    使用暹罗网络进行人脸识别

     

    如图所示,暹罗网络由两个相同的网络组成,它们共享相同的权重和体系结构。假设我们有两个输入,X1和X2。我们将输入X1馈送到网络A,即fw(X1),我们将输入X2馈送到网络B,即fw(X2)。正如您将注意到的,这两个网络具有相同的权重w,它们将为我们的输入X1和X2生成嵌入。然后,我们将这些嵌入提供给能量函数E,这将使我们在两个输入之间具有相似性。

    它可以表示如下:

    使用暹罗网络进行人脸识别

     

    暹罗网络的输入应该是成对的(X1, X2),以及它们的二进制标签Y∈(0,1),说明输入对是genuine pair(相同)还是 imposite pair(不同) 。正如您在下表中看到的那样,我们将句子作为成对使用,Label表示句子对是genuine (1)还是imposite(0):

    使用暹罗网络进行人脸识别

     

    暹罗网络使用相同的体系结构,通过查找两个输入值之间的相似性来学习。在涉及计算两个实体之间相似性的任务中,它是最常用的few-shot学习算法之一。它功能强大、健壮,可以作为低数据问题的解决方案。

    使用Siamese网络进行人脸识别

    我们将通过构建人脸识别模型来创建Siamese网络。我们网络的目标是了解两个人脸是相似还是不相似。我们使用面部的AT&T数据库,可以从这里下载:https://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html。

    下载并解压缩归档后,您可以看到文件夹s1,s2,直到s40,如下所示:

    使用暹罗网络进行人脸识别

     

    这些文件夹中的每一个都具有从不同角度拍摄的单个人的10个不同图像。例如,让我们打开文件夹s1。如您所见,一个人有10个不同的图像:

    使用暹罗网络进行人脸识别

     

    我们打开并检查文件夹s13:

    使用暹罗网络进行人脸识别

     

    我们将从同一个文件夹随机取两张图片,并将它们标记为genuine对,我们将从两个不同的文件夹取一张图片,并将它们标记为imposite对。

    使用暹罗网络进行人脸识别

     

    首先,我们将导入所需的Python库:

    import re
    import numpy as np
    from PIL import Image
    from sklearn.model_selection import train_test_split
    from keras import backend as K
    from keras.layers import Activation
    from keras.layers import Input, Lambda, Dense, Dropout, Convolution2D, MaxPooling2D, Flatten
    from keras.models import Sequential, Model
    from keras.optimizers import RMSprop
    使用暹罗网络进行人脸识别

     

    现在,我们定义一个函数来读取输入图像。read_image函数以图像为输入,返回一个NumPy数组:

    def read_image(filename, byteorder='>'):

    #first we read the image, as a raw file to the buffer
    with open(filename, 'rb') as f:
    buffer = f.read()

    #using regex, we extract the header, width, height and maxval of the image
    header, width, height, maxval = re.search(
    b"(^P5s(?:s*#.*[ ])*"
    b"(d+)s(?:s*#.*[ ])*"
    b"(d+)s(?:s*#.*[ ])*"
    b"(d+)s(?:s*#.*[ ]s)*)", buffer).groups()

    #then we convert the image to numpy array using np.frombuffer which interprets buffer as one dimensional array
    return np.frombuffer(buffer,
    dtype='u1' if int(maxval) < 256 else byteorder+'u2',
    count=int(width)*int(height),
    offset=len(header)
    ).reshape((int(height), int(width)))
    使用暹罗网络进行人脸识别

     

    让我们打开一个图像:

    Image.open("data/orl_faces/s1/1.pgm")
    使用暹罗网络进行人脸识别

     

    img = read_image('data/orl_faces/s1/1.pgm')
    img.shape
    使用暹罗网络进行人脸识别

     

    (112, 92)

    最后,我们将x_genuine_pair和x_imposite连接到X, y_genuine和y_imposite连接到Y:

    size = 2
    total_sample_size = 10000
    def get_data(size, total_sample_size):
    #read the image
    image = read_image('data/orl_faces/s' + str(1) + '/' + str(1) + '.pgm', 'rw+')
    #reduce the size
    image = image[::size, ::size]
    #get the new size
    dim1 = image.shape[0]
    dim2 = image.shape[1]
    count = 0

    #initialize the numpy array with the shape of [total_sample, no_of_pairs, dim1, dim2]
    x_geuine_pair = np.zeros([total_sample_size, 2, 1, dim1, dim2]) # 2 is for pairs
    y_genuine = np.zeros([total_sample_size, 1])

    for i in range(40):
    for j in range(int(total_sample_size/40)):
    ind1 = 0
    ind2 = 0

    #read images from same directory (genuine pair)
    while ind1 == ind2:
    ind1 = np.random.randint(10)
    ind2 = np.random.randint(10)

    # read the two images
    img1 = read_image('data/orl_faces/s' + str(i+1) + '/' + str(ind1 + 1) + '.pgm', 'rw+')
    img2 = read_image('data/orl_faces/s' + str(i+1) + '/' + str(ind2 + 1) + '.pgm', 'rw+')

    #reduce the size
    img1 = img1[::size, ::size]
    img2 = img2[::size, ::size]

    #store the images to the initialized numpy array
    x_geuine_pair[count, 0, 0, :, :] = img1
    x_geuine_pair[count, 1, 0, :, :] = img2

    #as we are drawing images from the same directory we assign label as 1. (genuine pair)
    y_genuine[count] = 1
    count += 1
    count = 0
    x_imposite_pair = np.zeros([total_sample_size, 2, 1, dim1, dim2])
    y_imposite = np.zeros([total_sample_size, 1])

    for i in range(int(total_sample_size/10)):
    for j in range(10):

    #read images from different directory (imposite pair)
    while True:
    ind1 = np.random.randint(40)
    ind2 = np.random.randint(40)
    if ind1 != ind2:
    break

    img1 = read_image('data/orl_faces/s' + str(ind1+1) + '/' + str(j + 1) + '.pgm', 'rw+')
    img2 = read_image('data/orl_faces/s' + str(ind2+1) + '/' + str(j + 1) + '.pgm', 'rw+')
    img1 = img1[::size, ::size]
    img2 = img2[::size, ::size]
    x_imposite_pair[count, 0, 0, :, :] = img1
    x_imposite_pair[count, 1, 0, :, :] = img2
    #as we are drawing images from the different directory we assign label as 0. (imposite pair)
    y_imposite[count] = 0
    count += 1

    #now, concatenate, genuine pairs and imposite pair to get the whole data
    X = np.concatenate([x_geuine_pair, x_imposite_pair], axis=0)/255
    Y = np.concatenate([y_genuine, y_imposite], axis=0)
    return X, Y
    使用暹罗网络进行人脸识别

     

    使用暹罗网络进行人脸识别

     

    现在,我们生成数据并检查数据大小。如你所见,我们有20,000个数据点,其中10,000对是genuine pairs,10,000对是imposite pairs:

    X, Y = get_data(size, total_sample_size)
    X.shape
    Y.shape
    使用暹罗网络进行人脸识别

     

    (20000, 2, 1, 56, 46)

    (20000, 1)

    接下来,我们将训练和测试的数据分成75%的训练和25%的测试比例:

    x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=.25)

    现在我们已经成功地生成了我们的数据,我们构建了我们的暹罗网络。首先,我们定义基本网络,它基本上是一个用于特征提取的卷积网络。我们构建了两个卷积层,其中包含ReLU激活和最大池化,然后是flat层:

    def build_base_network(input_shape):

    seq = Sequential()

    nb_filter = [6, 12]
    kernel_size = 3


    #convolutional layer 1
    seq.add(Convolution2D(nb_filter[0], kernel_size, kernel_size, input_shape=input_shape,
    border_mode='valid', dim_ordering='th'))
    seq.add(Activation('relu'))
    seq.add(MaxPooling2D(pool_size=(2, 2)))
    seq.add(Dropout(.25))

    #convolutional layer 2
    seq.add(Convolution2D(nb_filter[1], kernel_size, kernel_size, border_mode='valid', dim_ordering='th'))
    seq.add(Activation('relu'))
    seq.add(MaxPooling2D(pool_size=(2, 2), dim_ordering='th'))
    seq.add(Dropout(.25))
    #flatten
    seq.add(Flatten())
    seq.add(Dense(128, activation='relu'))
    seq.add(Dropout(0.1))
    seq.add(Dense(50, activation='relu'))
    return seq
    使用暹罗网络进行人脸识别

     

    接下来,我们将图像对提供给基础网络,基础网络将返回嵌入,即特征向量:

    input_dim = x_train.shape[2:]
    img_a = Input(shape=input_dim)
    img_b = Input(shape=input_dim)
    base_network = build_base_network(input_dim)
    feat_vecs_a = base_network(img_a)
    feat_vecs_b = base_network(img_b)
    使用暹罗网络进行人脸识别

     

    feat_vecs_a和feat_vecs_b是我们图像对的特征向量。接下来,我们将这些特征向量提供给能量函数以计算它们之间的距离,我们使用欧氏距离作为我们的能量函数:

    def euclidean_distance(vects):
    x, y = vects
    return K.sqrt(K.sum(K.square(x - y), axis=1, keepdims=True))
    def eucl_dist_output_shape(shapes):
    shape1, shape2 = shapes
    return (shape1[0], 1)
    distance = Lambda(euclidean_distance, output_shape=eucl_dist_output_shape)([feat_vecs_a, feat_vecs_b])
    使用暹罗网络进行人脸识别

     

    现在,我们将epochs设置为13,我们使用RMS prop进行优化并定义我们的模型:

    epochs = 13
    rms = RMSprop()
    model = Model(input=[input_a, input_b], output=distance)
    使用暹罗网络进行人脸识别

     

    接下来,我们将loss函数定义为contrastive_loss函数,并编译机器学习模型:

    def contrastive_loss(y_true, y_pred):
    margin = 1
    return K.mean(y_true * K.square(y_pred) + (1 - y_true) * K.square(K.maximum(margin - y_pred, 0)))
    model.compile(loss=contrastive_loss, optimizer=rms)
    使用暹罗网络进行人脸识别

     

    现在,我们训练我们的机器学习模型:

    img_1 = x_train[:, 0]
    img_2 = x_train[:, 1]
    model.fit([img_1, img_2], y_train, validation_split=.25, batch_size=128, verbose=2, nb_epoch=epochs)
    使用暹罗网络进行人脸识别

     

    现在,我们使用测试数据进行预测:

    pred = model.predict([x_test[:, 0], x_test[:, 1]])

    接下来,我们定义一个计算准确度的函数:

    def compute_accuracy(predictions, labels):
    return labels[predictions.ravel() < 0.5].mean()
    使用暹罗网络进行人脸识别

     

    机器学习模型的准确性:

    compute_accuracy(pred, y_test)

    0.9779092702169625

  • 相关阅读:
    深入理解JVM内幕:从基本结构到Java 7新特性
    通过Java反射做实体查询
    Hadoop教程(一)
    很不错的js特效
    java utf8字符 导出csv 文件的乱码问题。
    spring MVC使用Interceptor做用户登录判断
    Bootstrap--全局css样式之图片
    Bootstrap-全局css样式之按钮
    Bootstrap--全局css样式之表单
    Bootstarp--全局CSS样式之表格
  • 原文地址:https://www.cnblogs.com/wuhh123/p/11004808.html
Copyright © 2011-2022 走看看