第二章 使用孪生网络进行人脸识别

tech2023-05-18  106

孪生网络是一种基于度量的单样本学习算法,主要用于各类别数据点较少的应用中。孪生网络大致上两个对称的神经网络组成,具有相同的权重和架构,最后由能量函数E连接在一起。孪生网络的目的是了解两个输入值是否相似。

                                                      

使用孪生网络进行人脸识别

# encoding=utf-8 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 def read_image(filename, byteorder='>'): ''' 读取输入图像,返回一个Numpy数组 ''' # 首先将图像以raw格式读入缓冲区 with open(filename, 'rb') as f: buffer = f.read() # 使用正则表达式获取图片的头部、宽度、高度、最大值 header, width, height, maxval = re.search( b"(^P5\s(?:\s*#.*[\r\n])*" b"(\d+)\s(?:\s*#.*[\r\n])*" b"(\d+)\s(?:\s*#.*[\r\n])*" b"(\d+)\s(?:\s*#.*[\r\n]\s)*)", buffer).groups() # 使用np.frombuffer(该函数将缓冲区转换为一维数组)将图像转换为numpy数组 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("./1.pgm") img = read_image('./1.pgm') ind2 = np.random.randint(40) print(ind2) size = 2 total_sample_size = 10000 def get_data(size, total_sample_size): ''' 生成数据,对于孪生网络,数据应该是成对的(正和负),并带有二元标签 :param size: :param total_sample_size: :return: ''' # 读取图像 image = read_image('data/orl_faces/s' + str(1) + '/' + str(1) + '.pgm', 'rw+') # 缩减尺寸为原来的一半 image = image[::size, ::size] # 获取新尺寸 dim1 = image.shape[0] dim2 = image.shape[1] count = 0 # 初始化numpy数组 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 # 从同一个目录读取图像(正样本对) while ind1 == ind2: ind1 = np.random.randint(10) ind2 = np.random.randint(10) # 读取两张图像 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+') # 缩减尺寸 img1 = img1[::size, ::size] img2 = img2[::size, ::size] # 将图像存入初始化好的numpy数组中 x_geuine_pair[count, 0, 0, :, :] = img1 x_geuine_pair[count, 1, 0, :, :] = img2 # 因为从同一目录中取出,所以为正样本对,标签为1 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): # 从不同的目录读取图像(负样本对) while True: ind1 = np.random.randint(40) # 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 # 因为是从不同的目录取出,所以分配标签为0 y_imposite[count] = 0 count += 1 # 将正样本对和负样本对拼接 X = np.concatenate([x_geuine_pair, x_imposite_pair], axis=0) / 255 Y = np.concatenate([y_genuine, y_imposite], axis=0) return X, Y X, Y = get_data(size, total_sample_size) # 生成完数据并检查数据大小,拼接完后,有10000个正样本对和10000个负样本对 x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=.25) #将数据打乱分成75%的训练数据和25%的测试数据 def build_base_network(input_shape): ''' 构建孪生网络,首先定义基网络,是一个特征提取的卷积网络,建立两个带有Relu激活函数和最大池化的卷积层和扁平化层 ''' 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) # 得到图像对的特征向量,接下来输入欧氏距离能量函数,计算出距离 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 = RMSprop() model = Model(input=[img_a, img_b], output=distance) 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] img2 = x_train[:, 1] model.fit([img_1, img2], 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)