继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

tensorflow实现AlexNet

烙印99
关注TA
已关注
手记 393
粉丝 92
获赞 446

一、AlexNet网络介绍

AlexNet包含了6亿3000万个连接,6000万个参数和65万个神经元,拥有5个卷积层,其中3个卷积层后面连接了最大池化层,最后有3个全连接层。

二、AlexNet优点

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

2、训练时使用Dropout随机忽略一部分神经元,以避免模型过拟合。

3、在CNN中使用重叠的最大池化。

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

5、数据增强,增大了数据集的量。

三、实现

我们主要建立一个完整的AlexNet卷积神经网络,然后对它的每个batch的forward和backward的速度进行测试。

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

from datetime import datetime
import  math
import  time
import tensorflow as tf

batch_size = 32
num_batches = 100

def print_activations(t):
    print(t.op.name, '', t.get_shape().as_list())

接下来设计AlexNet的网络结构。这个inference函数将会很大,包括多个卷积和池化层。

def inference(images):
    parameters = []
    
    with tf.name_scope('conv1') as scope: #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),
                             trainable=True, name='biases')
        bias = tf.nn.bias_add(conv, biases)
        conv1 = tf.nn.relu(bias, name=scope)
        print_activations(conv1) #将这一层最后输出的tensor conv1的结构打印出来,并将这一层可训练的参数kernel、biases添加到parameters中
        parameters += [kernel, biases]
        
lrn1 = tf.nn.lrn(conv1, 4, bias=1.0, alpah=0.001/9, beta=0.75, name='lrn1')#depth_radius 设为4,
pool1 = tf.nn.max_pool(lrn1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
                               padding='VALID', name='pool1')#VALID为取样时不能超过边框,不像SAME模式那样可以填充边界外的点。
print_activations(pool1)#将输出结果pool1的结构打印出来

#第二层卷积层
    with tf.name_scope('conv2') as scope:  # 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(conv2)
 
lrn2 = tf.nn.lrn(conv2, 4, bias=1.0, alpah=0.001/9, beta=0.75, name='lrn2')#depth_radius 设为4,
pool2 = tf.nn.max_pool(lrn2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
                               padding='VALID', name='pool2')#VALID为取样时不能超过边框,不像SAME模式那样可以填充边界外的点。
print_activations(pool2)#将输出结果pool2的结构打印出来

#第三层
    with tf.name_scope('conv3') as scope:  # scope可以规范化变了名称
        kernel = tf.Variable(tf.truncated_normal([3, 3, 192, 384],
                                             dtype=tf.float32, stddev=1e-1), name='weights')
        conv = tf.nn.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)

#第四层
    with tf.name_scope('conv4') as scope:  # scope可以规范化变了名称
        kernel = tf.Variable(tf.truncated_normal([3, 3, 384, 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)
        conv4 = tf.nn.relu(bias, name=scope)
        parameters += [kernel, biases]
    print_activations(conv4)
    
#第五层
        with tf.name_scope('conv5') as scope:  # 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)
        conv3 = tf.nn.relu(bias, name=scope)
        parameters += [kernel, biases]
        print_activations(conv5)
        
    pool5 = tf.nn.max_pool(conv5, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1],
                            padding='VALID', name='pool5')
    print_activations(pool5)
    return pool5, parameters

接下来实现一个评估AlexNet每轮计算时间的函数time_tensorflow_run。这个函数的第一个输入时tensorflow的session,第二个变了是需要评测的运算算子,第三个是测试的名称。

先定义预热轮数num_steps_burn_in=10,作用时给程序热身,头几轮迭代有显存加载等问题可以跳过。所以我们只需考量10轮迭代之后的计算时间。同时,也记录总时间total_duration和平方和total_duration_squared用来计算方差。

#time_tensorflow_run函数时评估AlexNet每轮计算时间,用来计算某个算子的运行时间
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次迭代后,每10轮迭代显示当前迭代所需要的时间。同时每轮将total_duration和total_duration_squared累加以便后面计算每轮耗时的均值和标准差。

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

    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,最后将结果显示出来。
    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_variables_initializer()初始化所有参数。

接着进行AlexNet的forward计算的评测,这里直接使用time_tensorflow_run统计运行时间,传入的target就是pool5,即卷积网络最后一个池化层的输出。然后进行backward,这里需要给最后的输出pool5设置一个优化目标loss。我们使用tf.nn.l2_loss计算pool5的loss,在使用tf.gradients求相对于loss的所有模型参数的过程。

最后使用time_tensorflow_run统计backward的运算时间,这里的target就是求整个网络梯度gard的操作。

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)
        
        time_tensorflow_run(sess, pool5, "Forward")
        object = tf.nn.l2_loss(pool5)
        grad = tf.gradients(objective, parameters)
        time_tensorflow_run(sess, grad, "Forward-backward")

最后执行主函数

  1. run_benchmark()  

原文出处

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP