基于改进孪生网络的人脸识别方法(讲解+代码V1.0)

作为一个有“算法梦”的物理系渣渣,在读研期间水了一篇国内普刊的算法也算过足了瘾,最近工作之余,将当时的论文主体复现并讲解一下。

                                                                                                                                                                                              ———不要脸的作者君

【注1】由于本人水平有限,且不是“该领域的专业”硕士,本文只适合本科毕设、水普刊/EI会议论文、CV的入门人士或爱好者。如有不妥之处,可以评论区斧正,万分感谢!

【注2】本篇将略微介绍一些概念+代码讲解及浮现,完整代码见最后。我记得当时还做了一个系统还是什么来着,这篇文章先不讲,系统我会单独发一篇。

【注3】2023.12-2024.3 私信咨询我的朋友们很抱歉,之前不是秋招就是改论文,毕设,好久没上线了。有问题评论区交流,后续发布的代码都会写完整的使用方法。

1.  基本概念

1.1  人脸识别

人脸识别技术(Face recognition technology)是一种基于人的面部特征信息进行身份识别的技术。这一技术包含多个步骤,主要包括人脸图像获取、人脸定位、人脸特征提取以及人脸比对四个核心步骤。以下是对这些步骤的简要介绍:

(1)人脸图像获取:这是人脸识别过程中的第一步,包括使用摄像头或其他成像设备捕获人脸图像。这些图像可以是静态的照片或动态的视频序列。

(2)人脸定位:在获取的图像中确定人脸的位置,包括人脸的大小和角度。这个过程可能需要检测图像中的多张脸,并对每张脸分别进行处理。

(3)人脸特征提取:从定位的人脸中提取能够唯一标识个体的特征,如眼睛、鼻子、嘴巴的位置和大小,脸部轮廓等。这些特征被转换成一种能够代表人脸的数值形式,这一过程中,算法的选择对识别效果有很大影响。

(4)人脸比对:将提取出的人脸特征与数据库中的数据进行比对,确定身份。这个过程可以通过一对一(1:1)的验证方式来完成,比如解锁智能手机,或者通过一对多(1:N)的识别方式来完成,如机场的安检通道。

本篇主要讲解的是(3)和(4)的实现,因为一般来说,在有数据集的情况下,(1)一般和系统一起使用,(2)在实验室数据集中都是处理好的。

1.2  孪生网络

孪生网络(Siamese Network)是一种特殊的神经网络架构,主要用于解决相似性比较问题,比如人脸识别、签名验证或物体追踪等。孪生网络通过对两个输入数据进行特征提取,并比较这些特征来判断两个输入是否相似。其核心思想是两个相同的子网络共享相同的参数,这两个子网络可以并行处理两个不同的输入数据,输出这两个输入数据的特征表示。

图1  孪生网络论文原图
  1. 子网络:孪生网络由两个完全相同的网络组成,它们有相同的配置(层数和类型)、参数(权重和偏差)。这种结构确保了两个网络对输入数据的处理方式完全相同。
  2. 特征提取器:每个子网络都充当特征提取器,将输入数据转换为特征向量。特征提取器的构建通常基于卷积神经网络(CNN)或循环神经网络(RNN),取决于输入数据的类型。
  3. 比较机制:网络的输出是两个特征向量,比较机制对这两个向量进行比较,以判断输入是否相似。比较的方式可以是计算两个特征向量的欧式距离、余弦相似度或使用专门的比较层。

【注4】这里说的不是伪孪生网络(pseudo-siamese network),伪孪生网络可以由任意的两个神经网络拼接而成。

2.  数据集相关

2.1  数据集获取

AT&T是一个开源的小样本人脸识别数据集,一共有40组,每组有10张照片。你可以从官方网站、kaggle或者是下面的连接中下载。这些文件是PGM格式的,可以使用'xv'程序在UNIX (TM)系统上方便地查看。每个图像的大小为92x112像素,每个像素有256个灰度级。

Kaggle官方数据集--网络可能存在卡顿icon-default.png?t=N7T8https://www.kaggle.com/datasets/kasikrit/att-database-of-faces

csdn数据链接--适合国内用户icon-default.png?t=N7T8https://download.csdn.net/download/qq_40981869/89021867?spm=1001.2014.3001.5501

2.2  数据集预处理

这里的数据集预处理,大致分为两个部分。第一个是对这个数据集格式的问题,如下图2所示,可以看到原数据集的格式是pgm。另一个是

