训练方法基本与AlexNet一致,除了多尺度训练图像采样方法不一致
训练采用mini-batch梯度下降法,batch size=256
采用动量优化算法,momentum=0.9
采用L2正则化方法,惩罚系数0.00005,dropout比率设为0.5
初始学习率为0.001,当验证集准确率不再提高时,学习率衰减为原来的0.1倍,总共下降三次
总迭代次数为370K(74epochs)
数据增强采用随机裁剪,水平翻转,RGB颜色变化
设置训练图片大小的两种方法(定义S代表经过各向同性缩放的训练图像的Zui小边):
第一种方法针对单尺寸图像训练,S=256或384,输入图片从中随机裁剪224*224大小的图片,原则上S可以取任意不小于224的值
第二种方法是多尺度训练,每张图像单独从[Smin ,Smax]中随机选取S来进行尺寸缩放,由于图像中目标物体尺寸不定,训练中采用这种方法是有效的,可看作一种尺寸抖动的训练集数据增强
论文中提到,网络权重的初始化非常重要,由于深度网络梯度的不稳定性,不合适的初始化会阻碍网络的学习。先训练浅层网络,再用训练好的浅层网络去初始化深层网络.
2 VGG-16网络复现2.1 VGG-16网络结构(前向传播)复现复现VGG-16的16层网络结构,将其封装在一个Vgg16类中,注意这里我们使用已训练好的vgg16.npy参数文件,不需要自己再对模型训练,不需要编写用于训练的反向传播函数,只编写用于测试的前向传播部分即可。
下面代码我已添加详细注释,并添加一些print语句用于输出网络在每一层时的结构尺寸信息。
vgg16.py
import inspectimport os
import numpy asnp
import tensorflow astf
import time
import matplotlib.pyplot asplt
VGG_N =[103.939,116.779,123.68] # 样本RGB的平均值
class Vgg16():
def__init__(self,vgg16_path=None):
if vgg16_path isNone:
# os.getcwd()方法用于返回当前工作目录(npy模型参数文件)
vgg16_path =os.path.join(os.getcwd(),"vgg16.npy")
print("path(vgg16.npy):",vgg16_path)
# 遍历其内键值对,导入模型参数
self.data_dict =np.load(vgg16_path,encoding='latin1').item()
for x inself.data_dict: #遍历datat_dict中的每个键
print("key indata_dict:",x)
defforward(self,images):
print("build modelstarted...")
start_time = time.time()# 获取前向传播的开始时间
rgb_scaled = images* 255.0 # 逐像素乘以255
# 从GRB转换色彩通道到BGR
red, green, blue=tf.split(rgb_scaled,3,3)
# assert是加入断言,用断每个操作后的维度变化是否和预期一致
assertred.get_shape().as_list()[1:]== [224,224, 1]
assertgreen.get_shape().as_list()[1:]== [224,224, 1]
assert blue.get_shape().as_list()[1:]== [224,224, 1]
bgr = tf.concat([
blue -VGG_N[0],
green -VGG_N[1],
red -VGG_N[2]],3)
assertbgr.get_shape().as_list()[1:]== [224,224, 3]
#构建VGG的16层网络(包含5段(2+2+3+3+3=13)卷积,3层全连接)
# 第1段,2卷积层+Zui大池化层
print("==>input imageshape:",bgr.get_shape().as_list())
self.conv1_1 =self.conv_layer(bgr,"conv1_1")
print("=>after conv1_1shape:",self.conv1_1.get_shape().as_list())
self.conv1_2 =self.conv_layer(self.conv1_1,"conv1_2")
print("=>after conv1_2shape:",self.conv1_2.get_shape().as_list())
self.pool1 =self.max_pool_2x2(self.conv1_2,"pool1")
print("---after pool1shape:",self.pool1.get_shape().as_list())
# 第2段,2卷积层+Zui大池化层
self.conv2_1 =self.conv_layer(self.pool1,"conv2_1")
print("=>after conv2_1shape:",self.conv2_1.get_shape().as_list())
self.conv2_2 =self.conv_layer(self.conv2_1,"conv2_2")
print("=>after conv2_2shape:",self.conv2_2.get_shape().as_list())
self.pool2 =self.max_pool_2x2(self.conv2_2,"pool2")
print("---after pool2shape:",self.pool2.get_shape().as_list())