从零开始构建:使用CNN和TensorFlow进行人脸特征检测

简介: 从零开始构建:使用CNN和TensorFlow进行人脸特征检测

人脸检测系统在当今世界中具有巨大的用途,这个系统要求安全性,可访问性和趣味性!今天,我们将建立一个可以在脸上绘制15个关键点的模型。

人脸特征检测模型形成了我们在社交媒体应用程序中看到的各种功能。您在Instagram上找到的面部过滤器是一个常见的用例。该算法将掩膜(mask)在图像上对齐,并以脸部特征作为模型的基点。

image.png

Instagram自拍过滤器需要知道您的眼睛,嘴唇和鼻子在图像上的确切位置

让我们使用Keras(TensorFlow作为底层)开发模型!首先,我们需要一些数据来训练我们的模型。

数据

我们使用Omri Goldstein Kaggle 上的带有标记特征的人脸图像数据集。数据集包含大约7000张图像(96*96),这些图像带有可以在facial_keypoints.csv文件中找到的面部标志。

但是在这里我们有一个问题。大多数图像没有15个完整的点集。因此,我们只需要那些具有15个面部关键点的图像即可。

可以使用此脚本,我已经做了一些清理,并将修改后的数据保存在Dataset Archives GitHub中。Colab notebook需要使用wget命令下载ZIP文件。

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
# Download the dataset from Kaggle. Unzip the archive. You'll find the facial_keypoints.csv file there.
facial_keypoints = pd.read_csv( "files/face-images-with-marked-landmark-points/facial_keypoints.csv")
num_missing_keypoints = facial_keypoints.isnull().sum( axis=1 )
all_keypoints_present_ids = np.nonzero( num_missing_keypoints == 0 )[ 0 ]
# face_images.npz is present the same archive.
d = np.load( "files/face-images-with-marked-landmark-points/face_images.npz")
dataset = d[ 'face_images' ].T
dataset = np.reshape( dataset , ( -1 , 96 , 96 , 1 ) )
images = dataset[  all_keypoints_present_ids , : , : , : ]
keypoints = facial_keypoints.iloc[ all_keypoints_present_ids , : ].reset_index( drop=True ).values
x_train, x_test, y_train, y_test = train_test_split( images , keypoints , test_size=0.3 )
# Save all the processed data.
np.save( "processed_data/x_train.npy" , x_train )
np.save( "processed_data/y_train.npy" , y_train )
np.save( "processed_data/x_test.npy" , x_test )
np.save( "processed_data/y_test.npy" , y_test )

我们还将图像以及坐标(关键点)进行了标准化处理。我们对y_train和y_test进行了重塑操作,因为它们将成为卷积层(Conv2D)而不是全连接层(Dense)的输出。

x_train = np.load( "face_landmarks_cleaned/x_train.npy" ) / 255
y_train = np.load( "face_landmarks_cleaned/y_train.npy" ) / 96
x_test = np.load( "face_landmarks_cleaned/x_test.npy" ) / 255
y_test = np.load( "face_landmarks_cleaned/y_test.npy" ) / 96
y_train = np.reshape( y_train , ( -1 , 1 , 1 , 30 ))
y_test = np.reshape( y_test , ( -1 , 1 , 1 , 30 ))

提示:我们找到了另一个用于人脸特征检测的数据集,称为UTKFace。它包含68个面部关键点以及其他特征,例如年龄和性别。可以尝试一下!

讨论模型

下面让我们讨论该模型的结构。我对该模型做了一些实验。我们需要一个模型,该模型采用尺寸为(96,96)的图像作为输入并输出形状为(30,)的数组(15个关键点* 2个坐标)

1.第一种模型读取一张图像,并将其通过预先训练的VGG网络。接下来,将VGG的输出展平并通过多个全连接层。问题在于,即使损失很小,模型也可以为每个图像预测相同的关键点。

2.第二种模型是您可以在Colab notebook中找到的模型。我们不使用全连接层。相反,我们将图像传递给卷积层,并获得形状为(1,1,30)的输出。因此,卷积层为我们提供了输出。使用此模型,对于每张图像甚至在数据集之外的图像,预测值都是不同的!

