热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用Keras和CNN进行自定义AI人脸识别

目录介绍什么是CNN?设计CNN实现CNN训练CNN下一步?下载源8.4KB介绍如果您看过《少数派报告》电影,您可能还记得

目录

介绍

什么是CNN?

设计CNN

实现CNN

训练CNN

下一步?




  • 下载源8.4 KB

介绍

如果您看过《少数派报告》电影,您可能还记得汤姆·克鲁斯(Tom Cruise)走进一家Gap商店的场景。视网膜扫描仪读取他的眼睛,并为他播放定制的广告。好吧,这是2020年。我们不需要视网膜扫描仪,因为我们拥有人工智能(AI)和机器学习(ML)!

在本系列中,我们将向您展示如何使用深度学习进行面部识别,然后基于被识别的面部,使用神经网络语音合成(TTS)引擎播放自定义广告。

我们假设您熟悉AI/ML的基本概念,并且可以找到使用Python的方法。

在本文中,我们将讨论CNN,然后设计一个并使用KerasPython中实现它。


什么是CNN?

CNN是一种神经网络(NN),通常用于图像分类任务(例如人脸识别)以及任何其他输入具有网格状拓扑的问题。在CNN中,并非每个节点都连接到下一层的所有节点。换句话说,它们不是完全连接的NN。这有助于防止完全连接的NN中出现过拟合问题,更不用说由NN中的过多连接导致的超慢收敛。

CNN的概念依赖于称为卷积的数学运算,这在数字信号处理领域非常普遍。卷积被定义为两个函数(第三个函数)的乘积,表示前两个函数之间的重叠量。在CNN区域,通过在图像中滑动过滤器(即内核)来实现卷积。

在人脸识别中,卷积操作使我们能够检测图像中的不同特征。不同的过滤器可以检测垂直和水平边缘、纹理、曲线和其他图像特征。这就是为什么任何CNN中的第一层都是卷积层的原因。

CNN中另一个常见的层是池化层。池化用于减小图像表示的大小,这意味着减少了参数数量,并最终减少了计算量。最常见的池化类型是“max”,它使用滑动窗口(类似于卷积操作中的窗口)在每个位置从匹配的单元格组中获取最大值。最后,它根据收获的最大值构建图像的新表示形式。

最常见的CNN架构通常从卷积层开始,然后是激活层,然后是池化层,最后以传统的全连接网络(例如多层NN)结束。这种层次化的模型称为顺序模型。为什么最后要建立全连接网络?要学习变换图像中特征的非线性组合(在卷积和合并之后)。


设计CNN

这是我们将在CNN中实现的架构:


  • 输入层——NumPy数组(img_width,img_height,1);“ 1” 因为我们正在处理灰度图像;对于RGB图像,应该是(img_width,img_height,3)
  • Conv2D层——32个过滤器,过滤器大小为3
  • 激活层——必须使用非线性函数进行学习,在这种情况下,该函数为ReLU
  • Conv2D层——32个过滤器,过滤器大小为3,步幅为3
  • 使用ReLU功能的激活层
  • MaxPooling2D层——应用(2,2)合并窗口
  • 25%的DropOut层——通过从前一层中随机删除一些值(将它们设置为0)来防止过度拟合;又名稀释技术
  • Conv2D层——64个过滤器,过滤器大小为3
  • 使用ReLU功能的激活层
  • Conv2D层——64个过滤器,过滤器大小为3,步幅为3
  • 使用ReLU功能的激活层
  • MaxPooling2D层——应用(2,2)合并窗口
  • DropOut层,占25%
  • 展平层——转换要在下一层使用的数据
  • 致密层——代表完全连接的传统NN
  • 使用ReLU功能的激活层
  • DropOut层,占25%
  • 密集层,节点数与问题中的类数匹配——Yale数据集为15
  • 使用ReLU功能的激活层

上面的架构很常见;层参数已通过实验进行了微调。


实现CNN

现在,让我们在代码中实现我们的CNN架构-我们选择的一组图层。为了创建易于扩展的解决方案,我们将ML模型与一组抽象方法结合使用:


