paddle2.0高层API实现人脸关键点检测(人脸关键点检测综述_自定义网络_paddleHub_趣味ps)

本文介绍了人脸关键点检测的深度学习方法,包括DCNN、Face++版DCNN、TCDCN、MTCNN和DAN等经典模型。详细讲解了这些模型的原理和特点,并提供了数据预处理、模型训练和预测的实践指导。最后,文章展示了基于关键点检测的趣味应用,如人脸装饰预览。
摘要由CSDN通过智能技术生成

paddle2.0高层API实现人脸关键点检测(人脸关键点检测综述_自定义网络_paddleHub_趣味ps)

本文包含了:
- 人脸关键点检测综述
- 人脸关键点检测数据集介绍以及数据处理实现
- 自定义网络实现关键点检测
- paddleHub实现关键点检测
- 基于关键点检测的趣味ps

『深度学习7日打卡营·day3』

零基础解锁深度学习神器飞桨框架高层API,七天时间助你掌握CV、NLP领域最火模型及应用。

  1. 课程地址
    传送门:https://aistudio.baidu.com/aistudio/course/introduce/6771

  2. 目标

  • 掌握深度学习常用模型基础知识
  • 熟练掌握一种国产开源深度学习框架
  • 具备独立完成相关深度学习任务的能力
  • 能用所学为AI加一份年味

一、问题定义

人脸关键点检测,是输入一张人脸图片,模型会返回人脸关键点的一系列坐标,从而定位到人脸的关键信息。

人脸关键点检测是人脸识别和分析领域中的关键一步,它是诸如自动人脸识别、表情分析、三维人脸重建及三维动画等其它人脸相关问题的前提和突破口。近些年来,深度学习方法由于其自动学习及持续学习能力,已被成功应用到了图像识别与分析、语音识别和自然语言处理等很多领域,且在这些方面都带来了很显著的改善。因此,本文针对深度学习方法进行了人脸关键点检测的研究。

人脸关键点检测深度学习方法综述

Deep Convolutional Network Cascade for Facial Point Detection

2013 年,Sun 等人首次将 CNN 应用到人脸关键点检测,提出一种级联的 CNN(拥有三个层级)——DCNN(Deep Convolutional Network),此种方法属于级联回归方法。作者通过精心设计拥有三个层级的级联卷积神经网络,不仅改善初始不当导致陷入局部最优的问题,而且借助于 CNN 强大的特征提取能力,获得更为精准的关键点检测。

如图所示,DCNN 由三个 Level 构成。Level-1 由 3 个 CNN 组成;Level-2 由 10 个 CNN 组成(每个关键点采用两个 CNN);Level-3 同样由 10 个 CNN 组成。

DCNN 采用级联回归的思想,从粗到精的逐步得到精确的关键点位置,不仅设计了三级级联的卷积神经网络,还引入局部权值共享机制,从而提升网络的定位性能。最终在数据集 BioID 和 LFPW 上均获得当时最优结果。速度方面,采用 3.3GHz 的 CPU,每 0.12 秒检测一张图片的 5 个关键点。

Extensive Facial Landmark Localization with Coarse-to-fine Convolutional Network Cascade

2013 年,Face++在 DCNN 模型上进行改进,提出从粗到精的人脸关键点检测算法,实现了 68 个人脸关键点的高精度定位。该算法将人脸关键点分为内部关键点和轮廓关键点,内部关键点包含眉毛、眼睛、鼻子、嘴巴共计 51 个关键点,轮廓关键点包含 17 个关键点。

针对内部关键点和外部关键点,该算法并行的采用两个级联的 CNN 进行关键点检测,网络结构如图所示。

算法主要创新点由以下三点:

  • 把人脸的关键点定位问题,划分为内部关键点和轮廓关键点分开预测,有效的避免了 loss 不均衡问题
  • 在内部关键点检测部分,并未像 DCNN 那样每个关键点采用两个 CNN 进行预测,而是每个器官采用一个 CNN 进行预测,从而减少计算量
  • 相比于 DCNN,没有直接采用人脸检测器返回的结果作为输入,而是增加一个边界框检测层(Level-1),可以大大提高关键点粗定位网络的精度。

Face++版 DCNN 首次利用卷积神经网络进行 68 个人脸关键点检测,针对以往人脸关键点检测受人脸检测器影响的问题,作者设计 Level-1 卷积神经网络进一步提取人脸边界框,为人脸关键点检测获得更为准确的人脸位置信息,最终在当年 300-W 挑战赛上获得领先成绩。

TCDCN-Facial Landmark Detection by Deep Multi-task Learning

