Tensorflow-低级接口说明-LowLevelApis-翻译整理
这篇文章介绍使用Tensorflow'低级api编程的方法,包括:
- 管理你的tensorflow程序(运算图graph)和运行时(会话session),不依赖Estimators
- 使用tf.Session运行tensorflow操作
- 在低级编程中使用高级元素(dataset,layer,feature columns)
- 搭建自定义的train loop训练周期,不依赖于Estimators
推荐优先使用高级接口。了解低级接口的意义在于:
- 实验和调试更加简单
- 更好的理解高级接口的运作模式
张量值
张量tensor是tensorflow的核心数据单元,它是由数值构成的多维数组。张量的等级rank就是维度,整数元组shape表示了每个维度的长度。
3. # rank 0 ,shape [],标量 [1., 2., 3.] # rank 1,shape [3],向量 [[1., 2., 3.], [4., 5., 6.]] # rank 2,shape [2, 3],2x3矩阵 [[[1., 2., 3.]], [[7., 8., 9.]]] # rank 3,shape [2, 1, 3],2行1列3层深
维数rank等于方括号的层数,等于shape内数字个数。
Tensorflow使用Numpy arrays表示张量值。
浏览Tensorflow核心
Tensorflow核心编程就是两个事情:
- 构建计算图tf.graph
- 使用tf.Session执行计算图
Graph
计算图computational graph就是一系列Tensorflow操作单元的排列组合。
计算图由两部分构成:
- ops,操作。这是计算图的节点,它消耗张量,也产生张量。
- tensor,张量。这是图的边线edges,它展示了数值如何在图内流动。绝大多数tensorflow函数都返回tf.Tensor。
tf.Tensor并不包含数值,它只是控制计算图里面的元素
import tensorflow as tf a = tf.constant(3.0, dtype=tf.float32) b = tf.constant(4.0) #也是tf.float32 total = a + b print(a) print(b) print(total)
运行得到的不是7.0,而是三个张量,因为这里只是构建了计算图graph,而没有运行它。
Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32) Tensor("add:0", shape=(), dtype=float32
graph中的每个操作都有唯一自动赋予的名字,比如上面的'add:0',如果有更多add操作,就会是'add_1:0','add_2:0'等。
Tensorboard
信息板提供了视觉化的计算效果,使用步骤:
- 把计算图graph保存到Tensorboard的摘要文件,这将产生一个event事件文件。
import os import tensorflow as tf
#存储event文件夹
dir_path = os.path.dirname(os.path.realpath(__file__)) sum_path=os.path.join(dir_path,'models')
#不要使用斜杠 #构造计算图
a = tf.constant(3.0, dtype=tf.float32) b = tf.constant(4.0) total = a + b
#写入tensorboard该要
writer = tf.summary.FileWriter(sum_path) writer.add_graph(tf.get_default_graph())
#运行图
sess=tf.Session() sess.run(total)
运行上面的代码,将在.py所在文件夹内产生一个models文件夹,文件夹里面又一个events开头的文件,里面记录着tensorflow的运行情况,然后命令行cd进入当.py所在文件,执行以下命令启动tensorboard服务(按ctrl+C两次退出):
tensorboard --logdir models
然后打开浏览器,输入地址http://localhost:6006/就打开了Tensorboard页面,点击顶部的GRAPHS可以看到我们的加法运算操作,类似下图
Session
建造计算图graph之后,必须使用会话```session=tf.Session()``来运行它。如果说graph是.py文件,那么session就是让它变为可执行程序。
当使用session.run()来运行最终输出的张量节点的时候,tensorflow会自动反向跟踪整个graph并计算所有节点,如上面的代码中,最终输出是7.0。
也可以一次运行run多个张量:
import tensorflow as tf a = tf.constant(3.0, dtype=tf.float32) b = tf.constant(4.0) total = a + b sess=tf.Session() v=sess.run({'ab':(a,b),'total':total}) print(v)
得到一个字典:
{'ab': (3.0, 4.0), 'total': 7.0}
同样的graph使用tf.Session().run()都是全新的运算,可能得到不同的结果,例如:
import tensorflow as tf sess=tf.Session() vec = tf.random_uniform(shape=(3,))
out1 = vec + 1 out2 = vec + 2
print(sess.run(vec))
print(sess.run(vec))
print(sess.run(out1))
print(sess.run(out2))
print(sess.run((out1, out2)))
输出不同的随机值,注意((out1,out2))的结果:
[0.82387817 0.65216887 0.32529306]
[0.10036051 0.535251 0.38202 ]
[1.2352179 1.8258253 1.4338707]
[2.6720245 2.1600003 2.9119837]
(array([1.4428363, 1.3376999, 1.7375625],
dtype=float32),
array([2.4428363, 2.3377 , 2.7375627],
dtype=float32))
有些tensorflow函数返回的不是tf.Tensor而是tf.Operations,运行run一个operation操作会返回None。但可以使用这个技巧获得一些特别作用,比如:
init = tf.global_variables_initializer()
sess.run(init)
Feeding
标准格式下,graph总是产生相对固定的运行结果,这没有什么意义。但是graph可以接收外部的placeholder传入的变化的输入,placeholder就像一个promise承诺稍后提供数据,像一个函数那样。
import tensorflow as tf sess=tf.Session()
x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)
z = x + y
print(sess.run(z, feed_dict={x: 3, y: 4.5}))
print(sess.run(z, feed_dict={x: [1, 3], y: [2, 4]}))
输出
7.5
[3. 7.]
这段代码可以看作定义了一个函数,然后运行了它:
def zfunc(x,y): return x+y print(zfunc(3,4.5))
Datasets
Placeholder用于简单的实验,Datasets才是将数据输入模型的更好方法。
要从数据集datasets得到一个可运行的tf.tensor,需要先把它转为tf.data.Iterator迭代器,然后使用迭代器的get_next()方法。
如下示例代码,使用了try...catch...捕获异常,避免超过终点的错误:
import tensorflow as tf sess=tf.Session() my_data = [ [0, 1,], [2, 3,], [4, 5,], [6, 7,], ]
dataset = tf.data.Dataset.from_tensor_slices(my_data)
next_item = dataset.make_one_shot_iterator().get_next()
while True:
try:
print(sess.run(next_item))
except tf.errors.OutOfRangeError: break
Layers
可训练的模型必须能够改变graph的值,从而在在相同输入数据的时候获得新的输出。层Layer是推荐的方法,用来像graph里面添加可训练的参数。
Layers将变量和操作打包。比如密集连接层densely-connected-layer为所有的输入执行加权求和操作到每个输出,以及可选的激活函数activation function,由图层对象管理连接权重weighted和偏移值bias。
层的使用流程包括:
- 创建
- 初始
- 运行
import tensorflow as tf sess=tf.Session()
#创建一个节点的密集层,传入n个三元数组,units=2输出二维数组
x = tf.placeholder(tf.float32, shape=[None, 3])
linear_model = tf.layers.Dense(units=2) y = linear_model(x)
#初始化所有变量 init = tf.global_variables_initializer() sess.run(init)
#运行层,通过x传入数据
v=sess.run(y, {x: [[1, 2, 3],[4, 5, 6]]}) print(v)
注意,tf.global_variables_inistializer方法只初始化以上的graph,所以应该在graph建造完成之后运行。
打印出的结果
[[-2.037472 3.9676275] [-5.741477 10.678923 ]]
每个layer在创建的时候可以直接传递placeholder,比如上面的代码可以简化成下面
import tensorflow as tf sess=tf.Session()
x = tf.placeholder(tf.float32, shape=[None, 3])
y = tf.layers.dense(x, units=1)
#简写
init = tf.global_variables_initializer() sess.run(init)
print(sess.run(y, {x: [[1, 2, 3], [4, 5, 6]]}))
这次会打印出两个1元数组
[[-3.4608526] [-8.070822 ]]
Feature Columns
可以使用tf.feature_column.input_layer快速实验特征列,它只接受dense column密集列,如果是分类列Catergorical column,就必须经过指示列tf.feature_column.indicator_column包裹,示例代码如下。
import tensorflow as tf sess=tf.Session()
#特征数据
features = { 'sales' : [[5], [10], [8], [9]], 'department': ['sports', 'sports', 'gardening', 'gardening']}
#特征列
department_column = tf.feature_column.categorical_column_with_vocabulary_list( 'department', ['sports', 'gardening'])
department_column = tf.feature_column.indicator_column(department_column)
#组合特征列
columns = [ tf.feature_column.numeric_column('sales'), department_column ]
#输入层(数据,特征列)
inputs = tf.feature_column.input_layer(features, columns)
#初始化并运行
init = tf.global_variables_initializer() sess.run(tf.tables_initializer()) sess.run(init) v=sess.run(inputs)
print(v)
上面代码输出如下结果,可以看到input输入层将每个商品的features转为3维矢量,前两个0,1独热表示分类运动sport或园艺gardening,第三个数字表示销售数量salse。
[[ 1. 0. 5.] [ 1. 0. 10.] [ 0. 1. 8.] [ 0. 1. 9.]]
Training
最简单的训练流程包括:
-
构建计算图
- 定义数据
- 定义模型
- 损失函数
- 优化方法
- 初始化
- 多次训练
- 进行预测
下面来看一段完整的代码,尝试根据给定的线性数据推算线性函数模型并进行预测:
import tensorflow as tf
#两个输入数据,yi=-xi+1
xi =[[1,], [2,], [3,], [4,]] yi =[[0,], [-1,], [-2,], [-3,]]
#两个浮点占位器,不能使用整数,那将产生稀疏值
x = tf.placeholder(tf.float32, shape=[None, 1])
y_true = tf.placeholder(tf.float32, shape=[None, 1])
#定义模型,一个线性的密集层
y_pred = tf.layers.dense(x, units=1)
#设定损失函数,使用均方差,MSE=sum(squar(x-x'))/n
loss = tf.losses.mean_squared_error(labels=y_true, predictions=y_pred)
#设定优化器,梯度下降优化器
optimizer = tf.train.GradientDescentOptimizer(0.1) train = optimizer.minimize(loss)
#初始化以上全部变量
init = tf.global_variables_initializer()
sess = tf.Session() sess.run(init)
#进行训练 for i in range(1000): sess.run((train, loss),feed_dict={x:xi,y_true:yi})
#进行预测,正确结果应该输出-11
print(sess.run(y_pred,feed_dict={x:[[12,]],y_true:[[None]]}))
输出结果,非常接近我们正确值了。
[[-10.999997]]
如果降低训练次数1000到100,或者将优化器梯度下降参数从0.1降为0.01,那么都将产生稍大的误差。
本篇小结
- 张量值的等级rank和形状shape
-
Tensorflow的核心:
- 计算图graph:ops,tensor
- 会话运行时session:run,init
- 信息板tensorboard:summary,event文件
- 喂食数据feed:placeholder,feed_dict
- 数据集Datasets:iterator,get_next()
-
层Layer:
- 创建
- 初始化
- 运行
-
特征列Feature columns:
- input_layer(features,columns)
- indicator_column(categorical_column)
-
训练Train:features-graph-init-train-predict
sess.run((train, loss),feed_dict={x:xi,y_true:yi})