《深度学习 第五章 深度学习用于计算机视觉1》

1.实例化一个小型的卷积神经网络

from keras import layers
from keras import models

model = models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation = 'relu',input_shape = (28,28,1)))
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(64,(3,3),activation = 'relu'))

model.summary()

神经网络的接受形状为(image_height,image_width,image_channels)
这里输入的形状是(28,28,1)是灰度图像,所以是一通道的,28*28是图片的大小

查看目前的卷积神经网络架构
在这里插入图片描述
可以看到每个神经层,不管是Conv2D还是MaxPooling的输出都是形状为(height,width,channels)的3D张量,随之而网络的加深,通道数会越来越大,而高度和宽度越来越小,输出的时候变成了(3,3,64)的形状

下一步是把这个神经网络接一个Dense层堆积起来的密集连接分类器而密集连接的分类器只能处理1D张量,这个时候,需要把3D的张量flatten:

from keras import layers
from keras import models

model = models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation = 'relu',input_shape = (28,28,1)))
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(64,(3,3),activation = 'relu'))

#在卷积神经网络中添加分类器
model.add(layers.Flatten())
model.add(layers.Dense(64,activation = 'relu'))
model.add(layers.Dense(10,activation = 'softmax'))

model.summary()

在这里插入图片描述
我们可以看到在进入Dense层之间,有一个Flatten的网络输出数据是1D张量,已将(3,3,64)展平为(576,)的向量了
经过两个Dense层最终输出是10个数的向量,表示分别为0-9的概率

最后一层的激活函数用了‘softmax’,使输出的都是概率,并且和为1
各种激活函数

2.用卷积神经网络处理MNIST数字图像分类

from keras import layers
from keras import models

model = models.Sequential()
model.add(layers.Conv2D(32,(3,3),activation = 'relu',input_shape = (28,28,1)))
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(64,(3,3),activation = 'relu'))

#在卷积神经网络中添加分类器
model.add(layers.Flatten())
model.add(layers.Dense(64,activation = 'relu'))
model.add(layers.Dense(10,activation = 'softmax'))

#model.summary()

from keras.datasets import mnist
from keras.utils import to_categorical

(train_images,train_labels),(test_images,test_labels) = mnist.load_data()

train_images = train_images.reshape((60000,28,28,1))
train_images = train_images.astype('float32')/255

test_images = test_images.reshape((10000,28,28,1))
test_images = test_images.astype('float32')/255

train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

model.compile(optimizer = 'rmsprop',loss = 'categorical_crossentropy',metrics = ['accuracy'])

model.fit(train_images,train_labels,epochs = 5,batch_size = 64)

#测试机上对模型评估
test_loss,test_acc = model.evaluate(test_images,test_labels)
print(test_loss)
print(test_acc)

在这里插入图片描述
模型精度达到了99.24%,而用密集网络只能达到97.8%,效果非常好

总结该实验步骤:
1.下载数据集
2.将数据集reshape成可以输入神经网络的形状
3.搭建卷积神经网络
4.添加分类器(Dense层充当)
5.编译模型compile
6.训练模型fit
7.评估模型evaluate

分析原因
Dense层从输入特征空间中学到的是全局模式,即涉及所有像素的模式,卷积层Conv层学到的是局部模式,学到的是而二维小窗口(3,3)的大小

3.小型数据集上训练一个卷积神经网络
从kaggle官网https://www.kaggle.com/nafisur/dogs-vs-cats上下载下来数据,解压后:
在这里插入图片描述
现在的test文件夹中是三个文件夹,而test_set,training_set文件夹里面是猫狗图片的文件夹:
在这里插入图片描述
训练集猫狗图像各4000张,测试集猫狗图片各1000张

将图像复制到训练,验证,测试三个目录下
这里我们取猫狗的前1000张照片为训练集,后面的500张为验证集,再后面的500张为测试集:

