天天看点

使用keras框架进行猫狗分类一 .卷积运算二.准备数据集2.1 从 Kaggle官网中下载数据集2.2 通过脚本制作数据集分类三.构建网络四.数据预处理五.使用图像增强技术

使用keras框架进行猫狗分类

  • 一 .卷积运算
  • 二.准备数据集
  • 2.1 从 Kaggle官网中下载数据集
  • 2.2 通过脚本制作数据集分类
  • 三.构建网络
  • 四.数据预处理
  • 五.使用图像增强技术

一 .卷积运算

密集连接层和卷积层的根本区别在于,Dense层,从输入特征空间中学到的是全局模式。(比如对于MNIST数字,全局模式就是涉及所有像素的模式),而卷积学到的是局部模式,这让卷积具备了两个性质。

  • 平移不变性:卷积神经网络在图像右下角学到某个模式后,它在任何地方可以识别这个模式。比如说左上角。对于密集连接层来说,如果模式出现在新的位置,只能重新学习。这让卷积神经网络具有平移不变性。
  • 学习到模式空间结构。

二.准备数据集

2.1 从 Kaggle官网中下载数据集

猫狗分类的数据集不包含在Keras中,它是由2013年末公开并作为一项计算机视觉竞赛的一部分,当时卷积神经网络还不是主流算法。

数据集下载地址

https://www.kaggle.com/c/dogs-vs-cats/data

2.2 通过脚本制作数据集分类

创建数据集,验证集,和测试集。并且在每个目录下分别创建猫和狗的图片保存路径。

import os, shutil
original_dataset_dir ='D:/DownloadEI/train'
base_dir = 'D:/严少青毕设/CNN-BiLSTM/cnn-bilstm/base_data'
if not os.path.exists(base_dir):
    os.makedirs(base_dir)
train_dir = os.path.join(base_dir,'train')
if not os.path.exists(train_dir):
    os.makedirs(train_dir)
validation_dir = os.path.join(base_dir,'validation')
if not os.path.exists(validation_dir):
    os.makedirs(validation_dir)
test_dir = os.path.join(base_dir,'test')
if not os.path.exists(test_dir):
    os.makedirs(test_dir)
train_cats_dir = os.path.join(train_dir,'cat')
if not os.path.exists(train_cats_dir):
    os.makedirs(train_cats_dir)
train_dogs_dir = os.path.join(train_dir,'dog')
if not os.path.exists(train_dogs_dir):
    os.makedirs(train_dogs_dir)
validation_cats_dir = os.path.join(validation_dir,'cat')
if not os.path.exists(validation_cats_dir):
    os.makedirs(validation_cats_dir)
validation_dogs_dir = os.path.join(validation_dir,'dog')
if not os.path.exists(validation_dogs_dir):
    os.makedirs(validation_dogs_dir)
test_cats_dir = os.path.join(test_dir,'cat')
if not os.path.exists(test_cats_dir):
    os.makedirs(test_cats_dir)
test_dogs_dir = os.path.join(test_dir,'dog')
if not os.path.exists(test_dogs_dir):
    os.makedirs(test_dogs_dir)
           

将下载数据集导入新建的文件目录下:

frames = ['cat.{}.jpg'.format(i) for i in range(1500,2000)]
for frame in frames:
    src = os.path.join(original_dataset_dir,frame)
    dst = os.path.join(test_cats_dir,frame)
    shutil.copyfile(src,dst)
frames = ['dog.{}.jpg'.format(i) for i in range(1000)]
for frame in frames:
    src = os.path.join(original_dataset_dir,frame)
    dst = os.path.join(train_dogs_dir,frame)
    shutil.copyfile(src,dst)
frames = ['dog.{}.jpg'.format(i) for i in range(1000,1500)]
for frame in frames:
    src = os.path.join(original_dataset_dir,frame)
    dst = os.path.join(validation_dogs_dir,frame)
    shutil.copyfile(src,dst)
frames = ['dog.{}.jpg'.format(i) for i in range(1500,2000)]
for frame in frames:
    src = os.path.join(original_dataset_dir,frame)
    dst = os.path.join(test_dogs_dir,frame)
    shutil.copyfile(src,dst)
           

三.构建网络

