卷积神经网络 猫狗识别

一、卷积神经网络搭建
搭建框架,需要使用卷积层和池化层

from keras import models
from keras import layers

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'))
model.summary()

from keras import optimizers
model.compile(loss='binary_crossentropy',
        optimizer=optimizers.RMSprop(lr=1e-4),
        metrics=['acc'])

使用下采样的原因,一是减少需要处理的特征图的元素个数,避免导致过拟合,二是通过让连续卷积层的观察窗口越来越大(即窗口覆盖原始输入的比例越来越大),从而引入空间过滤器的层级结构。
最大池化的效果往往比平均池化和增加stride步幅这些替代方法更好。 简而言之,原因在于特征中往往编码了某种模式或概念在特征图的不同位置是否存在(因此得名特征图),而观察不同特征的最大值而不是平均值能够给出更多的信息。因此,最合理的子采样策略是首先生成密集的特征图(通过无步进的卷积),然后观察特征每个小图块上的最大激活, 而不是查看输入的稀疏窗口(通过步进卷积)或对输入图块取平均,因为后两种方法可能导致 错过或淡化特征是否存在的信息。

二、数据预处理

(1) 读取图像文件。
(2) 将 JPEG 文件解码为 RGB 像素网格。
(3) 将这些像素网格转换为浮点数张量。
(4)将像素值(0~255 范围内)缩放到 [0, 1] 区间(神经网络喜欢处理较小的输入值)

#使用 ImageDataGenerator 从目录中读取图像 
from keras.preprocessing.image import ImageDataGenerator
train_dir = 'D:\\Data\\downloads\\dogcat\\cats_and_dogs_small\\train'
validation_dir = 'D:\\Data\\downloads\\dogcat\\cats_and_dogs_small\\validation'
#返回一个迭代器
train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)

#从指定文件夹中生成以批量大小为batch_size返回图片的迭代器
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')
for  data_batch, label_batch in train_generator:
   print(data_batch.shape)
   print(label_batch.shape)
   break
#使用flow_from_directory方法后的结果输出
#data batch shape: (20, 150, 150, 3) 
#labels batch shape: (20,)

#可以显示迭代器中的图片
import matplotlib.pyplot as plt
plt.imshow(data_batch[0])

三、利用迭代器进行训练

history = model.fit_generator(
        train_generator,
        steps_per_epoch=100,
        epochs=30,
        validation_data=validation_generator,
        validation_steps=50)
        
#模型的保存,包括编译及参数
model.save('cats_and_dogs_small_1.h5')
#模型的加载,加载编译器及参数
from keras.model import load_model
model = load_model('xxx.h5')

四、图片增强处理及操作技术

#生成一个迭代器,包含使图片随机变化的参数
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)
        
#该操作可以读取某个文件夹下面的所有图片的绝对路径,fname得到每个图片名字,fnames是绝对路径的list
import os
train_cats_dir = 'D:\\Data\\downloads\\dogcat\\cats_and_dogs_small\\train\\cats'
fnames = [os.path.join(train_cats_dir, fname) for fname in os.listdir(train_cats_dir)]

#利用plt显示图片,plt.imshow传入的是图片的绝对路径,x是一个uint8格式的图片数组
import matplotlib.pyplot as plt
x = plt.imread(fnames[0])
plt.imshow(x)

#利用opencv也可以读取、显示和更改图片大小
import cv2 
a = cv2.imread('test.jpg')
cv2.imshow("Image1", a)
cv2.waitKey(0)
res = cv2.resize(a, (128, 256), interpolation=cv2.INTER_CUBIC)
plt.imsave(r'D:\Data\Python\machinelearning\SARsvm\test001a.jpg', res)

#利用preprocessing中的image的load_img方法,读取图片,此时返回的不是数组,须再通过其他方式转换为数组形式。此方法可以方便更改图片大小
import numpy as np
from keras.preprocessing import image
img_path = fnames[3]
img = image.load_img(img_path, target_size=(150, 150))
#返回一个PIL.Image.Image对象,想要灵活操作须变为数组形式
y = image.img_to_array(img, dtype='uint8')    #此处可以更改数据类型,但是转换后的数据在生成器时又变为float32
#有uint8时,y变为一个uint8类型的(150,150,3)的数组
y = y.reshape((1,) + y.shape)#将y数组修改为(1,150,150,3)形式

#利用其中flow方式传入图片,并显示迭代器随机修改后的样子
z = np.concatenate([y,y,y], axis=0)#大小为(3,150,150,3)
i = 0
for batch in datagen.flow(z, batch_size=3):   #此时每次batch大小为3
    plt.figure(i)
    imgplot = plt.imshow(image.array_to_img(batch[0]))
    #a=np.array(batch[0], dtype='uint8')  显示的另一种方法,不必将之转换为image对象
    #plt.imshow(a)
    i += 1
    if i%4 == 0:
        break

五、图片增强的具体代码

from keras.preprocessing.image import ImageDataGenerator
train_dir = 'D:\\Data\\downloads\\dogcat\\cats_and_dogs_small\\train'
validation_dir = 'D:\\Data\\downloads\\dogcat\\cats_and_dogs_small\\validation'

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)
#%%
model.save('cats_and_dogs_small_2.h5')

六、添加正则化和dropout处理

l1及l2正则化 L1 正则化(L1 regularization):添加的成本与权重系数的绝对值[权重的L1 范数(norm)]成正比。
L2 正则化(L2 regularization):添加的成本与权重系数的平方(权重的 L2 范数)成正比。 神经网络的 L2正则化也叫权重衰减(weight decay)。
l2(0.001) 的意思是该层权重矩阵的每个系数都会使网络总损失增加
0.001 * weight_ coefficient_value。注意,由于这个惩罚项只在训练时添加,所以这个网络的训练损失会比测试损失大很多。

from keras import regularizers 
model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001), activation='relu', input_shape=(10000,)))

regularizers.l1(0.001)
regularizers.l1_l2(l1=0.001, l2=0.001) 

dropout正则化 按一定概率随机丢弃某一层的输出
为了保持输出大小不变,还需除以该概率以变大

model = models.Sequential() 
model.add(layers.Dense(16, activation='relu', input_shape=(10000,))) model.add(layers.Dropout(0.5)) 
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dropout(0.5)) 
model.add(layers.Dense(1, activation='sigmoid'))

你可能感兴趣的:(卷积神经网络 猫狗识别)