当前位置: 首页 > news >正文

Python深度学习实战:人脸关键点(15点)检测pytorch实现

引言

人脸关键点检测即对人类面部若干个点位置进行检测,可以通过这些点的变化来实现许多功能,该技术可以应用到很多领域,例如捕捉人脸的关键点,然后驱动动画人物做相同的面部表情;识别人脸的面部表情,让机器能够察言观色等等。
在这里插入图片描述

如何检测人脸关键点

本文是实现15点的检测,至于N点的原理都是一样的,使用的算法模型是深度神经网络,使用CV也是可以的。

如何检测

这个问题抽象出来,就是一个使用神经网络来进行预测的功能,只不过输出是15个点的坐标,训练数据包含15个面部的特征点和面部的图像(大小为96x96),15个特征点分别是:left_eye_center, right_eye_center, left_eye_inner_corner, left_eye_outer_corner, right_eye_inner_corner, right_eye_outer_corner, left_eyebrow_inner_end, left_eyebrow_outer_end, right_eyebrow_inner_end, right_eyebrow_outer_end, nose_tip, mouth_left_corner, mouth_right_corner, mouth_center_top_lip, mouth_center_bottom_lip
因此神经网络需要学习一个从人脸图像到15个关键点坐标间的映射。

使用的网络结构

在本文中,我们使用深度神经网络来实现该功能,基本卷积块使用Google的Inception网络,也就是使用GoogLeNet网络,该结构的网络是基于卷积神经网络来改进的,是一个含有并行连接的网络。
众所周知,卷积有滤波、提取特征的作用,但到底采用多大的卷积来提取特征是最好的呢?这个问题没有确切的答案,那就集百家之长:使用多个形状不一的卷积来提取特征并进行拼接,从而学习到更为丰富的特征;特别是里面加上了1x1的卷积结构,能够实现跨通道的信息交互和整合(其本质就是在多个channel上的线性求和),同时能在feature map通道数上的降维(读者可以验证计算一下,能够极大减少卷积核的参数),也能够增加非线性映射次数使得网络能够更深。
下面是Inception块的示意图:
在这里插入图片描述
整个GoogLeNet的结构如下所示:
在这里插入图片描述
接下来是代码实现部分,后续作者会补充神经网络的相关原理知识,若对此感兴趣的读者也可继续关注支持~

代码实现

