网络结构
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