Deep Learning-TensorFlow (5) CNN卷积神经网络_CIFAR-10进阶图像分类模型(下)
2017-03-22 15:49
1156 查看
环境:Win8.1 TensorFlow1.0.1
软件:Anaconda3 (集成Python3及开发环境)
TensorFlow安装:pip install tensorflow (CPU版) pip install tensorflow-gpu (GPU版)
代码参考:TensorFlow cifar-10 示例代码
完整代码可在
@DiamonJoy下载,针对旧版修正如下:
修改 Loss(),改用 sparse_softmax_cross_entropy_with_logits();
修正Summary API;
修正部分 Image API 和 计算 Op;
关键代码添加中文注释。
上篇博文我们介绍了 CIFAR-10 以及针对这个数据集分类问题采取的图片预处理 distorted_inputs() 和建立的预测模型inference(),接下来根据返回的 logits 和实际的 labels 计算loss,然后进行train。
3.3 损失函数
我们回忆之前利用交叉熵(cross entropy)计算 loss 的方法:
此处 y_conv 是通过 tf.nn.softmax 后的 logits 值(属于每个类别的概率值),shape 为 [batch_size, num_classes],每个样本的 logit 向量元素和为1;y_ 是 onehot encoding 后的 labels 值,shape 为 [batch_size, num_classes],每个样本的 label 元素中只有一个为1,其余为0。TensorFlow 在后面的版本中,提供了更加便捷的 API,合并了 softmax 和 cross entropy
的计算:
在 CIFAR-10 中,labels 的 shape 为 [batch_size],每个样本的 label 为0到9的一个数,代表10个分类,这些类之间是相互排斥的,每个 CIFAR-10 图片只能被标记为唯一的一个标签:一张图片可能是一只狗或一辆卡车,而不能两者都是。因此我们需要对 label 值 onehot encoding,转化过程比较繁琐,新版的 TensorFlow API 支持对唯一值 labels
的 sparse_to_dense,只需要一步:
3.4 模型训练
在定义 loss 之后,我们需要定义接受 loss 并返回 train op 的 train()。
首先定义学习率(learning rate),并设置随迭代次数衰减,并进行 summary:
此外,我们对 loss 生成滑动均值和汇总,通过使用指数衰减,来维护变量的滑动均值(Moving Average)。当训练模型时,维护训练参数的滑动均值是有好处的,在测试过程中使用滑动参数比最终训练的参数值本身,会提高模型的实际性能即准确率。apply() 方法会添加 trained variables 的 shadow copies,并添加操作来维护变量的滑动均值到 shadow
copies。 average() 方法可以访问 shadow variables,在创建 evaluation model 时非常有用。滑动均值是通过指数衰减计算得到的,shadow variable 的初始化值和 trained variables 相同,其更新公式为 shadow_variable = decay * shadow_variable + (1 - decay) * variable。
然后,我们定义训练方法与目标,tf.control_dependencies 是一个 context manager,控制节点执行顺序,先执行[ ]中的操作,再执行 context 中的操作:
最后,动态调整衰减率,返回模型参数变量的滑动更新操作即 train op:
4. 训练过程
上述步骤完成了数据的输入,模型预测,损失和训练的定义,接下来依次调用,建立训练和汇总过程:
需要注意的是,一定要运行 start_queue_runners 启动前面提到的图片数据增广的线程,这里一共使用来16个线程来进行加速。
在每一 step 的训练过程中,需要先使用 session 的 run 方法执行对 images、labels 组成的 batch 传入 train_op 和 loss 的计算,记录每一个 step 花费的时间,每隔10个 step 会计算并展示当前的 loss,每秒钟训练的样本数量,以及训练一个 batch 数据所花费的时间,这样就可以比较方便地监控整个训练过程。
通过执行脚本 python cifar10_train.py 启动训练过程,第一次在 CIFAR-10 上启动任何任务时,会自动下载 CIFAR-10 数据集,该数据集大约有160M大小,随后输出:
5. 模型评价
cifar10_train.py 会周期性的在检查点文件中保存模型中的所有参数,但是不会对模型进行评估。cifar10_eval.py 会使用该检查点文件在另一部分数据集上测试预测性能。利用 inference() 函数重构模型,并使用了在评估数据集所有10,000张 CIFAR-10 图片进行测试。最终计算出的精度为 1 : N,N = 预测值中置信度最高的一项与图片真实 label 匹配的频次。为了监控模型在训练过程中的改进情况,评估用的脚本文件会周期性的在最新的检查点文件上运行,这些检查点文件是由上述的
cifar10_train.py 产生。
运行 cifar10_eval.py 文件后我们可以得到类似这样的输出:
我们在训练脚本会为所有学习变量计算其滑动均值(Moving Average),评估脚本则直接将所有学习到的模型参数替换成对应的滑动均值,这一替代方式可以在评估过程中提升模型的性能。
软件:Anaconda3 (集成Python3及开发环境)
TensorFlow安装:pip install tensorflow (CPU版) pip install tensorflow-gpu (GPU版)
代码参考:TensorFlow cifar-10 示例代码
完整代码可在
@DiamonJoy下载,针对旧版修正如下:
修改 Loss(),改用 sparse_softmax_cross_entropy_with_logits();
修正Summary API;
修正部分 Image API 和 计算 Op;
关键代码添加中文注释。
上篇博文我们介绍了 CIFAR-10 以及针对这个数据集分类问题采取的图片预处理 distorted_inputs() 和建立的预测模型inference(),接下来根据返回的 logits 和实际的 labels 计算loss,然后进行train。
3.3 损失函数
我们回忆之前利用交叉熵(cross entropy)计算 loss 的方法:
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2) + b_fc2) cross_entropy = tf.reduce_sum(-y_*tf.log(y_conv))
此处 y_conv 是通过 tf.nn.softmax 后的 logits 值(属于每个类别的概率值),shape 为 [batch_size, num_classes],每个样本的 logit 向量元素和为1;y_ 是 onehot encoding 后的 labels 值,shape 为 [batch_size, num_classes],每个样本的 label 元素中只有一个为1,其余为0。TensorFlow 在后面的版本中,提供了更加便捷的 API,合并了 softmax 和 cross entropy
的计算:
cross_entropy_loss = tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv)
在 CIFAR-10 中,labels 的 shape 为 [batch_size],每个样本的 label 为0到9的一个数,代表10个分类,这些类之间是相互排斥的,每个 CIFAR-10 图片只能被标记为唯一的一个标签:一张图片可能是一只狗或一辆卡车,而不能两者都是。因此我们需要对 label 值 onehot encoding,转化过程比较繁琐,新版的 TensorFlow API 支持对唯一值 labels
的 sparse_to_dense,只需要一步:
cross_entropy_loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=labels, name='cross_entropy_pre_example')这里的 labels 的 shape 为 [batch_size, 1]。再使用 tf.add_to_collection 把 cross entropy 的 loss 添加到整体 losses 的 collection 中。 最后,使用 tf.add_n 将整体 losses 的 collection中 的全部 loss 求和,得到最终的 loss 并返回,其中包含 cross entropy loss,还有后两个全连接层中的 weight 的 L2 loss。
tf.add_to_collection(name='losses', value=cross_entropy_loss) return tf.add_n(inputs=tf.get_collection(key='losses'), name='total_loss')
3.4 模型训练
在定义 loss 之后,我们需要定义接受 loss 并返回 train op 的 train()。
首先定义学习率(learning rate),并设置随迭代次数衰减,并进行 summary:
lr = tf.train.exponential_decay(INITIAL_LEARNING_RATE, global_step, decay_steps, LEARNING_RATE_DECAY_FACTOR, staircase=True) tf.summary.scalar('learning_rate', lr)
此外,我们对 loss 生成滑动均值和汇总,通过使用指数衰减,来维护变量的滑动均值(Moving Average)。当训练模型时,维护训练参数的滑动均值是有好处的,在测试过程中使用滑动参数比最终训练的参数值本身,会提高模型的实际性能即准确率。apply() 方法会添加 trained variables 的 shadow copies,并添加操作来维护变量的滑动均值到 shadow
copies。 average() 方法可以访问 shadow variables,在创建 evaluation model 时非常有用。滑动均值是通过指数衰减计算得到的,shadow variable 的初始化值和 trained variables 相同,其更新公式为 shadow_variable = decay * shadow_variable + (1 - decay) * variable。
_add_loss_summaries(total_loss): # 创建一个新的指数滑动均值对象 loss_averages = tf.train.ExponentialMovingAverage(0.9, name='avg') # 从字典集合中返回关键字'losses'对应的所有变量,包括交叉熵损失和正则项损失 losses = tf.get_collection('losses') # 创建'shadow variables'并添加维护滑动均值的操作 loss_averages_op = loss_averages.apply(losses + [total_loss]) # Attach a scalar summary to all individual losses and the total loss; do the # same for the averaged version of the losses. for l in losses + [total_loss]: # Name each loss as '(raw)' and name the moving average version of the loss # as the original loss name. tf.summary.scalar(l.op.name +' (raw)', l) tf.summary.scalar(l.op.name, loss_averages.average(l)) return loss_averages_op
然后,我们定义训练方法与目标,tf.control_dependencies 是一个 context manager,控制节点执行顺序,先执行[ ]中的操作,再执行 context 中的操作:
loss_averages_op = _add_loss_summaries(total_loss) # 损失变量的更新操作 with tf.control_dependencies([loss_averages_op]): opt = tf.train.GradientDescentOptimizer(lr) grads = opt.compute_gradients(total_loss) # 返回计算出的(gradient, variable) pairs # 返回一步梯度更新操作 apply_gradient_op = opt.apply_gradients(grads, global_step=global_step)
最后,动态调整衰减率,返回模型参数变量的滑动更新操作即 train op:
variable_averages = tf.train.ExponentialMovingAverage( MOVING_AVERAGE_DECAY, global_step) variables_averages_op = variable_averages.apply(tf.trainable_variables()) with tf.control_dependencies([apply_gradient_op, variables_averages_op]): train_op = tf.no_op(name='train') return train_op
4. 训练过程
上述步骤完成了数据的输入,模型预测,损失和训练的定义,接下来依次调用,建立训练和汇总过程:
def train(): """Train CIFAR-10 for a number of steps.""" # 指定当前图为默认graph with tf.Graph().as_default(): # 设置trainable=False,是因为防止训练过程中对global_step变量也进行滑动更新操作 global_step = tf.Variable(0, trainable=False) # Get images and labels for CIFAR-10. # 输入图像的预处理,包括亮度、对比度、图像翻转等操作 images, labels = cifar10.distorted_inputs() # Build a Graph that computes the logits predictions from the # inference model. logits = cifar10.inference(images) # Calculate loss. loss = cifar10.loss(logits, labels) # Build a Graph that trains the model with one batch of examples and # updates the model parameters. train_op = cifar10.train(loss, global_step) # 创建一个saver对象,用于保存参数到文件中 saver = tf.train.Saver(tf.global_variables()) # 返回所有summary对象先merge再serialize后的的字符串类型tensor summary_op = tf.summary.merge_all() # log_device_placement参数可以记录每一个操作使用的设备,这里的操作比较多,故设置为False sess = tf.Session(config=tf.ConfigProto( log_device_placement=FLAGS.log_device_placement)) # 变量初始化 init = tf.global_variables_initializer() sess.run(init) ckpt = tf.train.get_checkpoint_state(FLAGS.train_dir) if ckpt and ckpt.model_checkpoint_path: # Restores from checkpoint saver.restore(sess, ckpt.model_checkpoint_path) print ("restore from file") else: print('No checkpoint file found') # 启动所有的queuerunners tf.train.start_queue_runners(sess=sess) summary_writer = tf.summary.FileWriter(FLAGS.train_dir, graph=sess.graph) for step in xrange(FLAGS.max_steps): start_time = time.time() _, loss_value = sess.run([train_op, loss]) duration = time.time() - start_time # 用于验证当前迭代计算出的loss_value是否合理 assert not np.isnan(loss_value), 'Model diverged with loss = NaN' if step % 10 == 0: num_examples_per_step = FLAGS.batch_size examples_per_sec = num_examples_per_step / duration sec_per_batch = float(duration) format_str = ('%s: step %d, loss = %.2f (%.1f examples/sec; %.3f ' 'sec/batch)') print (format_str % (datetime.now(), step, loss_value, examples_per_sec, sec_per_batch)) if step % 100 == 0: summary_str = sess.run(summary_op) summary_writer.add_summary(summary_str, step) # Save the model checkpoint periodically. if step % 1000 == 0 or (step + 1) == FLAGS.max_steps: checkpoint_path = os.path.join(FLAGS.train_dir, 'model.ckpt') saver.save(sess, checkpoint_path, global_step=step)
需要注意的是,一定要运行 start_queue_runners 启动前面提到的图片数据增广的线程,这里一共使用来16个线程来进行加速。
在每一 step 的训练过程中,需要先使用 session 的 run 方法执行对 images、labels 组成的 batch 传入 train_op 和 loss 的计算,记录每一个 step 花费的时间,每隔10个 step 会计算并展示当前的 loss,每秒钟训练的样本数量,以及训练一个 batch 数据所花费的时间,这样就可以比较方便地监控整个训练过程。
通过执行脚本 python cifar10_train.py 启动训练过程,第一次在 CIFAR-10 上启动任何任务时,会自动下载 CIFAR-10 数据集,该数据集大约有160M大小,随后输出:
5. 模型评价
cifar10_train.py 会周期性的在检查点文件中保存模型中的所有参数,但是不会对模型进行评估。cifar10_eval.py 会使用该检查点文件在另一部分数据集上测试预测性能。利用 inference() 函数重构模型,并使用了在评估数据集所有10,000张 CIFAR-10 图片进行测试。最终计算出的精度为 1 : N,N = 预测值中置信度最高的一项与图片真实 label 匹配的频次。为了监控模型在训练过程中的改进情况,评估用的脚本文件会周期性的在最新的检查点文件上运行,这些检查点文件是由上述的
cifar10_train.py 产生。
运行 cifar10_eval.py 文件后我们可以得到类似这样的输出:
2017-03-22 19:00:00.223784: precision @ 1 = 0.099评估脚本只是周期性的返回 precision@1 (The script merely returns the precision @ 1 periodically),由于迭代次数很少,在该例中返回的准确率是9.9%。cifar10_eval.py 同时也返回其它一些可以在 TensorBoard 中进行可视化的简要信息,可以通过这些简要信息在评估过程中进一步的了解模型。
我们在训练脚本会为所有学习变量计算其滑动均值(Moving Average),评估脚本则直接将所有学习到的模型参数替换成对应的滑动均值,这一替代方式可以在评估过程中提升模型的性能。
相关文章推荐
- Deep Learning-TensorFlow (4) CNN卷积神经网络_CIFAR-10进阶图像分类模型(上)
- Deep Learning-TensorFlow (10) CNN卷积神经网络_ TFLearn 快速搭建深度学习模型
- TensorFlow应用之进阶版卷积神经网络CNN在CIFAR-10数据集上分类
- tensorflow用CNN实现CIFAR-10图像分类(cpu贼慢)
- tensorflow训练自己的数据集实现CNN图像分类2(保存模型&测试单张图片)
- 利用Keras实现多层感知器(MLP)模型和卷积神经网络(CNN)模型并对手写数字图像分类
- TensorFlow深度学习进阶教程:TensorFlow实现CIFAR-10数据集测试的卷积神经网络
- Deep Learning-TensorFlow (8) CNN卷积神经网络_《TensorFlow实战》及经典网络模型(上)
- 简单图像分类与识别CNN,Tensorflow,Cifar10(吴恩达Deep Learning)
- TensorFlow之CNN图像分类及模型保存与调用
- Deep Learning-TensorFlow (9) CNN卷积神经网络_《TensorFlow实战》及经典网络模型(下)
- TensorFlow学习笔记---CNN分类CIFAR-10数据集3
- 第三阶段-tensorflow项目之图像image相关--tensorflow搭建CNNs 之CIFAR-10多个GPU运行
- (3) Deep Learning模型之:CNN卷积神经网络(1)
- NearestNeighnor 实现cifar-10图像分类
- 【深度学习】笔记7: CNN训练Cifar-10技巧 ---如何进行实验,如何进行构建自己的网络模型,提高精度
- Tensorflow使用slim工具(vgg16模型)实现图像分类与分割
- CS231n-KNN模型分类Cifar10
- Deep Learning模型之:CNN卷积神经网络推导和实现
- (4)Deep Learning模型之:CNN卷积神经网络(2)模型训练