Tensorflow入门解读

参考:https://www.tensorflow.org/get_started/get_started


API分两类:
TensorFlow Core:适合细粒度的控制模型。
高层API:如 tf.contrib.learn,是对core的封装,更好用。但contrib目前不稳定。


TensorFlow程序分两块:1)构造计算图 2)运行计算图
计算图由节点和边组成,程序不会刻意构造边。
节点包括:常量节点,操作节点,占位符节点,变量节点等。
例:
node1 = tf.constant(3.0, dtype=tf.float32)
node2 = tf.constant(4.0) # also tf.float32 implicitly
print(node1, node2)
输出:Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32)
Const指出这是个常量节点。
例:
node3 = tf.add(node1, node2)
print("node3: ", node3)
输出:node3:  Tensor("Add:0", shape=(), dtype=float32)
Add指出这是一个操作节点。
节点不是值,节点只有经过计算后才能得到值。如何计算?用session.run()。
例:
sess = tf.Session()
print("sess.run(node3): ",sess.run(node3))
输出:sess.run(node3):  7.0
通得session.run()可以得到任意节点的计算值。
TensorBoard可以看到计算图,如何使用以后再讲。
占位符输入与运算符重载:
例:
a = tf.placeholder(tf.float32)
print(a)
输出:Tensor("Placeholder:0", dtype=float32)
可见:Placeholder是第三类节点。
例:
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b
print(adder_node)
输出:Tensor("add:0", dtype=float32)
可见:加号重载了tf.add()方法,也是一个操作节点,输出区别只有把Add换成了add。
例:
print(sess.run(a, {a: [1,3]}))
print(sess.run(adder_node, {a: 3, b:4.5}))
print(sess.run(adder_node, {a: [1,3], b: [2, 4]}))
输出:
[ 1.  3.]
7.5
[ 3.  7.]
对run的第二个参数的解释:第二个参数是feed_dict,它的作用是映射图元素到值。如{a: 3, b:4.5}把图元素a映射到值3。经过run()计算后的值的shape,与第一个参数相同。如a被映射到[1,3],前面a定义为float32类型,经过计算后,得到[ 1.  3.]。
乘法也被重载:
例:
add_and_triple = adder_node * 3.
print(sess.run(add_and_triple, {a: 3, b:4.5}))
输出:22.5
Variable是本节遇到的第四类节点。
例:
W = tf.Variable([.3], dtype=tf.float32)
print(W)
输出:<tf.Variable 'Variable:0' shape=(1,) dtype=float32_ref>
在应用中,Placeholder类型的节点用于训练数据x,Variable类型的节点用于随机变量参数。
例:定义线性模型:f(x)=0.3x-0.3
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
x = tf.placeholder(tf.float32)
linear_model = W * x + b
讨论:这里的系统和偏移只是初始值,随后可能需要调整。如果用常量节点,显然不合适。
注意:tf.Variable()并不初始化节点,Tensorflow采用了延迟式全局初始化的策略。
例:
init = tf.global_variables_initializer() #init指向初始化全局变量节点的子图
sess.run(init) #初始化全局变量节点
证明Tensorflow采用了延迟式全局初始化的策略:
反例:
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
x = tf.placeholder(tf.float32)
linear_model = W * x + b
print(sess.run(linear_model, {x:[1,2,3,4]}))
输出:抛出异常
。。。。。。tensorflow.python.framework.errors_impl.FailedPreconditionError: Attempting to use uninitialized value Variable_1。。。。。。
正例:
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
x = tf.placeholder(tf.float32)
linear_model = W * x + b
init = tf.global_variables_initializer()
sess.run(init)
print(sess.run(linear_model, {x:[1,2,3,4]}))  #f(x)=0.3x-0.3
输出:[ 0.          0.30000001  0.60000002  0.90000004]
linear_model在这里提供了预测值,即y·,我们自己提供实际值y,并定义和计算损失函数。
线性回归的标准损失模型:(预测值-实际值)的平方和。官网没用标准差。
例:
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
x = tf.placeholder(tf.float32)
y = tf.placeholder(tf.float32)
linear_model = W * x + b
init = tf.global_variables_initializer()
sess.run(init)
sess.run(linear_model, {x:[1,2,3,4]})
squared_deltas = tf.square(linear_model - y)
loss = tf.reduce_sum(squared_deltas) ##f(x)=0.3x-0.3
print(sess.run(loss, {x:[1,2,3,4], y:[0,-1,-2,-3]}))
输出:23.66,这就是平方和。
手工验证:(0-0)平方+(0.3+1)平方+(0.6+2)平方+(0.9+3)平方
          = 0+ 1.69 + 6.76 + 15.21
 = 23.66
