【PyTorch实战演练】深入剖析MTCNN(多任务级联卷积神经网络)并使用30行代码实现人脸识别
文章目录
- 0. 前言
- 1. 级联神经网络介绍
- 2. MTCNN介绍
- 2.1 MTCNN提出背景
- 2.2 MTCNN结构
- 3. MTCNN PyTorch实战
- 3.1 facenet_pytorch库中的MTCNN
- 3.2 识别图像数据
- 3.3 人脸识别
- 3.4 关键点定位
0. 前言
按照国际惯例,首先声明:本文只是我自己学习的理解,虽然参考了他人的宝贵见解及成果,但是内容可能存在不准确的地方。如果发现文中错误,希望批评指正,共同进步。
本文详细介绍MTCNN——多任务级联卷积神经网络的结构,并通过PyTorch实例说明MTCNN在人脸识别上的应用。
MTCNN的全称是Multi-Task Cascaded Convolutional Networks,它的缩写确实是MTCNN不是MTCCN.
1. 级联神经网络介绍
级联(cascaded)神经网络是一种人工神经网络的架构设计,它指的是多个神经网络层按照特定的方式连接起来,形成一个逐层处理信息的多层结构。在级联神经网络中,前一层次网络的输出作为后一层次网络的输入,这种结构允许在网络在深度方向上对复杂性和抽象层数进行增加
。