优点是快和多任务,不仅使用简单的端到端的人脸关键点检测方法,而且能够做到去分辨人脸的喜悦、悲伤、愤怒等分类标签属性,这样跟文章的标题或者说是文章的主题贴合——多任务。

Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Networks

2016 年,Zhang 等人提出一种多任务级联卷积神经网络(MTCNN, Multi-task Cascaded Convolutional Networks)用以同时处理人脸检测和人脸关键点定位问题。作者认为人脸检测和人脸关键点检测两个任务之间往往存在着潜在的联系,然而大多数方法都未将两个任务有效的结合起来,本文为了充分利用两任务之间潜在的联系,提出一种多任务级联的人脸检测框架,将人脸检测和人脸关键点检测同时进行。

MTCNN 包含三个级联的多任务卷积神经网络,分别是 Proposal Network (P-Net)、Refine Network (R-Net)、Output Network (O-Net),每个多任务卷积神经网络均有三个学习任务,分别是人脸分类、边框回归和关键点定位。网络结构如图所示:

MTCNN 实现人脸检测和关键点定位分为三个阶段。首先由 P-Net 获得了人脸区域的候选窗口和边界框的回归向量,并用该边界框做回归,对候选窗口进行校准,然后通过非极大值抑制(NMS)来合并高度重叠的候选框。然后将 P-Net 得出的候选框作为输入,输入到 R-Net,R-Net 同样通过边界框回归和 NMS 来去掉那些 false-positive 区域,得到更为准确的候选框;最后,利用 O-Net 输出 5 个关键点的位置。

DAN(Deep Alignment Networks)

2017 年,Kowalski 等人提出一种新的级联深度神经网络——DAN(Deep Alignment Network),以往级联神经网络输入的是图像的某一部分,与以往不同,DAN 各阶段网络的输入均为整张图片。当网络均采用整张图片作为输入时,DAN 可以有效的克服头部姿态以及初始化带来的问题,从而得到更好的检测效果。之所以 DAN 能将整张图片作为输入,是因为其加入了关键点热图(Landmark Heatmaps),关键点热图的使用是本文的主要创新点。DAN 基本框架如图所示:

DAN 包含多个阶段,每一个阶段含三个输入和一个输出,输入分别是被矫正过的图片、关键点热图和由全连接层生成的特征图,输出是面部形状(Face Shape)。其中,CONNECTION LAYER 的作用是将本阶段得输出进行一系列变换,生成下一阶段所需要的三个输入

PFLD: A Practical Facial Landmark Detector

这个人脸检测算法PFLD,全文名称为《PFLD: A Practical Facial Landmark Detector》。作者分别来自天津大学、武汉大学、腾讯AI实验室、美国天普大学。该算法对嵌入式设备非常优化,在骁龙845的芯片中效率可达140fps;另外模型大小较小,仅2.1MB;此外在许多关键点检测的benchmark中也取得了相当好的结果。综上,该算法在实际的应用场景中(如低算力的端上设备)有很大的应用空间。

PFLD模型设计

在模型设计上,PFLD的模型设计上骨干网络没有采用VGG16、ResNet等大模型,但是为了增加模型的表达能力,对Mobilenet的输出特征进行了结构上的修改。

PFLD的模型训练策略

一开始我们设计的那个简单的网络,采用的损失函数为MSE,所以为了平衡各种情况的训练数据,我们只能通过增加极端情况下的训练数据、平衡各类情况下的训练数据的比例、控制数据数据的采样形式(非完全随机采样)等方式进行性能调优。

  • 损失函数设计

    PFLD采用了一种很优雅的方式来处理上述各情况样本不均衡的问题,我们先看看其损失函数的设计:

    上式中 wn为可调控的权值函数(针对不同的情况选取不同的权值,如正常情况、遮挡情况、暗光情况等等),theta为人脸姿态的三维欧拉角(K=3),d为回归的landmark和groundtrue的度量(一般情况下为MSE,也可以选L1度量)。该损失函数设计的目的是,对于样本量比较大的数据(如正脸,即欧拉角都相对较小的情况),给予一个小的权值,在进行梯度的反向传播的时候,对模型训练的贡献小一些;对于样本量比较少的数据(侧脸、低头、抬头、表情极端),给予一个较大的权值,从而使在进行梯度的反向传播的时候,对模型训练的贡献大一些。该模型的损失函数的设计,非常巧妙的解决了平衡各类情况训练样本不均衡的问题。

  • 配合训练的子网络

    PFLD的训练过程中引入了一个子网络,用以监督PFLD网络模型的训练。该子网络仅在训练的阶段起作用,在inference的时候不参与;该子网络的用处,是对于每一个输入的人脸样本,对该样本进行三维欧拉角的估计,其groundtruth由训练数据中的关键点信息进行估计,虽然估计的不够精确,但是作为区分数据分布的依据已经足够了,毕竟还该网络的目的是监督和辅助训练收敛,主要是为了服务关键点检测网络。有一个地方挺有意思的是,该子网络的输入不是训练数据,而是PFLD主网络的中间输出,如下图:

