循环神经网络VGG

VGGnet

模型们在ImageNet竞赛上的top-5错误率概况:

 

目的:

探究在大规模图像识别任务中,卷积网络的深度与其性能之间的关系

做法:
VGG把 Alexnet 最开始的一个7*7的卷积核用 3个3*3的卷积核代替。

通过反复堆叠3*3的小型卷积核(stride:1,padding:1)和 2*2的最大池化层,不断加深网络结构来提升性能,成功地构筑了16~19层深的卷积神经网络。

为什么这么做?

(1)3x3是最小的能够捕获左、右、上、下和中心概念的尺寸; 
(2)AlexNet最开始的7*7的卷积核的感受野是:7*7 
……..VGG第一个卷积核的感受野:3*3 
……..第二个卷积核的感受野:(3-1)*1+3=5 
……..第三个卷积核的感受野:(5-1)*1+3=7 
……..可见三个3*3卷积核和一个7*7卷积核的感受野是一样的,但是3*3卷积核可以把网络做的更深。 
(3)多个3*3的卷积层比一个大尺寸的filter卷积层有更多的非线性,使得判决函数更加具有判断性。 
(4)多个3*3的卷积层比一个大尺寸的filter具有更少的参数。

成就:
VGGNet 相比之前state-of-the-art的网络结构,错误率大幅下降, 获得ILSVRC 2014比赛分类项目的第2名和定位项目的第1名。

贡献:
证明了使用很小的卷积(3*3),增加网络深度可以有效提升模型的效果,而且VGGNet对其他数据集具有很好的泛化能力

VGG的结构
为了在公平的原则下探究网络深度对模型精确度的影响,所有卷积层有相同的配置: 
卷积核大小为3*3,步长为1(stride:1),填充为1(padding:1); 
共有5个最大池化层,大小都为2*2,步长为2(stride:2); 
三个全连接层,前两层都有4096通道,第三层共1000路及代表1000个标签类别;最后一层为softmax层; 

所有隐藏层后都带有ReLU非线性激活函数;

下图为VGG16的结构图: 

è¿éåå¾çæè¿°


配置对比:

è¿éåå¾çæè¿°

这张图的意思是他们一共建了A, B, C, D, E, F 6个不同的网络。

结构A:和AlexNet类似,卷积层分为了5个stage,全连接层还是3层。只不过卷积层用的都是3x3大小的filter,具体的细节我会在下文接着阐述。

结构A-LRN:保留AlexNet里面LRN操作,其他与结构A无区别。

结构B:在A的 stage2 和 stage3 分别增加一个3*3的卷积层,共有10个卷积层,全连接层还是3层。

结构C:在B的基础上,stage3,stage4,stage5分别增加一个1*1的卷积层,有13个卷积层,全连接层还是3层,总计16层。

结构D:在C的基础上,stage3,stage4,stage5分别增加一个3*3的卷积层,有13个卷积层,全连接层还是3层,总计16层。

结构E:在D的基础上,stage3,stage4,stage5分别再增加一个3*3的卷积层,有16个卷积层,全连接层还是3层,总计19层。
参数(以VGG16为例):

è¿éåå¾çæè¿°

VGG结构需要注意的点:
1、卷积核都是3x3的 
2、参数最多的层:第一个全卷积层,占用内存最多的层:前两个卷积层 
3、卷积核个数从64到128到256的目的:stride:1,padding:1 的卷积,特征图大小不变,但是进经过2*2的pooling操作,每个特征图的w和h都变为1/2,特征图的大小变为1/4,将卷积核的个数翻倍,可以降低信息衰减 
4、使用了1*1卷积核,1*1卷积核有什么作用? 
(1)降维( dimension reductionality )。比如,一张500 * 500且厚度depth为100 的图片在20个filter上做1*1的卷积,那么结果的大小为500*500*20。 
(2)加入非线性。卷积层之后经过激励层,1*1的卷积在前一层的学习表示上添加了非线性激励( non-linear activation ),提升网络的表达能力;
 

代码实例:

读入文件

import tensorflow as tf
import os
import pickle
import numpy as np

CIFAR_DIR = "./cifar-10-batches-py"
print(os.listdir(CIFAR_DIR))

运行效果

# "def load_data(filename):\n",
#     "    \"\"\"read data from data file.\"\"\"\n",
#     "    with open(filename, 'rb') as f:\n",
#     "        data = pickle.load(f, encoding='bytes')\n",
#     "        return data[b'data'], data[b'labels']\n",
def load_data(filename):
    #读取文件
    with open(filename,'rb') as f:
        data = pickle.load(f,encoding='bytes')
        return data[b'data'],data[b'labels']