import os,shutil
#原始下载解压的数据集中猫狗地址的文件夹位置
original_dataset_dir_cats = 'E:/dataset/dataset/dataset/training_set/cats'
original_dataset_dir_dogs = 'E:/dataset/dataset/dataset/training_set/dogs'

#把较小的数据集保存出来叫‘cats_and_dogs_small’的文件夹
base_dir = 'E:/dataset/cats_and_dogs_small'
os.mkdir(base_dir)

train_dir = os.path.join(base_dir,'train')#在cats_and_dogs_small的文件夹里加一个train的文件夹
os.mkdir(train_dir)
validation_dir = os.path.join(base_dir,'validation')#在cats_and_dogs_small的文件夹里加一个validation的文件夹
os.mkdir(validation_dir)
test_dir = os.path.join(base_dir,'test')#在cats_and_dogs_small的文件夹里加一个test的文件夹
os.mkdir(test_dir)

#在train文件夹里面加cats的文件夹,dogs的文件夹
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,dogs文件夹
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,dogs文件夹
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)

先把文件夹都造好,这里造一个cats_and_dogs_small的数据集,里面三个文件夹,train,validation,test,三个文件夹里面有cats,dogs两个文件夹装图片
在这里插入图片描述

###把前1000张猫的图片复制到train_cats_dir
#将复制后的图片文件更改为cat.0.jpg
fnames_original = ['cat.{}.jpg'.format(i) for i in range(1,1001)]
fnames = ['cat.{}.jpg'.format(i) for i in range(1000)]
for fnames_original,fnames in zip(fnames_original,fnames):
    src = os.path.join(original_dataset_dir_cats,fnames_original)#选择原来文件里的猫图片
    dst = os.path.join(train_cats_dir,fnames)#复制后的文件里的猫图片
    shutil.copyfile(src,dst)#原来的猫图片复制到train_cats_dir文件夹里
    
###把接下来的500张猫图片作为验证集复制到validation_cats_dir
fnames_original = ['cat.{}.jpg'.format(i) for i in range(1001,1501)]
fnames =['cat.{}.jpg'.format(i) for i in range(1000,1500)]
for fnames_original,fnames in zip(fnames_original,fnames):
    src = os.path.join(original_dataset_dir_cats,fnames_original)
    dst = os.path.join(validation_cats_dir,fnames)
    shutil.copyfile(src,dst)
    
###把再接下来的500张猫图片作为验证集复制到test_cats_dir
fnames_original = ['cat.{}.jpg'.format(i) for i in range(1501,2001)]
fnames = ['cat.{}.jpg'.format(i) for i in range(1500,2000)]
for fnames_original,fnames in zip(fnames_original,fnames):
    src = os.path.join(original_dataset_dir_cats,fnames_original)
    dst = os.path.join(test_cats_dir,fnames)
    shutil.copyfile(src,dst)
    
###把前1000张狗的图片复制到train_dogs_dir
#将复制后的图片文件更改为dog.0.jpg
fnames_original = ['dog.{}.jpg'.format(i) for i in range(1,1001)]
fnames = ['dog.{}.jpg'.format(i) for i in range(1000)]
for fnames_original,fnames in zip(fnames_original,fnames):
    src = os.path.join(original_dataset_dir_dogs,fnames_original)#选择原来文件里的猫图片
    dst = os.path.join(train_dogs_dir,fnames)#复制后的文件里的猫图片
    shutil.copyfile(src,dst)#原来的猫图片复制到train_cats_dir文件夹里
    
###把接下来的500张猫图片作为验证集复制到validation_cats_dir
fnames_original = ['dog.{}.jpg'.format(i) for i in range(1001,1501)]
fnames =['dog.{}.jpg'.format(i) for i in range(1000,1500)]
for fnames_original,fnames in zip(fnames_original,fnames):
    src = os.path.join(original_dataset_dir_dogs,fnames_original)
    dst = os.path.join(validation_dogs_dir,fnames)
    shutil.copyfile(src,dst)
    