主网络和姿态估计子网络的详细配置如下表:

# 环境导入
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

import cv2
import paddle

paddle.set_device('gpu') # 设置为GPU

import warnings 
warnings.filterwarnings('ignore') # 忽略 warning
paddle.__version__
'2.0.0'

二、数据准备

传统人脸关键点检测数据库为室内环境下采集的数据库,比如Multi-pieFeret、FrgcAR、BioID 等人脸数据库。而现阶段人脸关键点检测数据库通常为复杂环境下采集的数据库.LFPW 人脸数据库有 1132 幅训练人脸图像和 300 幅测试人脸图像,大部分为正面人脸图像,每个人脸标定 29 个关键点。AFLW 人脸数据库包含 25993 幅从 Flickr 采集的人脸图像,每个人脸标定 21 个关键点。COFW 人脸数据库包含 LFPW 人脸数据库训练集中的 845 幅人脸图像以及其他 500 幅遮挡人脸图像,而测试集为 507 幅严重遮挡(同时包含姿态和表情的变化)的人脸图像,每个人脸标定 29 个关键点。MVFW 人脸数据库为多视角人脸数据集,包括 2050 幅训练人脸图像和 450 幅测试人脸图像,每个人脸标定 68 个关键点。OCFW 人脸数据库包含 2951 幅训练人脸图像(均为未遮挡人脸)和 1246 幅测试人脸图像(均为遮挡人脸),每个人脸标定 68 个关键点。

2.1 下载数据集

本次实验所采用的数据集来源为github的开源项目

目前该数据集已上传到 AI Studio 人脸关键点识别,加载后可以直接使用下面的命令解压。

# 覆盖且不显示
# !unzip -o -q data/data69065/data.zip   

解压后的数据集结构为

data/
|—— test
|   |—— Abdel_Aziz_Al-Hakim_00.jpg
    ... ...
|—— test_frames_keypoints.csv
|—— training
|   |—— Abdullah_Gul_10.jpg
    ... ...
|—— training_frames_keypoints.csv

其中,trainingtest 文件夹分别存放训练集和测试集。training_frames_keypoints.csvtest_frames_keypoints.csv 存放着训练集和测试集的标签。接下来,我们先来观察一下 training_frames_keypoints.csv 文件,看一下训练集的标签是如何定义的。

key_pts_frame = pd.read_csv('data/training_frames_keypoints.csv') # 读取数据集
print('Number of images: ', key_pts_frame.shape[0]) # 输出数据集大小
key_pts_frame.head(5) # 看前五条数据
Number of images:  3462
Unnamed: 0 0 1 2 3 4 5 6 7 8 ... 126 127 128 129 130 131 132 133 134 135
0 Luis_Fonsi_21.jpg 45.0 98.0 47.0 106.0 49.0 110.0 53.0 119.0 56.0 ... 83.0 119.0 90.0 117.0 83.0 119.0 81.0 122.0 77.0 122.0
1 Lincoln_Chafee_52.jpg 41.0 83.0 43.0 91.0 45.0 100.0 47.0 108.0 51.0 ... 85.0 122.0 94.0 120.0 85.0 122.0 83.0 122.0 79.0 122.0
2 Valerie_Harper_30.jpg 56.0 69.0 56.0 77.0 56.0 86.0 56.0 94.0 58.0 ... 79.0 105.0 86.0 108.0 77.0 105.0 75.0 105.0 73.0 105.0
3 Angelo_Reyes_22.jpg 61.0 80.0 58.0 95.0 58.0 108.0 58.0 120.0 58.0 ... 98.0 136.0 107.0 139.0 95.0 139.0 91.0 139.0 85.0 136.0
4 Kristen_Breitweiser_11.jpg 58.0 94.0 58.0 104.0 60.0 113.0 62.0 121.0 67.0 ... 92.0 117.0 103.0 118.0 92.0 120.0 88.0 122.0 84.0 122.0

5 rows × 137 columns

上表中每一行都代表一条数据,其中,第一列是图片的文件名,之后从第0列到第135列,就是该图的关键点信息。因为每个关键点可以用两个坐标表示,所以 136/2 = 68,就可以看出这个数据集为68点人脸关键点数据集。

Tips1: 目前常用的人脸关键点标注,有如下点数的标注

  • 5点
  • 21点
  • 68点
  • 98点

