Tensorflow 实现经典卷积神经网络AlexNet

AlexNet将CNN的基本原理应用到很深很广的网络中,AlexNet主要使用到的新技术点如下:

(1)成功使用ReLU作为CNN的激活函数,并验证其效果在较深网络中超过了Sigmoid成功解决了Sigmoid在网络较深时的梯度弥散问题。

(2)训练时使用Dropout随机忽略一部分神经元,以避免模型过拟合。在AlexNet中主要是最后几个全连接层使用了Dropout。

(3)在CNN中使用重叠的最大池化。此前CNN中普遍使用平均池化,ALexNet全部使用最大池化,避免平均池化的模糊化效果。并且AlexNet中提出让步长比池化核的尺寸小,这样池化层的输出之间会用重叠和覆盖,提升了模型的泛化能力。

(4)提出了LRN层,对局部神经元的活动创建竞争机制,使得其中响应比较大的值变得相对更大,并抑制其他反馈较小的神经元,增强了模型的泛化能力。

(5)使用CUDA加速深度卷积网络的训练,利用GPU强大的并行计算能力,处理神经网络训练时大量的矩阵运算。

(6)数据增强,随机地从256x256的原始图像中截取224x224大小的区域(以及水平翻转的镜像),相当于增加了(256-224)^2*2=2048倍的数据量。使用了数据增强后可以大大减轻过拟合,提升泛化能力。

整个AlexNet有8个需要训练参数的层(不包括池化层和LRN层),前5层为卷积层,后3层为全连接层。AlexNet最后一层是有1000类输出的Softmax层用作分类。LRN层出现在第一个及第二个卷积层后,而最大池化层出现在两个LRN层及最后一个卷积层后。Relu激活函数则应用再这8层每一层的后面。

我们建立一个完整的AlexNet卷积神经网络,然后对它每个batch的前馈计算和反馈计算的速度3进行测试。

首先导入几个接下来会用到的几个系统库,包括datetime,math和time,并载入Tensorflow。

from datetime import datetime

import math

import time

import tensorflow as tf

这里设置batch_size为32,num_batches为100,即总共测试100个batch的数据。

batch_size=32

num_batches=100

定义一个用来显示网络每一层结构的函数print_actications,展示每一个卷积层或池化层输出tensor的尺寸。这个函数接受一个tensor作为输入,并显示其名称和尺寸。

def print_activations(t):

    print t.op.name,'',t.get_shape().as_list()

接下来设计AlexNet的网络结构。我们先定义函数inference,它接受images作为输入,返回最后一层pool5(第5个池化层)及parameters(AlexNet中所有需要训练的模型参数)。这个inference函数将会很大,包括多个卷积和池化层。下面将拆为几个小段分别讲解:

首先是第一个卷积层conv1,这里使用Tensorflow中的name_scope,通过with tf.name_scope('conv1') as scope可以将scope内生成的Variable自动命名为conv1/xxx,便于区分不同卷积层之间的组件,然后定义第一个卷积层,和之前一样使用tf.truncated_normal阶段的正态分布函数(标准差为0.1)初始化卷积核的参数为kernel。卷积核尺寸为11x11,颜色通道为3,卷积核数量为64.准备好了kernel,再使用tf.nn.conv2d对输入images完成卷积操作,我们将strides步长设置为4x4(即在图片上每4x4区域只取样一次,横向间隔是4,纵向间隔也为4,每次取样的卷积核大小都为11X11),padding模式设为SAME。将卷积层的biases全部初始化为0,再使用tf.nn.bias_add将conv和biases加起来,并使用激活函数tf.nn.relu对结果进行非线性处理。最后砽print_activations将这一层最后输出的tensor conv1的结构打印出来,并将这一层可训练的参数kernel,biases添加到parameters中。

def inference(images):

        parameters=[]

        with tf.name_scope('conv1') as scope:

                kernel=tf.Variable(tf.truncated_normal([11,11,3,64],dtype=tf.float32,stddev=1e-1),name='weights')

                conv=tf.nn.conv2d(images,kernel,[1,4,4,1],padding='SAME')

                biases=tf.Variable(tf.constant(0.0,shape=[64],dtype=tf.float32),trianable=True,name='biases')

                bias=tf.nn.bias_add(conv,biases)

                conv1=tf.nn.relu(bias,name=scope)

                print_activations(conv1)

                parameters+=[kernel,biases]