class MLModel(metaclass=abc.ABCMeta):def __init__(self, dataSet=None):if dataSet is not None:self.objects = dataSet.objectsself.labels = dataSet.labelsself.obj_validation = dataSet.obj_validationself.labels_validation = dataSet.labels_validationself.number_labels = dataSet.number_labelsself.n_classes = dataSet.n_classesself.init_model()@abstractmethoddef init_model(self):pass@abstractmethoddef train(self):pass@abstractmethoddef predict(self, object):pass@abstractmethoddef evaluate(self):score = self.get_model().evaluate(self.obj_validation, self.labels_validation, verbose=0)print("%s: %.2f%%" % (self.get_model().metrics_names[1], score[1] * 100))@abstractmethoddef get_model(self):pass

在我们的例子中,dataset是本系列上一篇文章中描述的FaceDataSet类的实例。ConvolutionalModel类,它从MLModel中继承和实现其所有的抽象方法,是一个将包含我们的CNN架构的类。这里是:



class ConvolutionalModel(MLModel):def __init__(self, dataSet=None):if dataSet is None:raise Exception("DataSet is required in this model")self.shape = numpy.array([constant.IMG_WIDTH, constant.IMG_HEIGHT, 1])super().__init__(dataSet)self.cnn.compile(loss=constant.LOSS_FUNCTION,optimizer=Common.get_sgd_optimizer(),metrics=[constant.METRIC_ACCURACY])def init_model(self):self.cnn = Sequential()self.cnn.add(Convolution2D(32, 3, padding=constant.PADDING_SAME, input_shape=self.shape))self.cnn.add(Activation(constant.RELU_ACTIVATION_FUNCTION))self.cnn.add(Convolution2D(32, 3, 3))self.cnn.add(Activation(constant.RELU_ACTIVATION_FUNCTION))self.cnn.add(MaxPooling2D(pool_size=(2, 2)))self.cnn.add(Dropout(constant.DROP_OUT_O_25))self.cnn.add(Convolution2D(64, 3, padding=constant.PADDING_SAME))self.cnn.add(Activation(constant.RELU_ACTIVATION_FUNCTION))self.cnn.add(Convolution2D(64, 3, 3))self.cnn.add(Activation(constant.RELU_ACTIVATION_FUNCTION))self.cnn.add(MaxPooling2D(pool_size=(2, 2)))self.cnn.add(Dropout(constant.DROP_OUT_O_25))self.cnn.add(Flatten())self.cnn.add(Dense(constant.NUMBER_FULLY_CONNECTED))self.cnn.add(Activation(constant.RELU_ACTIVATION_FUNCTION))self.cnn.add(Dropout(constant.DROP_OUT_0_50))self.cnn.add(Dense(self.n_classes))self.cnn.add(Activation(constant.SOFTMAX_ACTIVATION_FUNCTION))self.cnn.summary()def train(self, n_epochs=20, batch=32):self.cnn.fit(self.objects, self.labels,batch_size=batch,epochs=n_epochs, shuffle=True)def get_model(self):return self.cnndef predict(self, image):image = Common.to_float(image)result = self.cnn.predict(image)print(result)def evaluate(self):super(ConvolutionalModel, self).evaluate()

在构造函数中,我们设置self.shape变量,该变量定义输入层的形状。在我们的例子中,对于Yale数据集,图像高度为320像素,宽度为243像素,self.shape =(320, 243, 1)


然后,我们调用super()从父构造函数获取所有与数据集相关的变量集,并调用init_model()初始化模型的方法。

最后,我们调用compile方法,该方法配置用于训练的模型并设置要在loss参数中使用的目标函数。在训练过程中,目标功能得到了优化(最小化或最大化)。accuracy参数定义在训练中评估模型的度量。optimizer参数定义权重的计算方式。最常见的优化器是梯度下降

我们的CNN模型定义为顺序的,并根据体系结构的要求添加所有层。train()方法使用表示层排列的sequential类的fit方法来训练CNN。此方法接收训练CNN的数据作为输入,该数据的正确分类以及一些可选参数,例如要运行的时期数。


