tensorflow 实现AlexNet(附lrn API介绍)

2012年,ALex提出了深度卷积网络模型AlexNet。AlexNet中包含了几个比较新的技术点,也首次在CNN中应用了RELU、Dropout、LRN等tricks。

在AlexNet中包含了5个卷积层,其中3个卷积层后面连接了maxpool层,最后还有三个全连接层。

AlexNet将LeNet的思想发扬光大,将CNN基本原理应用到了很深的网络中,其主要用到的创新点有

(1) 使用RELU作为激活函数,解决了在网络深度过深时的梯度消失问题

(2)训练时使用Dropout随机忽略一部分神经元,以免发生过拟合。在ALexNet中最后几个全连接层使用了Dropout。

(3)在CNN中使用最大池化层。使用最大池化层避免了平均池化的的模糊化效果。

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

(5)数据增强。使用了数据增强增加了样本数,大大减轻了过拟合,提高了模型泛化能力。

架构

一共需要训练参数的层有8层(不包括池化层和LRN层),前5层为卷积层,后3层为全连接层。最后一层为1000类输出的softmax层用作分类。

LRN层出现在第1和第2卷积层后,而最大池化层出现在两个LRN层及最后一个卷积层。

输入为224*224的图片大小,第一个卷积层使用较大的 11*11的卷积核,步长为4,有96个卷积核,之后为LRN层,然后是一个3*3的最大池化层,步长为2。之后的卷积核尺寸都较小,都是5*5或3*3的,且步长都为1,用来扫描所有像素。

# 首先导入需要的库
import tensorflow as tf
import math
import time
from datetime import datetime
batch_size = 32
num_batches = 100 # 总共测试多少个batch,这可以有原始数据计算而来,我们这里手动设置一个。
def inference(images):
    # images: 输入
    parameters = [] # 存放需要训练的参数
    with tf.name_scope('conv1') as scope:
        # 使用name_scope来对变量进行管理,用来区分不同卷机层之间的组件
        # conv1/xxx       
        kernel = tf.Variable(tf.truncated_normal([11, 11, 3, 96], dtype=tf.float32, stddev=0.1), name='weights') 
        # 初始化参数大小: [卷积核宽,卷积核高,卷积核channel,个数]
        # 卷积
        conv = tf.nn.conv2d(images, kernel, [1,4,4,1], padding="SAME") #  [1,4,4,1]为stride,“SAME”:输出大小计算方式为 (W-F)/S  + 1 
        biases = tf.Variable(tf.constant(0.0, shape=[96], dtype=tf.float32), trainable=True, name='biases') # 设置为可训练参数(默认就为True)
        # 加偏置
        bias = tf.nn.bias_add(conv, biases)
        conv1 = tf.nn.relu(bias, name=scope) # scope 是默认的conv1
        parameters += [kernel, biases] # 将可训练的参数放入到parameters中

        # 在第一个卷积层后放入LRN层和maxpool
        lrn1 = tf.nn.lrn(conv1, depth_radius=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") # 池化层,

    with tf.name_scope('conv2') as scope:
        kernel = tf.Variable(tf.truncated_normal([5,5,96, 256], dtype=tf.float32, stddev=0.1), name='weights')
        conv = tf.nn.conv2d(pool1, 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)
        conv2 = tf.nn.relu(bias, name=scope)
        parameters += [kernel, biases]
        lrn2 = tf.nn.lrn(conv2,  depth_radius=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")

    with tf.name_scope('conv3') as scope: # 该层后面没有lrn层和池化层
        kernel = tf.Variable(tf.truncated_normal([5,5,256, 384], dtype=tf.float32, stddev=0.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]

    with tf.name_scope('conv4') as scope: # 该层后面没有lrn层和池化层
        kernel = tf.Variable(tf.truncated_normal([5,5,384, 384], dtype=tf.float32, stddev=0.1), name='weights')
        conv = tf.nn.conv2d(conv3, 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)
        conv4 = tf.nn.relu(bias, name=scope)
        parameters += [kernel, biases]

    with tf.name_scope('conv5') as scope: # 该层后有一个池化层
        kernel = tf.Variable(tf.truncated_normal([5,5,384, 256], dtype=tf.float32, stddev=0.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]
        pool5 = tf.nn.max_pool(conv5, ksize=[1,3,3,1], strides=[1,2,2,1],padding='VALID', name='pool5')
        # 后面还有三个全连接层,
        # 先拉成一行,然后在继续全连接
        # pool_shape = pool5.get_shape().as_list  # [batch_size, 长,宽,channel]
        # nodes = pool_shape[1] * pool_shape[2] * pool_shape[3] # 为全连接层的输入节点
        # reshaped = tf.reshape(pool5, [pool_shape[0], nodes])
        return pool5, parameters
# 定义一个函数用来评估每轮的计算时间
def time_tensorflow_run(sess, target, info_string):
    # target 要计算时间的操作op
    # info_string 描述
    total_duration = 0.0 # 总时间
    total_duration_squared = 0.0 # 总时间平方和

    for i in range(num_batches):
        start_time = time.time()
        _ = sess.run(target)
        duration = time.time() - start_time
        if i % 10 == 0:
            print("%s, step: %d, duration = %.3f " % (datetime.now(), i, duration))
            total_duration += duration
            total_duration_squared += duration ** 2
    mn = total_duration / num_batches # 运行时间均值 
    vr = total_duration_squared / num_batches - mn ** 2 # 运行时间方差 E((x-mean(x))^2)  = E(x^2) - (Ex)^2
    std = math.sqrt(vr)
    print("%s: %s across %d steps, %.3f +/- %.3f sec/batch" % (datetime.now(), info_string, num_batches, mn, std))
# 主函数
# 这里比较简单,没有设置损失函数等用来计算loss的一些设置,在用自己的数据是需要设置loss, 最优化等op,然后去训练。
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=0.1)) # 这里可以换成自己的图像数据但是要注意输入格式
        pool5, parameters = inference(images)
        init = tf.global_variables_initializer()
        with tf.Session() as sess:
            sess.run(init)
            time_tensorflow_run(sess, pool5, "Forward")
run_benchmark()
2017-10-20 10:18:04.263110, step: 0, duration = 4.157 

这里写图片描述

LRN可以完成一种“邻近抑制”的操作,对局部输入区进行归一化、

norm = tf.nn.lrn(input, depth_radius. bias, alpha, beta,name)

参数:
input: a tensor
depth_raidus: 归一化窗口的一半(半径)
bias: (k)防止分母为0
alpha,beta参数

猜你喜欢

转载自blog.csdn.net/ifruoxi/article/details/78292572