###把再接下来的500张猫图片作为验证集复制到test_cats_dir
fnames_original = ['dog.{}.jpg'.format(i) for i in range(1501,2001)]
fnames = ['dog.{}.jpg'.format(i) for i in range(1500,2000)]
for fnames_original,fnames in zip(fnames_original,fnames):
    src = os.path.join(original_dataset_dir_dogs,fnames_original)
    dst = os.path.join(test_dogs_dir,fnames)
    shutil.copyfile(src,dst)
print('total training cat images:',len(os.listdir(train_cats_dir)))
print('total training dog images:',len(os.listdir(train_dogs_dir)))
print('total test cats images:',len(os.listdir(test_cats_dir)))
print('total test dogs images:',len(os.listdir(test_dogs_dir)))
print('total validation cats images:',len(os.listdir(validation_cats_dir)))
print('total validation dogs images:',len(os.listdir(validation_dogs_dir)))

在这里插入图片描述
构建网络
由于这是一个二分类问题,所以网络最后一层用sigmoid激活函数,返回出来是0或1

这里先随意选一个输入尺寸为150150,在flatten之前,将特征图处理到77的大小

###net
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'))

model.summary()

在这里插入图片描述
编译过程

###compile
from keras import optimizers

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

使用RMSprop优化器,因为网络最后一层是sigmoid所以使用交叉熵作为损失函数
在这里插入图片描述
输入神经网络之前对图像进行处理

###图像在输入神经网络之前进行数据处理
from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(rescale = 1./255)
test_datagen = ImageDataGenerator(rescale = 1./255)

train_dir = 'E:/dataset/cats_and_dogs_small/train'
train_generator = train_datagen.flow_from_directory(train_dir,target_size = (150,150),batch_size = 20,class_mode = 'binary')

validation_dir = 'E:/dataset/cats_and_dogs_small/validation'
validation_generator = test_datagen.flow_from_directory(validation_dir,target_size = (150,150),batch_size = 20,class_mode = 'binary')

for data_batch,labels_batch in train_generator:
    print('data batch shape:',data_batch.shape)
    print('data batch shape:',labels_batch.shape)
    break #生成器不会停止,会循环生成这些批量,所以我们就循环生成一次批量,打印大小出来看一下就可以了

注意,这个train_dir,validation_dir直接写train的文件地址,validation的文件地址就可以了,keras会自动检测里面有一个文件夹,就是几个类别(class)

用到一个生成器,批量生成(150,150,3)的图片,每20个为一批(batch_size=20),大小全都变成一样的150*150
发现报错了:
ImportError: Could not import PIL.Image. The use of array_to_img requires PIL.
少了pillow这个包,去安装一下,就可以了
在这里插入图片描述
训练模型
现在我们利用批量生成器来训练模型

###fit
history = model.fit_generator(train_generator,
                              steps_per_epoch = 100,
                              epochs = 30,
                              validation_data = validation_generator,
                              validation_steps = 50)


###save
model.save('cats_and_dogs_small_1.h5')

利用生成器,来训练模型就要用到fit_generator方法,他的第一个参数是一个python生成器,不断生成和输入组成的批量,第二个参数是从生成器中抽取多少个批量拟合,这里训练集里面2000张图,每个批量20张,所以一共需要100个批量才能读取完全部训练集

传入validation_data可以是一个生成器也可以是一个numpy数组组成的元组,这利用生成器,一样要限制读取的批量个数,1000张validation照片20个一批量,需要50个批量

这里要记录每一轮训练的acc,loss,所以用history记录历史记录
过程很漫长。。。

画出训练过程loss和acc的图像

###plot
import matplotlib.pyplot as plt

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1,len(acc) + 1)

plt.plot(epochs,acc,'bo',label = 'Training acc')
plt.plot(epochs,val_acc,'r',label = 'Validation acc')
plt.title('Training and Validation acc')
plt.legend()