模型不太好,偏差太大,需要调整参数值。
一个Variable节点,在初始化以后,可以用tf.assign()修改值,这正是Variable节点的价值所在。
例:继续上面的代码,模型修改为: f(x)=-x+1
sess.run([tf.assign(W, [-1.]), tf.assign(b, [1.])]) #调整参数值W=-1,b=1,并重新计算Variable节点
print(sess.run(loss, {x:[1,2,3,4], y:[0,-1,-2,-3]}))
输出:0.0,完美。(可惜是人给出的参数,不是模型学习得来的)
小结:本章的第一段core API就学完了,这里我们主要学习了四种常见的节点类型(常量节点,操作节点,占位符节点,变量节点)及其用法,建立了一个简单的线性回归模型。
下面简单讲讲其它的API。


Tensorflow当前版本为1.2.1,包结构如下:
Tensorflow
|-------core  核心包
    |-------python python接口包
|-------contrib 目前还在开发中,接口不稳定
|-------examples 样例
|-------tensorboard 计算图看板
第二段下面学习一个ft.train的API。tf.train API的包位置在tensorflow.python.training中。
优化器(optimizers)用于缓慢的修改变量的值,以使得损失函数达到最小。
最简单的优化器是坡度下降(gradient descent)优化器,它计算损失函数对特定变量的偏导来修改变量值。
tf.gradients用于求偏导,举个例子。
f(x,y)=xy中,对x求偏导,很明显是y。验证如下:
x=tf.Variable([[3,5]])
print(x) #1x2的矩阵
y=tf.Variable([[2],[6]])
print(y) #2x1的 矩阵
fx=tf.matmul(x, y) #得到1x1的矩阵


init=tf.global_variables_initializer()
sess.run(init)
print(sess.run(fx))
输出:
<tf.Variable 'Variable:0' shape=(1, 2) dtype=int32_ref>
<tf.Variable 'Variable_1:0' shape=(2, 1) dtype=int32_ref>
[[36]]
也就是说,矩阵X和Y相乘,得到矩阵[[36]],令它为矩阵Z。
如果对矩阵Z求X的偏导,应该得到Y。
x=tf.Variable([[3,5]])
y=tf.Variable([[2],[6]])
fx=tf.matmul(x, y) #得到1x1的矩阵
yy=tf.gradients(fx,[x]) #对模型fx求对x的偏导。
sess.run(tf.global_variables_initializer())
print(sess.run(yy))
输出:[array([[2, 6]])],可以看到,得到的yy正是设想的x的偏导y.


TensorFlow中的GradientDescentOptimizer优化器采用了类似的求导算法,底层细节被封装。
完整的代码如下:
import tensorflow as tf
W = tf.Variable([.3], dtype=tf.float32)  #W初值为0.3
b = tf.Variable([-.3], dtype=tf.float32) #b初值为-0.3
x = tf.placeholder(tf.float32) #x由训练数据提供
linear_model = W * x + b #建立模型
y = tf.placeholder(tf.float32) #y由标注数据给出
loss = tf.reduce_sum(tf.square(linear_model - y)) # 损失函数,由平方和表征
optimizer = tf.train.GradientDescentOptimizer(0.01) #最简单的优化器,坡度下降,学习率为0.01
train = optimizer.minimize(loss) #把损失函数值降到最小
x_train = [1,2,3,4]
y_train = [0,-1,-2,-3] #标注数据
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init) #初始化Variable类型节点
for i in range(1000): #1000次
    sess.run(train, {x:x_train, y:y_train}) #train是“把损失函数值降到最小”的节点,把这个节点根据训练样本计算1000次。这会影响到loss,进而影响到linear_model,从而调整W和b.
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x:x_train, y:y_train}) #经过1000次训练,拿出来看看参数是否已足够好。
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))
输出:W: [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11
在第一小节中,人为设置W=-1,b=1,得到完美结果。现在无需设置,通过学习,模型得到了非常近似的结果。
看TensorBoard的话,基本不知所云。
小结:
1.建立模型;
2.建立损失函数;
3.设法让损失函数最小化,以便让模型本次学习达到最优,达到局部最优;
4.重复第3步N次,这是一个渐近学习的过程,(可能)达到全局最优;
5.观察模型结果。




第三段简单学习tf.contrib.learn包,传说中它更简单。
评估器(estimator):tf.contrib.learn预定义了很多评估器,包括:
     |---- 线性回归器(linear regressors)
|---- 逻辑回归器(logistic regressors)
|---- 线性分类器(linear classifiers)
|---- 逻辑分类器(logistic classifiers)
|---- 其它许多神经网络的回归器与分类器。
本节使用最简单的线性回归器。
先搞清楚几个概念。
batch_size:一个批次的最小数量。比如x=[1., 2., 3., 4.],batch_size=4,就是一个批次把4个样本全部提给模型。
num_epochs:一个epoch指对所有样本的一次迭代。
steps:举列,20000张图片,batch_size=100,那1个epoch中就有200个steps.如果batch_size=20000,那1个epoch中就有1个step.
代码:
import tensorflow as tf
import numpy as np


features = [tf.contrib.layers.real_valued_column("x", dimension=1)] #"x"定义一个列名,1维数组。
estimator = tf.contrib.learn.LinearRegressor(feature_columns=features) #1.选择模型,线性回归器,f(x)=Wx+b
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7, 0.])
##每批4个样本,[1., 2., 3., 4.],一个epoch是指把所有训练数据完整的过一遍,所以这里过了1000遍训练数据。
input_fn = tf.contrib.learn.io.numpy_input_fn({"x":x_train}, y_train,
                                              batch_size=4,
                                              num_epochs=1000) #2. 给出训练策略。
