作为一个有“算法梦”的物理系渣渣,在读研期间水了一篇国内普刊的算法也算过足了瘾,最近工作之余,将当时的论文主体复现并讲解一下。
———不要脸的作者君
【注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)是一种特殊的神经网络架构,主要用于解决相似性比较问题,比如人脸识别、签名验证或物体追踪等。孪生网络通过对两个输入数据进行特征提取,并比较这些特征来判断两个输入是否相似。其核心思想是两个相同的子网络共享相同的参数,这两个子网络可以并行处理两个不同的输入数据,输出这两个输入数据的特征表示。
- 子网络:孪生网络由两个完全相同的网络组成,它们有相同的配置(层数和类型)、参数(权重和偏差)。这种结构确保了两个网络对输入数据的处理方式完全相同。
- 特征提取器:每个子网络都充当特征提取器,将输入数据转换为特征向量。特征提取器的构建通常基于卷积神经网络(CNN)或循环神经网络(RNN),取决于输入数据的类型。
- 比较机制:网络的输出是两个特征向量,比较机制对这两个向量进行比较,以判断输入是否相似。比较的方式可以是计算两个特征向量的欧式距离、余弦相似度或使用专门的比较层。
【注4】这里说的不是伪孪生网络(pseudo-siamese network),伪孪生网络可以由任意的两个神经网络拼接而成。
2. 数据集相关
2.1 数据集获取
AT&T是一个开源的小样本人脸识别数据集,一共有40组,每组有10张照片。你可以从官方网站、kaggle或者是下面的连接中下载。这些文件是PGM格式的,可以使用'xv'程序在UNIX (TM)系统上方便地查看。每个图像的大小为92x112像素,每个像素有256个灰度级。
Kaggle官方数据集--网络可能存在卡顿https://www.kaggle.com/datasets/kasikrit/att-database-of-faces
csdn数据链接--适合国内用户https://download.csdn.net/download/qq_40981869/89021867?spm=1001.2014.3001.5501
2.2 数据集预处理
这里的数据集预处理,大致分为两个部分。第一个是对这个数据集格式的问题,如下图2所示,可以看到原数据集的格式是pgm。另一个是
【注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()
2.3 图像对建立
这部分之前在另一篇文章中讲述过,孪生网络建立的图像对就是将相同的一类打一个标签,不相同的一类打一个标签。这种思路一直延伸到所有的度量学习分类器的建设中。如下公式所示,当结果为0的时候是相同类别,当结果为1的时候是不同类别。
好的,在我们知晓基本原理的之后,来根据这个思路建立图像对。在下面代码中,有英文注释,讲解了具体的代码定义。在这里,使用的时候只需要定义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
找个地方测试一下,正常来说可以得到如下的结果:
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 。
【注6】2022年开始写上面说到的小论文的时候,我记得用的是tf2.8还是2.9,由于当时的代码找不到了(随着上一台电脑gg)在写本篇文章的时候,该代码是使用的python3.9+tensorflow2.16。所以这里会有些问题,比若说下图中的form keras,我记得之前还是哪个版本用的是 from tensorflow.keras 如果说环境报错,自己修改一下。
【注7】如果配置graphviz 和pydot报错,可以尝试以下几种方法:
- pip install pydotplus
- 如果使用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,好像要去官网下什么东西。故有几种解决思路:
- 下载,完整配置
- 将版本降到2.9.3(实际上2.8-2.10应该都可以)
- 修改格式,将数据的1,56,46格式改为通道数在后面的,同时记得修改网络为channels_last
3.4 可视化分析
3.4.1 复现原始网络的准确率与损失
原始网络使用的参数如下表所示:
超参数 | 数值 |
batch_size | 32 |
learning_rate | 0.001 |
【注10】原文使用的优化器是RMSprop
整个训练过程的损失和准确率如下所示:
3.4.2 超参数控制实验
这种实验可以作的比较多,我这里就作一下不同batch_size和优化器的。
(1)batch_size变化,其余不变
batch size | accuracy(%) |
16 | nan |
32 | 97.68 |
64 | 97.36 |
128 | 95.77 |
(2)不同优化器,其余不变(batch_size用的128,learning_rate用的0.001)
优化器 | accuracy(%) |
rmsprop | 95.77 |
sgd | 50.20 |
adam | 93.02 |
【注11】超参数可以控制的变量还是挺多的,一般来说,在不同的论文中,根据要水的东西可以作不同方向的控制。
【注12】其它分析手段不做陈述,自行测试即可。
4 改进网络实现举例与展望
本章将讲述,我在普刊中是如何“创新”的,以及一些不完善之处和其它思路的展望。
【注13】如果是也想快乐水一篇的,我建议直接水ei会议,国内普刊基本上没有什么学术造假都可以过,ei水会也是如此,但是人家EI好歹是个核心...
4.1 网络改进思路与举例
一般来说一个中文普刊或者ei水汇的创新点,可以是一个较大的插入,或者说几个常见的组合。比如说我组合了距离函数、注意力机制和一个简单的系统。
【注14】由于曾经合作过的课题组还在使用马氏距离的变体(实际上他们搞reid和fer比较多),且用的东西都是很浅显的,这里就不公布具体的参数了,不过从上面的原始网络就能看出,主要评价指标acc在这个数据集上表现得很好,98-99%的准确率是个easy值。
4.1.1 距离函数
距离函数一般用于基于度量相关的学习,在分类任务中,可以用于寻找样本点之间的合适距离度量,对样本点进行分类。当然,进一步的,在识别任务中,计算新样本点和已有样本点之间的距离度量,判断新样本点和已有样本点是否是同一个样本点。
原始距离函数--欧式距离(又称范数距离)
论文使用变体--马氏距离
在很多和距离相关的优化问题中,都可以尝试不同的距离函数。下面来看一下简单的实现:
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])
那么对于后者,有什么思路呢?
- 训练前估计: 在训练模型之前,可以使用一个预训练模型(如果有的话)或者模型的一个初步版本来处理一部分训练数据,获取
feat_vecs_a
和feat_vecs_b
的输出。然后,使用这些输出来计算协方差矩阵及其逆。 - 动态更新: 另一种方法是在模型训练过程中动态更新逆协方差矩阵。这意味着在每个epoch开始时,利用当前模型状态处理一批数据,计算得到的特征用于更新逆协方差矩阵。这种方法可能会增加训练成本,但它可以更准确地反映模型生成的特征空间。
这里放一个单独加入马氏距离,使用adam优化器,其余超参数配置忘记了的实验结果图:
【注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对比),证明了方法有效:
【注16】其实这里就有简单的变体研究,换注意力机制+数据集扩充
4.1.3 应用--简易识别系统
好的,说了这么多,以上的实验无论是训练还是测试都局限于数据集AT&T。为了使之更加贴合实际,我们简单的创建一个识别系统。
【注17】由于是简单的识别系统,我们只需要测试一个人是否属于这个库即可,也就是说你只需要测试自己就行。
首先,先对上述模型进行保存,在model/train.py文件中加入模型保存,将h5文件保存在h5文件夹内。
model.save('../model/h5/test.h5')
好的,之后我们首先做一个人脸图像收集,并将其放在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所示的成功案例。
【注19】识别失败就是距离大于0.5,一般来说,如果你只衡量待测任务与一张图片的效果,模型的识别效率还是可以的。我上传的30轮模型足以应对,如果你还想进一步实验。需要更深层次的炼丹。
【注20】如此轻量级的模型,在脸部角度等大幅度外界环境变化下,精度会大幅下降。请勿抱有期待...
4.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(这个是必须的,不然没法使用简易测试)
项目中包括了原始网络在该任务上的完整流程、一些拓展方法的基本模块和一个简单的人脸识别测试模块。