1 数据
cifar-10数据,该数据集包含60000张32X32的彩色图像,其中训练集50000张,测试集10000张。标注为10类,每一类6000张图片,这10类分别是airplane、automobile bird cat deer dog frog horse ship truck,其中没有任何重叠的情况。
数据可从 https://github.com/tensorflow/models.git 下载,并且下载cifar10_input.py以读取cifar数据
2 网络构建
Layer名称 | 描述 |
conv1 | 卷积层和ReLu激活函数 |
pool1 | 最大池化 |
norm1 | LRN |
conv2 | 卷积层和ReLu激活函数 |
norm2 | LRN |
pool2 | 最大池化 |
fc1 | 全连接层和ReLu激活函数 |
fc2 | 全连接层和ReLu激活函数 |
logits | 模型Inference的输出结果 |
损失函数采用交叉熵+L2正则项,这是为了防止过拟合。一般来说L1正则会制造稀疏的特征,大部分无用特征会被置为0,而L2正则会让特征的权重不过大,使得特征的权重比较平均,因此,对fc1和fc2层的权重添加L2正则。
cifar10_input类中的distorted_input函数产生训练需要使用的数据,每次执行会产生一个batch_size的数量的样本。并对数据进行了数据增强(data Augmentation),包括随机的水平翻转、随机剪切一块24X24大小的图片,设置随机的亮度和对比度,以及对数据进行标准化,通过这些操作,原来的一幅图片样本可以变为多张图片,相当于扩大样本量。
LRN(局部响应归一化)操作最早见于Alex用CNN参加ImageNet比赛的论文,解释为:LRN层模仿了生物神经系统的“侧抑制”机制,对局部神经元的活动创建竞争环境,使得其中响应比较大的值变得相对更大,并抑制其他反馈较小的神经元,增强了模型的泛化能力。
最终输出的为top1的分类精度。
3 代码实现
#__author__ = 'Administrator'
'''
实现进阶的卷积神经网络
'''
import cifar10_input
import tensorflow as tf
import numpy as np
import time
import math
def weights_with_weight_loss(shape,stddev,w1):
'''
初始化权重,求权重的正则化项
:param shape: weights的shape
:param stddev: weights的初始标准方差
:param w1: 正则化项系数
:return:初始化的weights
'''
weights=tf.Variable(tf.truncated_normal(shape,stddev=stddev)) #weights
if w1 is not None:#w1存在的话 求weights的L2正则项
weights_loss=tf.multiply(tf.nn.l2_loss(weights),w1)
tf.add_to_collection('weights_loss', weights_loss)
return weights
def bias(value,shape):
'''
初始化bias项
:param value: bias的初始值
:param shape: bias的shape
:return: 初始化的b
'''
b=tf.Variable(tf.constant(value,shape=shape))
return b
def conv2d(x,kernel):
'''
卷积
:param x: 卷积对象,特征
:param kernel: 卷积核设置
:return:卷积后的特征
'''
feature=tf.nn.conv2d(x,kernel,[1,1,1,1],padding='SAME')#Strides=[1,1,1,1]表明输出图像与原图大小相等
return feature
def loss(logits,labels):
'''
计算带有L2正则项的loss
:param logits: 输出层的输出值
:param labels: 真实标签
:return:带有L2正则项的loss
'''
labels=tf.cast(labels,tf.int64)
cross_entropy=tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits,labels=labels,
name='cross_entropy_per_example')
cross_entropy_mean=tf.reduce_mean(cross_entropy,name='cross_entropy')
tf.add_to_collection('losses',cross_entropy_mean)
return tf.add_n(tf.get_collection('losses'),name='total_loss')
#参数设置
batch_size=128
max_steps=3000
data_dir='./cifar-10-batches-bin'
#导入数据,并进行数据增强处理
images_train,labels_train=cifar10_input.distorted_inputs(data_dir,batch_size=batch_size)
images_test,labels_test=cifar10_input.inputs(eval_data=True,data_dir=data_dir,batch_size=batch_size) #True:表明载入test数据
#构建模型
x=tf.placeholder(tf.float32,[batch_size,24,24,3]) #size 24X24 3个通道
y_=tf.placeholder(tf.int64,[batch_size])#存放标签
#卷积层1 池化1
w_conv1=weights_with_weight_loss([5,5,3,64],stddev=5e-2,w1=0.0)
b_conv1=bias(0.0,[64])
h_conv1=tf.nn.relu(conv2d(x,w_conv1)+b_conv1)
h_pool1=tf.nn.max_pool(h_conv1,[1,3,3,1],[1,2,2,1],padding='SAME') #核 3X3 步长: 2X2
h_norm1=tf.nn.lrn(h_pool1,4,bias=0.1,alpha=0.001/9.0,beta=0.75)
#卷积层2 池化2
w_conv2=weights_with_weight_loss([5,5,64,64],stddev=5e-2,w1=0.0)
b_conv2=bias(0.1,[64])
h_conv2=tf.nn.relu(conv2d(h_norm1,w_conv2)+b_conv2)
h_norm2=tf.nn.lrn(h_conv2,4,bias=0.1,alpha=0.001/9.0,beta=0.75)
h_pool2=tf.nn.max_pool(h_norm2,[1,3,3,1],[1,2,2,1],padding='SAME')
#全连接层1
h_pool2_flat=tf.reshape(h_pool2,[batch_size,-1])
dim=h_pool2_flat.get_shape()[1].value
w_fc1=weights_with_weight_loss([dim,384],stddev=0.04,w1=0.004)
b_fc1=bias(0.1,[384])
h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,w_fc1)+b_fc1)
#全连接层2
w_fc2=weights_with_weight_loss([384,192],stddev=0.04,w1=0.004)
b_fc2=bias(0.1,shape=[192])
h_fc2=tf.nn.relu(tf.matmul(h_fc1,w_fc2)+b_fc2)
#输出层
w_fc3=weights_with_weight_loss([192,10],stddev=1/192.0,w1=0.0)
b_fc3=bias(0.0,[10])
logits=tf.add(tf.matmul(h_fc2,w_fc3),b_fc3)
#计算loss,选择优化
loss=loss(logits,y_)
optimizer=tf.train.AdamOptimizer(1e-3).minimize(loss)
#输出分数最高的那一类的准确率
top_k_op=tf.nn.in_top_k(logits,y_,1)
#开启会话窗口
sess=tf.InteractiveSession()
tf.global_variables_initializer().run()
#启动图片数据增强的线程队列,利用16线程进行加速
tf.train.start_queue_runners()
#训练
for step in range(max_steps):
start_time=time.time()
images_batch,labels_batch=sess.run([images_train,labels_train])
loss_value,_=sess.run([loss,optimizer],feed_dict={x:images_batch,y_:labels_batch})
running_time=time.time()-start_time
if step%10==0:
example_per_sec=batch_size/running_time
sec_per_batch=float(running_time)
form_str=('step %d,loss=%.2f (%.1f example/sec; %.3f sec/batch)')
print(form_str % (step,loss_value,example_per_sec,sec_per_batch))
#检测
num_examples=10000
iter_num=int(math.ceil(num_examples/batch_size))
total_examples=iter_num*batch_size
true_count=0
step=0
while step<iter_num:
images_batch,labels_batch=sess.run([images_test,labels_test])
precidion=sess.run(top_k_op,feed_dict={x:images_batch,y_:labels_batch})
true_count+=np.sum(precidion)
step+=1
precision=true_count/total_examples
print('precision @1 %.2f '% precision)
4 实验结果
时间那块比较多,只输出后边一些
step 2930,loss=1.10 (345.0 example/sec; 0.371 sec/batch)
step 2940,loss=0.83 (344.1 example/sec; 0.372 sec/batch)
step 2950,loss=0.88 (342.1 example/sec; 0.374 sec/batch)
step 2960,loss=0.82 (345.9 example/sec; 0.370 sec/batch)
step 2970,loss=1.30 (345.0 example/sec; 0.371 sec/batch)
step 2980,loss=0.81 (345.8 example/sec; 0.370 sec/batch)
step 2990,loss=0.86 (342.2 example/sec; 0.374 sec/batch)
precision @1 0.71
step 2940,loss=0.83 (344.1 example/sec; 0.372 sec/batch)
step 2950,loss=0.88 (342.1 example/sec; 0.374 sec/batch)
step 2960,loss=0.82 (345.9 example/sec; 0.370 sec/batch)
step 2970,loss=1.30 (345.0 example/sec; 0.371 sec/batch)
step 2980,loss=0.81 (345.8 example/sec; 0.370 sec/batch)
step 2990,loss=0.86 (342.2 example/sec; 0.374 sec/batch)
precision @1 0.71
5 改进说明
1.增加max_steps,可以期望分类精度增加
2.如果max_steps比较大,使用学习速率衰减(decay)的SGD进行训练。