keepython 发表于 2019-8-21 22:31

tensorflow自主学习入门-从零开始篇(四)tensorflow手写数字识别加入tensorboard...

借手写数字识别入门tensorflow已经有一段时间了,实话说经过初步入门的阵痛以后,学习tensorflow已经开始顺水推舟、有条不紊的进行开来,这期间有了一些感悟,记录下来,也希望对大家有所帮助。
***
本片文章依然是接着tensorflow的这一系列,记录整理学习轨迹。
不过,不同于上面的三篇文章,本文的内容比较的少,只是记录了使用tensorboard来实现可视化的过程。具体原因是,一方面,我认为对于tensorflow的学习应该建立在知道与部分理解的基础上来进行的,相信到目前为止,依然会对已经实现的功能有所困惑,即使没有困惑,已经实现的代码肯定有可以继续挖掘,自主学习的点,因此这一阶段放慢学习的进度是必须的。另一方面,这一段时间都是针对学习本身的记录,缺少对学习路径以及心路历程的记录,因此借由本文技术篇幅较少,记录分享出来,供各位参考。
***
本文我会先介绍tensorboard 及其具体使用方法(在手写数字识别上的实施),不过本次tensorboard的使用分为两个部分第二部分是第一部分的升级版本,可能有些难度,但是很酷,大家可以根据情况学习,暂时无法理解的部分可以先知道,然后暂时放一放,然后是看完本文关于 tensorboard 的信息,你应该做到的点。最后,就是我所说的分享。
希望大家有所参考,各取所需:

1. **tensorboard代码实现及详解**
2. **你应该知道、理解及做到的点**
3.学习路径以及心路历程的记录


ps:不同于以忘的代码,这次需要注意的是还有很多的附加文件以及需要自己创建的文件夹,所以我会将本文的源码以及配置文件分享在文章的底部,想要在自己的机器上跑起来的朋友一定需要下载,同时代码中DIR定义为项目的绝对路径,大家需要视自己情况修改。



***

## 一 、tensorboard代码实现及详解
上代码:
***
##### 加载MNIST数据,导入所需模块
首先依旧是载入数据集,以及import 必须的模块。
这一次你会发现多出了os模块以及:*from tensorflow.contrib.tensorboard.plugins import projector*这一句。导入os模块是为了关掉tensorflow在运行过程中的warning具体解释[看这里](https://blog.csdn.net/gaoyong0519/article/details/54615309),而第二个是为了实现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)
```
注意:接下来的代码与以前的代码可能看起来有些不同(其实你仔细看实际上没有变化)
***
##### 定义部分常量
这一部分的具体解释都在代码注释中,其中注意点是:

1. DIR的写法,这里有一个小坑,没有发现可以留言询问
2. embedding的意义
3. 这里将

```
#运行次数
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, ,name='x_input')
    y = tf.placeholder(tf.float32, ,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(, stddev=0.1),name='W_1')# 初始化时一个非常重要的环节
      variable_summaries(W1)
    with tf.name_scope("biases_1"):
      b1 = tf.Variable(tf.zeros() + 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(, stddev=0.1),name='W_2')# 增加隐藏层设置2000个神经元,这里是故意定义一个复杂的神经网络
      variable_summaries(W2)
    with tf.name_scope('biases_b2'):
      b2 = tf.Variable(tf.zeros() + 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(, stddev=0.1),name='W3_output')
      variable_summaries(W3)
    with tf.name_scope("biases_3"):
      b3 = tf.Variable(tf.zeros() + 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文件用以实现最酷部分功能
实话讲,这一部分的代码是我拼凑起来的,但是找遍网上相关的代码以及解释,都还是差强人意,所以就斗胆献上解释,以供大家参考。

这一段代码的内容核心围绕两点: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)+'\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()
projector.visualize_embeddings(projector_writer,config)#图片可视化
```
***
##### 迭代训练生成模型
这一部分需要注意有两点:

1. run_option 的定义,有兴趣的朋友关于具体内容可以自行搜索
2. 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(, 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, ,name='x_input')
    y = tf.placeholder(tf.float32, ,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(, stddev=0.1),name='W_1')# 初始化时一个非常重要的环节
      variable_summaries(W1)
    with tf.name_scope("biases_1"):
      b1 = tf.Variable(tf.zeros() + 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(, stddev=0.1),name='W_2')# 增加隐藏层设置2000个神经元,这里是故意定义一个复杂的神经网络
      variable_summaries(W2)
    with tf.name_scope('biases_b2'):
      b2 = tf.Variable(tf.zeros() + 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(, stddev=0.1),name='W3_output')
      variable_summaries(W3)
    with tf.name_scope("biases_3"):
      b3 = tf.Variable(tf.zeros() + 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)+'\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()
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(, 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详解](https://blog.csdn.net/weixin_43745588/article/details/99580090))

```
tensorboard --logdir=projector
```

***
## 二 、你应该知道、理解及做到的点

1. 你应该知道,tensorboard的作用(为什么需要可视化、以及它的实际应用)这一点我没有在文章中说明,需要大家自行搜索。
2. 你应该理解,tensorboard各个部分的显示内容的作用,这一点可能会有一些难度,但是个人觉得是必须的部分。
3. 你应该做到:让本文的代码在你自己的机器上成功跑起来。成功定义:可以通过(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:[相关文章](https://gaussic.github.io/2017/08/16/tensorflow-tensorboard/)
***
最后,一如既往的:
我希望大家有问题可以私信问我,我会很愿意帮你解答,毕竟,这就是在以一种很有效率的方式帮助我的学习,加深我对它的理解。

希望本文对你有所帮助,接下来我会更新进一步优化加入卷积神经网络将识别准确率提升到99%以上 以及 关于若干tensorflow基础操作的文章。

xymoke 发表于 2019-8-21 22:41

授人以渔的都得赞

gada888 发表于 2019-8-21 23:14

千言万语,突然不知从哪开口。但AI的趋势是去大项目化,各方大公司都加大押注在单片机AI模块上。便携式AI项目会飞起。这样看来,你的单纯从软件角度考虑AI就有点偏。

pob777 发表于 2019-8-25 16:14

能解释下a = tf.ones()里面的1,5,5,3的含义么??

chunhwa 发表于 2019-11-3 16:15

最近一直在找这方面的资料。非常谢谢!

tytyol 发表于 2020-11-30 20:26

楼主,源码的链接还有吗

buge163 发表于 2020-12-8 11:49

感谢分享
页: [1]
查看完整版本: tensorflow自主学习入门-从零开始篇(四)tensorflow手写数字识别加入tensorboard...