import torch as tc
from torch import nn
from torch.nn import functional as F
from torch.utils.data import DataLoader
from torch.utils.data import TensorDataset
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.utils import shuffle# 对图片像素的处理
def proFunc1(data,testFlag:bool=False) -> tuple:data['Image'] = data['Image'].apply(lambda im: np.fromstring(im, sep=' '))# 处理nadata = data.dropna()  # 神经网络对数据范围较为敏感 /255 将所有像素都弄到[0,1]之间X = np.vstack(data['Image'].values) / 255X = X.astype(np.float32)# 特别注意 这里要变成 n channle w h 要跟卷积第一层相匹配X = X.reshape(-1, 1,96, 96) # 等会神经网络的输入层就是 96 96 黑白图片 通道只有一个# 只有训练集才有y 测试集返回一个None出去if not testFlag:  y = data[data.columns[:-1]].values# 规范化y = (y - 48) / 48  X, y = shuffle(X, y, random_state=42)  y = y.astype(np.float32)else:y = Nonereturn X,y# 工具类
class UtilClass:def __init__(self,model,procFun,trainFile:str='data/training.csv',testFile:str='data/test.csv') -> None:self.trainFile = trainFileself.testFile = testFileself.trainData = Noneself.testData = Noneself.trainTarget = Noneself.model = modelself.procFun = procFun@staticmethoddef procData(data, procFunc ,testFlag:bool=False) -> tuple:return procFunc(data,testFlag)def loadResource(self):rawTrain = pd.read_csv(self.trainFile)rawTest = pd.read_csv(self.testFile)self.trainData , self.trainTarget = self.procData(rawTrain,self.procFun)self.testData , _ = self.procData(rawTest,self.procFun,testFlag=True)def getTrain(self):return tc.from_numpy(self.trainData), tc.from_numpy(self.trainTarget)def getTest(self):return tc.from_numpy(self.testData)@staticmethoddef plotData(img, keyPoints, axis):axis.imshow(np.squeeze(img), cmap='gray') # 恢复到原始像素数据 keyPoints = keyPoints * 48 + 48 # 把keypoint弄到图上面axis.scatter(keyPoints[0::2], keyPoints[1::2], marker='o', c='c', s=40)# 自定义的卷积神经网络
class MyCNN(tc.nn.Module):def __init__(self,imgShape = (96,96,1),keyPoint:int = 15):super(MyCNN, self).__init__()self.conv1 = tc.nn.Conv2d(in_channels=1, out_channels =10, kernel_size=3)self.pooling = tc.nn.MaxPool2d(kernel_size=2)self.conv2 = tc.nn.Conv2d(10, 5, kernel_size=3)# 这里的2420是通过下面的计算得出的 如果改变神经网络结构了 # 需要计算最后的Liner的in_feature数量 输出是固定的keyPoint*2self.fc = tc.nn.Linear(2420, keyPoint*2)def forward(self, x):# print("start----------------------")batch_size = x.size(0)# x = x.view((-1,1,96,96))# print('after view shape:',x.shape)x = F.relu(self.pooling(self.conv1(x)))# print('conv1 size',x.shape)x = F.relu(self.pooling(self.conv2(x)))# print('conv2 size',x.shape)# print('end--------------------------')# 改形状x = x.view(batch_size, -1)# print(x.shape)x = self.fc(x)# print(x.shape)return x# GoogleNet基本的卷积块
class MyInception(nn.Module):def __init__(self,in_channels, c1, c2, c3, c4,) -> None:super().__init__()self.p1_1 = nn.Conv2d(in_channels, c1, kernel_size=1)self.p2_1 = nn.Conv2d(in_channels, c2[0], kernel_size=1)self.p2_2 = nn.Conv2d(c2[0], c2[1], kernel_size=3, padding=1)self.p3_1 = nn.Conv2d(in_channels, c3[0], kernel_size=1)self.p3_2 = nn.Conv2d(c3[0], c3[1], kernel_size=5, padding=2)self.p4_1 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)self.p4_2 = nn.Conv2d(in_channels, c4, kernel_size=1)def forward(self, x):p1 = F.relu(self.p1_1(x))p2 = F.relu(self.p2_2(F.relu(self.p2_1(x))))p3 = F.relu(self.p3_2(F.relu(self.p3_1(x))))p4 = F.relu(self.p4_2(self.p4_1(x)))# 在通道维度上连结输出return tc.cat((p1, p2, p3, p4), dim=1)# GoogLeNet的设计 此处参数结果google大量实验得出
b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))b2 = nn.Sequential(nn.Conv2d(64, 64, kernel_size=1),nn.ReLU(),nn.Conv2d(64, 192, kernel_size=3, padding=1),nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))b3 = nn.Sequential(MyInception(192, 64, (96, 128), (16, 32), 32),MyInception(256, 128, (128, 192), (32, 96), 64),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))b4 = nn.Sequential(MyInception(480, 192, (96, 208), (16, 48), 64),MyInception(512, 160, (112, 224), (24, 64), 64),MyInception(512, 128, (128, 256), (24, 64), 64),MyInception(512, 112, (144, 288), (32, 64), 64),MyInception(528, 256, (160, 320), (32, 128), 128),nn.MaxPool2d(kernel_size=3, stride=2, padding=1))b5 = nn.Sequential(MyInception(832, 256, (160, 320), (32, 128), 128),MyInception(832, 384, (192, 384), (48, 128), 128),nn.AdaptiveAvgPool2d((1,1)),nn.Flatten())uClass = UtilClass(model=None,procFun=proFunc1)
uClass.loadResource()
xTrain ,yTrain = uClass.getTrain()
xTest = uClass.getTest()dataset = TensorDataset(xTrain, yTrain)
trainLoader = DataLoader(dataset, 64, shuffle=True, num_workers=4)# 训练net并进行测试 由于显示篇幅问题 只能打印出极为有限的若干测试图片效果
def testCode(net):optimizer = tc.optim.Adam(params=net.parameters())criterion = tc.nn.MSELoss()for epoch in range(30):trainLoss = 0.0# 这里是用的是mini_batch 也就是说 每次只使用mini_batch个数据大小来计算# 总共有total个 因此总共训练 total/mini_batch 次# 由于不能每组数据只使用一次 所以在下面还要使用一个for循环来对整体训练多次for batchIndex, data in enumerate(trainLoader, 0):input_, y = datayPred = net(input_)loss = criterion(yPred, y)optimizer.zero_grad()loss.backward()optimizer.step()trainLoss += loss.item()# 只在每5个epoch的最后一轮打印信息if batchIndex % 30 ==29 and not epoch % 5 :print("[{},{}] loss:{}".format(epoch + 1, batchIndex + 1, trainLoss / 300))trainLoss = 0.0# 测试print("-----------test begin-------------")# print(xTest.shape)yPost = net(xTest)# print(yPost.shape)import matplotlib.pyplot as plt%matplotlib inlinefig = plt.figure(figsize=(20,20))fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05)for i in range(9,18):ax = fig.add_subplot(3, 3, i - 9 + 1, xticks=[], yticks=[])uClass.plotData(xTest[i], y[i], ax)print("-----------test end-------------")if __name__ == "__main__":# 训练MyCNN网络 并可视化在9个测试数据的效果图myNet = MyCNN()testCode(myNet)inception = nn.Sequential(b1, b2, b3, b4, b5, nn.Linear(1024, 30))testCode(inception)