图2  数据集格式

【注5】额,这句话是针对之前那篇比较浅显文章的,当时用的是原始数据集,没有处理成pgm格式,如果你使用的是本文的数据集直接进行下一步。

首先使用下面这个函数导入全部数据,格式为(40, 10, 112, 92),如果没有使用我的项目记得修改路径。这个代码运行后会生成一个矩阵数据文件,后续进行操作可以直接使用矩阵文件进行调用。

datasetFaces = []

for person in range(1, 41):
    temp = []

    for pose in range(1, 11):
        data = plt.imread('../data/s' + str(person) + '/' + str(pose) + '.pgm')
        temp.append(data)

    datasetFaces.append(np.array(temp))

datasetFaces = np.array(datasetFaces)
np.save('datasetFacesORL.npy', datasetFaces)

print('Total number of datasets:', len(datasetFaces))
print('Dataset size:', datasetFaces.shape)

 使用这个代码,简单可视化一下,在ipython里看数据集好丑:

datasetFaces = np.load('../data_Generated/datasetFacesORL.npy')
fig, axes = plt.subplots(datasetFaces.shape[0], datasetFaces.shape[1], figsize=(20, 40))

for person in range(datasetFaces.shape[0]):
    for pose in range(datasetFaces.shape[1]):
        axes[person, pose].imshow(datasetFaces[person, pose], cmap='gray')
        axes[person, pose].axis('off')
        axes[person, pose].set_title(f'Person {person + 1}\nPose {pose + 1}', fontsize=8)

plt.tight_layout()
plt.show()
图3  数据集可视化分析

2.3  图像对建立

这部分之前在另一篇文章中讲述过,孪生网络建立的图像对就是将相同的一类打一个标签,不相同的一类打一个标签。这种思路一直延伸到所有的度量学习分类器的建设中。如下公式所示,当结果为0的时候是相同类别,当结果为1的时候是不同类别。

S=d_\theta\left(x_i,x_j\right)

好的,在我们知晓基本原理的之后,来根据这个思路建立图像对。在下面代码中,有英文注释,讲解了具体的代码定义。在这里,使用的时候只需要定义size和total_sample_size的值即可,一般来说size=2(正负对,设定为2就完事了。)

def get_data_from_npy(size, total_sample_size, dataset_path='../data_Generated/datasetFacesORL.npy'):
    # Load the dataset
    data = np.load(dataset_path)

    # Reduce the size of the images
    data = data[:, :, ::size, ::size]

    # Get the new size
    dim1 = data.shape[2]
    dim2 = data.shape[3]

    count = 0

    # Initialize the numpy arrays for storing pairs
    x_genuine_pair = np.zeros([total_sample_size, 2, 1, dim1, dim2])  # 2 is for pairs
    y_genuine = np.ones([total_sample_size, 1])  # Genuine pairs have label 1

    x_imposite_pair = np.zeros([total_sample_size, 2, 1, dim1, dim2])
    y_imposite = np.zeros([total_sample_size, 1])  # Impostor pairs have label 0

    # Generate genuine pairs
    for i in range(40):
        for j in range(int(total_sample_size / 40)):
            while True:
                ind1, ind2 = np.random.randint(10, size=2)
                if ind1 != ind2:
                    break

            x_genuine_pair[count, 0, 0, :, :] = data[i, ind1]
            x_genuine_pair[count, 1, 0, :, :] = data[i, ind2]
            count += 1

    # Reset count for impostor pairs
    count = 0

    # Generate impostor pairs
    for i in range(int(total_sample_size / 10)):
        for j in range(10):
            while True:
                ind1, ind2 = np.random.randint(40, size=2)
                if ind1 != ind2:
                    break

            img1 = data[ind1, j]
            img2 = data[ind2, j]

            x_imposite_pair[count, 0, 0, :, :] = img1
            x_imposite_pair[count, 1, 0, :, :] = img2
            count += 1

    # Concatenate genuine and impostor pairs
    X = np.concatenate([x_genuine_pair, x_imposite_pair], axis=0) / 255
    Y = np.concatenate([y_genuine, y_imposite], axis=0)

    return X, Y

找个地方测试一下,正常来说可以得到如下的结果:

图4  图像对正确输出结果

 2.4  数据集划分

这个就属于常规操作了,孪生网络本质上还是属于监督学习,因此还是使用常规的数据划分手段。具体代码实现如下所示:

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