eval_input_fn = tf.contrib.learn.io.numpy_input_fn(
    {"x":x_eval}, y_eval, batch_size=4, num_epochs=1000)
estimator.fit(input_fn=input_fn, steps=1000) #3. 训练。1000个epochs,共有1000个steps. estimator.fit()开始训练一个模型。
train_loss = estimator.evaluate(input_fn=input_fn) #4.查看损失函数结果
eval_loss = estimator.evaluate(input_fn=eval_input_fn)
print("train loss: %r"% train_loss)
print("eval loss: %r"% eval_loss)
输出:
train loss: {'global_step': 1000, 'loss': 1.1486841e-09}
eval loss: {'global_step': 1000, 'loss': 0.0025281454}
这个模型训练得足够好,我们只是简单的选择LinearRegressor,指出训练方式,训练,直接看损失函数结果就完了。
想一想:最后W和b是多少?训练好的模型如果使用?


自定义模型
LinearRegressor的类继承关系:
sklearn.BaseEstimator, evaluable.Evaluable, trainable.Trainable
BaseEstimator
estimator.Estimator
LinearRegressor  
代码:
import numpy as np
import tensorflow as tf


def model(features, labels, mode):
    W = tf.get_variable("W", [1], dtype=tf.float64)
    b = tf.get_variable("b", [1], dtype=tf.float64)
    y = W*features['x'] + b
    loss = tf.reduce_sum(tf.square(y - labels))
    global_step = tf.train.get_global_step()
    optimizer = tf.train.GradientDescentOptimizer(0.01)
    train = tf.group(optimizer.minimize(loss),
                   tf.assign_add(global_step, 1))
    return tf.contrib.learn.ModelFnOps(
      mode=mode, predictions=y,
      loss=loss,
      train_op=train)


estimator = tf.contrib.learn.Estimator(model_fn=model)
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7, 0.])
input_fn = tf.contrib.learn.io.numpy_input_fn({"x": x_train}, y_train, 4, num_epochs=1000)
eval_input_fn = tf.contrib.learn.io.numpy_input_fn({"x": x_eval}, y_eval, 4, num_epochs=1000)
estimator.fit(input_fn=input_fn, steps=1000)
train_loss = estimator.evaluate(input_fn=input_fn)
eval_loss = estimator.evaluate(input_fn=eval_input_fn)
print("train loss: %r"% train_loss)
print("eval loss: %r"% eval_loss)
输出:
train loss: {'loss': 4.5856791e-11, 'global_step': 1000}
eval loss: {'loss': 0.010101089, 'global_step': 1000}
比较:这段代码与上一段的不同之处在于,上段代码定义estimator时,直接指定了一个子类。
estimator = tf.contrib.learn.LinearRegressor...
这段代码定义estimator,使用了python\learn\estimators\estimator的构造函数。
estimator = tf.contrib.learn.Estimator(model_fn=model),传入了一个模型函数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值