本文使用的数据可在此找到两个data文件,本文有你帮助的话,就给个点赞关注支持一下吧!

相关文章:

Python深度学习实战:人脸关键点(15点)检测pytorch实现

引言 人脸关键点检测即对人类面部若干个点位置进行检测,可以通过这些点的变化来实现许多功能,该技术可以应用到很多领域,例如捕捉人脸的关键点,然后驱动动画人物做相同的面部表情;识别人脸的面部表情,让机…...

linux简单入门

目录Linux简介Linux目录结构Linux文件命令文件处理命令文件查看命令常用文件查看命令Linux的用户和组介绍Linux权限管理Linux简介 Linux,全称GNU/Linux,是一种免费使用和自由传播的类UNIX操作系统,其内核由林纳斯本纳第克特托瓦兹&#xff0…...

给准备面试网络工程师岗位的应届生一些建议

你听完这个故事,应该会有所收获。最近有一个23届毕业的大学生和我聊天,他现在网络工程专业大四,因为今年6、7月份的时候毕业,所以现在面临找工作的问题。不管是现在找一份实习工作,还是毕业后找一份正式工作&#xff0…...

主线程与子线程之间相互通信(HandlerThread)

平时,我们一般都是在子线程中向主线程发送消息(要在主线程更新UI),从而完成请求的处理。那么如果需要主线程来向子线程发送消息,希望子线程来完成什么任务。该怎么做?这就是这篇文章将要讨论的内容。 一、…...

13基于双层优化的电动汽车日前-实时两阶段市场竞标

MATLAB代码:基于双层优化的电动汽车日前-实时两阶段市场竞标 关键词:日前-实时市场竞标 电动汽车 双层优化 编程语言:MATLAB平台 参考文献:考虑电动汽车可调度潜力的充电站两阶段市场投标策略_詹祥澎 内容简介:…...

REDIS19_zipList压缩列表详解、快递列表 - QuickList、跳表 - SkipList

文章目录①. 压缩列表 - zipList②. 快递列表 - QuickList③. 跳表 - SkipList①. 压缩列表 - zipList ①. ZipList是一种特殊的"双端链表",由一系列特殊编码的连续内存块组成。可以在任意一端进行压入/弹出操作,并且该操作的时间复杂度为O(1) (oxff:11111111) type…...

JavaScript 基础 - 第3天

文章目录JavaScript 基础 - 第3天笔记数组数组的基本使用定义数组和数组单元数据单元值类型数组长度属性操作数组JavaScript 基础 - 第3天笔记 数组 数组的基本使用 定义数组和数组单元 <script>// 1. 语法&#xff0c;使用 [] 来定义一个空数组// 定义一个空数组let…...

