相比于【三】,此卷积神经网络新增加了一些心技巧,这也是此CNN的关键。
1.对weights进行了L2正则化。在机器学习中,不管是分类还是回归任务,都因为特征过多而导致过拟合,一般可以通过减少特征或者惩罚不重要的特征来缓解这个问题。但通常我们不知道该惩罚哪些特征的权重,而正则化就是帮助我们乘法这些特称权重的,即特征的权重也会成为损失函数的一部分。可以理解为,为了使用某个特征,我们需要付出loss的代价,除非这个特征非常有效,否则就会被loss的增加覆盖效果。这样我们就可以筛选出最有效的特征,减少特征权重防止过拟合。这也就是奥卡姆剃刀法则,越简单的东西越有效。L1正则会制造稀疏的特征,大部分无用的特征会被重置为0,而L2则会让这些特征的权重不过大,使得特征的权重比较平均。
2.对图片进行了反转,随机剪切等数据增强,制造了更多样本
3.在每个卷积-最大池化后面使用了LRN层(局部响应标准化),增强了模型的泛化能力。局部响应归一化层完成一种“临近抑制”操作,对局部输入区域进行归一化。
NOTE:因为网络原因cifar10无法下载,因此只给出神经网络构建的代码实现,以及主要思路,代码我并没有实际运行过。
整体思路并没有太大改变,主要部分依旧是2层卷积+最大池化,不过在第一次池化过后,接一层LRN,第二次连接LRN是在第2次卷积之后连接的。在2次卷积+池化过后是1层flatten,最后为2层全连接层,第1层全连接层将隐含节点减半,第二层全连接层设置隐含节点数为10,即分类的数目。损失函数依旧使用交叉熵。
# -*- coding: utf-8 -*-
"""
Created on Tue Jul 23 13:59:18 2019
@author: Administrator
"""
#cd cifar10
import tensorflow as tf
import numpy as np
import time
import cifar10,cifar10_input
max_steps=3000
batch_size=128
data_dir='/cifar-10-batches-bin'
def variable_with_weight_loss(shape,stddev,wl):
var=tf.Variable(tf.truncated_normal(shape,stddev=stddev))
if wl is not None:
weight_loss=tf.multiply(tf.nn.l2_loss(var),wl,name='weight_loss')
tf.add_to_collection('losses',weight_loss)
return var
#使用cifar10类下载数据集,并解压,展开到其默认位置
cifar10.maybe_download_and_extract()
images_train,labels_train=cifar10_input.distorted_inputs(data_dir=data_dir,\
batch_size=batch_size)
images_test,labels_test=cifar10_input.inputs(eval_data=True,\
data_dir=data_dir,\
batch_size=batch_size)
#图片大小24*24,图片通道3,因为batch_size在之后的网络结构中要用到,所以需要预先设定
image_holder=tf.placeholder(tf.float32,[batch_size,24,24,3])
label_holder=tf.placeholder(tf.int32,[batch_size])
#第一层卷积+池化
weight1=variable_with_weight_loss(shape=[5,5,3,64],stddev=5e-2,wl=0.0)
kernel1=tf.nn.conv2d(image_holder,weight1,[1,1,1,1],padding='SAME')
bias1=tf.Variable(tf.constant(0.0,shape=[64]))
conv1=tf.nn.relu(tf.nn.bias_add(kernel1,bias1))
pool1=tf.nn.max_pool(conv1,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')
norm1=tf.nn.lrn(pool1,4,bias=1.0,alpha=0.001/9.0,beta=0.75)
#第二层卷积+池化
weight2=variable_with_weight_loss(shape=[5,5,64,64],stddev=5e-2,wl=0.0)
kernel2=tf.nn.conv2d(norm1,weight2,[1,1,1,1],padding='SAME')
bias2=tf.Variable(tf.constant(0.1,shape=[64]))
conv2=tf.nn.relu(tf.nn.bias_add(kernel2,bias2))
norm2=tf.nn.lrn(conv2,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')
pool2=tf.nn.max_pool(norm2,ksize=[1,3,3,1],strides=[1,2,2,1],padding='SAME')
#flatten
reshape=tf.reshape(pool2,[batch_size,-1])
dim=reshape.get_shape()[1].value
weight3=variable_with_weight_loss(shape=[dim,384],stddev=0.04,wl=0.004)
bias3=tf.Variable(tf.constant(0.1,shape=[384]))
local3=tf.nn.relu(tf.matmul(reshape,weight3)+bias3)
#全连接层,隐含节点数减半
weight4=variable_with_weight_loss(shape=[384,192],stddev=0.04,wl=0.004)
bias4=tf.Variable(tf.constant(0.1,shape=[192]))
local4=tf.nn.relu(tf.matmul(local3,weight4)+bias4)
#全连接层
weight5=variable_with_weight_loss(shape=[192,10],stddev=1/192.0,wl=0.0)
bias5=tf.Variable(tf.constant(0.0,shape=[10]))
logits=tf.add(tf.matmul(local4,weight5),bias5)
def loss(logits,labels):
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')
loss=loss(logits,label_holder)
train_op=tf.train.AdamOptimizer(1e-3).minimize(loss)
top_k_op=tf.nn.in_top_k(logits,label_holder,1)
sess=tf.InteractiveSession()
tf.global_variables_initializer.run()
tf.train.start_queue_runners()
for step in range(max_steps):
start_time=time.time()
image_batch,label_batch=sess.run([images_train,labels_train])
_,loss_value=sess.run([train_op,loss],feed_dict={image_holder:image_batch,\
label_holder:label_batch})
duration=time.time()-start_time
if step%10==0:
examples_per_sec=batch_size/duration
sec_per_batch=float(duration)
format_str=('step %d,loss=%.2f(%.1f example/sec;%.3f sec/batch)')
print(format_str%(step,loss_value,examples_per_sec,sec_per_batch))
num_examples=10000
import math
num_iter=int(math.ceil(num_examples/batch_size))
true_count=0
total_sample_count=num_iter*batch_size
step=0
while step