plt.figure()

plt.plot(epochs,loss,'bo',label = 'Training loss')
plt.plot(epochs,val_loss,'r',label = "Validation loss")
plt.title('Training and Validation loss')
plt.legend()

plt.figure()

在这里插入图片描述
在这里插入图片描述
这些图说明模型过拟合了,在epoch = 5的时候就过拟合了,精确度只能达到70%左右,这是因为模型数目太少了,所以应该考虑如何降低过拟合的程度,比如dropout,正则化之类的

试着测试一张图片的预测效果
首先随便选一张照片,并将它缩小到(150,150,3)的形状,只有这样的形状才能往神经网络里面输入

#提取目录下所有图片,更改尺寸后保存到另一目录
import matplotlib.pyplot as plt
from PIL import Image
import os.path

def convertjpg(jpgfile,outdir,width=150,height=150):#将图片缩小到(150,150)的大小
    img=Image.open(jpgfile)
    try:
        new_img=img.resize((width,height),Image.BILINEAR)   
        new_img.save(os.path.join(outdir,os.path.basename(jpgfile)))
    except Exception as e:
        print(e)
        
jpgfile = 'E:/dataset/dataset/dataset/test_set/cats/cat.4046.jpg'#读取原图像
convertjpg(jpgfile,"E:/")#图像大小改变到(150,150)

img_scale = plt.imread('E:/cat.4046.jpg')
plt.imshow(img_scale)#确实变到了(150,150)大小

然后加载训练好的模型,将图片输入到神经网络里面

###导入模型
from keras.models import load_model
model = load_model('cats_and_dogs_small_1.h5')
#model.summary()

img_scale = img_scale.reshape(1,150,150,3).astype('float32')
img_scale = img_scale/255 #归一化到0-1之间

result = model.predict(img_scale)
print(result)
if result>0.5:
    print('这张照片可能是狗,是狗的概率是:',result)
else:
    print('这张照片可能是猫,是猫的概率是:',1-result)

因为之前训练的是用0-1之间的数进行训练的,所以这里也要对准备测试的图片进行归一化,得到的是一个概率值,是否为狗的概率值,如果这个概率大于0.5,说明更可能是狗,如果小于0.5,说明不太可能是狗,那么更可能是猫

img_scale = img_scale.reshape(1,150,150,3).astype('float32')

这句话非常重要,不写的话会报错:
ValueError: Error when checking input: expected conv2d_1_input to have 4 dimensions, but got array with shape (150, 150, 3),一张照片是一个3D张量,但是输入神经网络的得是4D张量,加了这句之后会发现:
在这里插入图片描述
随便测两张测试集里面的图片:
在这里插入图片描述

4.数据增强来降低过拟合
过拟合的原因是样本太少,通过对样本图像的随机变化呢,来增加样本个数,使训练的时候不会看到相同的图片,keras里的ImageDataGenerator方法可以实现

from keras.preprocessing import image
import os
import matplotlib.pyplot as plt

train_cats_dir = 'E:/dataset/cats_and_dogs_small/train/cats'

fnames = [os.path.join(train_cats_dir,fname) for fname in os.listdir(train_cats_dir)]
#print(fnames) #所有训练集中1000张猫的文件名
#利用ImageDataGenerator实例读取
from keras.preprocessing.image import 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') #填充创建像素的一种办法

#选择一张图片进行图像增强
img_path = fnames[3]
img = image.load_img(img_path,target_size = (150,150))#度读取图像并调整图像大小为(150,150,3)
x = image.img_to_array(img)#将其转化为(150,150,3)的numpy数组
x = x.reshape((1,) + x.shape)#将其形状改变为(1,150,150,3)的形状

i = 0
plt.figure()
for batch in datagen.flow(x,batch_size = 1):
    plt.subplot(2,2,i+1)
    plt.imshow(image.array_to_img(batch[0]))
    i += 1
    if i % 4 == 0:
        break
    
