1.图像分类实际上就是给定一张图片,然后通过卷积神经网特征提取,通过提取的特征进行类别的判定
CIFAR-10数据集包含10小类,60000个32*32的彩色图像。有50000个训练图像和10000个测试图像。
数据集下载路径:http://www.cs.toronto.edu/~kriz/cifar.html
2.TensorFlow训练框架搭建
(1)Data(数据的读取和数据打包)
(2)Net(网络的搭建,采用slim)
(3)Loss
(4)Summary(完成了我们训练过程中日志的记录)
(5)Session(构造计算图之后,对节点进行计算)
3.模型优化:
实战:我们在pycharm中新建一个工程,新建文件夹cifar10,该文件夹下
1.新建文件夹data存放着test和train两个打包好的tfrecord文件:
2.新建logdirs文件夹存放log日志信息
3.新建model文件夹存放训练好的模型
新建python文件readcifar10.py:
import tensorflow as tf
def read(batchsize=64, type=1, no_aug_data=1):
reader = tf.TFRecordReader()
if type == 0: #从train中进行读取
file_list = ["data/train.tfrecord"]
if type == 1: #从test中进行读取,搭建模型的时候,我们每训练一个epoch,我们会从test文件进行一次测试
file_list = ["data/test.tfrecord"]
filename_queue = tf.train.string_input_producer(#读取tfrecord文件中的图片数据
file_list, num_epochs=None, shuffle=True)
_, serialized_example = reader.read(filename_queue)
batch = tf.train.shuffle_batch([serialized_example], batchsize, capacity=batchsize * 10,
min_after_dequeue= batchsize * 5)
feature = {'image': tf.FixedLenFeature([], tf.string),
'label': tf.FixedLenFeature([], tf.int64)}
features = tf.parse_example(batch, features = feature)
images = features["image"]
img_batch = tf.decode_raw(images, tf.uint8)
img_batch = tf.cast(img_batch, tf.float32)
img_batch = tf.reshape(img_batch, [batchsize, 32, 32, 3])
if type == 0 and no_aug_data == 1:#如果我们从训练集中读取数据的话,我们添加数据增强,对测试样本我们不进行数据增强的
distorted_image = tf.random_crop(img_batch,[batchsize, 28, 28, 3])#随机裁剪
distorted_image = tf.image.random_contrast(distorted_image,lower=0.8,upper=1.2)#随机对比度
distorted_image = tf.image.random_hue(distorted_image,max_delta=0.2)#随机饱和度
distorted_image = tf.image.random_saturation(distorted_image,lower=0.8,upper=1.2)#随机色调
img_batch = tf.clip_by_value(distorted_image, 0, 255) #取值范围的约束
img_batch = tf.image.resize_images(img_batch, [32, 32])
label_batch = tf.cast(features['label'], tf.int64)
#对于图片数据呢,我们通常归一化到-1到1之间,原始数据是0-255
img_batch = tf.cast(img_batch, tf.float32) / 128.0 - 1.0
#
return img_batch, label_batch#返回图片和label
#完成了tensorflow对数据的读取
新建train.py文件:
import tensorflow as tf
import readcifar10
slim = tf.contrib.slim#引入slim包
import os
import resnet
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
def model(image, keep_prob=0.8, is_training=True):#定义网络模型,输入是image,输出是全链接之后的概率分布值
batch_norm_params = {
"is_training": is_training,
"epsilon":1e-5,#防止我们batch_norm层归一化时除0
"decay":0.997,#衰减系数
'scale':True,
'updates_collections':tf.GraphKeys.UPDATE_OPS#能够对batch_norm的参数进行收集
}
with slim.arg_scope(
[slim.conv2d],
weights_initializer = slim.variance_scaling_initializer(),#卷积参数初始化方式
activation_fn = tf.nn.relu,#卷积层的激活方式
weights_regularizer = slim.l2_regularizer(0.0001),#定义对权值的正则化约束
normalizer_fn = slim.batch_norm,
normalizer_params = batch_norm_params):#指定batch_norm层的参数
with slim.arg_scope([slim.max_pool2d], padding="SAME"):
net = slim.conv2d(image, 32, [3, 3], scope='conv1')#第一个卷积层,输入是image,通道是32,卷积核大小为3*3,命名为conv1
net = slim.conv2d(net, 32, [3, 3], scope='conv2')#第二个卷积的输入应为第一个卷积的输出
net = slim.max_pool2d(net, [3, 3], stride=2, scope='pool1')
net = slim.conv2d(net, 64, [3, 3], scope='conv3')#通道数翻倍
net = slim.conv2d(net, 64, [3, 3], scope='conv4')
net = slim.max_pool2d(net, [3, 3], stride=2, scope='pool2')
net = slim.conv2d(net, 128, [3, 3], scope='conv5')
net = slim.conv2d(net, 128, [3, 3], scope='conv6')
net = slim.max_pool2d(net, [3, 3], stride=2, scope='pool3')
net = slim.conv2d(net, 256, [3, 3], scope='conv7')
net = tf.reduce_mean(net, axis=[1, 2]) #nhwc--n11c,对当前的特征图取均值,对第一维和第二维,即hw求均值,得到[n11c】
net = slim.flatten(net)#将【n,1,1,c]变为【n,c]
net = slim.fully_connected(net, 1024)#添加全链接层,输出为1024
slim.dropout(net, keep_prob)#通过dropout层来对神经元进行正则化,keep_prob为概率值,训练时取小于1的值和测试时等于1
net = slim.fully_connected(net, 10)#最后一个全链接层输出10
return net #10 维的向量
def loss(logits, label):#采用交叉熵损失函数,输入是我们预测出的概率分布值,另一个是实际的label值
one_hot_label = slim.one_hot_encoding(label, 10)#对于label进行one-hot编码
slim.losses.softmax_cross_entropy(logits, one_hot_label)#添加交叉熵损失函数
reg_set = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)#获取正则化的loss
l2_loss = tf.add_n(reg_set)#计算总体上的l2_loss
slim.losses.add_loss(l2_loss)#将l2loss添加到loss中
totalloss = slim.losses.get_total_loss()
return totalloss, l2_loss#输出最后的loss
def func_optimal(batchsize, loss_val):#定义优化器
global_step = tf.Variable(0, trainable=False)
# 定义指数衰减的学习率
lr = tf.train.exponential_decay(0.001,#初始学习率
global_step,
decay_steps= 50000// batchsize,#每次衰减的步长
decay_rate= 0.95,#每次衰减0。95
staircase=False)#False学习率以平滑的曲线下降,True学习率就会向楼梯一样下降
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)#对batch_norm进行更新
with tf.control_dependencies(update_ops):
op = tf.train.AdamOptimizer(lr).minimize(loss_val, global_step)#定义优化器
return global_step, op, lr#global_step拿到当前的迭代次数,通过op完成网络的参数的调节
def train():#搭建整个训练的代码
batchsize = 64
floder_log = 'logdirs'#日志存放的目录
floder_model = 'model'#模型存放的路径
if not os.path.exists(floder_log):
os.mkdir(floder_log)
if not os.path.exists(floder_model):
os.mkdir(floder_model)
tr_summary = set()#存放训练样本的日志信息
te_summary = set()#存放测试样本的日志信息
##data
tr_im, tr_label = readcifar10.read(batchsize, 0, 1)#获取文件队列中的图片和label
te_im, te_label = readcifar10.read(batchsize, 1, 0)
##定义网络
input_data = tf.placeholder(tf.float32, shape=[None, 32, 32, 3],name='input_data')#输入数据
input_label = tf.placeholder(tf.int64, shape=[None],name='input_label')
keep_prob = tf.placeholder(tf.float32, shape=None,name='keep_prob')
is_training = tf.placeholder(tf.bool, shape=None,name='is_training')
logits = model(input_data, keep_prob=keep_prob, is_training=is_training)#调用模型,拿到输出的结果
##定义loss
total_loss, l2_loss = loss(logits, input_label)
tr_summary.add(tf.summary.scalar('train total loss', total_loss))#向日志中添加loss
tr_summary.add(tf.summary.scalar('test l2_loss', l2_loss))
te_summary.add(tf.summary.scalar('train total loss', total_loss))
te_summary.add(tf.summary.scalar('test l2_loss', l2_loss))
##accurancy,计算精度
pred_max = tf.argmax(logits, 1)#获取当前概率分布中最大的值所对应的索引
correct = tf.equal(pred_max, input_label)#判断这个值是否和label相等
accurancy = tf.reduce_mean(tf.cast(correct, tf.float32))#对判断结果进行统计
tr_summary.add(tf.summary.scalar('train accurancy', accurancy))
te_summary.add(tf.summary.scalar('test accurancy', accurancy))
##调用优化器,将loss传入,优化参数
global_step, op, lr = func_optimal(batchsize, total_loss)
tr_summary.add(tf.summary.scalar('train lr', lr))
te_summary.add(tf.summary.scalar('test lr', lr))
tr_summary.add(tf.summary.image('train image', input_data * 128 + 128))
te_summary.add(tf.summary.image('test image', input_data * 128 + 128))
#with tf.Session() as sess:
with tf.Session(config=config) as sess:
sess.run(tf.group(tf.global_variables_initializer(),tf.local_variables_initializer()))#局部和全局变量的初始化
tf.train.start_queue_runners(sess=sess,coord=tf.train.Coordinator())#启用文件队列线程,多线程管理器
saver = tf.train.Saver(tf.global_variables(), max_to_keep=5)#最大存入月个
ckpt = tf.train.latest_checkpoint(floder_model)#获取模型文件中最新的model
if ckpt:
saver.restore(sess, ckpt)#如果最新文件存在,则对当前的graph进行恢复
epoch_val = 100
tr_summary_op = tf.summary.merge(list(tr_summary))#合并日志信息
te_summary_op = tf.summary.merge(list(te_summary))
summary_writer = tf.summary.FileWriter(floder_log, sess.graph)#定义summary_writer,参数为log文件的路径和当前的网络
for i in range(50000 * epoch_val):#总的迭代次数为样本总量*epoch
train_im_batch, train_label_batch = \
sess.run([tr_im, tr_label])#获取训练样本
feed_dict = {#赋值
input_data:train_im_batch,
input_label:train_label_batch,
keep_prob:0.8,
is_training:True
}
_, global_step_val, \
lr_val, \
total_loss_val, \
accurancy_val, tr_summary_str = sess.run([op,global_step,lr,total_loss,accurancy, tr_summary_op],feed_dict=feed_dict)#实现参数更新
summary_writer.add_summary(tr_summary_str, global_step_val)#将tr_summary_str, global_step_val写入
if i % 100 == 0:#每隔100次打印
print("{},{},{},{}".format(global_step_val,lr_val, total_loss_val,accurancy_val))
if i % (50000 // batchsize) == 0:#测试
test_loss = 0
test_acc = 0
for ii in range(10000//batchsize):
test_im_batch, test_label_batch = \
sess.run([te_im, te_label])
feed_dict = {
input_data: test_im_batch,
input_label: test_label_batch,
keep_prob: 1.0,
is_training: False
}
total_loss_val, global_step_val, \
accurancy_val, te_summary_str = sess.run([total_loss,global_step,
accurancy, te_summary_op],
feed_dict=feed_dict)
summary_writer.add_summary(te_summary_str, global_step_val)
test_loss += total_loss_val
test_acc += accurancy_val
print('test:', test_loss * batchsize / 10000,test_acc* batchsize / 10000)#对于测试集平均的loss,和acc
if i % 1000 == 0:#每隔1000次保存模型
saver.save(sess, "{}/model.ckpt{}".format(floder_model, str(global_step_val)))#模型存储语句,用global的值进行命名
return
if __name__ == '__main__':
train()
结果:
训练过程:
在tensorboard中的可视化:
我们现在看model文件夹下的checkpoint文件(记录了最新的模型):
在模型训练的时候我们通常将模型保存为3个文件:
.meta定义了graph的结构,.data则存放了graph这些变量值,.index是索引
进行模型优化呢,通常修改:
1.修改网络结构,可以采用RexNet网络
2.学习率的参数以及学习率衰减的策略
3.加入更多的数据增强的方法
4.采用不同的优化器
一天更新两篇,血槽快没了,今天就到这吧。每天都要加油嘎!
金乘
原创文章 9获赞 11访问量 1820
关注
私信
展开阅读全文
作者:金乘