Tensorflow--alexNet 手写数字识别

网络结构

layer1:conv+relu+maxpooling+lrn(针对channel)

layer2:conv+relu+maxpooling+lrn(针对channel)

layer3:conv+relu+maxpooling+lrn(针对channel)

layer4:conv+relu

layer5:conv+relu+maxpooling+lrn

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

layer6: FC+relu_dropout

layer7:FC+relu_dropout

out: FC+softmax

print('设定占位符')
x=tf.placeholder(tf.float32,[None,n_input])
y=tf.placeholder(tf.float32,[None,n_classes])
keep_prob=tf.placeholder(tf.float32)

print('定义网络的权重和偏置参数')
weights={
    'wc1':tf.Variable(tf.random_normal([11,11,1,96])),
    'wc2':tf.Variable(tf.random_normal([5,5,96,256])),
    'wc3':tf.Variable(tf.random_normal([3,3,256,384])),
    'wc4':tf.Variable(tf.random_normal([3,3,384,384])),
    'wc5':tf.Variable(tf.random_normal([3,3,384,256])),
    'wd1':tf.Variable(tf.random_normal([2*2*256,4096])),
    'wd2':tf.Variable(tf.random_normal([4096,4096])),
    'out':tf.Variable(tf.random_normal([4096,n_classes]))
}
biases={
    'bc1':tf.Variable(tf.random_normal([96])),
    'bc2':tf.Variable(tf.random_normal([256])),
    'bc3':tf.Variable(tf.random_normal([384])),
    'bc4':tf.Variable(tf.random_normal([384])),
    'bc5':tf.Variable(tf.random_normal([256])),
    'bd1':tf.Variable(tf.random_normal([4096])),
    'bd2':tf.Variable(tf.random_normal([4096])),
    'out':tf.Variable(tf.random_normal([n_classes]))
}

# -*- coding: utf-8 -*-
"""
Created on Mon Jul  9 09:52:43 2018

@author: 
"""
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import input_data

mnist = input_data.read_data_sets('data/', one_hot=True)
trainimg   = mnist.train.images
trainlabel = mnist.train.labels
testimg    = mnist.test.images
testlabel  = mnist.test.labels
print ("MNIST ready")
#%%
print('定义网络超参数')
learning_rate=.01
training_iters=20000
batch_size=128
display_step=10

n_input=784
n_classes=10
dropout=.75

print('设定占位符')
x=tf.placeholder(tf.float32,[None,n_input])
y=tf.placeholder(tf.float32,[None,n_classes])
keep_prob=tf.placeholder(tf.float32)

print('定义网络的权重和偏置参数')
weights={
    'wc1':tf.Variable(tf.random_normal([11,11,1,96])),
    'wc2':tf.Variable(tf.random_normal([5,5,96,256])),
    'wc3':tf.Variable(tf.random_normal([3,3,256,384])),
    'wc4':tf.Variable(tf.random_normal([3,3,384,384])),
    'wc5':tf.Variable(tf.random_normal([3,3,384,256])),
    'wd1':tf.Variable(tf.random_normal([2*2*256,4096])),
    'wd2':tf.Variable(tf.random_normal([4096,4096])),
    'out':tf.Variable(tf.random_normal([4096,n_classes]))
}
biases={
    'bc1':tf.Variable(tf.random_normal([96])),
    'bc2':tf.Variable(tf.random_normal([256])),
    'bc3':tf.Variable(tf.random_normal([384])),
    'bc4':tf.Variable(tf.random_normal([384])),
    'bc5':tf.Variable(tf.random_normal([256])),
    'bd1':tf.Variable(tf.random_normal([4096])),
    'bd2':tf.Variable(tf.random_normal([4096])),
    'out':tf.Variable(tf.random_normal([n_classes]))
}

#%%
#%%
'卷积操作'
def conv2d(x,W,b,strides=1):
    x=tf.nn.conv2d(x,W,strides=[1,strides,strides,1],padding='SAME')
    x=tf.nn.bias_add(x,b)
    return tf.nn.relu(x)
'池化操作'
def maxpool2d(x,k=2):
    return tf.nn.max_pool(x,ksize=[1,k,k,1],strides=[1,k,k,1],padding='SAME')
'局部归一化'
def norm(x,lsize=4):
    return tf.nn.lrn(x,lsize,bias=1.0,alpha=.001/9.0,beta=.75)