plt.show()

在这里插入图片描述
这就是通过随机数据增强生成的猫图片,但是这样网络看到的输入数据仍然是高度相关的,这些输入都来自少量原始图像,这样不足以完全消除过拟合,为了尽可能大的消除过拟合,这里想模型里面添加一个Dropout层,添加到密集连接分类器前

###定义一个包含Dropout的新卷积神经网络
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.Dropout(0.5))#添加的Dropout层
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'])

###训练模型
#图像的预处理
from keras.preprocessing.image import ImageDataGenerator
train_datagen = ImageDataGenerator(rescale = 1./255, #将图像乘1/255缩放到0-1之间的数
                                   rotation_range = 40, #图像随机旋转角度范围
                                   width_shift_range = 0.2, #图片在水平方向上平移的比例
                                   height_shift_range = 0.2, #图像在垂直方向上平移的比例
                                   shear_range = 0.2,  #随机错切变换的角度
                                   zoom_range = 0.2, #图像随机缩放的范围
                                   horizontal_flip = True,) #随机将一半图像的水平翻转

validation_datagen = ImageDataGenerator(rescale = 1./255)##注意!!!验证集是不能数据增强的

#生成批量数据,32个为一批,使用二进制标签(class_mode)
train_dir = 'E:/dataset/cats_and_dogs_small/train'
train_generator = train_datagen.flow_from_directory(train_dir,
                                                    target_size = (150,150),
                                                    batch_size = 32,
                                                    class_mode = 'binary')

validation_dir = 'E:/dataset/cats_and_dogs_small/validation'
validation_generator = validation_datagen.flow_from_directory(validation_dir,
                                                              target_size = (150,150),
                                                              batch_size = 32,
                                                              class_mode = 'binary')
#利用批量生成器拟合模型,一共训练100轮
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')

###画loss和acc在训练集和验证集上的对比图
import matplotlib.pyplot as plt

acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1,len(acc) + 1)

plt.plot(epochs,acc,'bo',label = 'Training acc')
plt.plot(epochs,val_acc,'r',label = 'Validation acc')
plt.title('Training and Validation acc')
plt.legend()

plt.figure()

plt.plot(epochs,loss,'bo',label = 'Training loss')
plt.plot(epochs,val_loss,'r',label = "Validation loss")
plt.title('Training and Validation loss')
plt.legend()

plt.figure()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
精度可以提高到80%多,精度明显提高了

同样的方法测试几张图片
在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在《python深度学习》的第八章中,主要讨论了在ImageNet大规模视觉识别挑战(ILSVRC)上训练深度神经网络的主题。其中最后一章讨论了SqueezeNet深度学习架构[1]。SqueezeNet是在2016年的一篇论文中提出的,它在准确度上和AlexNet相当,但参数减少了50倍,模型大小小于0.5MB。 在这一章中,还提到了一个名为test_alexnet.py的脚本,用以测试在ImageNet上训练的CNN模型。这个脚本没有进行任何修改,因为该章节中的test_*.py脚本旨在成为可以应用于任何在ImageNet上训练的CNN模型的模板。 此外,这一章还介绍了处理问题的一种方法,即使用softmax温度。在使用softmax温度时,需要尝试多种不同的温度值,以找到合适的温度值。 总结起来,《python深度学习》第八章主要涵盖了SqueezeNet深度学习架构、在ImageNet上训练的CNN模型的测试脚本以及使用softmax温度来处理问题的方法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Python视觉深度学习系列教程 第三卷 第8章 在ImageNet上训练SqueezeNet](https://blog.csdn.net/bashendixie5/article/details/122175562)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [《python深度学习》学习笔记与代码实现(第八章:8.1,8.2,8.3)](https://blog.csdn.net/qq_41718518/article/details/90216766)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值