TensorFlow笔记
安装TensorFlow
首先TensorFlow官网有详细的说明
linux环境比较简单,以下记录是关于Windows的
虽然官网有详细的说明,但实际还是会遇到问题的,如果想做一些改进问题就会更多了,以下是我的安装记录
安装Python
注意一定要安装64位版本,比如我一不小心就装了个32位版本,只好卸载重新安装
python -v
….
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 23 2018, 23:31:17) [MSC v.1916 32 bit (Intel)] on win32
点击这里下载Python3.6.8 64位版本
安装Visual Studio Code
强烈推荐安装,可以在IDE里编写、调试代码
该IDE里提供的Terminal也比Windows自带的cmd好用,后续地命令可以在这个工具里执行
安装虚拟环境(官方也说了推荐这种方式)
- 首先进入想要创建虚拟环境的目录
- 执行以下命令,在该目录下创建名为venv的虚拟环境,后续所有包都会安装在这个目录下
1
2pip install virtualenv
virtualenv --system-site-packages -p python ./venv官方提供的命令会报错,命令中不能使用python3
连续执行以下几个命令,具体可参考官方说明
1
2
3
4
5
6
7.\venv\Scripts\activate #激活虚拟环境
pip install --upgrade pip #更新&安装pip
pip install --upgrade tensorflow #更新&安装tensorflow
测试会用到的一些包
pip install matplotlib
pip install opencv-python
pip install tqdm如果import cv2报错,则可以换成其它版本
1
2pip uninstall opencv-python
pip install opencv-python==3.4.5.20
设置VScode使用python虚拟环境
在VScode的扩展面板里搜索并安装”Python for VScode“
打开设置(在界面左下角),搜索python.pythonPath
修改Workspace Settings,指定刚才的虚拟环境python的路径,比如
E:\DL\venv\Scripts\python.exe
修改完成后,需要重启VScode
基础知识
shape理解
shape表示张量各维度的数据长度,比如shape=(1,2,3),3个数字表示3维
第1个维度数字是1,表示只第1个维度的数据长度是1
第2个维度数字是2,表示只第2个维度的数据长度是2
第3个维度数字是3,表示只第3个维度的数据长度是3
1
2[x, y] #只有一个维度,长度是2,所以这个张量的shape=(2,), 或者(2,0)
[[[x,y,z], [x,y,z]]] #这个张量的shape=(1,2,3)
CNN原理
https://www.jianshu.com/p/fe428f0b32c1
注:多通道卷积:将每个通道的卷积结果相加,得到1个feature map,而不是多个feature map
如像素大小12x12, 3通道(rgb)对应的shape为12x12x3,与8个3x3的卷积核卷积后得到的shape为:10x10x8
tf函数
定义变量相关的函数
tf.placeholder
定义占位符
1 | x = tf.placeholder("float",[None,784]) |
定义一个输入x,有784个维度,但具体的数据暂未给出
tf.Variable
1 | W = tf.Variable(<initial-value>, name=<optional-name>) |
用于生成一个初始值为initial-value
的变量。必须指定初始化值
举例:
1 | W = tf.Variable(tf.zeros([784,10])) |
定义2个矩阵变量,分别是权重和偏置,训练过程就是不段变换这2个矩阵\
tf.get_variable
1 | W = tf.get_variable(name, shape=None, dtype=tf.float32, initializer=None, |
获取已存在的变量(要求不仅名字,而且初始化方法等各个参数都一样),如果不存在,就新建一个。
可以用各种初始化方法,不用明确指定值。
tf.variable_scope
设置变量名
1 | with tf.variable_scope('mynet'): |
定义的变量名是:mynet/b
tf.zeros_like
1 | tf.zeros_like(tensor, dtype=None, name=None, optimize=True) |
创建一个所有元素都设置为零的张量,张量的类型与tensor相同
tf.truncated_normal
产生随机正太分布
变量操作相关的函数
tf.matmu
矩阵乘法
softmax:回归函数,将给定的输入x,权重W和偏置b计算所得值回归到[0-1]的范围
1 | y = tf.nn.softmax(tf.matmul(x,W) + b) |
tf.reduce_sum
累加和
以下代码为求交叉熵
1 | cross_entropy = -tf.reduce_sum(y_*tf.log(y)) |
tf.cast
1 | cast(x, dtype, name=None) |
将x的数据格式转化成dtype.例如,原来x的数据格式是bool,
那么将其转化成float以后,就能够将其转化成0和1的序列。反之也可以
tf.reduce_mean
求平均值
tf.squeeze
1 | squeeze(input,axis=None,name=None,squeeze_dims=None) |
该函数返回一个张量,这个张量是将原始input中所有维度为1的那些维都删掉的结果axis
可以用来指定要删掉的为1的维度,此处要注意指定的维度必须确保其是1,否则会报错
例子:
1 | # 't' 是一个维度是[1, 2, 1, 3, 1, 1]的张量 |
tf.slice
这个函数的作用是从输入数据input中提取出一块切片
切片的尺寸是size,切片的开始位置是begin。
切片的尺寸size表示输出tensor的数据维度,其中size[i]表示在第i维度上面的元素个数。
tf.concat
1 | tf.concat(values, axis, name='concat') |
其中:
values应该是一个tensor的list或者tuple。
axis则是我们想要连接的维度。
tf.concat返回的是连接后的tensor。
比如,如果list中的tensor的shape都是(2,2,2),如果此时的axis为2,即连接第三个维度,那么连接后的shape是(2,2,4),具体表现为对应维度的堆砌。例子如下:
1 | t1 = [[[1, 2], [2, 3]], [[4, 4], [5, 3]]] |
输出结果为
1 | <tf.Tensor 'concat_2:0' shape=(2, 2, 4) dtype=int32> |
再sess.run()一下拿出具体tensor为:
1 | [[[ 1, 2, 7, 4], |
可见符合(2,2,4)的shape。
tf.train.string_input_producer
这个函数需要传入一个文件名list,系统会自动将它转为一个文件名队列。
此外tf.train.string_input_producer还有两个重要的参数,一个是num_epochs,它就是我们上文中提到的epoch数。另外一个就是shuffle,shuffle是指在一个epoch内文件的顺序是否被打乱。
summary
tensorboard 作为一款可视化神器,可以说是学习tensorflow时模型训练以及参数可视化的法宝。
而在训练过程中,主要用到了tf.summary()的各类方法,能够保存训练过程以及参数分布图并在tensorboard显示。
参考TensorFlow框架(2)之TensorBoard详解
TFRecord
Tfrecord是tensorflow官方推荐的训练数据存储格式,它更容易与网络应用架构相匹配。
Tfrecord本质上是二进制的Protobuf数据,因而其读取、传输的速度更快。Tfrecord文件的每一条记录都是一个tf.train.Example
的实例。
使用tfrecord文件格式的另一个好处是数据结构统一,屏蔽了底层的数据结构。在类似于图像分类的任务中,原始数据是各个图片以单独的小文件的形式存在,label又以文件夹的形式存在,处理这样的数据比较麻烦,比如随机打乱,分batch等操作;而所有原始数据转换为一个或几个单独的tfrecord文件后处理起来就会比较方便。
生成tfrecord文件
何把原始数据转换为tfrecord文件格式,请参考下面的代码片段:
1 | def _bytes_feature(value): |
使用tfrecord文件
- 定义与保存文件时对应的解析文件方法
1 | def parse_exmp(serial_exmp): |
使用TFRecordDataset读取tfrecord文件
1
2
3
4
5
6
7
8
9
10def get_tf_data():
'''读取tfrecord数据'''
dataset = tf.data.TFRecordDataset([tf_filename1, tf_filename2])
dataset = dataset.map(parse_exmp)
dataset = dataset.shuffle(1000)
dataset = dataset.repeat(1).batch(batch_size)
iterator = dataset.make_one_shot_iterator()
one_element = iterator.get_next()
return one_element使用session获取实际的数据
1
2
3
4
5
6
7
8sess = tf.Session()
while(True):
try:
result = sess.run(one_element)
print(result[0], result[1])
except tf.errors.OutOfRangeError:
print("end!")
break
tf.data的使用
参考:https://zhuanlan.zhihu.com/p/38421397
模型的保存与恢复(Saver)
将训练好的模型参数保存起来,以便以后进行验证或测试,这是我们经常要做的事情。tf里面提供模型保存的是tf.train.Saver()模块。
模型保存,先要创建一个Saver对象:如
1 | saver=tf.train.Saver() |
在创建这个Saver对象的时候,有一个参数我们经常会用到,就是 max_to_keep 参数,这个是用来设置保存模型的个数,默认为5,即 max_to_keep=5,保存最近的5个模型。如果你想每训练一代(epoch)就想保存一次模型,则可以将 max_to_keep设置为None或者0,如:
1 | saver=tf.train.Saver(max_to_keep=0) |
但是这样做除了多占用硬盘,并没有实际多大的用处,因此不推荐。
当然,如果你只想保存最后一代的模型,则只需要将max_to_keep设置为1即可,即
1 | saver=tf.train.Saver(max_to_keep=1) |
创建完saver对象后,就可以保存训练好的模型了,如:
1 | saver.save(sess,'model/mnist.ckpt',global_step=step) |
生成的文件在model目录下,文件名的前缀是1
2
3
4
5
6
7
8
9
10
11
12
第一个参数sess,这个就不用说了。第二个参数设定保存的路径和名字,第三个参数将训练的次数作为后缀加入到模型名字中。
> saver.save(sess, 'my-model', global_step=0) ==> filename: 'my-model-0'
> ...
> saver.save(sess, 'my-model', global_step=1000) ==> filename: 'my-model-1000'
模型的恢复用的是restore()函数,它需要两个参数restore(sess, save_path),save_path指的是保存的模型路径。我们可以使用tf.train.latest_checkpoint()来自动获取最后一次保存的模型。如:
```python
model_file=tf.train.latest_checkpoint('model/')
saver.restore(sess,model_file)
PB文件
生成pb文件
tf.graph_util.convert_variables_to_constants函数,会将计算图中的变量取值以常量的形式保存。
1 | import tensorflow as tf |
分析pb文件
使用Tensorboard分析pb文件,有两种方法
方法一:
- 利用pb文件恢复计算图
- 利用Tensorboard查看计算图的结构
方法二
- 利用tensorflow提供的tools里的import_pb_to_tensorboard.py这个工具,但是这个工具linux版本的tensorflow没有安装(Win下默认安装),需要的可以去下载[https://github.com/tensorflow/tensorflow/tree/master/tensorflow/python/tools]
方法一
- 从pb文件中恢复计算图
1 | import tensorflow as tf |
- 利用Tensorboard查看计算图
在命令行运行以下命令,启动Tensorboard
1 | #命令行运行里执行 |
方法二
利用tools里面的import_pb_to_tensorboard.py工具
1 | 命令行 |
或者
1 | import sys |
经过查看源码,第二种方法其实是对第一种方法的包装。
两种方法是一致的,只不过第二种方法更加便捷。
示例代码
1 | #coding=UTF-8 |
参考链接
学习过程中参考了以下文章
TensorFlow框架(1)之Computational Graph详解
TensorFlow框架(2)之TensorBoard详解
TensorFlow框架(3)之MNIST机器学习入门
TensorFlow框架(4)之CNN卷积神经网络详解