Tensorflow-低级接口说明(转)

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

信息板提供了视觉化的计算效果,使用步骤:

  1. 把计算图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

最简单的训练流程包括:

  1. 构建计算图
    • 定义数据
    • 定义模型
    • 损失函数
    • 优化方法
  2. 初始化
  3. 多次训练
  4. 进行预测

下面来看一段完整的代码,尝试根据给定的线性数据推算线性函数模型并进行预测:

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})

探索人工智能的新边界

如果您发现文章错误,请不吝留言指正;
如果您觉得有用,请点喜欢;
如果您觉得很有用,感谢转发~



作者:zhyuzh3d
链接:https://www.jianshu.com/p/52eb3e90706e
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

posted @ 2019-05-22 10:08  大汤姆  阅读(336)  评论(0编辑  收藏  举报