VGG网络
VGG网络是2014年ILSVRC竞赛的第二名(第一名是GoogleNet,即后来的inception),由牛津大学的计算机视觉实验组提出。原始论文地址https://arxiv.org/abs/1409.1556
VGG的出现证明了网络深度的增加可以提升模型的效果,它由一系列的卷积、池化堆叠而成,在论文中作者搭建了不同深度的6种VGG模型,命名A-E,网络深度依次加深。通常VGG16和VGG19是指D、E两个版本。
下表是原始论文中的6个版本VGG结构,A-LRN是在A版本的基础上使用了AlexNet中的LRN层,用来对比。
VGG的另一个特点是使用的卷积只有11和33的卷积,2个33的卷积代替55卷积,3个33卷积代替77的卷积,尽管它们的感受野相同,但使用多个小卷积代替大卷积,在保证感受野不变的情况下可以使参数量减小,且提升了网络的深度。比如55的卷积需要的参数量是25个,而用2个小的33卷积代替只需要18个。
此外VGG中使用了1*1的卷积,作者认为1x1卷积可以增加决策函数的非线性能力,非线性是由激活函数决定的,1x1卷积是线性映射,在同样的维度上映射特征图。
VGG的输入是224*224尺寸的图像,且经过特殊处理后才输入网络,处理不仅包括归一化等常规操作,并且每个像素值还减去了在总的训练集的均值。
在Keras中内置了处理输入的函数。
from keras.applications.imagenet_utils import preprocess_input
img = preprocess_input(img) # img是要输入的图像
# 查看preprocess_input函数的部分源码如下
# 该函数针对TensorFlow、caffe、Torch的处理并不相同,对tf只需将图像像素值缩放到-1和1之间,caffe则将图片通道变为BGR,做中心化但不缩放像素值范围,Torch缩放像素值在0到1之间,然后标准化。
if mode == 'tf':
x /= 127.5
x -= 1.
return x
if mode == 'torch':
x /= 255.
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]
else:
if data_format == 'channels_first':
# 'RGB'->'BGR'
if backend.ndim(x) == 3:
x = x[::-1, ...]
else:
x = x[:, ::-1, ...]
else:
# 'RGB'->'BGR'
x = x[..., ::-1]
mean = [103.939, 116.779, 123.68]
std = None
Keras搭建VGG16并进行花卉分类
一个在线可视化vgg16结构的网站: https://dgschwend.github.io/netscope/#/preset/vgg-16
数据集来自谷歌的一个鲜花数据集,网址http://download.tensorflow.org/example_image/flower_photo.tgz
该数据集比较小,包含五类鲜花的照片,chamomile(甘菊)、 tulip(郁金香)、rose(玫瑰)、sunflower(向日葵)、dandelion(蒲公英),每一类图片有800张左右,且大小不一,但图像都比较小约为,400x300。
对数据集的处理,采用npy格式存储数据。OpenCV读取图像后,直接使用preprocess_input 函数处理,然后存入npy文件。标签采用to_categorical进行独热编码转换标签。
使用Keras搭建VGG16,比较方便,按照论文中的结构一层层累积即可。每层卷积使用relu激活函数,最后输出softmax分类,类别为5,优化器采用sgd(在网上一个博客看到说采用Adam优化效果更好,但我试了没有sgd效果好?),分类交叉熵损失categorical_crossentropy。
Keras的另一个好处是keras.applications模块内置了许多模型,包括VGG、ResNet、InceptionV3、DenseNet121等。因此我们可以使用内置的VGG16,只需修改最后的全连接层输出类别即可。
import numpy as np
from keras.models import Model, load_model
from keras.layers import Dropout, Flatten, Dense, Input
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.utils import plot_model,to_categorical
from keras import optimizers
import os
import cv2
from keras.applications import VGG16
from keras.applications.vgg16 import preprocess_input
from keras.callbacks import TensorBoard
class vgg():
def __init__(self, shape, num_classes, data_path, label_path, model_path):
self.shape = shape
self.num_classes = num_classes
self.data_path = data_path
self.label_path = label_path
self.model_path = model_path
self.log_path = "./logs"
self.classes = self.classname()
def classname(self, prepath="D://Datasets//flower_photos//flower_photos//"):
# 数据集的类别序号和对应名称,注意的是序号是从1开始,而label中编码实际是从0开始
classes = os.listdir(prepath) # 类别序号和名称
class_dict