TensorFlow简明入门宝典

TensorFlow是由谷歌公司推出的一个人工智能学习系统,也是当前最为流行的深度学习框架之一。学习Tensorflow最好的资料就是其官网上的文档(参加文献【1】)。本文是“TensorFlow简明入门宝典”系列文章的第一篇,希望可以帮助对TensorFlow感到既陌生又神秘的朋友快速上手。


对于安装配置TensorFlow请参考【Ubuntu上安装配置Tensorflow及Jupyter详解】


TensorFlow中的核心数据单位就是tensor(张量),张量在编程语言中最straightforward的解释就是多维数组。一个张量的rank就是指其维数。例如:

# a rank 0 tensor; this is a scalar with shape []
3 

# a rank 1 tensor; this is a vector with shape [3], 3表示拆掉最外层的[], 剩下的元素有3个
[1., 2., 3.] 

# a rank 2 tensor; a matrix with shape [2, 3]
# 2表示拆掉最外层的[],剩下的元素有2个,再拆掉一层[],每组剩下的元素都是3个
[[1., 2., 3.], [4., 5., 6.]] 

# a rank 3 tensor with shape [2, 1, 3], 可以拆3次[],每次剩下的元素分别是2, 1, 3
[[[1., 2., 3.]], [[7., 8., 9.]]]

同样,在使用TensorFlow之前需要先引用它,用于线性代数计算的NumPy也常常会被用到,这里一并引入。

import tensorflow as tf
import numpy as np

一、计算图、节点、操作、常量、变量,以及占位符

TensorFlow是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。TensorFlow的核心编程可以分解为两个离散的部分:

  • 构建计算图
  • 执行计算图

计算图(computational graph)是一系列被安排成图(graph)中节点(node)的TensorFlow操作。每个节点都以0或多个张量作为输入,并产生一个张量作为输出。节点的一种类型就是constant。例如,下面的语句构建了一个非常简单的计算图,其中创建了两个浮点数张量node1和node2。

node1 = tf.constant(3.0, dtype=tf.float32)
node2 = tf.constant(4.0) # also tf.float32 implicitly

注意node1和node2是两个节点(张量),要取得它们的值就必须对它们进行evaluate,而要对node进行evaluate,我们就必须在一个session中执行计算图。一个session是对TensorFlow运行时的状态和控制所进行的封装。


下面的代码创建了一个Session对象,并调用它的run方法。

sess = tf.Session()
print(sess.run([node1, node2]))
执行上述代码,会得到结果如下:

[3.0, 4.0]

我还可以通过把操作(操作也是节点)组合成张量节点的方法来实现更加复杂的计算。例如,把两个constant节点相加并生成一个新图的代码如下:

node3 = tf.add(node1, node2)
print("node3:", node3)
print("sess.run(node3):", sess.run(node3))

输出的结果如下:

node3: Tensor("Add:0", shape=(), dtype=float32)
sess.run(node3): 7.0

一个计算图还可以通过接受外部输入的方法来进行参数化,这被称为placeholders(占位符),一个placeholder可以理解为一种承诺,即后面会提供数值。例如:

a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b  # + provides a shortcut for tf.add(a, b)

然后就像函数调用一样,当我们evaluate这个图的时候,就要为placeholders提供输入值:

print(sess.run(adder_node, {a: 3, b: 4.5}))
print(sess.run(adder_node, {a: [1, 3], b: [2, 4]}))

输出的结果如下:

7.5
[ 3.  7.]

向图中继续加入一个新的操作会产生一个更加复杂的图:

add_and_triple = adder_node * 3.
print(sess.run(add_and_triple, {a: 3, b: 4.5}))

跟预想的一样,上述代码会输出:

22.5

既然有Constant,很自然地会设想应该也会有Variable。的确如此,Variables允许我们向图中增加可训练的参数。构建Variables一般要指定类型和初始值,例如:

W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
x = tf.placeholder(tf.float32)
linear_model = W * x + b
Variable和constant的一个区别就在于constant在你调用tf.constant时就会被初始化,而且它们的值不会再改变。相反,在你调用tf.Variable时,Variable并不会被初始化。为了初始化你程序中的Variables,你必须显式地调用下面这个特殊的语句:
init = tf.global_variables_initializer()
sess.run(init)
因为x是一个placeholder,所以我们可以(通过同时给出几个x的值)来评估前面定义的linear_model,即
print(sess.run(linear_model, {x: [1, 2, 3, 4]}))
输出的结果如下:

[ 0.          0.30000001  0.60000002  0.90000004]


二、利用TensorFlow求解线性回归


我们已经越来越接近线性回归问题的求解了。在通常的线性回归问题中,我们需要在一些形如(x,y)这样的train data训练linear_model。因此,再启用一个新的placeholder y。然后把最小二乘误差(linear_model-y)2作为损失函数(loss function),下面的代码中调用了tf.square来计算最小二乘误差

y = tf.placeholder(tf.float32)
squared_deltas = tf.square(linear_model - y)
loss = tf.reduce_sum(squared_deltas)

