Keras深度学习实战——使用卷积神经网络实现性别分类
0. 前言
在 《卷积神经网络详解与实现》 中,我们了解了卷积神经网络 ( Convolutional Neural Network
, CNN
) 的工作原理以及 CNN
模型在解决图像识别问题中的优越性。在本节中,我们将通过构建性别分类模型来验证 CNN
模型性能,从而进一步加深对 CNN
工作原理的了解。
1. 数据集与模型分析
首先,我们需要了解本节用于性别分类的数据集,数据集取自 Celeb A ,可以自行构建数据集,也可以下载使用此 数据集 ,提取码: nql9
。 CelebA
是一个大规模的人脸属性数据集,其中包含超过 20
万张名人图像,每张图像有 40
个属性注释。
接下来,我们定义用于性别分类的神经网络模型策略:
首先获取图像的数据集,并根据图像中人物的性别标记每个图像
我们使用的数据集中男性和女性图像分别具有约 8000
张图像
数据集准备完成后,我们将图像整形为相同大小,以便将其输入到 CNN
模型中
构建 CNN
模型,其中输出层具有 1
个节点,用于输出 0
或 1
两种标签表示男性或女性
使用二分类交叉熵损失函数,并最小化损失值
2. 构建卷积神经网络实现性别分类
在本节中,我们将采用上一小节中定义的策略使用 Keras
实现性别分类模型。
- 首先,加载数据集并检查其内容,从数据集中取
8000
- 张男性图像和
8000
- 张女性图像:
import numpy as np from skimage import io from glob import glob from matplotlib import pyplot as plt import cv2 x = [] y = [] for i in glob('man_woman/a_resized/*.jpg')[:8000]: try: image = io.imread(i) x.append(image) y.append(0) except: continue for i in glob('man_woman/b_resized/*.jpg')[:8000]: try: image = io.imread(i) x.append(image) y.append(1) except: continue
在以上代码中,使用 glob
方法获取目录下相应图片,使用 skimage
读取相对应的图像,为了对数据集有所了解,我们查看数据集图像:
plt.subplot(221) plt.imshow(x[0]) plt.title('Male') plt.subplot(222) plt.imshow(x[1]) plt.title('Male') plt.subplot(223) plt.imshow(x[-1]) plt.title('FeMale') plt.subplot(224) plt.imshow(x[-2]) plt.title('FeMale') plt.show()
- 创建输入和输出数组:
x2 = [] for i in range(len(x)): img = cv2.cvtColor(x[i], cv2.COLOR_BGR2GRAY) img2 = cv2.resize(img, (64, 64)) x2.append(img2) plt.subplot(221) plt.imshow(x[0]) plt.title('Original') plt.subplot(222) plt.imshow(x2[0], cmap='gray') plt.title('Transformed') plt.subplot(223) plt.imshow(x[-1]) plt.title('Original') plt.subplot(224) plt.imshow(x2[-1], cmap='gray') plt.title('Transformed') plt.show()
为了简单起见,在以上代码中,我们将彩色图像转换为灰度图像。此外,我们将图像尺寸调整为较小的形状 (64 x 64 x 1)
,结果如下:
- 创建训练和测试数据集。首先,我们将输入和输出列表转换为数组,然后对输入进行归一化,并使用
reshape
- 方法进行整形,使其可以作为
CNN
- 网络输入形状:
# 输入的值介于0到255之间,因此对其进行缩放 x2 = np.array(x2) / 255. x2 = x2.reshape(x2.shape[0], x2.shape[1], x2.shape[2], 1) y = np.array(y)
将输入和输出数组拆分为训练和测试数据集:
from sklearn.model_selection import train_test_split x_train, x_test, y_train, y_test = train_test_split(x2, y, test_size=0.2) # 打印训练和测试集形状 print(x_train.shape, x_test.shape, y_train.shape, y_test.shape)
打印训练和测试集形状,输出数组的形状如下:
(6400, 64, 64, 1) (1600, 64, 64, 1) (6400,) (1600,)
在以上数组形状中,第一个维度表示图片数量, x_train
和 x_test
中的第 2
和第 3
维度表示图片的尺寸,而最后一个维度表示图片的通道数,因为我们使用灰度图像,因此维度为 1
。
- 构建卷积神经网路并编译模型:
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense from keras.models import Sequential model = Sequential() model.add(Conv2D(64, kernel_size=(3, 3), activation='relu',input_shape=(64,64,1))) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(128, kernel_size=(3, 3), activation='relu',padding='same')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(256, kernel_size=(3, 3), activation='relu',padding='same')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(512, kernel_size=(3, 3), activation='relu',padding='same')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(1024, kernel_size=(3, 3), activation='relu',padding='same')) model.add(Flatten()) model.add(Dense(100, activation='relu')) model.add(Dense(1, activation='sigmoid')) model.summary()
该模型的简要架构信息输出如下:
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 48, 48, 64) 640 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 24, 24, 64) 0 _________________________________________________________________ conv2d_1 (Conv2D) (None, 24, 24, 128) 73856 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 12, 12, 128) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 12, 12, 256) 295168 _________________________________________________________________ max_pooling2d_2 (MaxPooling2 (None, 6, 6, 256) 0 _________________________________________________________________ conv2d_3 (Conv2D) (None, 6, 6, 512) 1180160 _________________________________________________________________ max_pooling2d_3 (MaxPooling2 (None, 3, 3, 512) 0 _________________________________________________________________ conv2d_4 (Conv2D) (None, 3, 3, 1024) 4719616 _________________________________________________________________ flatten (Flatten) (None, 9216) 0 _________________________________________________________________ dense (Dense) (None, 100) 921700 _________________________________________________________________ dense_1 (Dense) (None, 1) 101 ================================================================= Total params: 7,191,241 Trainable params: 7,191,241 Non-trainable params: 0 _________________________________________________________________
可以看到,卷积层输出中的通道数将等于该层中指定的卷积核数。此外,卷积层后使用了池化层,以减小图片尺寸。
- 然后,我们编译模型,使用二进制交叉熵损失(因为输出中只包括两个类),使用
adam
- 优化器最小化损失值,如下所示:
model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['acc'])
- 最后,拟合模型:
history = model.fit(x_train, y_train, batch_size=32, epochs=50, verbose=1, shuffle=True, validation_data = (x_test, y_test))
拟合模型后,我们可以看到构建的卷积神经网路在预测数据集图像中识别性别的准确率可以到达 90%
左右。
模型的分类准确率可以通过以下方法进一步提高:
CNN Dropout
本节中,我们构建并训练了一个用于进行性别分类的卷积神经网路模型,并未使用任何提升 CNN
模型的优化技术, CNN
模型就可以以 90%
以上的准确率完成性别分类任务,充分展示了 CNN
模型的强大拟合能力。
Be First to Comment