在第一个卷积层后再添加LRN层和最大池化层。先使用tf.nn.lrn对前面输出的tensor conv1 进行lrn处理,这里使用的depth_radius 设为4,bias设为1,alpha为0.001/9,beta为0.75,基本都是AlexNet论文中的推荐值。不过目前除了AlexNet,其他景点的卷积神经网络模型基本都放弃了LRN(主要是效果不明显),而我们使用LRN也会让前馈、反馈的速度大大下降(整体速度下降1/3)。使用tf.nn.max_pool对前面的输出lrn1进行最大池化处理,这里的池化尺寸为3x3,即将3x3大小的像素块降为1x1的像素,取样的步长为2x2,padding模式设为VALID,即取样时不能超过边框,不像SAME模式那样可以填充边界外的点。最后将输出结果pool1的结构打印出来。

lrn1=tf.nn.lrn(conv1,4,bias=1.0,alpha=0.001/9,beta=0.75,name='lrn1')

pool1=tf.nn.max_pool(lrn1,ksize=[1,3,3,1],strides=[1,2,2,1],padding='VALID',name='pool1')

print_activations(pool1)

接下是第二个卷积层,大部分步骤和第一个卷积层相同,只有几个参数不同。主要区别在与我们的卷积和尺寸是5x5,输入通道数(即上一层输出通道数,也就是上一层卷积核数量)为64,卷积核数量为192.同时,卷积的步长也全部设为1,即扫描全图像素。

      with tf.name_scope('conv2') as scope:

                kernel=tf.Variable(tf.truncated_normal([5,5,64,192],dtype=tf.float32,stddev=1e-1),name='weights')

                conv=tf.nn.conv2d(pool1,kernel,[1,1,1,1],padding='SAME')

                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)

                parameters+=[kernel,biases]

        print_activations(pool2)

接下来对第2个卷积层的输出conv2进行处理,同样是先做LRN处理,再进行最大池化处理,参数和之前完全一样。

lrn2=tf.nn.lrn(conv2,4,bias=1.0,alpha=0.001/9,beta=0.75,name='lrn2')

pool2=tf.nn.max_pool(lrn2,ksize=[1,3,3,1],strides=[1,2,2,1],padding='VALID',name='pool2')

print_activations(pool2)

下面是创建第3个卷积层,基本结构和前面两个类似,也只是参数不同。这一层的卷积核尺寸为3X3,输入通道数为192,卷积核数量继续扩大为384,同时卷积的步长全部为1,其他地方和前面保持一致。

      with tf.name_scope('conv3') as scope:

                kernel=tf.Variable(tf.truncated_normal([3,3,192,384],dtype=tf.float32,stddev=1e-1),name='weights')

                conv=tf.conv2d(pool2,kernel,[1,1,1,1],padding='SAME')

                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)

                parameters+=[kernel,biases]

        print_activations(conv3)

第4个卷积层和之前也类似,这一层的卷积核尺寸为3x3,输入通道数为384,但是卷积核数量降为256.

with tf.name_scope('conv4') as scope:

                kernel=tf.Variable(tf.truncated_normal([3,3,256,256],dtype=tf.float32,stddev=1e-1),name='weights')

                conv=tf.nn.conv2d(conv3,kernel,[1,1,1,1],padding='SAME')

                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)

                parameters+=[kernel,biases]

        print_activations(conv4)

最后的第5个卷积层同样是3X3大小的卷积核,输入通道数为256,卷积核数量也为256

  with tf.name_scope('conv5') as scope:

                kernel=tf.Variable(tf.truncated_normal([3,3,256,256],dtype=tf.float32,stddev=1e-1),name='weights)

                conv=tf.nn.conv2d(conv4,kernel,[1,1,1,1],padding='SAME')

                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)

                parameters+=[kernel,biases]

        print_activations(conv5)

在第5个卷积层之后,还有一个最大池化层,这个池化层和前两个卷积层后的池化层一致,最后我们返回这个池化层的输出pool5.至此,inference函数就完成了,它可以创建AlexNet的卷积部分。在正式使用AlexNet来训练或预测时,还需要添加3个全连接层,隐含节点数分别为4096,4096和1000。

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