23.3.26总结

康托展开 是一个全排列与自然数的映射关系&#xff0c;康托展开的实质是计算当前序列在所有从小到大的全排列中的顺序&#xff0c;跟其逆序数有关。 例如&#xff1a;对于 1,2,3,4,5 来说&#xff0c;它的康托展开值为 0*4&#xff01;0*3&#xff01;0*2&#xff01;0*1&…...

【Java学习笔记】37.Java 网络编程

Java 网络编程 网络编程是指编写运行在多个设备&#xff08;计算机&#xff09;的程序&#xff0c;这些设备都通过网络连接起来。 java.net 包中 J2SE 的 API 包含有类和接口&#xff0c;它们提供低层次的通信细节。你可以直接使用这些类和接口&#xff0c;来专注于解决问题&…...

Azure OpenAI 官方指南03|DALL-E 的图像生成功能与安全过滤机制

2021年1月&#xff0c;OpenAI 推出 DALL-E。这是 GPT 模型在图像生成方面的人工智能应用。其名称来源于著名画家、艺术家萨尔瓦多 • 达利&#xff08;Dal&#xff09;和机器人总动员&#xff08;Wall-E&#xff09;。DALL-E 图像生成器&#xff0c;能够直接根据文本描述生成多…...

【数据结构】堆

文章目录前言堆的概念及结构堆初始化堆的判空堆的销毁插入数据删除数据堆的数据个数获取堆顶数据用数组创建堆对数组堆排序有关topk问题整体代码展示写在最后前言 &#x1f6a9;前面了解了树&#xff08;-> 传送门 <-&#xff09;的概念后&#xff0c;本章带大家来实现一…...

电脑硬盘文件数据误删除/格式化为什么可以恢复? 怎么恢复?谈谈文件删除与恢复背后的原理

Hello 大家好&#xff0c; 我是元存储~ 主页&#xff1a;元存储的博客_CSDN博客 1. 硬盘数据丢失场景 我们在每天办公还是记录数据的时候&#xff0c;文件存储大多数都是通过硬盘进行存储的&#xff0c;因此&#xff0c;使用多了&#xff0c;各种问题就会出现&#xff0c;比如…...

Gateway服务网关

Spring Cloud Gateway为微服务架构提供一种简单有效的统一的 API 路由管理方式。Gateway网关是所有微服务的统一入口。网关的核心功能特性&#xff1a;请求路由和负载均衡&#xff1a;一切请求都必须先经过gateway&#xff0c;但网关不处理业务&#xff0c;而是根据某种规则&am…...

K8S + GitLab + Jenkins自动化发布项目实践(一)

K8S GitLab Jenkins自动化发布项目实践&#xff08;一&#xff09;发布流程设计安装Docker服务部署Harbor作为镜像仓库部署GitLab作为代码仓库常用Git命令发布流程设计 #mermaid-svg-pe9VmFytb9GmqMvG {font-family:"trebuchet ms",verdana,arial,sans-serif;font-…...

【数据结构篇C++实现】- 堆

文章目录&#x1f680;一、堆的原理精讲⛳&#xff08;一&#xff09;堆的概念⛳&#xff08;二&#xff09;看图识最大堆⛳&#xff08;三&#xff09;详解堆是用数组表示的树&#x1f680;二、堆的向下调整算法&#x1f680;三、堆的向上调整算法&#x1f680;四、将任意一棵…...

C++笔试题

作用域运算符(::)的作用&#xff1a;1.存在具有相同名称的局部变量时&#xff0c;访问全局变量。2.在类之外定义类相关函数。3.访问类的静态变量。4.在多重继承的情况下&#xff0c;如果两个基类中存在相同的变量名&#xff0c;可以使用作用域运算符来进行区分。5.限定成员函数…...

【Python】基本语法

数据类型 通过 print(type(x)) 可以输出 x 的数据类型&#xff0c;type() 函数可以获取数据类型 整数 a 10 print(type(a)) 浮点数 a 0.5 print(type(a)) 字符串 a hello print(type(a)) 获取字符串长度 a hello print(len(a))字符串拼接 a hello b world prin…...