Tips2:本次所采用的68标注,标注顺序如下:

# 计算标签的均值和标准差,用于标签的归一化
key_pts_values = key_pts_frame.values[:,1:] # 取出标签信息
data_mean = key_pts_values.mean() # 计算均值
data_std = key_pts_values.std()   # 计算标准差
print('标签的均值为:', data_mean)
print('标签的标准差为:', data_std)
标签的均值为: 104.4724870017331
标签的标准差为: 43.17302271754281

2.2 查看图像

def show_keypoints(image, key_pts):
    """
    Args:
        image: 图像信息
        key_pts: 关键点信息,
    展示图片和关键点信息
    """
    plt.imshow(image.astype('uint8'))  # 展示图片信息
    for i in range(len(key_pts)//2,):
        plt.scatter(key_pts[i*2], key_pts[i*2+1], s=20, marker='.', c='b')  # 展示关键点信息 蓝色散点
# 展示单条数据

n = int(np.random.randint(1, 3462, size=1)) # n为数据在表格中的索引 
image_name = key_pts_frame.iloc[n, 0] # 获取图像名称
key_pts = key_pts_frame.iloc[n, 1:].as_matrix() # 将图像label格式转为numpy.array的格式
key_pts = key_pts.astype('float').reshape(-1) # 获取图像关键点信息
print(key_pts.shape)
plt.figure(figsize=(10, 10)) # 展示的图像大小
show_keypoints(mpimg.imread(os.path.join('data/training/', image_name)), key_pts) # 展示图像与关键点信息
plt.show() # 展示图像
(136,)

在这里插入图片描述

2.3 数据集定义

使用飞桨框架高层API的 paddle.io.Dataset 自定义数据集类,具体可以参考官网文档 自定义数据集

作业1:自定义 Dataset,完成人脸关键点数据集定义

按照 __init__ 中的定义,实现 __getitem____len__.

# 按照Dataset的使用规范,构建人脸关键点数据集

from paddle.io import Dataset

class FacialKeypointsDataset(Dataset):
    # 人脸关键点数据集
    """
    步骤一:继承paddle.io.Dataset类
    """
    def __init__(self, csv_file, root_dir, transform=None):
        """
        步骤二:实现构造函数,定义数据集大小
        Args:
            csv_file (string): 带标注的csv文件路径
            root_dir (string): 图片存储的文件夹路径
            transform (callable, optional): 应用于图像上的数据处理方法
        """
        self.key_pts_frame = pd.read_csv(csv_file) # 读取csv文件
        self.root_dir = root_dir # 获取图片文件夹路径
        self.transform = transform # 获取 transform 方法

    def __getitem__(self, idx):
        """
        步骤三:实现__getitem__方法,定义指定index时如何获取数据,并返回单条数据(训练数据,对应的标签)
        """

        # 实现 __getitem__
        image_dir = os.path.join(self.root_dir, self.key_pts_frame.iloc[idx, 0])
        # 读取图像
        image = mpimg.imread(image_dir)
        
        # 去除图像\alpha通道
        if image.shape[-1] == 4:
            image = image[..., 0:3]
        
        # 读取关键点
        key_pts = self.key_pts_frame.iloc[idx, 1:].as_matrix()  # 不读取name
        key_pts = key_pts.astype('float').reshape(-1)  # [136, 1]
        
        # 数据增强
        if self.transform:
            image, key_pts = self.transform([image, key_pts])
        
        # to_numpy
        image = np.array(image, dtype='float32')
        key_pts = np.array(key_pts, dtype='float32')

        return image, key_pts

    def __len__(self):
        """
        步骤四:实现__len__方法,返回数据集总数目
        """
        
        # 实现 __len__
        return len(self.key_pts_frame)
        

2.4 训练集可视化

实例化数据集并显示一些图像。

# 构建一个数据集类
face_dataset = FacialKeypointsDataset(csv_file='data/training_frames_keypoints.csv',
                                      root_dir='data/training/')

# 输出数据集大小
print('数据集大小为: ', len(face_dataset))
# 根据 face_dataset 可视化数据集
num_to_display = 3

for i in range(num_to_display):
    
    # 定义图片大小
    fig = plt.figure(figsize=(20,10))
    
    # 随机选择图片
    rand_i = np.random.randint(0, len(face_dataset))
    sample = face_dataset[rand_i]

    # 输出图片大小和关键点的数量
    print(i, sample[0].shape, sample[1].shape)

    # 设置图片打印信息
    ax = plt.subplot(1, num_to_display, i + 1)
    ax.set_title('Sample #{}'.format(i))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值