VGG


研究背景:

  • 小卷积核
  • 多尺度
  • 加深网络深度

单尺度测试结果对比结论:

  • LRN对网络性能提升没有帮助
  • 对于同一个网络结构多尺度训练可以提高网络精度
  • 一定程度加深网络可以提高网络精度 

多尺度测试结果对比结论:

  • 对比单尺度预测,多尺度综合预测,能够提升预测的精度
  • 尺度抖动scale jittering(多尺度训练、多尺度测试)有利于网络性能的提升

感受野

定义:卷积神经网络 每一层输出的特征图上的像素点在输入图片上映射的区域大小,即特征图上的一个点跟原图上有关系的点的区域。

原始输入:7x7

conv1:3x3 stride=1 valid

  (input-k+2padding)/stride+1

feature:(7-3)/1+1=5

conv1:5x5,图上的一个点由原始输入的3x3个点卷积得到,所以感受野为3

conv2:3x3 stride=1 valid

feature:(5-3)/1+1=3

conv2:3x3,图上的一个点由conv1的3x3卷积得到,而conv1上的一个点由原始输入的3X3个点得到,步长为1,横向观察,可以发现conv2的一个点可以由原始输入的5x5个点得到,故conv2层的感受野为5

 如果conv1:5X5 stride=1,对应conv1层的感受野为5

 一个5x5的卷积核感受野的大小与两个3x3卷积核的感受野等效

一个7x7的卷积核感受野的大小与三个3x3卷积核的感受野等效

感受野计算公式:

网络结构:

5个卷积块,小卷积核堆积,通道数量依次增加一倍,卷积结束后进行maxpool,三个全连接层

为什么使用3*3卷积核?

  • 深度更深并增加了非线性
  • 参数量减少      参数量=(kernel*kenel*channel)*卷积核个数

1*1卷积核的作用? 

  • 一种为决策增加非线性因素的方式
  • 因为卷积后边通常跟着一层relu 

训练数据处理:

各向同性的缩放(等比缩放:图像长宽缩放比例相同)训练图像最小边

resize:各项异性缩放,不考虑物体是否会发生形变

先将图片进行等比变化,最小边长度为256,然后对等比变化后的图像进行随机裁剪成224*224,之后将裁剪得到的图像块进行随机水平翻转与RGB颜色转换

目的:增加数据量,使网络不容易发生过拟合,可以提高网络准确度和泛化能力

import numpy as np
from PIL import Image
S = 256
crop_size = 224
image_path = ''
or_image = Image.open('image_path')#加载图片
image_w, image_h = or_image.size#获取原始图片宽高
scale = S/(min(image_w,image_h))#0.4 将图片最小边缩小为224
new_w = np.int(image_w*scale)#计算等比缩放后图像的长宽
new_h = np.int(image_h*scale)
print(new_w, new_h)#256 341
resize_image = or_image.resi ze((new_w, new_h), Image.BICUBIC)#使用线性差值方式缩放
max_offset_width = np.random.randint(low=0, high=new_w-crop_size+1,dtype='int32')
max_offset_height = np.random.randint(low=0, high=new_w-crop_size+1,dtype='int32')

超参数设置:

批量大小:batchsize = 256

权重衰减:weight decay = 5*10^(-4)

学习率:learning rate = 0.01 衰减因子为0.1

动量:momentum = 0.9(优化方式为带动量的SGD)

迭代步数:370K

轮数:epoches = 75

卷积核初始化方式:均值为0 方差为1的高斯分布(深层网络使用浅层网络权重初始化)

偏置初始化方式:初始化为0

全连接层初始化方式:高斯分布(std=0.005),bias常数初始化(0.1)

 特点:

  • 小卷积核
  • 小池化核  Alexnet采用3*3池化核,VGG采用2*2池化核
  • 层数更深
  • 全连接转卷积  使其可以接收任意大小作为输入

数据增强代码

#计算将图片最小边缩放为目标尺寸(smallest_side)时图像的宽高为多少
#即返回目标宽高
def _smallest_size_at_least(height, width, smallest_side):
    smallest_side = tf.convert_to_tensor(smallest_side, dtype=tf.int32)
    height = tf.to_float(height)
    width = tf.to_float(width)
    smallest_side = tf.float(smallest_side)
    scale = tf.cond(tf.greater(height,width),lambda:smallest_side/width,lambda:smallest_side/height)
    new_height = tf.cast(tf.rint(height*scale),tf.int32)
    new_width = tf.cast(tf.rint(width*scale),tf.int32)
    return new_height,new_width
#对图片进行等比变化,等比缩放后最小边长为smallest_side
def _aspect_preserving_resize(image,smallest_side):
    smallest_side = tf.convert_to_tensor(smallest_side,dtype=tf.int32)
    shape = tf.shape(image)
    height = shape[0]
    width = shape[1]
    new_height, new_width = _smallest_size_at_least(height,width,smallest_side)
    image = tf.image.convert_image_dtype(image,dtype=tf.float32)
    resized_image = tf.image.resize_images(image,[new_height,new_width],method=tf.image.ResizeMethod.BICUBIC)
    return resized_image
#随机裁剪224*224的图像块
def random_crop(image,crop_height,crop_width):
    original_shape = tf.reshape(img_data_jpg)
    #判断original_shape的维度是否为3,如果是 不抛出异常
    rank_assertion = tf.Assert(tf.equal(tf.rank(img_data_jpg),3),['Rank of image must be equal to 3])
    #cropped_shape = [224,224,3]
    with tf.control_dependencies([rank_assertion]):
        cropped_shape = tf.stack([crop_height,crop_width,original_shape[2])
    #判断原图大小与剪切图像块的大小,若原图小于图像块尺寸,抛出异常
    size_assertion = tf.Assert(tf.logical_and(tf.greater_equal(original_shape[0],crop_height),tf.greater_equal(original_shape[1],crop_width)),['Crop size greater than the image size.'])
    #确定最大裁剪范围
    max_offset_height = tf.reshape(original_shape[0] - crop_height + 1,[])
    max_offset_width = tf.reshape(orginal_shape[1] -crop_width + 1,[])
    #生成随机裁剪的起点
    offset_height = tf.random_uniform([], maxval=max_offset_height,dtype=tf.int32)
    offset_width = tf.random_uniform([],maxval=max_offset_width,dtype=tf.int32)
    #裁剪的偏移量
    offsets = tf.cast(tf.stack([offset_height,offset_width,0),tf.int32)
    #对图片进行裁剪
    with tf.control_dependencies([size_assertion]):
        image = tf.slice(img_data_jpg,offsets,cropped_shape)
    return tf.reshape(image,cropped_shape)
#进行数据处理
#图像缩小最小尺寸为256,最大尺寸为512
resize_side_min = RESIZE_SIDE_MIN
reside_side_max = RESIZE_SIDE_MAX
#读出的为未解码的图片
image_raw_data_jpg = tf.gfile.GFile('./timg1.jpeg,'rb').read()
#图像解码
img_data_jpg = tf.image.decode_jpeg(image_raw_data_jpg)
#随机产生最小边尺寸
resize_side = tf.random_uniform([],minval=resize_side_min,maxval=resize_side_max + 1,dtype=tf.int32)
#对图片进行等比缩放
resize_img = _aspect_preserving_resize(img_data_jpg,resize_side)
#对缩放后的图片进行随机裁剪
crop_img = random_crop(resize_img,crop_height,crop_width)
#左右反转
image_data = tf.image.random_flip_left_right(crop_img)
#调整图像亮度
image_data = tf.image.random_brightness(image_data,0.5)