深度学习一个经典的分类问题是“猫狗大战”,即让AI看一张图片,然后它将告诉你这张图片里是究竟是猫还是狗。
由Kaggle举办的风靡一时的猫狗分类竞赛..
经过参赛选手们的不懈努力,在所有目前已公开的模型中,我们点开了一个获赞数较高的模型,它能够在训练集和测试集上同时取得接近90%的准确率。
横轴是训练次数,纵轴是准确率,粗的点是训练集结果,细的线是验证集结果..
既然AI能够在关于猫狗的二分类问题中取得这么好的效果,那我们试试加大力度,看一看AI能不能解决一些难度更高的图像分类问题呢~
在西方艺术发展历史上,艺术风格经历了多次变革,我们随机选取了四个时期,即中世纪、文艺复兴、后文艺复兴和现代艺术时期,然后把这些图片收集起来,分类别存在电脑里,作为数据准备。
下边给大家展示的四幅图,就分别是这四个时期的作品之一,有看官能认出来每一张图片分别属于哪一个时期吗?(相信大部分朋友应该和我一样傻傻分不清~~)
所以有人能告诉我图3是啥吗..
数据介绍
我们通过公开网站找到各个时期的画作,作为演示案例,随机选取了每个时期的一部分画作进行分析,包括中世纪(80张)、文艺复兴(80张)、后文艺复兴(80张)、现代艺术(90张)。按照深度学习的数据划分方式,我们把这些照片储存在训练集文件夹(/data/train)和测试集文件夹(/data/validation),每个时期的画作又各自储存在各自的文件夹中。
图像数据生成器:在读入每一张图片的同时,对图像进行像素增减、旋转、平移或放缩等操作,达到识别度更高的效果,也就是所谓的“数据增强”。
除了传入参数以外,IMSIZE是我们传入图片的大小,train_generator是训练集数据生成器,validation_generator是测试集数据生成器。
在使用ImageDataGenerator时,调用flow_from_directory函数,它告诉程序target_size(图像大小)是299×299,batch_size(每次训练图片的数量)是50,class_mode是'categorical',声明这是一个多分类问题。在测试集生成器中也传入了相应的参数,具体的参数取值可以在代码中找到哦~以下是详细代码:
IMSIZE=299
train_generator = ImageDataGenerator(
rescale=1./255,
shear_range=0.5,
rotation_range=30,
zoom_range=0.2,
width_shift_range=0.2,
height_shift_range=0.2,
horizontal_flip=True).flow_from_directory(
'../case2-picture style/data/train',
target_size=(IMSIZE, IMSIZE),
batch_size=50,
class_mode='categorical')
validation_generator = ImageDataGenerator(rescale=1./255).flow_from_directory(
'../case2-picture style/data/validation',
target_size=(IMSIZE,IMSIZE),
batch_size=20,
class_mode='categorical')
当我们使用数据生成器的时候,需要配合next()函数来查看每次读入数据的具体情况。因为自变量(图片)和因变量(类别)都需要用到numpy包里的数据格式来储存,所以我们会导入这个包。代码和结果如下:
import numpy as np
X,Y=next(validation_generator)
我们看到,自变量X,也就是每一次读入的图片集,有20张,长是299,宽是299,是三通道的彩色图片。对于因变量Y,也是有20个对应的值,4分别代表4个不同的绘画时期类别。
from matplotlib import pyplot as plt
for i in range(10):
ax[i].imshow(X[i,:,:,:])
都是艺术啊!..
训练模型
01
逻辑回归
from keras import Model
input_layer=Input([IMSIZE,IMSIZE,3])
x=input_layer
x=BatchNormalization()(x)
x=Flatten()(x)
x=Dense(4,activation='softmax')(x)
output_layer=x
model1=Model(input_layer,output_layer)
逻辑回归的训练结果如上,测试集上的准确率差不多可以达到35%左右,如果盲猜的话,准确率大概是25%(就像平时做四选一单选题?..)。如果以这个准确率作为基准,那么逻辑回归的结果还算是可以的。接下来,我们利用两个在图像识别领域赫赫有名的神经网络来训练这个数据集,一个是AlexNet,另一个是InceptionV3。
02
AlexNet
看着就很吓人的AlexNet网络层..
现在我们来做细致地拆分,讲讲AlexNet的网络结构!
(不会有人真的想听吧?)
(有兴趣的同学请期待狗熊会新作《深度学习入门》,文风风趣又不失专业性,内容严谨,覆盖面广,很值得收藏和阅读!)
简单来讲,AlexNet在神经网络领域的主要创新(贡献)在于,成功验证了激活函数ReLU的效果好于当时普遍使用的Sigmoid,另外还有以下几点(节选自《深度学习入门》)
1. 训练时使用Dropout随机忽略一部分神经元,以避免模型过拟合,一般在全连接层使用。
2. 在CNN中使用重叠的最大池化(步长小于卷积核)。
3. 提出LRN(Local Response Normalization,即局部响应归一化)层,逐渐被BN(Batch Nomalization)所代替。
4. 使用CUDA加速神经网络的训练,利用了GPU强大的计算能力。受限于当时计算能力,Alexnet使用两块GPU进行训练。
5. 数据增强,随机地从256×256的图片中截取224×224大小的区域(以及水平翻转的镜像)。
我们在这里只简单看看ReLU和Sigmoid的区别:
Sigmoid存在“梯度消失”的现象,即一阶导趋于0,而relu在正半轴上并不会..
下面是AlexNet模型的代码,相比于逻辑回归,多出来的几个函数主要是Conv2D和MaxPooling,以下面这段代码为例
Conv2D(96,[11,11],strides = [4,4], activation = 'relu')(x)
其中,96代表卷积核的个数,[11,11]是卷积核的大小,strides是步长,激活函数为relu。对于池化层参数解释类似,在此不进行赘述。
MaxPooling2D([3,3], strides = [2,2])
AlexNet完整的生成代码如下:
from keras import Model
IMSIZE = 227
input_layer = Input([IMSIZE,IMSIZE,3])
x = input_layer
x = BatchNormalization()(x)
x = Conv2D(96,[11,11],strides = [4,4], activation = 'relu')(x)
x = MaxPooling2D([3,3], strides = [2,2])(x)
x = Conv2D(256,[5,5],padding = "same", activation = 'relu')(x)
x = MaxPooling2D([3,3], strides = [2,2])(x)
x = Conv2D(384,[3,3],padding = "same", activation = 'relu')(x)
x = Conv2D(384,[3,3],padding = "same", activation = 'relu')(x)
x = Conv2D(256,[3,3],padding = "same", activation = 'relu')(x)
x = MaxPooling2D([3,3], strides = [2,2])(x)
x = Flatten()(x)
x = Dense(4096,activation = 'relu')(x)
x = Dropout(0.5)(x)
x = Dense(4096,activation = 'relu')(x)
x = Dropout(0.5)(x)
x = Dense(4,activation = 'softmax')(x)
output_layer=x
model=Model(input_layer,output_layer)
接下来我们用AlexNet模型训练我们的绘画作品分类,结果如下:
AlexNet在测试集上的准确率可以达到57.5%,是一个不错的提升!接下来让我们再看看InceptionV3模型的效果。
04
Inception V3
这是Inception网络的一个模块,可以看作层的集合..
Inception系列网络的创新在于同时使用多个不同尺寸的卷积核,同时大量使用1×1的卷积核,它带来的好处之一是需要训练的参数减少了,想更深入了解Inception系列网络结构的朋友可以找来相关的材料进行阅读,这里我们就不详细展开了。
由于InceptionV3的网络结构十分庞大,在计算资源有限的前提下,训练起来相当困难,所以我们选择“站在牛人的肩膀上”,通过迁移学习的方法用InceptionV3模型实现这里的绘画分类任务。
迁移学习:简单来讲,“迁移学习”是把别人训练好的模型参数结果直接拿过来,应用到我们当前的任务中,这个过程就叫“迁移”。
由于迁移学习要用到别人训练出的模型结构和参数估计,因此我们需要一个文件,这个文件不仅包含了模型结构,还包含了这个模型当时训练出来的所有参数,这些参数很可能来自一个巨大的数据集,例如ImageNet,幸运的是这些文件就在keras上。接下来我们看一下如何迁移学习InceptionV3模型。
from keras import Model
base_model = InceptionV3(weights = ‘imagenet’,include_top=False)
x = GlobalAveragePooling2D()(x)
predictions = Dense(4,activation='softmax')(x)
迁移学习的结果如下,在这个四分类问题中,InceptionV3的分类准确率达到了73.75%!看到这里,小编不由得发出感慨