在MINIST识别数字这篇博客中,构建了一个小型卷积神经网络。这里复用整体的结构,即卷积神经网络使用Conv2层(使用relu进行激活)和MaxPooling2D层交替堆叠构成。

但是这里处理的是更大的图像,需要相应的增加网络,即再增加一个Conv2D+MaxPooling2D的组合,这可以增加网络尺寸,降低特征图大小,使其连接Flatten时候尺寸不会太大。本例中输入尺寸是150*150,最后连接Flatten层大小为7*7。

因为这个问题是二分类问题,网络最后一层使用sigmoid层进行激活。

from keras import  models
from keras import  layers
import os
network = models.Sequential()
network.add(layers.Conv2D(32,(3,3),activation='relu',input_shape=(150,150,3)))
network.add(layers.MaxPool2D(2,2))
network.add(layers.Conv2D(64,(3,3),activation='relu'))
network.add(layers.MaxPool2D(2,2))
network.add(layers.Conv2D(128,(3,3),activation='relu'))
network.add(layers.MaxPool2D(2,2))
network.add(layers.Conv2D(128,(3,3),activation='relu'))
network.add(layers.MaxPool2D(2,2))
network.add(layers.Flatten())
network.add(layers.Dropout(0.5))
network.add(layers.Dense(512,activation='relu'))
network.add(layers.Dense(1,activation='sigmoid'))
           

定义优化器和损失函数

from keras import  optimizers
network.compile(optimizer=optimizers.RMSprop(learning_rate=1e-4),
                loss= 'binary_crossentropy',
                metrics='accuracy')
           

四.数据预处理

数据预处理的步骤如下:

  • (1)读取图像文件
  • (2) 将JPEG文件解码为RGB像素网络
  • (3)将这些像素转换为浮点张量
  • (4) 将像素值缩放到 0-1 区间
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(
    rescale= 1./255
)
test_datagen = ImageDataGenerator(rescale= 1./255)
train_generator = train_datagen.flow_from_directory(
    'D:/严少青毕设/CNN-BiLSTM/cnn-bilstm/base_data/train',
    target_size=(150,150),
    batch_size=20,
    class_mode='binary'
)
validation_generator = test_datagen.flow_from_directory(
    'D:/严少青毕设/CNN-BiLSTM/cnn-bilstm/base_data/validation',
    target_size=(150,150),
    batch_size=20,
    class_mode='binary'
)
           

它生成了150x150的RGB图像[形状为(20,150,150,3)]与二进制标签形状为【20,】组成的批量,生成器会不断生成这些批量,会不断循环目标文件夹的图像。

利用生成器我们可以让模型进行拟合,使用fit_generator方法进行拟合,它在数据生成器上效果与fit相同。它的第一个参数是Python生成器,可以不断的生成输入和目标批量。因为数据是不断生成的,每轮提取多少样本,这是steps_per_epoch参数的作用;运行了steps_per_epoch个梯度下降后,拟合进入下一轮次。验证集也是同理。

history = network.fit_generator(
        train_generator,
        steps_per_epoch=100,
        epochs=100,
        validation_data=validation_generator,
        validation_steps=50
    )
           

在训练结束后保存模型

五.使用图像增强技术

如果按照上述方式训练网络,训练精度随着时间线性增加,知道接近百分之百,而验证集精度则停留在70-72%之间。验证损失仅在第五轮后就达到最小值,然后保持不变。这是因为训练样本相对较少。我们要使用dropout和L2正则化来解决过拟合问题。

数据增强是计算机视觉领域的一种新方法,在深度学习处理图像的时候几乎都会用到这种方法,它就是数据增强。

过拟合是因为学习样本太少,导致无法训练处能够泛化到新数据的模型。如果拥有无限数据,模型就能学习到数据分布的所有内容,永远不会过拟合。数据增强是从现有的训练样本中生成更多的训练数据,其方法是利用多种能生产可信图像的随机变换来增加数据内容,从而具有泛化能力。

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
)
           

开始训练

Found 1000 images belonging to 2 classes.
Epoch 1/100
100/100 [==============================] - 55s 538ms/step - loss: 0.6943 - accuracy: 0.5000 - val_loss: 0.6882 - val_accuracy: 0.5460
           

继续阅读