用栈实现队列(图示超详解哦)

全文目录引言用栈实现队列题目介绍思路简述实现栈的部分队列的部分创建队列判断队列是否为空在队列尾入在队列头出访问队头元素释放队列总结引言 在上一篇文章中&#xff0c;我们了解了用两个队列实现栈。在这篇问章中将继续介绍用两个栈实现队列的OJ练习&#xff1a; 用栈实现…...

Spring - Spring 注解相关面试题总结

文章目录01. Spring 配置方式有几种&#xff1f;02. Spring 如何实现基于xml的配置方式&#xff1f;03. Spring 如何实现基于注解的配置&#xff1f;04. Spring 如何基于注解配置bean的作用范围&#xff1f;05. Spring Component, Controller, Repository, Service 注解有何区别…...

【数据结构】实现二叉树的基本操作

目录 1. 二叉树的基本操作 2. 具体实现 2.1 创建BinaryTree类以及简单创建一棵树 2.2 前序遍历 2.3 中序遍历 2.4 后序遍历 2.5 层序遍历 2.6 获取树中节点的个数 2.7 获取叶子节点的个数 2.8 获取第K层节点的个数 2.9 获取二叉树的高度 2.10 检测值为val的元素是否…...

代码随想录算法训练营第五十二天| ● 300.最长递增子序列 ● 674. 最长连续递增序列 ● 718. 最长重复子数组