fixW = tf.assign(W, [-1.])
fixb = tf.assign(b, [1.])
sess.run([fixW, fixb])
print(sess.run(loss, {x: [1, 2, 3, 4], y: [0, -1, -2, -3]}))
当我们为参数W和b分别赋值-1和1时,损失为0。输出如下:
0.0

但是机器学习的任务是在给定任意的初始W和b时,让算法自行不断调整参数,以获得使损失最小化的参数。这里最为常用的优化算法就是梯度下降。在TensorFlow中提供的API tf.train可以帮我们完成模型训练的过程。

optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)

注意要把参数的初始值重新初始化到一个随机值。

init = tf.global_variables_initializer() 
sess = tf.Session()
sess.run(init) 

for i in range(1000):
  sess.run(train, {x: [1, 2, 3, 4], y: [0, -1, -2, -3]})

print(sess.run([W, b]))

最终输出的参数如下,可见已经非常接近标准答案了。(误差是不可避免的)

[array([-0.9999969], dtype=float32), array([ 0.99999082], dtype=float32)]

这部分的Jupyter notebook文件可以从链接【2】中获取。


三、tf.estimator


tf.estimator是一个高层的TensorFlow库,它可以简化机器学习的机制,完成包括:

执行训练循环;执行evaluation循环;管理数据集。tf.estimator还定义了很多一般模型。


下面这个例子演示了如何利用tf.estimator来简化之前的线性回归。

import tensorflow as tf
import numpy as np

# Declare list of features. We only have one numeric feature. There are many
# other types of columns that are more complicated and useful.
feature_columns = [tf.feature_column.numeric_column("x", shape=[1])]

# An estimator is the front end to invoke training (fitting) and evaluation
# (inference). There are many predefined types like linear regression,
# linear classification, and many neural network classifiers and regressors.
# The following code provides an estimator that does linear regression.
estimator = tf.estimator.LinearRegressor(feature_columns=feature_columns)

# TensorFlow provides many helper methods to read and set up data sets.
# Here we use two data sets: one for training and one for evaluation
# We have to tell the function how many batches
# of data (num_epochs) we want and how big each batch should be.
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.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=None, shuffle=True)
train_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=1000, shuffle=False)
eval_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_eval}, y_eval, batch_size=4, num_epochs=1000, shuffle=False)

# We can invoke 1000 training steps by invoking the  method and passing the
# training data set.
estimator.train(input_fn=input_fn, steps=1000)

# Here we evaluate how well our model did.
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("train metrics: %r"% train_metrics)
print("eval metrics: %r"% eval_metrics)

执行上述代码,结果如下:

train metrics: {'loss': 1.2712867e-09, 'global_step': 1000}
eval metrics: {'loss': 0.0025279333, 'global_step': 1000}

前面我们提到tf.estimator还定义了很多一般模型,例如上述代码中就使用了tf.estimator.LinearRegressor。但是,tf.estimator并没有将你锁定在预定义的模型中。假设我们想创造一个个性化的而且没有被内置于TensorFlow中的模型,我们还是可以使用它。这时就需要使用tf.estimator.Estimator,而且事实上,tf.estimator.LinearRegressor其实是tf.estimator.Estimator的一个子类。


假设现在我们要自己实现线性回归,这里我们并不打算为tf.estimator.Estimator的创建一个子类,其实只要为这个类提供一个model_fn的方法来告知tf.estimator 如何 evaluate 预测, 训练步骤以及损失即可。来看下面这个例子:

import numpy as np
import tensorflow as tf

# Declare list of features, we only have one real-valued feature
def model_fn(features, labels, mode):
  # Build a linear model and predict values
  W = tf.get_variable("W", [1], dtype=tf.float64)
  b = tf.get_variable("b", [1], dtype=tf.float64)
  y = W * features['x'] + b
  # Loss sub-graph
  loss = tf.reduce_sum(tf.square(y - labels))
  # Training sub-graph
  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))
  # EstimatorSpec connects subgraphs we built to the
  # appropriate functionality.
  return tf.estimator.EstimatorSpec(
      mode=mode,
      predictions=y,
      loss=loss,
      train_op=train)

estimator = tf.estimator.Estimator(model_fn=model_fn)
# define our data sets
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.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=None, shuffle=True)
train_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_train}, y_train, batch_size=4, num_epochs=1000, shuffle=False)
eval_input_fn = tf.estimator.inputs.numpy_input_fn(
    {"x": x_eval}, y_eval, batch_size=4, num_epochs=1000, shuffle=False)

# train
estimator.train(input_fn=input_fn, steps=1000)
# Here we evaluate how well our model did.
train_metrics = estimator.evaluate(input_fn=train_input_fn)
eval_metrics = estimator.evaluate(input_fn=eval_input_fn)
print("train metrics: %r"% train_metrics)
print("eval metrics: %r"% eval_metrics)
执行上述代码,结果如下:
train metrics: {'loss': 1.227995e-11, 'global_step': 1000}
eval metrics: {'loss': 0.01010036, 'global_step': 1000}

你会注意到的一点是我们编写的函数model_fn()与之前手动首先的线性回归训练模型非常类似。这里就不再多做解释了。



参考文献

【1】https://www.tensorflow.org/get_started/get_started

【2】http://pan.baidu.com/s/1c1Ofiak


(本文完)

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白马负金羁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值