3.  原始网络实现与分析

3.1  原始网络搭建

这里所说的原始网络,实际上就是一般讲解书中,或者是原文中所提到的基干网络,我们可以使用分析手段运行下,看看这个图是啥子样子。

def build_base_network(input_shape):
    seq = Sequential()

    nb_filter = [6, 12]
    kernel_size = (3, 3)  # 使用元组定义kernel_size

    # convolutional layer 1
    seq.add(Conv2D(nb_filter[0], kernel_size, input_shape=input_shape, padding='valid', data_format='channels_last'))
    seq.add(Activation('relu'))
    seq.add(MaxPooling2D(pool_size=(2, 2)))
    seq.add(Dropout(0.25))

    # convolutional layer 2
    seq.add(Conv2D(nb_filter[1], kernel_size, padding='valid', data_format='channels_last'))
    seq.add(Activation('relu'))
    seq.add(MaxPooling2D(pool_size=(2, 2)))
    seq.add(Dropout(0.25))

    # flatten
    seq.add(Flatten())
    seq.add(Dense(128, activation='relu'))
    seq.add(Dropout(0.1))
    seq.add(Dense(50, activation='relu'))
    return seq

 对于这个基干网络的图结构如下所示,我这里使用的是plot_model方法,这个方法需要配置graphviz 和pydot 。

图5  原始基干网络结构

【注6】2022年开始写上面说到的小论文的时候,我记得用的是tf2.8还是2.9,由于当时的代码找不到了(随着上一台电脑gg)在写本篇文章的时候,该代码是使用的python3.9+tensorflow2.16。所以这里会有些问题,比若说下图中的form keras,我记得之前还是哪个版本用的是 from tensorflow.keras 如果说环境报错,自己修改一下。

【注7】如果配置graphviz 和pydot报错,可以尝试以下几种方法:

  1. pip install pydotplus
  2. 如果使用1中的办法,pydot没报错,开始报错graphviz了,则按照提示去官网下载graphviz安装,我安装的10.1版本,记得去path里配置路径。

3.2  距离函数搭建

在距离函数的搭建时,有两种思路,一个是使用Lambda来计算欧式距离,一个是将欧式距离化为keras层结构。这里分别展示,各位可以根据自己的喜好选择。

(1)Lambda方法

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)

(2)层结构

class EuclideanDistanceLayer(Layer):
    def __init__(self, **kwargs):
        super(EuclideanDistanceLayer, self).__init__(**kwargs)

    def call(self, inputs):
        x, y = inputs
        return K.sqrt(K.sum(K.square(x - y), axis=1, keepdims=True))

    def compute_output_shape(self, input_shape):
        shape1, shape2 = input_shape
        return (shape1[0], 1)

3.3  模型搭建与训练

好,现在可以开始搭建模型训练的架构。我们按照顺序依次:导入数据-->构建图像对-->导入基干网络-->定义流程-->开始训练,前三个已经讲过了,这一节讲述流程定义。按照孪生网络定义,在一次训练过程中,一组图像对的两章图片,分别进入左右两个网络中。具体实现如下所示:

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)

之前,我们在上面的距离函数使用了两种编码形式,因此在这里也是两种编码形式

(1)Lambda方法

distance = Lambda(euclidean_distance, output_shape=eucl_dist_output_shape)([feat_vecs_a, feat_vecs_b])

(2)层结构

distance = EuclideanDistanceLayer()([feat_vecs_a, feat_vecs_b])

 之后,就是比较常规的:连接整个模型、定义优化器、定义损失函数。

(1)连接整个模型(层结构):

from keras.models import Model
model = Model(inputs=[img_a, img_b], outputs=distance)

(2)优化器与损失函数,这里都使用的是第一个浮现论文的兄弟的原版参数,可以根据需要自行修改。

# 优化器
from keras.optimizers import RMSprop

# 损失函数
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=RMSprop(learning_rate=0.001))

【注8】 补充acc指标:在原有代码中,只在测试集给出了acc的值,这对于我们观察训练是比较不友好的,因此可以补充acc的指标,并将其放在模型编译中。

好的,一切就绪之后,可以开始模型训练,模型的训练很简单,代码如下:

img_1 = x_train[:, 0]
img_2 = x_train[:, 1]

model.fit([img_1, img_2], y_train, validation_split=.25, epochs=15,
          batch_size=128, verbose=1)

这个项目其实很小,我是用笔记本版的3050,只需要40s-60s就跑完了。

