前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >4. 经典卷积网络之AlexNet

4. 经典卷积网络之AlexNet

作者头像
和蔼的zhxing
发布2018-09-04 11:16:45
1K0
发布2018-09-04 11:16:45
举报

原文:《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:这个可以翻译做:随机失活,用的比较多,可以考虑在训练的时候使用这个,能够有效减少过拟合。

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

代码语言:javascript
复制
#实现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()
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.05.22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • overlap pooling
  • 减少过拟合
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档