300.最长递增子序列 看完题后的思路 dp[i] [0,i]子数组中,以nums[i]结尾的子序列的长度 dp[i]dp[j]1 j从i-1向0遍历,在所有nums[j]<nums[i]中dp[j]最大 初始化 dp[0]1 代码 class Solution {public int lengthOfLIS(int[] nums) {if (nums.length0){return 0;}int[] dpne…...

手机验证发送及其验证(基于springboot+redis)保姆级

在Java开发中&#xff0c;发送手机验证码时需要考虑以下几个问题&#xff1a; 验证码的有效期&#xff1a;验证码应该有一定的有效期&#xff0c;一般设置为几分钟或者十几分钟。过期的验证码应该被认为是无效的&#xff0c;不能用于验证用户身份。手机号码格式的校验&#xf…...

【JavaScript 逆向】数美滑块逆向分析

声明本文章中所有内容仅供学习交流&#xff0c;相关链接做了脱敏处理&#xff0c;若有侵权&#xff0c;请联系我立即删除&#xff01;案例目标验证码&#xff1a;aHR0cHM6Ly93d3cuaXNodW1laS5jb20vbmV3L3Byb2R1Y3QvdHcvY29kZQ以上均做了脱敏处理&#xff0c;Base64 编码及解码方…...

多任务之线程

文章目录一、多任务是什么&#xff1f;二、多任务-线程四、通过继承Tread类完成创建线程五、资源竞争六、同步与互斥锁七、对峙与避免死锁一、多任务是什么&#xff1f; 多个函数同时执行一件事情就是多任务&#xff0c;没有多任务的时候任务执行都是按照顺序的&#xff0c;而…...

(数字图像处理MATLAB+Python)第二章数字图像处理基础-第二节:色度学基础与颜色模型

文章目录一&#xff1a;颜色匹配二&#xff1a;CIE 1931-RGB系统三&#xff1a;CIE 1931标准色度系统四&#xff1a;CIE 1976Lab均匀颜色空间五&#xff1a;孟塞尔表色系统&#xff08;1&#xff09;孟塞尔明度(Value&#xff0c;记为V)&#xff08;2&#xff09;孟塞尔彩度(Ch…...

【华为OD机试 2023最新 】 网上商城优惠活动(C++)

文章目录 题目描述输入描述输出描述备注用例题目解析C++题目描述 某网上商场举办优惠活动,发布了满减、打折、无门槛3种优惠券,分别为: 每满100元优惠10元,无使用数限制,如100199元可以使用1张减10元,200299可使用2张减20元,以此类推;92折券,1次限使用1张,如100元,…...

记一次CentOS 8 部署packstack部署OpenStack失败案例,请直接看最后

首先你需要一台安装好CentOS8 的虚拟机&#xff0c;相关参数如图。两块网卡&#xff0c;网卡1 NAT IP 192.168.100.100 GW192.168.100.2 网卡2 可不做配置。能ping通百度。创建完成虚拟机记得打好快照。 开机编辑基本配置环境变量 [rootlocalhost ~]# nmcli connection show NA…...

【2023春招】美团技术岗笔试10min+AK

随手投递了前端&移动端,笔试2道算法+选择+行测题(为什么笔试会有行测题?) 目录 T1-火车栈结构 题意 输入描述 输出描述 样例 AC_Code T2-春游...

Echarts实现图表自适应屏幕分辨率

一&#xff1a;简介 之前做项目的时候要实现echarts图表随浏览器窗口大小变化而改变&#xff0c;echarts本身提供了一个resize()方法&#xff0c;然后我们需要用一个函数实现浏览器窗口监听&#xff0c;最初我选用的是window.onresize方法&#xff0c;当页面只有一个图表时可以…...

【2023年第十一届泰迪杯数据挖掘挑战赛】B题:产品订单的数据分析与需求预测 建模及python代码详解 问题一

相关链接 【2023年第十一届泰迪杯数据挖掘挑战赛】B题&#xff1a;产品订单的数据分析与需求预测 建模及python代码详解 问题一 【2023年第十一届泰迪杯数据挖掘挑战赛】B题&#xff1a;产品订单的数据分析与需求预测 建模及python代码详解 问题二 1 题目 一&#xff0e;问题…...

网站建设亿玛酷神奇5/seo关键词教程

根据网上的案例&#xff0c;自己做了实际配置&#xff0c;记录如下&#xff0c;以备后续参考&#xff1a; 环境说明&#xff1a; JAVA_HOMED:\Programs\Java\ TOMCAT_HOMED:\Programs\tomcat8030 1. 生成证书&#xff1a; D:\Programs\Java\bin>keytool.exe -genkey -alias …...

常州网站开发公司/百度知道答题赚钱

引言 提到事务,你肯定不陌生,和数据库打交道的时候,我们总是会用到事务。最经典的例子就是转账,你要给朋友小王转100块钱,而此时你的银行卡只有100块钱。 转账过程具体到程序里会有一系列的操作,比如查询余额、做加减法、更新余额等,这些操作必须保证是一体的,不然等…...

什么是电子商务网站/教你如何快速建站

今天&#xff0c;上线一个客户网站之后&#xff08;使用的是广州新一代虚拟空间&#xff09;发现在读取上传的pdf文件的时候读取错误&#xff0c;通过直接在浏览器输入文件地址的时候发现文件地址被重定向了&#xff08;呵呵&#xff01;&#xff09;&#xff0c;结果就是pdf文…...

海外网站建设/百度导航如何设置公司地址

上一篇文章中讲解了UE4中对类&#xff08;UCLASS&#xff09;的反射支持&#xff0c;这篇文章我们还是以实例的形式来讲解虚幻4对结构体&#xff08;USTRUCT&#xff09;以及枚举&#xff08;UENUM&#xff09;的支持。 结构体 首先让我们看一下测试结构体反射支持的代码&#…...

政府网站 banner 源码/附近的电脑培训班在哪里

继承 继承是什么&#xff1f; 继承是c的三大特性之一继承。 那么继承有什么作用&#xff1f; 继承可以提高我们代码的复用性。既然是复用&#xff0c;简单来说就是重复利用。 再举一个重复利用的例子ctrlc&#xff0c;ctrlv&#xff0c;也是重复利用&#xff0c;其实复用你…...

怎样建立商贸网站/百度快照手机入口

A一我护灯近次感观片近次感观片近次感观片近JAX(async JavaScript and XML)&#xff0c;指的是通过 JavaScript 的异步通信&#xff0c;从服务器获取 XML 文档从中提取数据&#xff0c;再更新当前网页的对应部分&#xff0c;而不用刷新整个网页。后来&#xff0c;AJAX 这个词就…...