class CifarData:
    def __init__(self,filenames,need_shuffle):
        all_data = []
        all_labels = []
        for filename in filenames:
            data,labels = load_data(filename)
            all_data.append(data)
            all_labels.append(labels)
        #将data排成m行n列的矩阵,标签排成1行n列的矩阵
        self._data = np.vstack(all_data)
        self._data = self._data / 127.5-1
        self._labels = np.hstack(all_labels)
        self._num_examples = self._data.shape[0]
        print(self._data.shape)
        print(self._labels.shape)
        self._need_shuffle = need_shuffle
        self._indicator = 0
        #如果需要打乱数据,则打乱数据
        if self._need_shuffle:
            self._shuffle_data()

    def _shuffle_data(self):
        p = np.random.permutation(self._num_examples)
        self._data = self._data[p]
        self._labels = self._labels[p]

    def next_batch(self,batch_size):
        end_indicator = self._indicator + batch_size
        if end_indicator > self._num_examples:
            if self._need_shuffle:
                self._shuffle_data()
                self._indicator = 0
                end_indicator = batch_size
            else:
                raise Exception("erro")
        if end_indicator >self._num_examples:
            raise Exception("erro")
        batch_data = self._data[self._indicator:end_indicator]
        batch_labels = self._labels[self._indicator:end_indicator]
        self._indicator = end_indicator
        return batch_data,batch_labels

train_filenames = [os.path.join(CIFAR_DIR,'data_batch_%d' %i)for i in range(1,6)]
test_filenames = [os.path.join(CIFAR_DIR,'test_batch')]
train_data = CifarData(train_filenames,True)
test_data = CifarData(test_filenames,False)

运行效果

占位符,每次放进计算图 None个样本,每个样本3072个特征
x = tf.placeholder(tf.float32,[None,3072])
#将x转化为图片模式,32*32的3张图片
x_image = tf.reshape(x,[-1,3,32,32])
x_image = tf.transpose(x_image,[0,2,3,1])
#输出的y表示图片属于第几类
y = tf.placeholder(tf.int64,[None])

#conv1:神经元图 32*32
conv1_1 = tf.layers.conv2d(x_image,
                           32,#输出大小
                         (3,3),#卷积核大小
                         padding='same',
                        activation=tf.nn.relu,
                        name='conv1')
conv1_2 = tf.layers.conv2d(conv1_1,
                           32,#输出大小
                         (3,3),#卷积核大小
                         padding='same',
                        activation=tf.nn.relu,
                        name='conv1_2')
conv1_3 = tf.layers.conv2d(conv1_2,
                           32,#输出大小
                         (3,3),#卷积核大小
                         padding='same',
                        activation=tf.nn.relu,
                        name='conv1_3')
#池化层:减少计算量 16*16
pooling1 = tf.layers.max_pooling2d(conv1_3,
                                  (2,2),#核大小
                                  (2,2),#步长
                                  name = 'pool1')
#conv2:神经元图  16*16
conv2_1 = tf.layers.conv2d(pooling1,32,#输出大小
                         (3,3),#卷积核大小
                         padding='same',
                        activation=tf.nn.relu,
                        name='conv2_1')
conv2_2 = tf.layers.conv2d(conv2_1,32,#输出大小
                         (3,3),#卷积核大小
                         padding='same',
                        activation=tf.nn.relu,
                        name='conv2_2')
conv2_3 = tf.layers.conv2d(conv2_2,32,#输出大小
                         (3,3),#卷积核大小
                         padding='same',
                        activation=tf.nn.relu,
                        name='conv2_3')
#池化层:减少计算量 8*8
pooling2 = tf.layers.max_pooling2d(conv2_2,
                                  (2,2),#核大小
                                  (2,2),#步长
                                  name = 'pool2')
# 8*8
conv3_1 = tf.layers.conv2d(pooling2,32,(3,3),padding='same',activation=tf.nn.relu,name='conv3_1')
conv3_2 = tf.layers.conv2d(conv3_1,32,(3,3),padding='same',activation=tf.nn.relu,name='conv3_2')
conv3_3 = tf.layers.conv2d(conv3_2,32,(3,3),padding='same',activation=tf.nn.relu,name='conv3_3')
#4*4
pooling3 = tf.layers.max_pooling2d(conv3_3,(2,2),(2,2),name='pool3')
#形成全连接层
flatten = tf.layers.flatten(pooling3)

