4. 经典卷积网络之AlexNet

原文:《ImageNet Classification with Deep Convolutional Neural Networks》 我没有读原文,这个已经很老的文章了,分类领域应用CNN的经典文章。 先看结构:

AlexNet

咋一看像是两个网络,实际上并不是这样,文章中是用两个GPU来训练的,所以华城这样了,实际上就是一系列卷积池化和全连接层构成的,具体的网络结构列表:

这是个参数列表,实际训练或者检测的时候是从下往上走的,显示11-11的卷积层。 有几个点要说一下:

前面的两个大卷积使用了一个叫做LRN(local response nornalization)的方法进行局部标准化,一般来说Relu激活函数是不需要对输入进行标准化的,但是实验之后确实发现使用这种方法可以提高性能,在这之后LRN用的就很少了,基本上被BN替代掉。

overlap pooling

带overlap的pooling就是说pooling的模板核的大小要大于移动的步长,这样的话就会出现重叠,一般而言pooling是不带overlap的。

减少过拟合

  1. 数据增强:对图片进行变换可以增大数据集,第一种方法就是原图大小是256-256,在图片上随机选取224-224的小块进行训练,还可以对这些块进行水平翻转进一步增强数据量。
  2. dropout:这个可以翻译做:随机失活,用的比较多,可以考虑在训练的时候使用这个,能够有效减少过拟合。

其他的就没有什么说的了,比较简单,这个框架基本可以不用修改可以用到一些典型的图像分类任务之中,并且可以得到比较好的性能。 贴一下代码,写了详细的注释:

#实现AlexNet,基本是按照tensorflow那本书来写的,然后我加详细的注释。


#导入库文件
from datetime import datetime
import math
import time
import tensorflow as tf

#batch和num_batch设置
batch_size=32
batch_num=100

#定义一个函数,输出每一层的结构 t是一个tensor,作为输入
def print_activations(t):
    print(t.op.name,'',t.get_shape().as_list)