级联网络的重要特点是其动态构建
特性,即可以从一个小规模的基本网络开始,并随着训练过程自动添加更多的隐藏单元或子网络,逐渐扩展成一个更深层次的结构,然后通过只针对新增部分数据进行训练来更新权重,即增量式学习
(Incremental Learning)。这与传统的——构建完整模型后统一进行训练更新权重的思路非常不同。
使用传统的思路,如果发现我们的模型并不适用于待解决的任务,导致要调整模型结构时,通常会意味着之前的训练模型的工作全部白费了。
总结起来级联神经网络具有以下优点:
-
自适应结构:级联网络设计允许根据训练数据或学习过程动态调整网络结构,比如自动增加新的层或神经元,以适应更复杂的模式识别任务。
-
学习效率提升:可以通过增量学习或局部训练来加快学习速度,只针对新增加的部分进行训练优化。在某些情况下,级联网络可以采用非传统的权重更新机制,不需要在整个网络上执行全局误差反向传播算法。
-
鲁棒性和容错性:分层结构有助于提高系统的鲁棒性,单个层次的错误可能在后续层次中得到修正。
2. MTCNN介绍
2.1 MTCNN提出背景
MTCNN是Kaipeng Zhang等人在论文——Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks中提出的,其宗旨是通过多任务级联CNN解决两个问题:人脸检测(找出图像中人脸的位置和边界框)和人脸对齐(精确定位面部特征点)。
2.2 MTCNN结构
MTCNN的构建思路可以简单分为下面几个步骤:
- 准备步骤:对图像进行缩放,建立图像金字塔;
- 第一步Proposal-Net:快速选出若干候选框,为下一步准备;
- 第二步Refine-Net:对第一步的众多候选框进行精选,留下置信度大的候选框;
- 第三步Output-Net:输出最终bounding box、人脸关键特征定位和置信度。
详细来说P-Net、R-Net和O-Net的结构如下:
通过Netron可以看到facenet_pytorch库中的MTCNN的结构及详细参数如下:
-
P-Net (Proposal Network):
- 输入是原始图像。
- 首先通过一个卷积层(Conv2d)将3通道的输入图像转换为10通道特征图,使用3x3的卷积核(kernel_size=(3, 3))。
- 紧接着使用PReLU激活函数(prelu1)进行非线性变换。
- 使用最大池化层(MaxPool2d)下采样特征图(pool1),步长为2。
- 再经过两个卷积层(Conv2d)提取更深层次的特征,并分别用PReLU激活函数(prelu2和prelu3)进行非线性处理。
- 最后通过两个1x1卷积层(Conv2d)生成两个输出:一个是softmax4_1用于预测每个像素是否为人脸的概率分布,另一个是conv4_2用于回归bounding box的位置信息。
-
R-Net (Refine Network):
- 输入是P-Net的候选区域。
- 类似于P-Net,R-Net也包含多个卷积层与激活函数,以及池化层进行特征提取和下采样。
- 在最后,通过两个全连接层(Dense或Linear)生成两个输出:softmax5_1用于判断候选框内是否为人脸并给出置信度,dense5_2用于进一步细化人脸框的位置。
-
O-Net (Output Network):
- 输入同样是前一级网络(R-Net)筛选后的候选区域。
- O-Net具有更多的卷积层以获取更精细的特征表达,同样在最后阶段通过三个全连接层生成三个输出:softmax6_1用于人脸分类,dense6_2用于人脸框回归精修,dense6_3用于估计关键点(如眼睛、嘴巴等)的位置。
整个MTCNN模型通过逐步筛选和优化候选区域,在不同尺度上定位和识别图像中的人脸,从而实现高效准确的人脸检测。
3. MTCNN PyTorch实战
3.1 facenet_pytorch库中的MTCNN
facenet_pytorch
库中的MTCNN
类是一个用于人脸检测的多任务级联卷积神经网络模型实现。直接使用MTCNN
类的最大好处就是该模型已经训练好
,可以拿来即用,其初始化时接受多个参数,以下是对这些参数的详细解释:
-
image_size(默认值:160):输出图像的大小(像素),图像会调整为正方形。
-
margin(默认值:0):在最终图像上添加到边界框的边距(以像素为单位)。需要注意的是,与davidsandberg/facenet库中的应用方式稍有不同,该库在调整原始图像大小之前就对原始图像应用了边距,导致边距与原始图像大小相关(这是davidsandberg/facenet的一个bug)。
-
min_face_size(默认值:20):要搜索的人脸的最小尺寸。
-
thresholds(默认值:[0.6, 0.7, 0.7]):MTCNN人脸检测阈值列表,分别对应P-Net、R-Net和O-Net三个阶段的阈值。
-
factor(默认值:0.709):用于创建人脸大小缩放金字塔的比例因子。
-
post_process(默认值:True):是否在返回前对图像张量进行后处理。
-
select_largest(默认值:True):如果检测到多个人脸,是否选择面积最大的一个返回。若设为False,则选择概率最高的人脸返回。
-
selection_method(默认值:None):指定使用哪种启发式方法进行选择,如果设置此参数将覆盖
select_largest
:"probability"
:选择概率最高的。"largest"
:选择面积最大的框。"largest_over_threshold"
:选择超过一定概率的最大框。"center_weighted_size"
:基于框大小减去离图像中心加权距离平方后的结果进行选择。
-
keep_all(默认值:False):如果设为True,则返回所有检测到的人脸,并按照
select_largest
参数设定的顺序排列。如果指定了保存路径,第一张人脸将被保存至该路径,其余人脸将依次保存为<save_path>1, <save_path>2等。 -
device(默认值:None):运行神经网络前向传递时所使用的设备。图像张量和模型会在前向传递前复制到这个设备上。
3.2 识别图像数据
这块没有特殊要求,随便去网上下载,以下是我自己的识别对象数据:
3.3 人脸识别
- 代码
from facenet_pytorch import MTCNN
import torch
from torch.utils.data import DataLoader
from torchvision import datasets
import osdevice = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
print('the device is:{}'.format(device))model = MTCNN(image_size=160, margin=0, min_face_size=10,thresholds=[0.7,0.7,0.7],factor=0.7, post_process=True, device=device)
path = os.path.abspath('face_img') #在face_img文件夹下面还要再加一个class_folder文件夹
dataset = datasets.ImageFolder(path)
imgs_list = list(sorted(os.listdir(os.path.join(path,'class_folder'))))def collate_fn(x):return x[0]loader = DataLoader(dataset, collate_fn = collate_fn, num_workers=0)
index = 0
#detected_faces = []for pic,_ in loader:aligned, confidence = model(pic , return_prob=True)if confidence is not None:print('Confidence of {} containing human face is {:.8f}'.format(imgs_list[index], confidence))detected_faces.append(aligned)else:print('No human face detected in {}'.format(imgs_list[index]))index += 1# 以下是人脸对齐的还原实现
#face_numpy = (detected_faces[0] + 1) * 127.5 # 由于是 [-1, 1] 范围,将其映射到 [0, 255]
#face_numpy = face_numpy.numpy().astype(np.uint8)
#face_image = Image.fromarray(face_numpy.transpose(1, 2, 0)) # 将 Numpy 数组转为 PIL 图像格式,并注意调整通道顺序为 (H, W, C)#plt.imshow(face_image)
#plt.show()
- 输出
Confidence of art.png containing human face is 0.99512947
No human face detected in ironman.png
Confidence of man.png containing human face is 0.99643928
No human face detected in ogre.png
Confidence of thanos.png containing human face is 0.96726525
Confidence of woman.png containing human face is 0.99991846
可见MTCNN不认为钢铁侠和食人魔魔法师算“人脸”。MTCNN的输出有2部分:
- 对齐后的人脸张量:其范围是[-1, 1],可以将其线性还原到[0, 255]并输出对其后的人脸,例如下图:
- 包含人脸的置信度:即上面的0.99512947等置信度数值。
3.4 关键点定位
也可以使用mtcnn.detect()
得到人脸得关键点(眼睛、鼻子、嘴角)定位,代码如下:
from facenet_pytorch import MTCNN
import torch
from torch.utils.data import DataLoader
from torchvision import datasets
import os
import numpy
import matplotlib
import matplotlib.pyplot as pltdevice = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
print('the device is:{}'.format(device))model = MTCNN(image_size=160, margin=0, min_face_size=10,thresholds=[0.7,0.7,0.7],factor=0.7, post_process=True, device=device)path = os.path.abspath('face_img') #在face_img文件夹下面还要再加一个class_folder文件夹
dataset = datasets.ImageFolder(path)
imgs_list = list(sorted(os.listdir(os.path.join(path,'class_folder'))))def collate_fn(x):return x[0]loader = DataLoader(dataset, collate_fn = collate_fn, num_workers=0)
index = 0
detected_faces = []for pic,_ in loader:aligned, confidence = model(pic , return_prob=True)if confidence is not None:print('Confidence of {} containing human face is {:.8f}'.format(imgs_list[index], confidence))detected_faces.append(aligned)boxes, probs, points = model.detect(pic, landmarks=True)points = points.squeeze(0)for x,y in points:plt.scatter(x,y,s=10,c='r')plt.imshow(pic)plt.savefig('{}_aligned.jpg'.format(imgs_list[index]))plt.close()else:print('No human face detected in {}'.format(imgs_list[index]))index += 1
最终保存的图像为:
可以看出MTCNN的关键点定位也是很准确的。上面代码的boxs即为人脸边界框,这里不再画出效果。
相关文章:

