第五章,深度学习用于计算机视觉
密集连接层和卷积层的根本区别在于:Dense层(全连接层)从输入特征空间中学到是全局模式,卷积层学到的是局部模式。
卷积神经网络学到的模式具有平移不变性,可以学到模式的空间层次结构。
对于包括两个空间轴(高度和宽度)和一个深度轴(通道轴,每个维度都是一个特征(或过滤器))的3D张量,卷积也叫做特征图。
卷积工作原理:输入的特征图上滑动设定的窗口,提取不同位置图块,图块与权重矩阵(卷积核)作张量积(wx)。转换成1D向量。对向量进行空间重组,转换为3D输出特征图。
影响输出尺寸的要素:
1.填充:在输入特征图的每一边添加上适当数目的行和列,是的每个输入方块都能成卷积窗口的中心。对于Conv2D,可以通过padding参数来填充。Valid表示不使用填充(默认参数值),same表示填充后输出的高宽与输入相同。
2.步幅:两个连续窗口的距离。
采用下采样(一个样值序列隔几个样值取样一次)原因:减少需要处理的特征图元素个数;通过让连续卷积层的观察窗口越来越大,从而引入空间过滤器的层级结构。
import os,shutil
#原始数据集解压目录的路径(下载下来含数据的根目录)
original_dataset_dir='D:\\jupyter_code\\kaggle\\train'
#保存较小数据集的目录(执行后创建)
base_dir='D:\\jupyter_code\\kaggle\\train1'
os.mkdir(base_dir)
train_dir=os.path.join(base_dir,'train')
os.mkdir(train_dir)
validation_dir=os.path.join(base_dir,'validation')
os.mkdir(validation_dir)
test_dir=os.path.join(base_dir,'test')
os.mkdir(test_dir)
#添加猫狗训练图像
train_cats_dir=os.path.join(train_dir,'cats')
os.mkdir(train_cats_dir)
train_dogs_dir=os.path.join(train_dir,'dogs')
os.mkdir(train_dogs_dir)
#添加猫狗验证图像
validation_cats_dir=os.path.join(validation_dir,'cats')
os.mkdir(validation_cats_dir)
validation_dogs_dir=os.path.join(validation_dir,'dogs')
os.mkdir(validation_dogs_dir)
#添加猫狗测试图像
test_cats_dir=os.path.join(test_dir,'cats')
os.mkdir(test_cats_dir)
test_dogs_dir=os.path.join(test_dir,'dogs')
os.mkdir(test_dogs_dir)
#复制猫1000到训练集,猫1000-1500到验证集,猫1500-2000到测试集
fnames=['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(train_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['cat.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(validation_cats_dir,fname)
shutil.copyfile(src,dst)
fnames=['cat.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(test_cats_dir,fname)
shutil.copyfile(src,dst)
#复制狗1000到测试集,狗1000-1500到验证集,狗1500-2000到测试集
fnames=['dog.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(train_dogs_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1000,1500) ]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(validation_dogs_dir,fname)
shutil.copyfile(src,dst)
fnames=['dog.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
src=os.path.join(original_dataset_dir,fname)
dst=os.path.join(test_dogs_dir,fname)
shutil.copyfile(src,dst)
#将猫狗分类的小型卷积神经网络实例化
from keras import layers
from keras import models
model=models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(150,150,3)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation='relu'))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Flatten())
model.add(layers.Dense(512,activation='relu'))
model.add(layers.Dense(1,activation='sigmoid'))
#配置模型用于训练
from keras import optimizers
model.compile(loss='binary_crossentropy',optimizer=optimizers.RMSprop(lr=1e-4),metrics=['acc'])
#使用ImageDataGenerator从目录中读取图像
from keras.preprocessing.image import ImageDataGenerator
#将所有图像乘以1/255缩放
train_datagen=ImageDataGenerator(rescale=1./255)
test_datagen=ImageDataGenerator(rescale=1./255)
#参数(目标目录,图像大小调整为150*150,批次大小,二进制标签)
train_generator=train_datagen.flow_from_directory(
train_dir,
target_size=(150,150),
batch_size=20,
class_mode='binary'
)
validation_generator=test_datagen.flow_from_directory(
validation_dir,
target_size=(150,150),
batch_size=20,
class_mode='binary'
)
#生成器输出:150*150的RGB图像与二进制标签组成的批量。
#利用批量生成器拟合模型
history=model.fit_generator(
train_generator,
#运行了steps_per_steps个批量后,拟合过程将进入下一轮次。
steps_per_epoch=100,
epochs=30,
validation_data=validation_generator,
#说明需要从验证生成器中抽取多少个批次用于评估
validation_steps=50
)
数据增强:从现有的训练样本中生成更多的训练数据,利用多种能够生成可信图像的随机变换来增加样本。
#利用ImageDataGenerator来设置数据增强
datagen=ImageDataGenerator(
#图像随机旋转角度值范围
rotation_range=40,
#水平垂直上平移的范围
width_shift_range=0.2,
height_shift_range=0.2,
#随机错切变换的角度
shear_range=0.2,
#图像随机缩放的范围
zoom_range=0.2,
#随机将一半的图像水平翻转,
horizontal_flip=True,
#填充新创建新像素(可能来源于旋转或平移)的方法,
fill_mode='nearest'
)
#显示几个随机增强后的训练图像
from keras.preprocessing import image
fnames=[os.path.join(train_cats_dir,fname) for fname in os.listdir(train_cats_dir)]
img_path=fnames[3]
img=image.load_img(img_path,target_size=(150,150))
x=image.img_to_array(img)
x=x.reshape((1,)+x.shape)
i=0
for batch in datagen.flow(x,batch_size=1):
plt.figure(i)
imgplot=plt.imshow(image.array_to_img(batch[0]))
i+=1
if i % 4 ==0:
break
plt.show()
#上述方法不足以完全消除过拟合,为了进一步降低过拟合,添加dropout层,添加到密集链接分类器前
#定义一个包含dropout的新卷积神经网络
model=models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(150,150,3)))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Conv2D(64,(3,3),activation='relu'))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation='relu'))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Conv2D(128,(3,3),activation='relu'))
model.add(layers.MaxPool2D((2,2)))
model.add(layers.Flatten())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(512,activation='relu'))
model.add(layers.Dense(1,activation='sigmoid'))
model.compile(loss='binary_crossentropy',
optimizer=optimizers.RMSprop(lr=1e-4),
metrics=['acc'])
#利用数据增强生成器训练卷积神经网络
train_datagen=ImageDataGenerator(
rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
)
test_datagen=ImageDataGenerator(rescale=1./255)
train_generator=train_datagen.flow_from_directory(
train_dir,
target_size=(150,150),
batch_size=32,
class_mode='binary'
)
validation_generator=test_datagen.flow_from_directory(
validation_dir,
target_size=(150,150),
batch_size=32,
class_mode='binary'
)
history=model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=100,
validation_data=validation_generator,
validation_steps=50
)