'''
接下来是设计AlexNet的结构,我们定义一个函数(inferen),接受image作为输入,
返回最后一层pool(第五个池化层),以及所有需要训练的模型参数,这个函数比较大,
包括多个卷积层和池化层。每一层我们利用name_scope命名。
'''
def inference(image):
    parameters=[]     #存参数

    #第一层,11*11*3的卷积核,一共有64个,原文是96个,
    with tf.name_scope('conv1') as scope:
        kernel=tf.Variable(tf.truncated_normal([11,11,3,64],dtype=tf.float32,stddev=0.1),name='weights')
        conv=tf.nn.conv2d(image,kernel,[1,4,4,1],padding='SAME')   #四个维度上的步长,分别是batch_num,height,width,纵向一般为1
        biases=tf.Variable(tf.constant(0.0,shape=[64],dtype=tf.float32),trainable=True,name='biases')
        bias=tf.nn.bias_add(conv,biases)
        conv1=tf.nn.relu(bias,name=scope)
        print_activations(conv1)            #打印tensor参数
        parameters+=[kernel,biases]         #参数存储

    lrn1=tf.nn.lrn(conv1,bias=1.0,alpha=0.001/9,beta=0.75,name='lrn1')   #local response normalization--局部响应标准化
    pool1=tf.nn.max_pool(lrn1,ksize=[1,3,3,1],strides=[1,2,2,1],padding='VALID',name='pool1')
    print_activations(pool1)
    #最大值pool,池化核3*3,池化步长2*2



    #第二层和第一层基本一样,不同的是卷积核和步长设置
    with tf.name_scope('conv2') as scope:
        kernel=tf.Variable(tf.truncated_normal([5,5,64,192],dtype=tf.float32,stddev=0.1),name='weights')
        conv=tf.nn.conv2d(pool1,kernel,[1,1,1,1],padding='SAME')   #四个维度上的步长,分别是batch_num,height,width,纵向一般为1
        biases=tf.Variable(tf.constant(0.0,shape=[192],dtype=tf.float32),trainable=True,name='biases')
        bias=tf.nn.bias_add(conv,biases)
        conv2=tf.nn.relu(bias,name=scope)
        print_activations(conv2)            #打印tensor参数
        parameters+=[kernel,biases]

    lrn2 = tf.nn.lrn(conv2, bias=1.0, alpha=0.001 / 9, beta=0.75, name='lrn2')  # local response normalization--局部响应标准化
    pool2 = tf.nn.max_pool(lrn2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name='pool1')
    print_activations(pool2)

    with tf.name_scope('conv3') as scope:
        kernel=tf.Variable(tf.truncated_normal([3,3,192,384],dtype=tf.float32,stddev=0.1),name='weights')
        conv=tf.nn.conv2d(pool2,kernel,[1,1,1,1],padding='SAME')   #四个维度上的步长,分别是batch_num,height,width,纵向一般为1
        biases=tf.Variable(tf.constant(0.0,shape=[384],dtype=tf.float32),trainable=True,name='biases')
        bias=tf.nn.bias_add(conv,biases)
        conv3=tf.nn.relu(bias,name=scope)
        print_activations(conv3)            #打印tensor参数
        parameters+=[kernel,biases]

    with tf.name_scope('conv4') as scope:
        kernel=tf.Variable(tf.truncated_normal([3,3,384,256],dtype=tf.float32,stddev=0.1),name='weights')
        conv=tf.nn.conv2d(conv3,kernel,[1,1,1,1],padding='SAME')   #四个维度上的步长,分别是batch_num,height,width,纵向一般为1
        biases=tf.Variable(tf.constant(0.0,shape=[256],dtype=tf.float32),trainable=True,name='biases')
        bias=tf.nn.bias_add(conv,biases)
        conv4=tf.nn.relu(bias,name=scope)
        print_activations(conv4)            #打印tensor参数
        parameters+=[kernel,biases]

    with tf.name_scope('conv2') as scope:
        kernel=tf.Variable(tf.truncated_normal([3,3,256,256],dtype=tf.float32,stddev=0.1),name='weights')
        conv=tf.nn.conv2d(conv4,kernel,[1,1,1,1],padding='SAME')   #四个维度上的步长,分别是batch_num,height,width,纵向一般为1
        biases=tf.Variable(tf.constant(0.0,shape=[256],dtype=tf.float32),trainable=True,name='biases')
        bias=tf.nn.bias_add(conv,biases)
        conv5=tf.nn.relu(bias,name=scope)
        print_activations(conv5)            #打印tensor参数
        parameters+=[kernel,biases]

    pool5=tf.nn.max_pool(conv5,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME',name='pool5')

    print_activations(pool5)

    return pool5,parameters



#三个全链接层,4096-4096-1000,接受一个pool层,返回1*1000个向量(评分)

def FC(pool,parameters):    #全连接层函数,接受卷积层最后池化输出的tensor
    with tf.name_scope('FC'):
        with tf.name_scope('FC1'):
            pool_x=tf.reshape(pool,[-1,7*7*256])
            W_FC1=tf.Variable(tf.truncated_normal([7*7*256,4096],dtype=tf.float32,stddev=0.1),name='W_FC1')
            b_1=tf.Variable(tf.constant(0.01,shape=[4096]),dtype=tf.float32,trainable=True,name='b_1')
            FC1=tf.nn.relu(tf.matmul(pool_x,W_FC1)+b_1)
            parameters+=[W_FC1,b_1]
            print_activations(FC1)

        with tf.name_scope('FC2'):
            W_FC2=tf.Variable(tf.truncated_normal([4096,4096],dtype=tf.float32,stddev=0.1,name='W_FC2'))
            b_2=tf.Variable(tf.constant(0.01,shape=[4096]),dtype=tf.float32,trainable=True,name='b_2')
            FC2=tf.nn.relu(tf.matmul(FC1,W_FC2)+b_2)
            parameters += [W_FC2, b_2]
            print_activations(FC2)

        with tf.name_scope('FC3'):
            W_FC3=tf.Variable(tf.truncated_normal([4096,1000],dtype=tf.float32,stddev=0.1,name='W_FC3'))
            b_3=tf.Variable(tf.constant(0.01,shape=[1000]),dtype=tf.float32,trainable=True,name='b_2')
            FC3=tf.nn.relu(tf.matmul(FC2,W_FC3)+b_3)
            parameters += [W_FC3, b_3]
            print_activations(FC3)

    return FC3,parameters



'''
session 是tensorflow的session,第二个参数是需要评测的运算算子,第三个变量是测试的名称
我们通过batch_num+num_step_burn_in来计算次数,使用time.time()来计算时间,每轮Session.run(target
来执行,初始热身的num_step_burn_in次迭代后,每十轮显示当前迭代所需要的时间,同时每轮将total_duration
和total_duration_squared累加,以便后面计算每轮平均耗时和耗时标准差。
'''
def time_tensorflow_run(session,target,info_string):
    num_step_burn_in=10
    total_duration=0.0
    total_duration_squared=0.1
    for i in range(batch_num+num_step_burn_in):
        start_time=time.time()
        _=session.run(target)
        duration=time.time()-start_time
        if(i>=num_step_burn_in):
            if not i%10:          #每十个显示一次
                print('%s:step %d, duration=%.3f' %(datetime.now(),i-num_step_burn_in,duration))
            total_duration+=duration
            total_duration_squared+=duration*duration
    mn=total_duration/batch_num      #平均时间
    vr=total_duration_squared/batch_num-mn*mn        #计算方差
    sd=math.sqrt(vr)         #计算标准差
        #print('sd:'+str(sd))
        #print(sd)

    print(str(datetime.now())+'\t'+info_string+'\t'+'\t:'+'Ave_time:'+str(mn)+'\tsd:\t'+str(sd))

'''
接下来我们定义主函数 run_benchmark,首先我们使用 with tf.Graph.as_default()来定义默认的Graph来方便后面使用,
首先我们先不使用ImageNet来进行训练,只是测试其前馈和反馈的耗时,我们使用tf.randon_normal来随机生成一些图像数据,
然后使用前面的inference和FC函数来构建整个AlexNet网络,得到一个输出层和两个参数(卷积参数和全脸阶层参数),接下来
我们利用tf.sesion()来创建新的session并初始化所有参数。
'''

def run_benchmark():
    with tf.Graph().as_default():
        image_size=224
        images=tf.Variable(tf.random_normal(
                                            [batch_size,
                                            image_size,
                                            image_size,
                                            3],               #batch_sz和图像大小224*224*3
                                            dtype=tf.float32,
                                            stddev=1e-1
                                            ))
        pool5,parameters=inference(images)
        FC3,parameters=FC(pool5,parameters)
        init=tf.global_variables_initializer()
        sess=tf.Session()
        sess.run(init)
        '''
        下面是会模型的评测,直接使用time_tensorflow_run来统计运行时间,传入的target是FC3,即全连接的最后一个输出层,然后进行反馈
        即训练过程的评测,和前馈不同的是我们需要给最后的输出设置一个loss,一般的loss需要用到数据损失和模型损失,我们这里不传入labels,所以
        只计算模型损失,使用L2来计算,
        '''
        time_tensorflow_run(sess,FC3,'forward')
        objecttive=tf.nn.l2_loss(FC3)
        grad=tf.gradients(objecttive,parameters)
        time_tensorflow_run(sess,grad,'forward-backward')

run_benchmark()

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏CSDN技术头条

详解 BP 神经网络基本原理及 C 语言实现

BP(Back Propagation)即反向传播,指的是一种按照误差反向传播来训练神经网络的方法。而 BP 神经网络即为一种按照误差反向传播的方法训练的神经网...

4894
来自专栏Small Code

【TensorFlow】TensorFlow 的卷积神经网络 CNN - 无TensorBoard版

前面 有篇博文讲了多层感知器,也就是一般的前馈神经网络,文章里使用 CIFAR10 数据集得到的测试准确率是 46.98%。今天我们使用更适合处理图像的卷积神经...

2897
来自专栏邹成卓的专栏

三维变换矩阵的理解

3D空间中的一个点的坐标,可以用(x,y,z)来表示。对这个点的坐标变换有三种操作:缩放、平移、旋转。

2K2
来自专栏机器学习原理

深度学习——LeNetLeNet解析

2074
来自专栏数据结构与算法

概率论中几个入门公式

临时整理一下,以后会慢慢补 独立 独立:对于事件$A$和$B$,如果$P(AB)$=$P(A)P(B)$,那么称$A$和$B$是独立的。 所谓独立,即两事件的结...

3176
来自专栏Python小屋

Python扩展库scipy.misc中图像转换成pillow图像

众所周知,在数字图像处理领域中有很多基准测试图像,这些图像用来作为科研人员PK自己的算法时的参考,给大家提供一个公平的样本,针对同一个问题进行处理时,可以用这些...

3245
来自专栏机器之心

资源 | GitHub新项目:轻松使用多种预训练卷积网络抽取图像特征

选自GitHub 机器之心整理 参与:思源 最近 GitHub 有一个非常有意思的项目,它可以使用多种预训练 TensorFLow 模型计算图像特征。对于每一个...

3286
来自专栏机器之心

教程 | 使用Keras实现多输出分类:用单个模型同时执行两个独立分类任务

之前我们介绍了使用 Keras 和深度学习的多标签分类(multi-label classification),参阅 https://goo.gl/e8RXtV...

6902
来自专栏和蔼的张星的图像处理专栏

7.SSD目标检测之一:运行SSD模型

需要在跟踪模型的前面把检测模型加进去,传统使用一些背景建模和轨迹建模的方式来做,对于动摄像头以及复杂背景的适应性都比较差,所以考虑用深度学习的方法来做。我以前也...

3292
来自专栏宏伦工作室

动手实现notMNIST数据集图片分类

2053

扫码关注云+社区

领取腾讯云代金券