#实现矩阵相乘的功能
y_ = tf.layers.dense(flatten,10)
# #使用softmax:exp(x_i)/sum(exp(x_i)),转化为【1.。。0】之间的数
# p_y_1 = tf.nn.softmax(y_)
# #如5:转化为[0,0,0,0,1,0,0,0,0,0 ]
# y_one_hot = tf.one_hot(y,10,dtype=tf.float32)
# loss = tf.reduce_mean(tf.square(y_one_hot - p_y_1))

#交叉熵损失函数 实现了 y转化为概率,y的one_hot编码,loss = ylogy_
loss = tf.losses.sparse_softmax_cross_entropy(labels=y,logits=y_)
#计算准确率
predict = tf.argmax(y_,1)
correct_prediction = tf.equal(predict,y)
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
#定义如何去求最优解,使用梯度下降法
#  "with tf.name_scope('train_op'):\n",
#     "    train_op = tf.train.AdamOptimizer(1e-3).minimize(loss)"
with tf.name_scope('train_op'):
    train_op = tf.train.AdamOptimizer(1e-3).minimize(loss)
def variable_summary(var,name):
    with tf.name_scope(name):
        mean = tf.reduce_mean(var)
        with tf.name_scope('stddev'):
            stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
        tf.summary.scalar('mean',mean)
        tf.summary.scalar('stddev',stddev)
        tf.summary.scalar('min',tf.reduce_mean(var))
        tf.summary.scalar('max',tf.reduce_max(var))
        tf.summary.histogram('histogram',var) #打印出数据的直方图
        
with tf.name_scope('scope'):
    variable_summary(conv1_1,'conv1_1')
    variable_summary(conv1_2,'conv1_2')
    variable_summary(conv2_1,'conv2_1')
    variable_summary(conv2_2,'conv2_2')
    variable_summary(conv3_1,'conv3_1')
    variable_summary(conv3_2,'conv3_2')
loss_summary = tf.summary.scalar('loss',loss)
accuracy_summary = tf.summary.scalar('accuracy',accuracy)

source_image = (x_image + 1) * 127.7 # 逆向归一化过程
inputs_summary = tf.summary.image('inputs_image',source_image)

#使得所有summary聚合计算
merged_summary = tf.summary.merge_all()

#merged_summary_test = tf.summary.merge([loss_summary,accuracy_summary]) 测试集的需要显示出的数据

#指定得到的结果存储的文件夹
LOG_DIR = '.' #指定路径
run_label = 'run_vgg_tensorboard' #指定文件夹名字
run_dir = os.path.join(LOG_DIR,run_label)##路径,文件夹名称
#如果文件夹不存在,就创建
if not os.path.exists(run_dir):
    os.mkdir(run_dir)
train_log_dir = os.path.join(LOG_DIR,'train')
#test_log_dir = os.path.join(LOG_DIR,'test')
if not os.path.exists(train_log_dir):
    os.mkdir(train_log_dir)
# if not os.path.exists(test_log_dir):
#     os.mkdir(test_log_dir)
#初始化变量
init = tf.global_variables_initializer()
batch_size = 20
train_step = 100

output_summary_every_step = 100#每100步输入计算出的图示
#建立会话
with tf.Session() as sess:
    sess.run(init)
    #完成文件的写入
    train_writer = tf.summary.FileWriter(train_log_dir,#路径
                                         sess.graph)#写入的计算图
    #test_writer = tf.summary.FileWriter(test_log_dir,sess.graph)
    
    for i in range(train_step):
        batch_data,batch_labels = train_data.next_batch(batch_size)
        
        eval_ops = [loss,accuracy,train_op]
        should_output_summary = (i%output_summary_every_step == 0)        
        if should_output_summary:
            eval_ops.append(merged_summary)
        eval_ops_results = sess.run(eval_ops,
                                    feed_dict={
                                        x:batch_data,
                                        y:batch_labels})
        loss_val,acc_val = eval_ops_results[0:2]
        if should_output_summary:
            train_summary_str = eval_ops_ results[-1]
            train_writer.add_summary(train_summary_str,i+1)
            
        if (i+1)%50 == 0:
            print('[train]step %d,loss:%4.5f,acc:%4.5f'%(i+1,loss_val,acc_val))

运行最终效果

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值