【PyTorch实战演练】深入剖析MTCNN(多任务级联卷积神经网络)并使用30行代码实现人脸识别
文章目录 0. 前言1. 级联神经网络介绍2. MTCNN介绍2.1 MTCNN提出背景2.2 MTCNN结构 3. MTCNN PyTorch实战3.1 facenet_pytorch库中的MTCNN3.2 识别图像数据3.3 人脸识别3.4 关键点定位 0. 前言 按照国际惯例,首先声明:本文只是我自己学习的理解ÿ…...
MFC中字符串string类型和CString类型互转方法
在Microsoft Foundation Classes (MFC)中,CString是一个非常方便的类,用于处理C风格的字符串。有时,你可能需要在MFC的CString和C标准库中的std::string之间进行转换。下面是如何在两者之间进行转换的方法: CString转std::string…...

Jmeter-使用http proxy代理录制脚本
Jmeter-使用http proxy代理录制脚本 第1步:打卡jmeter工具新增1个线程组 第2步:给线程组添加1个HTTP请求默认值 第3步:设置下HTTP请求默认值第4步:在工作台中新增1个----HTTP代理服务器 第5步:设置HTTP代理服务器 …...
C++训练营:new 运算符
大家好: 衷心希望各位点赞。 您的问题请留在评论区,我会及时回答。 一、new 运算符 new 运算符用于动态分配一片内存空间,并返回这片内存空间的首地址,可将该首地址存入一个指针变量中,主要有以下三种格式。 二、格…...

C# 用Trace.WriteLine输出调试信息无法查看
写程序就会遇见BUG,这时候在代码不同部位输出一些标记的信息对查找错误非常有必要,一般情况下我们都是使用Console.WriteLine()方法来打印信息到控制台窗口,但有时候使用Console.WriteLine()方法会存在不方便的情况,比如鄙人遇到的…...

【Echarts】柱状图上方显示数字以及自定义值,标题和副标题居中,鼠标上显示信息以及自定义信息
欢迎来到《小5讲堂》 大家好,我是全栈小5。 这是《前端》系列文章,每篇文章将以博主理解的角度展开讲解, 特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对知识点的理解和掌握…...

