想象一下,就像汤姆·克鲁斯走进一家Gap商店,视网膜扫描仪读取他的眼睛,并为他播放定制广告一样。现在是2020年,不需要视网膜扫描仪,因为拥有人工智能(AI)和机器学习(ML)!
在这个系列中,将向展示如何使用深度学习进行面部识别,然后——基于被识别的面部——使用神经网络文本到语音(TTS)引擎播放定制广告。欢迎在CodeProject上浏览代码,或者下载.zip文件在自己的机器上浏览代码。
假设熟悉AI/ML的基本概念,并且能够使用Python进行操作。
为什么使用别人的CNN?
到目前为止,已经完成了设计、实现和训练自己的面部识别CNN所需的一切。在本文中,将探讨一种替代方法——使用预训练的VGG(牛津大学视觉几何组)模型。这些CNN已经在大型数据集上设计和训练,取得了优异的结果。
为什么要重用别人为他们的数据集设计和训练的CNN,显然与数据集不同?嗯,主要原因是有人花费了大量的CPU/GPU时间在大型数据集上训练这些模型。可以很好地利用这种训练。在另一个模型中重用已经训练过的CNN的想法被称为“迁移学习”。
一些知名的VGG模型包括VGG16、VGG19、ResNet50、InceptionV3和Xception。它们具有不同的架构,所有这些模型都可以在Keras中找到。这些模型都是在包含大约120万张图像的ImageNet数据集上训练的。
在本文中,将适应VGG16模型。
VGG16架构图显示,这个CNN的输入定义为(224, 224, 3)。因此,如果想将这个CNN适应问题,有两个选择。可以裁剪和调整图像大小到224 x 224。或者,可以将VGG16的输入层更改为(our_img_width, our_img_height, 3)用于彩色图像(RGB),或者更改为(our_img_width, our_img_height, 1)用于灰度图像。
请注意,VGG16的输出层包含1,000个类别。由于问题没有那么多可能的类别,必须更改输出层的形状。
实现VGG16
将使用VGG16作为基础模型,并从中派生出一个新的CNN——VGGNet。这个新的CNN将具有VGG16的层和权重,以及在输入层(以适应图像宽度、高度和颜色方案)以及输出层(以适应类别数量)的一些修改。
要实现自定义VGGNet模型,让创建一个类,该类继承自MLModel,就像在本系列的中所做的那样。在这个类中,命名为VggModel,除了init_model()之外的所有方法都将具有在ConvolutionalModel类中相同的实现。代码如下:
def init_model(self):
base_model = VGG16(weights=constant.IMAGENET, include_top=False,
input_tensor=Input(shape=(constant.IMG_WIDTH,
constant.IMG_HEIGHT,
3
)), pooling='max', classes=15)
base_model.summary()
for layer in base_model.layers:
layer.trainable = False
x = base_model.get_layer('block5_pool').output
# Stacking a new simple convolutional network on top of it
x = Convolution2D(64, 3)(x)
x = MaxPooling2D(pool_size=(2, 2))(x)
x = Flatten()(x)
x = Dense(constant.NUMBER_FULLY_CONNECTED, activation=constant.RELU_ACTIVATION_FUNCTION)(x)
x = Dense(self.n_classes, activation=constant.SOFTMAX_ACTIVATION_FUNCTION)(x)
self.vgg = Model(inputs=base_model.input, outputs=x)
self.vgg.summary()
请注意,在CNN的末尾添加了以下层:Flatten、Dense、MaxPooling和Dense。附加到VGG末尾的“迷CNN”的目的是将其block5_pool连接起来,使其适应问题,具有正确的类别数量。
还设置了添加层的layer.trainable属性为False。这让在额外的训练中保留原始模型的权重,将不得不进行额外的训练以适应新层。可以通过调用self.vgg.summary()获得修改后的模型的完整描述。
在类的构造函数中使用以下损失和优化器函数:
def __init__(self, dataSet=None):
super().__init__(dataSet)
opt = keras.optimizers.Adam(learning_rate=0.001)
self.vgg.compile(loss=keras.losses.binary_crossentropy,
optimizer=opt,
metrics=[constant.METRIC_ACCURACY])
应用于耶鲁数据集
现在让将VGGNet模型应用于耶鲁面部数据集。哇:仅在三个周期内就实现了超过93%的准确率!
只是为了提醒:从头开始开发的CNN在50个周期后给大约85%的准确率。因此,使用预训练模型显著提高了算法收敛。