训练CNN

现在,代码已经准备就绪,该开始训练我们的CNN了。让我们实例化ConvolutionalModel类,在Yale数据集上进行训练,然后调用评估方法。


cnn = ConvolutionalModel(dataSet)
cnn.train(n_epochs=50)
cnn.evaluate()

在进行了50个时期的训练后,我们在测试图像上的准确性达到了近85%。


这意味着我们的CNN现在将以85%的概率识别出数据集中15个主题中的每个主题。简短的练习还不错吧?

现在,我们已经训练了CNN,如果我们想预测新的传入数据(意味着来自图像的新面孔),则可以使用之前详细介绍的ConvolutionalModel类中的predict(image)方法来进行。如何运作?该调用看起来像下一个调用,它应符合某些假设。


cnn.predict(np.expand_dims(image, axis=0))

首先,输入图像必须具有与先前训练的CNN输入层相同的尺寸或形状。其次,在我们归一化数据的predict()方法中,它应该是相同类型的输入,即像素值矩阵,因此无需提供归一化的图像像素矩阵。第三,我们可能需要为输入的面部图像添加一个维度,因为在经过训练的CNN中,我们考虑了数据集中样本数量的第4个维度。这可以使用numpyexpand_dims()方法来实现。第四,假定将提供面部图像,在较大图片的情况下,先前文章中提供的面部检测方法可证明是有用的。


最后,predict()方法的输出可以在上图中看到。此方法将输出脸部属于每个可能类别或个人的概率(对于训练后的数据集为15)。在这种情况下,我们可以看到类别4的可能性最高,这正是输入的面部图像所指的类别或人物。


下一步?

现在我们知道了如何从头开始构建自己的CNN。在下一篇文章中,我们将研究一种替代方法——利用预先训练的模型。我们将使用一个经过训练的CNN来对具有数百万个图像的数据集进行人脸识别训练,并对其进行调整以解决我们的问题。敬请关注!


推荐阅读
  • Learning to Paint with Model-based Deep Reinforcement Learning
    本文介绍了一种基于模型的深度强化学习方法,通过结合神经渲染器,教机器像人类画家一样进行绘画。该方法能够生成笔画的坐标点、半径、透明度、颜色值等,以生成类似于给定目标图像的绘画。文章还讨论了该方法面临的挑战,包括绘制纹理丰富的图像等。通过对比实验的结果,作者证明了基于模型的深度强化学习方法相对于基于模型的DDPG和模型无关的DDPG方法的优势。该研究对于深度强化学习在绘画领域的应用具有重要意义。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了在wepy中运用小顺序页面受权的计划,包含了用户点击作废后的从新受权计划。 ... [详细]
  • 本文介绍了在满足特定条件时如何在输入字段中使用默认值的方法和相应的代码。当输入字段填充100或更多的金额时,使用50作为默认值;当输入字段填充有-20或更多(负数)时,使用-10作为默认值。文章还提供了相关的JavaScript和Jquery代码,用于动态地根据条件使用默认值。 ... [详细]
  • 提升Python编程效率的十点建议
    本文介绍了提升Python编程效率的十点建议,包括不使用分号、选择合适的代码编辑器、遵循Python代码规范等。这些建议可以帮助开发者节省时间,提高编程效率。同时,还提供了相关参考链接供读者深入学习。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • PHP中的单例模式与静态变量的区别及使用方法
    本文介绍了PHP中的单例模式与静态变量的区别及使用方法。在PHP中,静态变量的存活周期仅仅是每次PHP的会话周期,与Java、C++不同。静态变量在PHP中的作用域仅限于当前文件内,在函数或类中可以传递变量。本文还通过示例代码解释了静态变量在函数和类中的使用方法,并说明了静态变量的生命周期与结构体的生命周期相关联。同时,本文还介绍了静态变量在类中的使用方法,并通过示例代码展示了如何在类中使用静态变量。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
author-avatar
mobiledu2502852923
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有