HTML 语义化:构建优质网页的关键
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
Flutter入门学习——Flutter和Dart
因为工作的需要,也为了个人发展,现在的话,转战Flutter跨端开发了,虽然目前的项目只发了android端,但是那天尝试了一下Ios的打包流程,也能运行,只是IOS那边的打包稍微复杂一些。 差不多学习了一…...
C++中的内存管理方式
一、C内存管理方式简介 C语言中的内存管理方式在C中可以继续使用,但是在有些地方就无能为力,而且使用起来比较麻烦。因此C中引入了自己的内存管理方式,通过new和delete操作符进行动态内存管理。 二、new语法 new可以申请1个或多个空间&…...

macos m1 arm芯片 使用jpype报错 FileNotFoundError: [Errno 2] JVM DLL not found
startJVM(jpype.getDefaultJVMPath()) 报错 Traceback (most recent call last):File "/Users/thomas990p/PycharmProjects/tuya/volcano-biz-scripts/WenKongFa/FinalCode/java2python/CallJavaAPI.py", line 12, in <module>startJVM(jpype.getDefaultJVMPa…...
Hive中UNION ALL和UNION的区别
1.概述 Hive官方提供了一种联合查询的语法,原名为Union Syntax,用于联合两个表的记录进行查询,此处的联合和join是不同的,join是将两个表的字段拼接到一起,而union是将两个表的记录拼接在一起。 换言之, jo…...

selenium高级应用
常见控件应用 复杂的控件操作1.操作Ajax选项2.滑动滑块操作 WebDriver的特殊操作元素class值包含空格property、attribute、text的区别定位动态id 截图功能页面截图页面截图,返回截图的二进制数据页面截图,返回base64的字符串截取指定元素。先定位元素&a…...
微信小程序重新加载当前页面、刷新当前页面
重新加载页面 使用wx.reLanuch(),url: 路径当前页面跳转, 页面所有数据重新初始化,已配置的数据不会保存 wx.reLaunch({url: /pages/orders/createOrder/createOrder, // 当前页面的路径}) reLanuch()的方法,会有一个…...

如何查找、恢复误清空的 Android 回收站?
“我的回收站里有一些照片。当我点击“恢复”时,没有任何反应。我可以将我的 Android 手机插入我的电脑。这样我就可以手动恢复它们。但我在 Android 上找不到 bin 文件夹。我还可以做些什么?” 随着 Android 手机上的文件数量不断增加,了解…...

Node.js作用
Node.js可以开发应用 开发服务器应用 开发工具类应用 开发桌面端应用...
Web爬虫入门:原理、实现与常见问题解决指南
引言: 在当今数据驱动的时代,网络上蕴藏着无尽的信息宝藏,而爬虫技术则是探索和利用这些宝藏的重要工具。爬虫,简单来说,就是一种自动化程序,它能够模拟人类浏览网页的行为,从中提取所需数据。…...

蓝桥杯练习题——归并排序
1.火柴排队 思路 1.求最小值的时候,可以直接按升序排序,这样得到的值就是最小值 2.求最小交换次数的时候,不能直接排序,因为只能交换相邻的数,只需要知道他们的相对大小,所以可以先用离散化,把…...

C语言--- 指针运算笔试题详解
目录 题目1: 题目2: 题目3: 题目4: 题目5: 题目6: 题目7: 题目1: #include <stdio.h> int main() {int a[5] { 1, 2, 3, 4, 5 };int *ptr (int *)(&a 1);print…...

甘特图是什么,怎么制作?一文让你看懂
甘特图是什么 甘特图是一种项目管理工具,通过图形化的方式直观的能体现出任务、进度和资源在时间里的关系。 白话文就是: 项目分解成了哪些任务?每天计划做什么任务?当前每个任务的进度是多少?项目整体进度是多少?这个项目有…...
mysql笔记:6. 存储引擎
文章目录 查看引擎信息常用引擎介绍InnoDBMyISAMMEMORY存储引擎的选择 数据库存储引擎是数据库底层组件,数据库管理系统使用数据引擎进行创建、查询、更新和删除数据。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等,使用不同的存储引擎&#…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...

GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
C语言中提供的第三方库之哈希表实现
一. 简介 前面一篇文章简单学习了C语言中第三方库(uthash库)提供对哈希表的操作,文章如下: C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...