教你用TensorFlow搭建AlexNet

版权声明:很高兴认识你,我叫邵龙飞 原创文章,转载请注明 https://blog.csdn.net/qq_37482202/article/details/84966723

勿满足于眼前的小小成就。你要问自己,我这辈子只有这样吗。

AlexNet模式是在2012年提出来的,并且在当年获得了ILSVRC的冠军,top-5的错误率为16.4%,比第二名的成绩26.2%高出许多,也从此开始确立了深度学习在计算机视觉的统治地位,是一块重要的里程碑。

该模型包含了几个比较新的技术点:

  1. 成功使用ReLu作为CNN的激活函数,验证了其效果在较深网络中比Sigmoid更好
  2. 成功应用Dropout,验证了其在实际中的效果
  3. 在CNN中使用重叠的最大池化,打破了之前普遍使用平均池化的模式,AlexNet全部使用最大池化,避免平均池化的模糊化效果,并提出了让步长比池化核尺寸小一些可以提升特征的丰富性
  4. 提出了LRN层,对局部神经元的活动创建竞争机制,使其中响应大的更大,小的更小,增强了模型的泛化能力
  5. 使用CUDA加速深度卷积网络的训练
  6. 使用了数据增强,使用了PCA

接下来将会使用TensorFlow搭建AlexNet,使用的数据为随机图片数据,如果你有兴趣可以自行下载ImageNet的数据进行训练兵测试

首先导入常用库并定义batch_size,num_batches

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())

定义一个函数inference,接受images为参数,返回第五个池化层和所有需要训练的模型参数

首先定义第一个卷积层,使用tf.truncated_normal截断的正太分布函数初始化卷积核的参数kernel,卷积核的尺寸为11X11,颜色通道为3,卷积核的数量为64。使用tf.nn.conv2d对输入的images进行卷积操作,将strides步长设置为4X4,padding模式设置为SAME,将卷积核的biases全部初始化为0,再使用tf.nn.bias_ass将conv和biases加起来,并使用激活函数tf.nn.relu对结果进行非线性处理,最后使用开始定义的print_activations将结构打印出来,将可训练的参数添加到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), trainable=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进行LRN处理,将depth_radius设为4,bias设为1,alpha设为0.001/9,beta设为0.75。对前面的输出进行最大池化,池化尺寸为3X3,padding模式设为VALID。

    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)

定义后面的卷积层和池化层,步骤大体和前面相似,最后返回第五层池化和需要训练的参数,正式使用时需要自行添加3个全连接层。

    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(conv2)

    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)

    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.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:
        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:
        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)

    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_strps_burn_in的作用是给程序热身,前几轮迭代有显存加载、cache命中等因素所以跳过。循环结束后计算每轮迭代的平均耗时和标准差,打印输出。

def time_tensorflow_run(session, target, info_string):
    num_steps_burn_in = 10
    total_duration = 0.0
    total_duration_squard = 0.0

    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(),1-num_steps_burn_in,duration))
               total_duration+=duration
               total_duration_squard+=duration*duration

    mn=total_duration/num_batches
    vr=total_duration_squard/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))

定义主函数,首先使用with.Graph().as_default()定义默认的Graph方便后面使用,使用tf.random_normal函数构造正态分布的随机tensor代替输入的图片数据,使用之前定义的inference构建整个AlexNet网络,使用tf.Session()创建新的Session并初始化所有参数。然后进行forword计算的评测,使用tf.nn.l2_loss计算pool5d的loss,再使用tf.gardients求相对于loss的所有模型参数的梯度。

最后运行主函数。

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

run_benchmark()

运行程序会首先打印出AlexNet的网络结构,然后会打印出每轮的迭代时间消耗

conv1   [32, 56, 56, 64]
pool1   [32, 27, 27, 64]
conv2   [32, 27, 27, 192]
pool2   [32, 13, 13, 192]
conv3   [32, 13, 13, 384]
conv4   [32, 13, 13, 256]
conv5   [32, 13, 13, 256]
pool5   [32, 6, 6, 256]
2018-12-12 14:08:11.891345:step -9,duration=0.525
2018-12-12 14:08:16.898325:step -9,duration=0.501
2018-12-12 14:08:21.928768:step -9,duration=0.508

猜你喜欢

转载自blog.csdn.net/qq_37482202/article/details/84966723