【注9】关于报错,考虑到实际环境中,各位使用的环境,tf版本不同,这里有一个由于版本原因会出现的报错。就是运行模型,出现什么格式不对 ,这是因为你使用了tf2.11版本以上,这个版本的win11系统没法调用gpu,好像要去官网下什么东西。故有几种解决思路:

  1. 下载,完整配置
  2. 将版本降到2.9.3(实际上2.8-2.10应该都可以)
  3. 修改格式,将数据的1,56,46格式改为通道数在后面的,同时记得修改网络为channels_last

3.4  可视化分析 

3.4.1  复现原始网络的准确率与损失

原始网络使用的参数如下表所示:

超参数数值

batch_size

32

learning_rate

0.001

【注10】原文使用的优化器是RMSprop

整个训练过程的损失和准确率如下所示:

图6  损失与准确率可视化结果

3.4.2   超参数控制实验

这种实验可以作的比较多,我这里就作一下不同batch_size和优化器的。

(1)batch_size变化,其余不变

batch sizeaccuracy(%)
16nan
3297.68
6497.36
12895.77

(2)不同优化器,其余不变(batch_size用的128,learning_rate用的0.001)

优化器accuracy(%)
rmsprop95.77
sgd50.20
adam93.02

【注11】超参数可以控制的变量还是挺多的,一般来说,在不同的论文中,根据要水的东西可以作不同方向的控制。 

【注12】其它分析手段不做陈述,自行测试即可。

4  改进网络实现举例与展望

本章将讲述,我在普刊中是如何“创新”的,以及一些不完善之处和其它思路的展望。

【注13】如果是也想快乐水一篇的,我建议直接水ei会议,国内普刊基本上没有什么学术造假都可以过,ei水会也是如此,但是人家EI好歹是个核心...

4.1  网络改进思路与举例

一般来说一个中文普刊或者ei水汇的创新点,可以是一个较大的插入,或者说几个常见的组合。比如说我组合了距离函数、注意力机制和一个简单的系统。

【注14】由于曾经合作过的课题组还在使用马氏距离的变体(实际上他们搞reid和fer比较多),且用的东西都是很浅显的,这里就不公布具体的参数了,不过从上面的原始网络就能看出,主要评价指标acc在这个数据集上表现得很好,98-99%的准确率是个easy值。

4.1.1  距离函数

距离函数一般用于基于度量相关的学习,在分类任务中,可以用于寻找样本点之间的合适距离度量,对样本点进行分类。当然,进一步的,在识别任务中,计算新样本点和已有样本点之间的距离度量,判断新样本点和已有样本点是否是同一个样本点。

原始距离函数--欧式距离(又称L_{2}范数距离)

d=||x-y||{_{2}}^{2}=\sum_{i=1}^{n}(x_{i}-y_{i})^{2}

论文使用变体--马氏距离

d=\sqrt{(Lx-Ly)^{^{T}}(Lx-Ly)} 

在很多和距离相关的优化问题中,都可以尝试不同的距离函数。下面来看一下简单的实现:

class MahalanobisDistanceLayer(Layer):
    def __init__(self, inverse_covariance, **kwargs):
        self.inverse_covariance = K.constant(inverse_covariance)  # 将逆协方差矩阵转换为Keras张量
        super(MahalanobisDistanceLayer, self).__init__(**kwargs)

    def call(self, inputs):
        x, y = inputs
        diff = K.expand_dims(x - y, -1)  # 将差值变形以适应矩阵乘法
        temp = K.dot(diff, self.inverse_covariance)  # 计算 (x-y) 和 逆协方差矩阵的乘积
        mahalanobis_square = K.dot(K.permute_dimensions(temp, (0, 2, 1)), diff)  # 计算马氏距离平方
        return K.sqrt(K.maximum(mahalanobis_square, K.epsilon()))  # 计算马氏距离并确保数值稳定性

    def compute_output_shape(self, input_shape):
        shape1, _ = input_shape
        return (shape1[0], 1)