print_activations(pool5)

return pool,parameters

全连接层大致如下:

reshape=tf.reshape(pool2,[batch_size,-1])

dim=reshape.get_shape()[1].value

weight=variable_with_weight_loss(shape=[dim,384],stddev=0.04,wl=0.004)

bias=tf.Variable(tf.constant(0.1,shape=[384]))

local=tf.nn.relu(tf.matmul(reshape,weight3)+bias)

下面还有2个全连接层,与上类似,这里不再赘述。

接下来实现一个品谷AlexNet每轮计算时间的函数time_tensorflow_run。这个函数的第一个输入就是tensorflow的SESSION,第二个变量是需要评测的运算算子,第三个变量是测试的名称。先定义预热轮数num_steps_burn_in=10,它的作用是给程序热身,头几轮迭代有现存加载、cache命中等问题一次可以跳过,我们只考量10轮迭代之后的计算时间。同时,也记录总时间total_duration和平方和total_duration_squared用以计算方差。

def time_tensorflow_run(session,target,info_string):

    num_steps_burn_in=10

    total_duration=0.0

    total_duration_squared=0.0

进行num_batches+num_steps_burn_in次迭代计算,使用time.time()记录时间,每次迭代通过session.run(target)执行。在初始热身的Num_steps_burn_in次迭代后,每次迭代显示迭代所需要的时间。同时每轮将total_duration和平方和total_duration_squared累加以便后面计算每轮耗时的均值和标准差。

for i in range(num_batches+num_steps_burn_in):

start_time=time.time()

_=session.run(target)

duration=time.time()-start_time

if i>=num_steps_burn_in:

  if not i%10:

    print '%s:step %d,duration=%.3f' % (datetime.now(),i-num_steps_burn_in,duration))

  total_duration+=duration

  total_duration_squared+=duration*duration

在循环结束后,计算每轮迭代的平均耗时mn和标准差sd,最后将结果显示出来,这样就完成了计算每轮迭代耗时的评测函数time_tensorflow_run。

mn=total_duration/num_batches

vr=total_duration_squared/num_batches-mn*mn

sd=math.sqrt(vr)

print '%s:%s across %d steps,%.3f +/- %.3f sec / batch' % (datetime.now(),info_string,num_batches,mn,sd)

接下来是主函数run_benchmark.首先使用with tf.Graph().as_default()定义默认的Graph方便后面使用。我们使用tf.random_normal函数构造正态分布(标准差为0.1)的随机tensor,第一个维度是batch_size,即每轮迭代的样本数,第二个和第三个维度是图片的查询image_size=224,第四个维度是图片的颜色通道数。接下来,使用前面定义的inference函数侯建整个AlexNet网络,得到最后一个池化层的输出pool5和网络中需要训练的参数的几何parameters、接下来我们使用tf.Session()创建新的Session并通过tf.global_variable_initializer()初始化所有参数。

def run_benchmark():

with tf.Graph().as_default():

  image_size=224

  images=tf.Variable(tf.random_normal([batch_size,image_size,image_size,3],dtype=tf.float32,stddev=1e-1))

  pool5,parameters=inference(images)

  init=tf.global_variables_initializer()

  sess=tf.Session()

  sess.run(init)

下面进行AlexNet的forward计算的评测,这里直接使用time_tensorflow_run统计运算时间,传入的target就是pool5,即卷积网络最后一个池化层的输出。然后进行backward,即训练过程的评测,这里和forward计算有些不同,我们需要给最后的pool5设置一个优化目标loss。使用tf.nn.l2_loss计算pool5的loss,再使用tf.gradients求相对于loss的所有模型参数的梯度,这样就模拟了一个训练的过程。当然,训练时还有一个根据梯度更新参数的过程,最后我们使用time_tensorflow_run统计backward的运算时间,这里的target就是求整个网络梯度gard的操作。

time_tensorflow_run(sess,pool5,'Forward")

objective=tf.nn.l2_loss(pool5)

grad=tf.gradients(objective,parameters)

time_tensorflow_run(sess,grad,"Forward-backward")

最后执行主函数

run_benchmark()

---------------------

作者:河南骏

来源:CSDN

原文:https://blog.csdn.net/Eason_oracle/article/details/79013385

版权声明:本文为博主原创文章,转载请附上博文链接!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容