几种卷积神经网络

前言

深度学习在计算机视觉(computer version)领域非常成功,举个简单的例子——让计算机分辨图片的上的动物是猫还是狗是非常难以实现的事情,但是借助于 卷积神经网络(CNN) 这是非常容易实现的事情。卷积神经网络是本章介绍的重点,在这篇博文中我将结合一些简单的例子说明什么是卷积神经网络,以及简单介绍几个框架模型并用已经预训练的模型来解决一个简单分类问题。最后探索一下最新的深度可分离卷积(参数更少运行效率更高)
另:本系列的所有代码都以jupyter notebook格式托管到github上,大家可以去下载看下
https://github.com/Wangzg123/KerasDeepLearningDemo

一、卷积神经网络

卷积神经网络(Convolutional Neural Networks)也就是我们常说的CNN,使用最频繁的领域就是计算机视觉领域,它在视觉上的表现是非常杰出的。我们先来看下图片在计算机中的表现形式。一张彩色照片通常有3个通道,分别是R(red)、G(green)和B(blue),每个像素一个颜色值,那么他们的堆叠就是一张图片。如下示(当然图片的像素点不会那么少)假如一张长480和宽480的彩色照片写成矩阵形式就是(480, 480,3)
在这里插入图片描述

1、什么是卷积神经网络
卷积

介绍完图片在计算机的表现之后,我们先来看下卷积计算,关于卷积先来看下下面的动图。假如有一张773的图片,那么我们通过一个f = 333,步长 = 2,填充层 = 0的卷积核(输入层的通道数等于卷积核的通道数)可以得到一个3 * 3的输出。我们这边来介绍下卷积计算的公式

设一张n * n的图片,filter 是 f * f、padding是p,strided 是 s,那么经过卷积计算之后的size(向下取整)是
[(n + 2p - f)/ s + 1, (n + 2p - f)/ s + 1]

通过上面的公式可以得到目标的size是 [ (7 + 20 - 3)/2 + 1, (7 + 20 - 3)/2 + 1 ] = [ 3, 3],值得说明的是如果有两个卷积核,那么输出的形状就是 [ 3, 3, 2],其中2就是卷积核的个数,通过卷积计算我们就可以将图片的特征采集成不同的输出。
在这里插入图片描述

池化

池化层用的方法有最大值池化(Max pooling) 和平均值池化(average pooling),而实际用的较多的是Max pooling。这里就说一下Max pooling,其实思想非常简单,就是把filter堆积在图片上输出最大的那个值。其中池化的公式也和卷积计算的公式一致,但在卷积神经网络中Maxpoing的fiter通常为22,stride=2 ,这样可以把一张nn的图片采样为n/2 * n/2的图片。
在这里插入图片描述

全连接层

通过上面的介绍我们可以知道通过卷积、池化之后的输出是一个个小的图片,而在神经网络算法中我们是以下这种形式,那么全连接层的概念就是将这些“小图片”全部拉成一个长向量(flatten)然后乘以权重输出到我们的目标函数中即可
在这里插入图片描述
介绍完上面的卷积+池化+全连接层的概念,我们来看下这样的一个网络,假如这个网络是为了识别手写数字。这个网络的计算方式如下所示,通俗点说卷积神经网络就是不断的进行卷积池化计算,将特征不断提取的过程
在这里插入图片描述

2、关于卷积、池化的直观理解

关于卷积计算,其实就是通过不同的filter提取图片的特征,如下示不同的卷积核(filter)可以提取不同的特征
在这里插入图片描述
池化我觉得下面的这个例子非常棒,非常直观的诠释了池化的直观理解
在这里插入图片描述

二、从头开始训练一个卷积神经网络

我们接下来来做一个基于keras实现的一个猫狗识别的例子,从头训练一个卷积神经网络并实现可以自动识别出猫狗的模型,这篇代码选自《python深度学习》一书,更加详细的代码请查看我的github(见前言)