【补充1】如果你的马氏距离是在网络的最后使用的话,上述call中的代码需要使用如下的全新版本:

   def call(self, inputs):
        x, y = inputs
        diff = x - y
        temp = K.dot(diff, self.inverse_covariance)  # 计算 (x-y) 和 逆协方差矩阵的乘积
        mahalanobis_square = K.sum(temp * diff, axis=1, keepdims=True)
        return K.sqrt(K.maximum(mahalanobis_square, K.epsilon()))  # 计算马氏距离并确保数值稳定性

 可以很清晰的看出,这里的马氏距离多了一个协方差矩阵,在代码运行中,有两种思路。一种较为简单的是你设计一个合适的协方差矩阵,另一种比较复杂的是将其作为一个自适应参数,和整个训练过程一起进行。这里给出前者的一个简单案例(就是单位矩阵,其实当协方差矩阵使用单位矩阵的时候,就是欧式距离):

inverse_covariance = np.eye(50)
distance = MahalanobisDistanceLayer(inverse_covariance)([feat_vecs_a, feat_vecs_b])

那么对于后者,有什么思路呢?

  1. 训练前估计: 在训练模型之前,可以使用一个预训练模型(如果有的话)或者模型的一个初步版本来处理一部分训练数据,获取 feat_vecs_afeat_vecs_b 的输出。然后,使用这些输出来计算协方差矩阵及其逆。 
  2. 动态更新: 另一种方法是在模型训练过程中动态更新逆协方差矩阵。这意味着在每个epoch开始时,利用当前模型状态处理一批数据,计算得到的特征用于更新逆协方差矩阵。这种方法可能会增加训练成本,但它可以更准确地反映模型生成的特征空间。

这里放一个单独加入马氏距离,使用adam优化器,其余超参数配置忘记了的实验结果图:

图7  原始网络--替换马氏距离

【注15】我在论文中使用的是方法2,但说实话,在人脸识别任务中的效果一般。诸位感兴趣的可以去FER任务中尝试一下,结合半监督的时候对模型稳定性有一定程度的提升。另外,在元度量学习中,马氏距离由于其参数的动态更新,在一定程度上优于欧式距离,是很多工作常使用的。除此之外,reid使用孪生网络应该可以实现一个轻量级模型的路子,值得一试。

4.1.2  注意力机制

注意力机制,大家都懂,基本上是水文必备。我在论文中用的最简单的SE模块,其实也是因为原始网络承受不住其它的层深。

def squeeze_excite_block(input, ratio=16):
    init = input
    channel_axis = 1 if K.image_data_format() == 'channels_first' else -1
    filters = init.shape[channel_axis]
    se_shape = (1, 1, filters)

    se = GlobalAveragePooling2D()(init)
    se = Reshape(se_shape)(se)
    se = Dense(filters // ratio, activation='relu', kernel_initializer='he_normal', use_bias=False)(se)
    se = Dense(filters, activation='sigmoid', kernel_initializer='he_normal', use_bias=False)(se)

    if K.image_data_format() == 'channels_first':
        se = Permute((3, 1, 2))(se)

    x = multiply([init, se])
    return x

这次在测试集上的效果为下图所示,注意,这里的参数是adam,batch_size=128,也就是说加入马氏距离和注意力机制之后,模型的精度得到3%的提升(和3.4.2表2对比),证明了方法有效

图8  测试集效果展示

 【注16】其实这里就有简单的变体研究,换注意力机制+数据集扩充

4.1.3  应用--简易识别系统

好的,说了这么多,以上的实验无论是训练还是测试都局限于数据集AT&T。为了使之更加贴合实际,我们简单的创建一个识别系统。

【注17】由于是简单的识别系统,我们只需要测试一个人是否属于这个库即可,也就是说你只需要测试自己就行。

首先,先对上述模型进行保存,在model/train.py文件中加入模型保存,将h5文件保存在h5文件夹内。

model.save('../model/h5/test.h5')
图9  模型保存路径

 好的,之后我们首先做一个人脸图像收集,并将其放在picture文件夹下,该代码使用的是main文件的如下部分:

# 测试截取的图片
if not saved:
# 保存处理后的图像到本地
   cv2.imwrite('./model/picture/processed_image.jpg', processed_frame)
   saved = True

【注18】只有在第一遍收集人脸信息的时候才使用该代码,后续的过程中隐去该部分。同时在第一次隐去后续测试的部分。

正常来说,会得到如图9所示,picture下的一个文件,这个就是本地的“待测试文件”。之后,使用main文件进行测试,直接运行即可。

import numpy as np

from model.distance_function import *
import cv2
import tensorflow as tf
from keras.models import load_model


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)))


def compute_accuracy(predictions, labels):
    predictions = tf.reshape(predictions, [-1])  # 将预测结果展平
    a = tf.reduce_mean(tf.cast(labels[predictions < 0.5], dtype=tf.float32))
    return tf.where(a > 1, tf.ones_like(a), a)


