简单 VGG 的女优人脸识别实现

opencv + python + keras

绪论

Github 项目地址

很久很久以前,就想着有没有机会能够写一个能识别女优人脸的程序,因为这个东西似乎市场需求很大但是却没什么人去做,那么今天就让我来简单写一下吧,计算机视觉与深度学习发展到今天,也不用争论这个东西的泡沫到底破灭不破灭了,抓紧时间做出点真正有用的应用比争来争去靠谱多了,不是吗?

opencv 安装

首先安装 opencv

1
2
$ brew tap homebrew/science
$ brew install opencv3 --with-python3 --without-python

指定 python 需要调用包的位置

1
$ ln -s /usr/local/Cellar/opencv3/3.2.0/lib/python3.6/site-packages/cv2.cpython-36m-darwin.so /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/cv2.so

pip 换国内源加速

1
$ pip install -i https://pypi.tuna.tsinghua.edu.cn/simple --upgrade h5py numpy

VGG 网络架构

首先参考 Keras 官网给出的 VGG 网络实现:Keras.VGG

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import numpy as np
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.optimizers import SGD

# Generate dummy data
x_train = np.random.random((100, 100, 100, 3))
y_train = keras.utils.to_categorical(np.random.randint(10, size=(100, 1)), num_classes=10)
x_test = np.random.random((20, 100, 100, 3))
y_test = keras.utils.to_categorical(np.random.randint(10, size=(20, 1)), num_classes=10)

model = Sequential()
# input: 100x100 images with 3 channels -> (100, 100, 3) tensors.
# this applies 32 convolution filters of size 3x3 each.
model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(100, 100, 3)))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(256, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))

sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy', optimizer=sgd)

model.fit(x_train, y_train, batch_size=32, epochs=10)
score = model.evaluate(x_test, y_test, batch_size=32)

上述样例代码实现的应该是从 32 过滤器起步到 256 最后池化为 10 位输出分类器的 VGG 神经网络,下图则是从 64 到 512 的结构示意图,大体上来说可以分为两个大块,一个是卷积层,一个是池化层

卷积层通过指定大小的 filter(一般为 3x3,最小)来实现对图片的卷积,通过相比 AlexNet 更小的 filter 可以得到更多的 channel,达到更高的精度

池化层是对卷积过后的结果进行降采样,上述例子中在 100 _100 输入进来后,经过 MaxPooling2D 的池化会得到 50_ 50 的输出,同样还有 MeanPooling 等其他函数

Dropout 可以提高效率,具体参考网上资料

下图是本项目定义的 VGGnet 结构,相对上面的样例代码还是有一点区别,主要表现在图片格式以及网络结构上

参考 paper

Keras

Keras 实在是一个非常方便的深度学习库,而且官方文档给的很详细,同时中文文档也写的很好,所有的东西都可以在上面查询,这里就记录一些重点内容

TF 卷积核与 TH 卷积核

Keras 提供了两套后端,Theano 和 Tensorflow

二者在实际应用中最常见的错误大概就是输入样本的结构不对了,其应该为:

  • “channels_first” — th — (3,128,128)
  • “channels_last” —tf — (128,128,3)

注意如果没有设置过的话,在所有的层级当中都会默认这个参数为 “channels_last”

切换后端

如果你至少运行过一次 Keras,你将在下面的目录下找到 Keras 的配置文件:

1
$HOME/.keras/keras.json

如果该目录下没有该文件,你可以手动创建一个

文件的默认配置如下:

1
2
3
4
5
6
{
"image_data_format": "channels_last",
"epsilon": 1e-07,
"floatx": "float32",
"backend": "tensorflow"
}

将 backend 字段的值改写为你需要使用的后端:theano 或 tensorflow 或者 CNTK,即可完成后端的切换

我们也可以通过定义环境变量 KERAS_BACKEND 来覆盖上面配置文件中定义的后端:

1
2
KERAS_BACKEND=tensorflow python -c "from keras import backend;"
Using TensorFlow backend.

opencv 处理图片

opencv docs

所有你需要的处理图片的 API 和接口都在上述函数中了,尽情使用

结果 & 后续

最终模型的表现不怎么样,test acc 只有 25%,不过我本人亲自尝试识别之后发现效果还是不错的,可能是由于女优们长得真的太像了(这是什么原因呢?)也由于我的图片训练素材没有仔细筛选,最后结果不怎么样,训练精度到是达到了 98% 以上,但是这都没什么用

作为学习和体验的话整个过程下来还是收获颇多,也希望以后能够进一步了解深度学习的魅力

后面有空的时候可能会再完善优化一下这个东西吧,毕竟可以造福广大宅男