我们的模型是这样的。

model_layers = [
    tf.keras.layers.Conv2D( 256 , input_shape=( 96 , 96 , 1 ) , kernel_size=( 3 , 3 ) , strides=2 , activation='relu' ),
    tf.keras.layers.Conv2D( 256 , kernel_size=( 3 , 3 ) , strides=2 , activation='relu' ),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Conv2D( 128 , kernel_size=( 3 , 3 ) , strides=1 , activation='relu' ),
    tf.keras.layers.Conv2D( 128 , kernel_size=( 3 , 3 ) , strides=1 , activation='relu' ),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Conv2D( 128 , kernel_size=( 3 , 3 ) , strides=1 , activation='relu' ),
    tf.keras.layers.Conv2D( 128 , kernel_size=( 3 , 3 ) , strides=1 , activation='relu' ),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Conv2D( 64 , kernel_size=( 3 , 3 ) , strides=1 , activation='relu' ),
    tf.keras.layers.Conv2D( 64 , kernel_size=( 3 , 3 ) , strides=1 , activation='relu' ),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Conv2D( 32 , kernel_size=( 3 , 3 ) , strides=1 , activation='relu' ),
    tf.keras.layers.Conv2D( 32 , kernel_size=( 3 , 3 ) , strides=1 , activation='relu' ),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Conv2D( 30 , kernel_size=( 3 , 3 ) , strides=1 , activation='relu' ),
    tf.keras.layers.Conv2D( 30 , kernel_size=( 3 , 3 ) , strides=1 , activation='relu' ),
    tf.keras.layers.Conv2D( 30 , kernel_size=( 3 , 3 ) , strides=1 ),
]
model = tf.keras.Sequential( model_layers )
model.compile( loss=tf.keras.losses.mean_squared_error , optimizer=tf.keras.optimizers.Adam( lr=0.0001 ) , metrics=[ 'mse' ] )

在执行回归任务时,我们使用 均方误差(MSE)。如果您有大量的数据,那么较小的学习率总是好的。

训练和相关推论

我们训练模型约250次,批处理数量为50个。训练后,我们将在测试集上进行一些预测。

import matplotlib.pyplot as plt
fig = plt.figure(figsize=( 50 , 50 ))
for i in range( 1 , 6 ):
    sample_image = np.reshape( x_test[i] * 255  , ( 96 , 96 ) ).astype( np.uint8 )
    pred = model.predict( x_test[ i : i +1  ] ) * 96
    pred = pred.astype( np.int32 )
    pred = np.reshape( pred[0 , 0 , 0 ] , ( 15 , 2 ) )
    fig.add_subplot( 1 , 10 , i )
    plt.imshow( sample_image.T , cmap='gray' )
    plt.scatter( pred[ : , 0 ] , pred[ : , 1 ] , c='yellow' )
plt.show()

生成预测值

注意:请记住输入图像的旋转角度。在旋转90度的图像上训练的模型无法为没有进行旋转的图像生成正确的预测。

如果您未对模型和训练参数进行修改,则经过250次训练后的模型应如下图所示:

image.png

结果

印象相当深刻吧?就这样!您刚刚从头开始构建了一个人脸特征检测模型。 在Colab notebook中,我设置了一个代码单元,您可以将网络上的图像或摄像头拍摄的图像放入其中并运行模型。