'==========================================================================='
print('构建网络ALexNet结构')
def alex_net(x,weights,biases,dropout):
    '输出的数据做reshape'
    x=tf.reshape(x,shape=[-1,28,28,1])
    
    '第一层 卷积计算(conv+relu+pool)'
    '卷积'
    conv1=conv2d(x,weights['wc1'],biases['bc1'])
    pool1=maxpool2d(conv1)
    norm1=norm(pool1)
        
    '第2层 卷积计算(conv+relu+pool)'
    conv2=conv2d(norm1,weights['wc2'],biases['bc2'])
    pool2=maxpool2d(conv2)
    norm2=norm(pool2)
    
    '第3层 卷积计算(conv+relu+pool)'
    '卷积'
    conv3=conv2d(norm2,weights['wc3'],biases['bc3'])
    pool3=maxpool2d(conv3)
    norm3=norm(pool3)
    '第4层 卷积计算(conv+relu+pool)'
    conv4=conv2d(norm3,weights['wc4'],biases['bc4'])
    '第5层 卷积计算(conv+relu+pool)'
    conv5=conv2d(conv4,weights['wc5'],biases['bc5'])    
    '池化'
    pool5=maxpool2d(conv5)
    norm5=norm(pool5)
    '可以加上dropout'
    
    '全连接1'
    '向量化'
    fc1=tf.reshape(norm5,[-1,weights['wd1'].get_shape().as_list()[0]])
    fc1=tf.add(tf.matmul(fc1,weights['wd1']),biases['bd1'])
    fc1=tf.nn.relu(fc1)
    'dropout'
    fc1=tf.nn.dropout(fc1,dropout)
    
    '全连接2'
    fc2=tf.reshape(fc1,[-1,weights['wd2'].get_shape().as_list()[0]])
    fc2=tf.add(tf.matmul(fc2,weights['wd2']),biases['bd2'])
    fc2=tf.nn.relu(fc2)
    'dropout'
    fc2=tf.nn.dropout(fc2,dropout)
    
    return tf.add(tf.matmul(fc2,weights['out']),biases['out'])
#%%    
print('训练评估模型')
print('1. 定义损失函数和优化器,并构建评估函数')
pred=alex_net(x,weights,biases,keep_prob)
print('2. 损失函数和优化器')
cost=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred,labels=y))
optim=tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
print('3. 评估函数')
correct_pred=tf.equal(tf.argmax(pred,1),tf.argmax(y,1))
acc=tf.reduce_mean(tf.cast(correct_pred,tf.float32))

#%%
print('训练')
init=tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    step=1
    print('开始训练')
    while step*batch_size < training_iters:
        batch_x,batch_y=mnist.train.next_batch(batch_size)
        sess.run(optim,feed_dict={x:batch_x,y:batch_y,keep_prob:dropout})
        if step%display_step==0:
            '显示此时的损失和正确率'
            cost_train,acc_train=sess.run([cost,acc],feed_dict={x:batch_x,y:batch_y,keep_prob:dropout})
            print('iter:%d,loss:%d,train acc:%f'%(step*batch_size,cost_train,acc_train))
        step+=1
    print('optimization finish !!!')

#%%

 

LRN全称为Local Response Normalization,即局部响应归一化层,LRN函数类似DROPOUT和数据增强作为relu激励之后防止数据过拟合而提出的一种处理方法。这个函数很少使用,基本上被类似DROPOUT这样的方法取代,见最早的出处AlexNet论文对它的定义, 《I

i:代表下标,你要计算像素值的下标,从0计算起

j:平方累加索引,代表从j~i的像素值平方求和

x,y:像素的位置,公式中用不到

a:代表feature map里面的 i 对应像素的具体值

N:每个feature map里面最内层向量的列数

k:超参数,由原型中的blas指定

α:超参数,由原型中的alpha指定

n/2:超参数,由原型中的deepth_radius指定

β:超参数,由原型中的belta指定

 

背景知识: 

tensorflow官方文档中的tf.nn.lrn函数给出了局部响应归一化的论文出处 ,详见http://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks 

为什么要有局部响应归一化(Local Response Normalization)?详见http://blog.csdn.net/hduxiejun/article/details/70570086

 

ps:

1、AlexNet将LeNet的思想发扬光大,把CNN的基本原理应用到了很深很宽的网络中。AlexNet主要使用到的新技术点如下:

(1)成功使用ReLU作为CNN的激活函数,并验证其效果在较深的网络超过了Sigmoid,成功解决了Sigmoid在网络较深时的梯度弥散问题。虽然ReLU激活函数在很久之前就被提出了,但是直到AlexNet的出现才将其发扬光大。

(2)训练时使用Dropout随机忽略一部分神经元,以避免模型过拟合。Dropout虽有单独的论文论述,但是AlexNet将其实用化,通过实践证实了它的效果。在AlexNet中主要是最后几个全连接层使用了Dropout。

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

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

 

2、为什么输入数据需要归一化(Normalized Data)?

   归一化后有什么好处呢?原因在于神经网络学习过程本质就是为了学习数据分布,一旦训练数据与测试数据的分布不同,那么网络的泛化能力也大大降低;另外一方面,一旦每批训练数据的分布各不相同(batch 梯度下降),那么网络就要在每次迭代都去学习适应不同的分布,这样将会大大降低网络的训练速度,这也正是为什么我们需要对数据都要做一个归一化预处理的原因。

   对于深度网络的训练是一个复杂的过程,只要网络的前面几层发生微小的改变,那么后面几层就会被累积放大下去。一旦网络某一层的输入数据的分布发生改变,那么这一层网络就需要去适应学习这个新的数据分布,所以如果训练过程中,训练数据的分布一直在发生变化,那么将会影响网络的训练速度。

mageNet Classification with Deep ConvolutionalNeural Networks》

3.后期争议
在2015年 Very Deep Convolutional Networks for Large-Scale Image Recognition.提到LRN基本没什么用。

在Alexnet模型中首次提出这个概念。 
参考文献:

[LRN]:ImageNet Classification with Deep Convolutional Neural Networks
 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值