借手写数字识别入门tensorflow已经有一段时间了,实话说经过初步入门的阵痛以后,学习tensorflow已经开始顺水推舟、有条不紊的进行开来,这期间有了一些感悟,记录下来,也希望对大家有所帮助。
本片文章依然是接着tensorflow的这一系列,记录整理学习轨迹。
不过,不同于上面的三篇文章,本文的内容比较的少,只是记录了使用tensorboard来实现可视化的过程。具体原因是,一方面,我认为对于tensorflow的学习应该建立在知道与部分理解的基础上来进行的,相信到目前为止,依然会对已经实现的功能有所困惑,即使没有困惑,已经实现的代码肯定有可以继续挖掘,自主学习的点,因此这一阶段放慢学习的进度是必须的。另一方面,这一段时间都是针对学习本身的记录,缺少对学习路径以及心路历程的记录,因此借由本文技术篇幅较少,记录分享出来,供各位参考。
本文我会先介绍tensorboard 及其具体使用方法(在手写数字识别上的实施),不过本次tensorboard的使用分为两个部分第二部分是第一部分的升级版本,可能有些难度,但是很酷,大家可以根据情况学习,暂时无法理解的部分可以先知道,然后暂时放一放,然后是看完本文关于 tensorboard 的信息,你应该做到的点。最后,就是我所说的分享。
希望大家有所参考,各取所需:
- tensorboard代码实现及详解
- 你应该知道、理解及做到的点
- 学习路径以及心路历程的记录
ps:不同于以忘的代码,这次需要注意的是还有很多的附加文件以及需要自己创建的文件夹,所以我会将本文的源码以及配置文件分享在文章的底部,想要在自己的机器上跑起来的朋友一定需要下载,同时代码中DIR定义为项目的绝对路径,大家需要视自己情况修改。
一 、tensorboard代码实现及详解
上代码:
加载MNIST数据,导入所需模块
首先依旧是载入数据集,以及import 必须的模块。
这一次你会发现多出了os模块以及:from tensorflow.contrib.tensorboard.plugins import projector这一句。导入os模块是为了关掉tensorflow在运行过程中的warning具体解释看这里,而第二个是为了实现tensorboard中的个人觉得比较酷的功能,当然暂时可以不理解,知道即可。
# coding: utf-8
import os
from tensorflow.contrib.tensorboard.plugins import projector
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
import time#用于获取迭代运行时间,比较不同方案
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
#加载数据
mnist = input_data.read_data_sets("MNIST_data",one_hot=True)
注意:接下来的代码与以前的代码可能看起来有些不同(其实你仔细看实际上没有变化)
定义部分常量
这一部分的具体解释都在代码注释中,其中注意点是:
- DIR的写法,这里有一个小坑,没有发现可以留言询问
- embedding的意义
- 这里将
#运行次数
max_staps= 50001
image_num = 3000#最高为10000测试数据集总共有这么多的图片
#定义回归模型
keep_prob=tf.placeholder(tf.float32)
DIR = "./"
#定义会话
sess = tf.Session()
#载入图片测试集图片从第零张图片开始一直到3000张图片打包成一个包
embedding = tf.Variable(tf.stack(mnist.test.images[:image_num]),trainable=False,name='embedding')
封装一个记录函数
主要使用tensorflow方法tf.summary.scalar 记录一个值,并且给这个值一个名字,同时在tensorboard中画出直方图记录
这一部分知道即可
def variable_summaries(var):
with tf.name_scope('summaries'):
mean = tf.reduce_mean(var)#计算参数的平均值
tf.summary.scalar('mean',mean)#平均值
with tf.name_scope('stddev'):
stddev = tf.sqrt(tf.reduce_mean(tf.square(var-mean)))#计算参数的标准差
tf.summary.scalar('stddev',stddev)#标准差
tf.summary.scalar('max',tf.reduce_mean(var))#最大值
tf.summary.scalar('min',tf.reduce_min(var))#最小值
tf.summary.histogram('histogram',var)#直方图
构建模型添加隐藏层并加入tensorboard可视化
这一步虽然看起来复杂,但是与上一篇文章的内容确实完全相同。
核心就是tf.name_scope()这个方法,以及在调用了placeholder和Variable方法后面加name='定义的名字'参数。
如果你能成功让本文的代码在你的机器上跑起来,通过对比 (DISTRIBUTIONS)里面的数据,你就会明白tf.name_scope的用法。
with tf.name_scope('input'):
x = tf.placeholder(tf.float32, [None, 784],name='x_input')
y = tf.placeholder(tf.float32, [None, 10],name='y_input') ##输入的真是值的占位符
with tf.name_scope('input_reshape'):
image_reshape_input = tf.reshape(x,[-1,28,28,1])#-1代表一次传进来任意值#维度是1
tf.summary.image('input',image_reshape_input,10)#一共放十张图片
#创建一个简单的神经网络
with tf.name_scope('layer'):
with tf.name_scope("weight_1"):
W1 = tf.Variable(tf.truncated_normal([784, 2000], stddev=0.1),name='W_1') # 初始化时一个非常重要的环节
variable_summaries(W1)
with tf.name_scope("biases_1"):
b1 = tf.Variable(tf.zeros([2000]) + 0.1,name='b_2')
variable_summaries(b1)
with tf.name_scope('wx_plus_b1'):
wx_plus_b1 = tf.matmul(x, W1) + b1
with tf.name_scope('tanh_1'):
L1 = tf.nn.tanh(wx_plus_b1) # 使用双曲正切
L1_drop = tf.nn.dropout(L1, keep_prob) # tensorflow封装好的dropout函数,L1是我们需要控制的神经元,keep_prob是工作的神经元的百分比
# 注意使用dropout后会使模型的训练速度下降
with tf.name_scope("weight_2"):
W2 = tf.Variable(tf.truncated_normal([2000, 1000], stddev=0.1),name='W_2') # 增加隐藏层设置2000个神经元,这里是故意定义一个复杂的神经网络
variable_summaries(W2)
with tf.name_scope('biases_b2'):
b2 = tf.Variable(tf.zeros([1000]) + 0.1,name='b_2') # 期望其出项过度拟合的情况
variable_summaries(b2)
with tf.name_scope('wx_plus_b2'):
wx_plus_b2 = tf.matmul(L1_drop, W2) + b2
with tf.name_scope('tanh_2'):
L2 = tf.nn.tanh(wx_plus_b2)
L2_drop = tf.nn.dropout(L2, keep_prob)
with tf.name_scope("weight_3"):
W3 = tf.Variable(tf.truncated_normal([1000, 10], stddev=0.1),name='W3_output')
variable_summaries(W3)
with tf.name_scope("biases_3"):
b3 = tf.Variable(tf.zeros([10]) + 0.1,name='b3_output')
variable_summaries(b3)
# 注意这里的知识点是tensorflow中矩阵相乘的规则
with tf.name_scope('softmax'):
with tf.name_scope('wx_plus_b3'):
wx_plus_b3 = tf.matmul(L2_drop, W3) + b3
with tf.name_scope('prediction'):
prediction = tf.nn.softmax(wx_plus_b3)
构建评估模型并加入tensorboard可视化
这一部分关于tf,name_scope()内容和上面一部分是一样的。
但是,这一部分有新的tf.summary.scalar('名字',传入参数 )如果你成功打开tensorboard可视化界面,你会在(SCALARS)里面看到你定义的name以及对应的直方图。没错,tf.summary.scalar() 的作用就是在SCALARS里面加入对应的数据流并绘制其直方图。
其余部分与上一篇内容相似。
ps 注意:本篇文章这一部分的梯度下降学习率使用的是0.1,这个数据是经过多次训练学习出来的数据,有兴趣的朋友可以更换这里的优化器(optimizer)或者更改这里的学习率试试看,这也是学习的过程 。
#定义损失函数和优化器
with tf.name_scope('loss'):
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=prediction))
#损失函数
tf.summary.scalar('loss', loss)
with tf.name_scope('train'):
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
with tf.name_scope('accuracy'):
with tf.name_scope('correct_prediction'):
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1)) # 计算预测值和真实值
with tf.name_scope('accuracy'):
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
tf.summary.scalar('accuracy', accuracy)
实话讲,这一部分的代码是我拼凑起来的,但是找遍网上相关的代码以及解释,都还是差强人意,所以就斗胆献上解释,以供大家参考。
这一段代码的内容核心围绕两点:metadata.tsv以及projector.visualize_embeddings图片可视化
首先,metadata.tsv (制表符分隔值 格式文件是一种用于储存数据的文本格式文件,其数据以表格结构储存。每一行储存一条记录。 每条记录的各个字段间以制表符作为分隔。) 知道就好,它用于存储我们训练过程中生成的数据,用来供给可视化,所以围绕这一文件展开的操作有: 打开、写入以及使用tf自带的方法写入数据等等。
其次,这里的projector.visualize_embeddings 图片可视化,使用的是projector\data\mnist_10k_sprite.png 图片,当然对它进行了一定的分割,这些图片就是你最后在tensorboard的PROJECTOR中看到的动态可视化的过程。
#产生metadata文件
if tf.gfile.Exists(DIR+'projector/projector/metadata.tsv'):
tf.gfile.DeleteRecursively(DIR+'projector/projector/metadata.tsv')
with open(DIR+'projector/projector/metadata.tsv','w') as f:#用写的方式去打开这个文件,如果没有这个文件,就会生成这样的一个文件
labels = sess.run(tf.argmax(mnist.test.labels[:],1))#argmax用于求元素最大的标签的位置
for i in range(image_num):
f.write(str(labels[i])+'\n')
#合并所有的summary图像
merged = tf.summary.merge_all()
projector_writer = tf.summary.FileWriter(DIR+'projector/projector',sess.graph)
saver = tf.train.Saver()
config = projector.ProjectorConfig()
embed = config.embeddings.add()
embed.tensor_name = embedding.name
embed.metadata_path = DIR+'projector/projector/metadata.tsv'
embed.sprite.image_path = DIR+'projector/data/mnist_10k_sprite.png'
embed.sprite.single_image_dim.extend([28,28])
projector.visualize_embeddings(projector_writer,config)#图片可视化
迭代训练生成模型
这一部分需要注意有两点:
- run_option 的定义,有兴趣的朋友关于具体内容可以自行搜索
- summary ,_ = ... 在这里的应用,你应该注意道后面的merged参数,仔细将它和前面的参数进行对比,尤其是它的最初的定义,你一定会有所收获。
#Train开始训练
start = time.clock()
sess.run(init)
for i in range(max_staps):
bath_xs, bath_ys = mnist.train.next_batch(100)
run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
run_metadata = tf.RunMetadata()
#注意这里不同于上一部分的是模型需要传入的参数增加了keep_prob(需要运行的神经元的数量)
summary ,_ = sess.run([merged,train_step], feed_dict={x:bath_xs,y:bath_ys,keep_prob:0.7},options=run_options,run_metadata=run_metadata)
projector_writer.add_run_metadata(run_metadata, 'step%03d' % i)
projector_writer.add_summary(summary, i)
if i % 10 == 0:
acc = sess.run(accuracy, feed_dict={x:mnist.test.images, y: mnist.test.labels,keep_prob:1})
print("Iter " + str(i) + ",Testing Accuracy " + str(acc))
end = time.clock()
saver.save(sess,DIR+'projector/projector/a_model.ckpt',global_step=max_staps)
projector_writer.close()
sess.close()
print('Running time: %s Seconds'%int(end-start))#显示代码总的迭代使用时间
print('训练完成')
最后上总代码!:
# coding: utf-8
import os
from tensorflow.contrib.tensorboard.plugins import projector
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
import time#用于获取迭代运行时间,比较不同方案
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
#加载数据
mnist = input_data.read_data_sets("MNIST_data",one_hot=True)
#运行次数
max_staps= 3001
image_num = 3000#最高为10000测试数据集总共有这么多的图片
#定义回归模型
keep_prob=tf.placeholder(tf.float32)
DIR = "C:/Users/Geek/Desktop/tensorflow/手写数字识别csdn博客"
#定义会话
sess = tf.Session()
#载入图片测试集图片从第零张图片开始一直到3000张图片打包成一个包
embedding = tf.Variable(tf.stack(mnist.test.images[:image_num]),trainable=False,name='embedding')
#参数概要
#tensorflow方法tf.summary.scalar 记录一个值,并且给这个值一个名字
def variable_summaries(var):
with tf.name_scope('summaries'):
mean = tf.reduce_mean(var)#计算参数的平均值
tf.summary.scalar('mean',mean)#平均值
with tf.name_scope('stddev'):
stddev = tf.sqrt(tf.reduce_mean(tf.square(var-mean)))#计算参数的标准差
tf.summary.scalar('stddev',stddev)#标准差
tf.summary.scalar('max',tf.reduce_mean(var))#最大值
tf.summary.scalar('min',tf.reduce_min(var))#最小值
tf.summary.histogram('histogram',var)#直方图
with tf.name_scope('input'):
x = tf.placeholder(tf.float32, [None, 784],name='x_input')
y = tf.placeholder(tf.float32, [None, 10],name='y_input') ##输入的真是值的占位符
with tf.name_scope('input_reshape'):
image_reshape_input = tf.reshape(x,[-1,28,28,1])#-1代表一次传进来任意值#维度是1
tf.summary.image('input',image_reshape_input,10)#一共放十张图片
#创建一个简单的神经网络
with tf.name_scope('layer'):
with tf.name_scope("weight_1"):
W1 = tf.Variable(tf.truncated_normal([784, 2000], stddev=0.1),name='W_1') # 初始化时一个非常重要的环节
variable_summaries(W1)
with tf.name_scope("biases_1"):
b1 = tf.Variable(tf.zeros([2000]) + 0.1,name='b_2')
variable_summaries(b1)
with tf.name_scope('wx_plus_b1'):
wx_plus_b1 = tf.matmul(x, W1) + b1
with tf.name_scope('tanh_1'):
L1 = tf.nn.tanh(wx_plus_b1) # 使用双曲正切
L1_drop = tf.nn.dropout(L1, keep_prob) # tensorflow封装好的dropout函数,L1是我们需要控制的神经元,keep_prob是工作的神经元的百分比
# 注意使用dropout后会使模型的训练速度下降
with tf.name_scope("weight_2"):
W2 = tf.Variable(tf.truncated_normal([2000, 1000], stddev=0.1),name='W_2') # 增加隐藏层设置2000个神经元,这里是故意定义一个复杂的神经网络
variable_summaries(W2)
with tf.name_scope('biases_b2'):
b2 = tf.Variable(tf.zeros([1000]) + 0.1,name='b_2') # 期望其出项过度拟合的情况
variable_summaries(b2)
with tf.name_scope('wx_plus_b2'):
wx_plus_b2 = tf.matmul(L1_drop, W2) + b2
with tf.name_scope('tanh_2'):
L2 = tf.nn.tanh(wx_plus_b2)
L2_drop = tf.nn.dropout(L2, keep_prob)
with tf.name_scope("weight_3"):
W3 = tf.Variable(tf.truncated_normal([1000, 10], stddev=0.1),name='W3_output')
variable_summaries(W3)
with tf.name_scope("biases_3"):
b3 = tf.Variable(tf.zeros([10]) + 0.1,name='b3_output')
variable_summaries(b3)
# 注意这里的知识点是tensorflow中矩阵相乘的规则
with tf.name_scope('softmax'):
with tf.name_scope('wx_plus_b3'):
wx_plus_b3 = tf.matmul(L2_drop, W3) + b3
with tf.name_scope('prediction'):
prediction = tf.nn.softmax(wx_plus_b3)
with tf.name_scope('loss'):
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=prediction))#损失函数
tf.summary.scalar('loss', loss)
#tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)
#除去name参数用以指定该操作的name,与方法有关的一共两个参数:
#第一个参数logits:就是神经网络最后一层的输出,未经过soft_max
#第二个参数labels:实际的标签,需要是one-hot格式
#定义损失函数和优化器
with tf.name_scope('train'):
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
#评估训练好的模型
#计算模型在测试集上的准确率
#tf.cast作用:布尔型转化为浮点数,并且取平均值,得到准确率
with tf.name_scope('accuracy'):
with tf.name_scope('correct_prediction'):
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1)) # 计算预测值和真实值
with tf.name_scope('accuracy'):
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
tf.summary.scalar('accuracy', accuracy)
#产生metadata文件
if tf.gfile.Exists(DIR+'projector/projector/metadata.tsv'):
tf.gfile.DeleteRecursively(DIR+'projector/projector/metadata.tsv')
with open(DIR+'projector/projector/metadata.tsv','w') as f:#用写的方式去打开这个文件,如果没有这个文件,就会生成这样的一个文件
labels = sess.run(tf.argmax(mnist.test.labels[:],1))#argmax用于求元素最大的标签的位置
for i in range(image_num):
f.write(str(labels[i])+'\n')
#合并所有的summary
merged = tf.summary.merge_all()
projector_writer = tf.summary.FileWriter(DIR+'projector/projector',sess.graph)
saver = tf.train.Saver()
config = projector.ProjectorConfig()
embed = config.embeddings.add()
embed.tensor_name = embedding.name
embed.metadata_path = DIR+'projector/projector/metadata.tsv'
embed.sprite.image_path = DIR+'projector/data/mnist_10k_sprite.png'
embed.sprite.single_image_dim.extend([28,28])
projector.visualize_embeddings(projector_writer,config)#图片可视化
init = tf.global_variables_initializer()
#Train开始训练
start = time.clock()
sess.run(init)
for i in range(max_staps):
bath_xs, bath_ys = mnist.train.next_batch(100)
run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
run_metadata = tf.RunMetadata()
#注意这里不同于上一部分的是模型需要传入的参数增加了keep_prob(需要运行的神经元的数量)
summary ,_ = sess.run([merged,train_step], feed_dict={x:bath_xs,y:bath_ys,keep_prob:0.7},options=run_options,run_metadata=run_metadata)
projector_writer.add_run_metadata(run_metadata, 'step%03d' % i)
projector_writer.add_summary(summary, i)
if i % 10 == 0:
acc = sess.run(accuracy, feed_dict={x:mnist.test.images, y: mnist.test.labels,keep_prob:1})
print("Iter " + str(i) + ",Testing Accuracy " + str(acc))
end = time.clock()
saver.save(sess,DIR+'projector/projector/a_model.ckpt',global_step=max_staps)
projector_writer.close()
sess.close()
print('Running time: %s Seconds'%int(end-start))
print('训练完成')
训练完成后,cmd进入第一级的projector目录输入(详见我的另一篇文章:【TensorBoard】如何启动tensorboard详解)
tensorboard --logdir=projector
二 、你应该知道、理解及做到的点
- 你应该知道,tensorboard的作用(为什么需要可视化、以及它的实际应用)这一点我没有在文章中说明,需要大家自行搜索。
- 你应该理解,tensorboard各个部分的显示内容的作用,这一点可能会有一些难度,但是个人觉得是必须的部分。
- 你应该做到:让本文的代码在你自己的机器上成功跑起来。成功定义:可以通过(http://localhost:6006/) 打开tensorboard面板
三 、学习路径以及心路历程的记录
现阶段作者还是新大二材料学生一枚,但是对于人工智能有很强的兴趣,加上python功底还算可以,以前做过一点scrapy爬虫和数据分析。所以,毅然的入了tensorflow的坑。
说一说目前的学习状态
暑假早晨8:00起床洗漱吃饭以后,给自己20分钟时间进入状态,开始通过百度云网盘的课程学习人工智能的算法部分,当然由于数学功底还是有所欠缺(高数8学分),需要恶补一些数学知识。这一过程有时候会开小差,看看油管视频什么的(一般看华农兄弟和美食作家王刚,小时候在城中村长大,比较喜欢他们的感觉)。
中午会去食堂吃饭(没错,我暑假留校),然后看情况会睡个午觉,主要是保持大脑清醒(学习已经非常枯燥了,怎么还能亏待身体?对吧)然后就是两个小时的打杂时间,这一部分会干一些自己其他的事,比如回回消息,刷刷新闻,偶尔会良心发泄看看英语(捂脸),目前最开心的就是看到自己的文章被点赞或者回答被采纳。
下午会开始写一些自己的东西,比如前一段时间的(算法或者tensorflow)学习笔记,或者突然自己的感想,大概会花费2-4个小时,期间累了会听听播客的(故事FM、狗熊有话说)然后吃饭、keep上跑个“法特莱跑”然后回宿舍擦擦汗平静下来,继续写东西。
写完以后基本就是休息时间了,这一段时间我会拿平板看看书,不过看情况,也可能会看美剧(毒枭1-3季),看看自己的大脑待机情况,书也不会定死,有可能是小说也有可能是工具类的书,然后累了就睡或者消遣消遣,比较随意。
一个前ACM银奖大佬给我说学习一定要形成自己的程式(个人理解就是模式与模型吧),然后一直运行,可能中间有几次中断,但是记得就好,不要过多深究,别和自己过不去,大佬今年拿到了中科大的保研,感觉大佬是一个很理性优雅的人(早就觉得程序员更像是艺术家或者是哲学家了,这是《黑客与画家》里面的观点)。
我觉得目前的学习状态就挺适合的,比较温和,当然开学后可能需要有所改进,也希望本文对你有所帮助,谢谢大家。
项目源码以及配套环境
链接: https://pan.baidu.com/s/10nw_hIFFIsdNENTq9RPh5g 提取码: 2333
ps:相关文章
最后,一如既往的:
我希望大家有问题可以私信问我,我会很愿意帮你解答,毕竟,这就是在以一种很有效率的方式帮助我的学习,加深我对它的理解。
希望本文对你有所帮助,接下来我会更新进一步优化加入卷积神经网络将识别准确率提升到99%以上 以及 关于若干tensorflow基础操作的文章。