目录
相关文章
|
29天前
|
机器学习/深度学习 TensorFlow 算法框架/工具
【大作业-04】手把手教你构建垃圾分类系统-基于tensorflow2.3
本文介绍了基于TensorFlow 2.3的垃圾分类系统,通过B站视频和博客详细讲解了系统的构建过程。系统使用了包含8万张图片、245个类别的数据集,训练了LeNet和MobileNet两个卷积神经网络模型,并通过PyQt5构建了图形化界面,用户上传图片后,系统能识别垃圾的具体种类。此外,还提供了模型和数据集的下载链接,方便读者复现实验。垃圾分类对于提高资源利用率、减少环境污染具有重要意义。
36 0
【大作业-04】手把手教你构建垃圾分类系统-基于tensorflow2.3
|
3天前
|
机器学习/深度学习 TensorFlow 算法框架/工具
利用Python和TensorFlow构建简单神经网络进行图像分类
利用Python和TensorFlow构建简单神经网络进行图像分类
14 3
|
19天前
|
机器学习/深度学习 数据可视化 TensorFlow
使用TensorFlow构建一个简单的图像分类模型
【10月更文挑战第18天】使用TensorFlow构建一个简单的图像分类模型
44 1
|
26天前
|
机器学习/深度学习 SQL 数据采集
基于tensorflow、CNN网络识别花卉的种类(图像识别)
基于tensorflow、CNN网络识别花卉的种类(图像识别)
22 1
|
1月前
|
机器学习/深度学习 TensorFlow API
使用 TensorFlow 和 Keras 构建图像分类器
【10月更文挑战第2天】使用 TensorFlow 和 Keras 构建图像分类器
|
2月前
|
机器学习/深度学习 数据采集 数据可视化
深度学习实践:构建并训练卷积神经网络(CNN)对CIFAR-10数据集进行分类
本文详细介绍如何使用PyTorch构建并训练卷积神经网络(CNN)对CIFAR-10数据集进行图像分类。从数据预处理、模型定义到训练过程及结果可视化,文章全面展示了深度学习项目的全流程。通过实际操作,读者可以深入了解CNN在图像分类任务中的应用,并掌握PyTorch的基本使用方法。希望本文为您的深度学习项目提供有价值的参考与启示。
|
3月前
|
Java Spring Apache
Spring Boot邂逅Apache Wicket:一次意想不到的完美邂逅,竟让Web开发变得如此简单?
【8月更文挑战第31天】Apache Wicket与Spring Boot的集成提供了近乎无缝的开发体验。Wicket以其简洁的API和强大的组件化设计著称,而Spring Boot则以开箱即用的便捷性赢得开发者青睐。本文将指导你如何在Spring Boot项目中引入Wicket,通过简单的步骤完成集成配置。首先,创建一个新的Spring Boot项目并在`pom.xml`中添加Wicket相关依赖。
93 0
|
3月前
|
Apache UED 数据安全/隐私保护
揭秘开发效率提升秘籍:如何通过Apache Wicket组件重用技巧大翻新用户体验
【8月更文挑战第31天】张先生在开发基于Apache Wicket的企业应用时,发现重复的UI组件增加了维护难度并影响加载速度。为优化体验,他提出并通过面板和组件重用策略解决了这一问题。例如,通过创建`ReusableLoginPanel`类封装登录逻辑,使得其他页面可以轻松复用此功能,从而减少代码冗余、提高开发效率及页面加载速度。这一策略还增强了应用的可维护性和扩展性,展示了良好组件设计的重要性。
52 0
|
3月前
|
安全 Apache 数据安全/隐私保护
你的Wicket应用安全吗?揭秘在Apache Wicket中实现坚不可摧的安全认证策略
【8月更文挑战第31天】在当前的网络环境中,安全性是任何应用程序的关键考量。Apache Wicket 是一个强大的 Java Web 框架,提供了丰富的工具和组件,帮助开发者构建安全的 Web 应用程序。本文介绍了如何在 Wicket 中实现安全认证,
43 0
|
3月前
|
Java 前端开发 Apache
Apache Wicket与Spring MVC等Java Web框架大PK,究竟谁才是你的最佳拍档?点击揭秘!
【8月更文挑战第31天】在Java Web开发领域,众多框架各具特色。Apache Wicket以组件化开发和易用性脱颖而出,提高了代码的可维护性和可读性。相比之下,Spring MVC拥有强大的生态系统,但学习曲线较陡;JSF与Java EE紧密集成,但在性能和灵活性上略逊一筹;Struts2虽成熟,但在RESTful API支持上不足。选择框架时还需考虑社区支持和文档完善程度。希望本文能帮助开发者找到最适合自己的框架。
44 0

热门文章

最新文章

下一篇
无影云桌面