# 导入库
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))
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(optimizer=optimizers.RMSprop(lr=1e-4), loss='binary_crossentropy', 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_first = 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')
# 绘制曲线
acc = history_first.history['acc']
val_acc = history_first.history['val_acc']
loss = history_first.history['loss']
val_loss =history_first.history['val_loss']
Epochs = range(1, len(loss) + 1)
plt.plot(Epochs, acc, 'bo', label='Training acc')
plt.plot(Epochs, val_acc, 'b', label='Validation acc')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()

plt.figure()
plt.plot(Epochs, loss, 'bo', label='Training loss')
plt.plot(Epochs, val_loss, 'b', label='Validation loss')
plt.xlabel('Epochs')
plt.ylabel('loss')
plt.title('Training and Validation loss')
plt.legend()

plt.show()

在这里插入图片描述

三、迁移学习

想要将深度学习应用于小型图像数据集,一种常用且非常高效的方法是使用预训练网络。预训练网络(pretrained network)是一个保存好的网络,之前已在大型数据集(通常是大规模图像分类任务)上训练好。如果这个原始数据集足够大且足够通用,那么预训练网络学到的特征的空间层次结构可以有效地作为视觉世界的通用模型,而使用这种预训练模型的方式就是——迁移学习

1、几种卷积网络模型

在介绍怎么进行迁移学习之前,我们先来学习下几种非常出名的卷积神经网络模型

VGG

VGGNet是牛津大学计算机视觉组和Google DeepMind公司一起研发的深度卷积神经网络,并取得了2014年Imagenet比赛定位项目第一名和分类项目第二名。该网络主要是泛化性能很好,容易迁移到其他的图像识别项目上,可以下载VGGNet训练好的参数进行很好的初始化权重操作,很多卷积神经网络都是以该网络为基础,比如FCN,UNet,SegNet等。vgg版本很多,常用的是VGG16,VGG19网络。网络架构如下示
在这里插入图片描述

Resnet

残差神经网络的基本模块(Resnet),输入为x,输出为F(x)+x,F(x)代表网络中数据的一系列乘、加操作,假设神经网络最优的拟合结果输出为H(x)=F(x)+x,那么神经网络最优的F(x)即为H(x)与x的残差,通过拟合残差来提升网络效果。为什么转变为拟合残差就比传统卷积网络要好呢?因为训练的时候至少可以保证残差为0,保证增加残差学习单元不会降低网络性能,假设一个浅层网络达到了饱和的准确率,后面再加上这个残差学习单元可以保证梯度消失问题
在这里插入图片描述

Inception

Inception也叫googlenet,目前已经有v1 v2 v3的多个版本,网络架构如下示,可以看到网络层架更深且也更复杂
在这里插入图片描述

2、预训练的模型

如前所述,用于图像分类的卷积神经网络包含两部分:首先是一系列池化层和卷积层,最后是一个密集连接分类器。第一部分叫作模型的卷积基(convolutional base)。对于卷积神经网络而言,特征提取就是取出之前训练好的网络的卷积基,在上面运行新数据,然后在输出上面训练一个新的分类器
在这里插入图片描述

from keras.applications import VGG16
from keras import models
from keras import layers
# 导入vgg16的模型,但不包括最后一层
conv_base = VGG16(weights='imagenet', include_top=False, input_shape=(150, 150, 3))
# 定义一个模型并加入vgg16
model = models.Sequential()
model.add(conv_base)
model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
# 冻结vgg层
conv_base.trainable = False
from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
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, fill_mode='nearest')
test_datagen = ImageDataGenerator(rescale=1./255)
# 引入数据集目录
train_dir = r'E:\2--jupyter_notebook\python deeplearning\datasets\dog_cat_classify\cats_and_dogs_small\train'
validation_dir = r'E:\2--jupyter_notebook\python deeplearning\datasets\dog_cat_classify\cats_and_dogs_small\validation'
test_dir = r'E:\2--jupyter_notebook\python deeplearning\datasets\dog_cat_classify\cats_and_dogs_small\test'
# 生成器
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')
# 编译并训练模型
model.compile(loss='binary_crossentropy', optimizer=optimizers.RMSprop(lr=2e-5), metrics=['acc'])
history = model.fit_generator(train_generator, steps_per_epoch=100, epochs=30, validation_data=validation_generator, validation_steps=50)
# 绘制曲线
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(loss) + 1)
plt.plot(Epochs, acc, 'ro', label='Training acc')
plt.plot(Epochs, val_acc, 'r', label='Validation acc')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()

plt.figure()
plt.plot(Epochs, loss, 'ro', label='Training loss')
plt.plot(Epochs, val_loss, 'r', label='Validation loss')
plt.xlabel('Epochs')
plt.ylabel('loss')
plt.title('Training and Validation loss')
plt.legend()

plt.show()

在这里插入图片描述

四、深度可分离卷积

最后我们来看下深度可以分离卷积的例子,它是一种比较新的网络架构,其特点是参数更少运算更快,并且表现的准确度也和普通的卷积神经网络的模型差不多,如下所示的单元,传统卷积计算所需要的filter的参数是4608,而深度可分离卷积的参数个数是656,实验结果也表示其识别的准确度差不多。
在这里插入图片描述

五、总结

以上介绍了卷积、池化和全连接的计算过程,也介绍了几个框架,如VGG、Inception等。并通过keras这个框架实现猫狗识别的例子,而后为了提高准确度而通过迁移学习来更改我们的模型来提升准确度,最后介绍了比较新的深度可分离卷积,这种网络比传统的卷积计算代价更低,和vgg等一样,基于深度可分离卷积的是Xception模型(有兴趣的可以自行学习)。其实在计算机视觉还有很多例子,比如人脸识别,yolo等,以后有机会我再总结发布博客吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值