# 加载模型
model = load_model('./model/h5/test.h5', custom_objects={'MahalanobisDistanceLayer': MahalanobisDistanceLayer,
                                                         'contrastive_loss': contrastive_loss,
                                                         'compute_accuracy': compute_accuracy})
test_pic = cv2.imread('./model/picture/processed_image.jpg')
test_pic = cv2.cvtColor(test_pic, cv2.COLOR_BGR2GRAY)
test_pic = cv2.resize(test_pic, (56, 46))
test_pic = np.expand_dims(test_pic, axis=0)
test_pic = np.moveaxis(test_pic, -1, 1)


saved = False

# 加载Haar级联人脸检测模型
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

# 打开默认摄像头
cap = cv2.VideoCapture(0)

while True:
    # 逐帧捕获
    ret, frame = cap.read()
    if not ret:
        break

    # 将捕获的帧转换为灰度
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # (480, 640)

    # 在灰度帧上进行人脸检测
    faces = face_cascade.detectMultiScale(gray, 1.1, 4)

    # 为每个检测到的人脸画矩形框
    for (x, y, w, h) in faces:
        cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)

        # 裁剪
        cropped_face = gray[y:y+h, x:x+w]

        # 转换形状
        processed_frame = cv2.resize(cropped_face, (56, 46))
        # print(processed_frame.shape)

        # 测试截取的图片
        if not saved:
            # 保存处理后的图像到本地
            cv2.imwrite('./model/picture/processed_image.jpg', processed_frame)
            saved = True

        # processed_frame = processed_frame / 255.0
        processed_frame = np.expand_dims(processed_frame, axis=0)
        processed_frame = np.moveaxis(processed_frame, -1, 1)
        print(processed_frame.shape, test_pic.shape)

        a = np.expand_dims(processed_frame, axis=0) / 255
        b = np.expand_dims(test_pic, axis=0) / 255
        c = model.predict([a, b])

        print(c)
        print(c.ravel() < 0.5)

    # 显示结果帧
    cv2.imshow('frame', frame)

    # 按'q'退出循环
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 释放摄像头资源
cap.release()
cv2.destroyAllWindows()

上述代码,编写到print(c.ravel() < 0.5),如果是true,就是模型判定和库里的人是一个,如果是false就是判定和库里的人不是一个。具体可以如图10所示的成功案例。

图10  识别成功--True

【注19】识别失败就是距离大于0.5,一般来说,如果你只衡量待测任务与一张图片的效果,模型的识别效率还是可以的。我上传的30轮模型足以应对,如果你还想进一步实验。需要更深层次的炼丹。

【注20】如此轻量级的模型,在脸部角度等大幅度外界环境变化下,精度会大幅下降。请勿抱有期待...

4.2  展望

这一节与其说是展望,不如说是水文思路,毕竟常规的人脸识别,早就被搞透了。

  1. 孪生网络可以考虑使用在目标追踪,比如说行人重识别上,这个方向感觉可以水一水。
  2. 医学领域的应用,可以参考一下参考文献2

5.  参考文献

【1】Chopra S, Hadsell R, LeCun Y. Learning a similarity metric discriminatively, with application to face verification[C]//2005 IEEE computer society conference on computer vision and pattern recognition (CVPR'05). IEEE, 2005, 1: 539-546.

【2】Gao Y, Gong M, Ong YS, Qin AK, Wu Y, Xie F. A Collaborative Multimodal Learning-Based Framework for COVID-19 Diagnosis. IEEE Trans Neural Netw Learn Syst. 2023 Jul 4;PP. doi: 10.1109/TNNLS.2023.3290188. Epub ahead of print. PMID: 37402198.

6  项目使用方法与下载链接

6.1  项目使用方法

我在文件中也存放了各个文件的解释,原始数据集只需下载好,在项目中新建一个data文件夹解压就可以了。(这个不是必须的)

需要在model文件下创建h5文件夹和picture文件夹,创建及使用的方法见4.1.3(这个是必须的,不然没法使用简易测试)

项目中包括了原始网络在该任务上的完整流程、一些拓展方法的基本模块和一个简单的人脸识别测试模块。

6.2  下载链接

GitHub链接icon-default.png?t=N7T8https://github.com/damoshishen/FR_twin_network

  • 13
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

物理系的计算机选手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值