Tensorflow 入门

我是一个很懒的人,我想试试

希望我能坚持到最后,把tensorflow的官方教程全部翻译出来

提高自己,也帮助他人

我的博客:终身学习者

Tensorflow 入门

本篇是Tensorflow编程入门指南。在开始本教程前,请先安装 TensorFlow。为了充分利用本指南,你需要知道以下知识:

  • 如何使用 Python 编程。
  • 至少知道一点 Arrays 知识。
  • 最好能懂一点机器学习的知识。但即使你一点机器学习的知识都不懂也没有关系,这依然可以是你阅读的第一份教程。

TensorFlow 提供了多个 APIs。最低级的 API——TensorFlow Core 提供完整的编程控制。我们建议机器学习研究者和其他需要对模型进行精确控制的人员来使用TensorFlow Core。更高级的 APIs 建立在 TensorFlow Core之上。这些更高级的 APIs 相比于 TensorFlow Core 也更加容易学习与使用。另外,更高级的 API 使得不同用户之间的重复任务更容易也更一致。像 tf.estimator 这样的高级 API 可以帮助您管理数据集,评价,训练和推理。
本指南将以 Tensorflow Core 开始。接下来,我们将演示如何在 tf.estimator 中运行相同的模型。理解 Tensorflow Core 原理将在你使用更抽象的高级 API 时能够更好的理解事情内部的工作原理。

Tensors

Tensorflow 数据的核心单位是张量 (tensor)。一个张量是由一组任意维度的原始值组成。张量的 (rank) 是它的维数, 下面是一些张量的例子:

3  # a rank 0 tensor; a scalar with shape []  
[1.,  2.,  3.]  # a rank 1 tensor; a vector with shape [3]  
[[1.,  2.,  3.],  [4.,  5.,  6.]]  # a rank 2 tensor; a matrix with shape [2, 3]  
[[[1.,  2.,  3.]],  [[7.,  8.,  9.]]]  # a rank 3 tensor with shape [2, 1, 3]

TensorFlow Core 教程

Importing TensorFlow

TensorFlow 程序规范导入语句如下:

import tensorflow as tf

这使得 Python 可以访问所有的 TensorFlow 类(classes), 方法(methods)和符号(symbols)。接下来大多数的教程都假设你已完成了此项工作。

The Computational Graph

你可能会认为 Tensorflow Core 程序都是包含以下两个部分:

  1. 构建 computational graph。
  2. 执行 computational graph。

计算图 (computational graph) 是一系列排列成节点图的 TensorFlow 操作。让我们来构建一个简单的计算图。每个节点将输入零个或多个张量并产生一个张量作为输出。每个类型的节点都是一个常量。类似于所有的 TensorFlow 常量,它没有输入,而只输出一个内部存储值。我们可以创建两个浮点型张量node1node2

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)

注意,打印节点不会像你预期的那样输出 3.04.0 。相反,他们在评估时将会分别输出 3.0 和 4.0. 为了实际评估节点,我们必须在会话 (session) 内运行计算图。session 封装了 Tensorflow 运行时的控制和状态。

以下代码创建了一个 Session 对象并调用了 run 方法运行计算图来评估node1node2。通过在 session 中运行计算图:

sess = tf.Session()  
print(sess.run([node1, node2]))

我们就可以看到期望的答案 3.0 和 4.0:

[3.0,  4.0]

我们可以通过将张量节点与操作相结合来构建更复杂的计算(操作也是节点)。例如,我们可以增加两个常量节点并产生一个新的图(graph):

from future import print_function
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

Tensorflow 提供一个名为TensorBoard的有效的程序,它可以将计算图显示为图。以下一个截屏显示了TensorBoard将图可视化:

TensorBoard screenshot

就目前来看,这张图并不特别有趣,因为它总是产生一个不变的结果。图可以被参数化来接收称为占位符的外部输入。占位符是接下来提供值的变量。

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

这三行有点像一个函数(function)或者一个lambda,其中我们定义了两个参数(a和b)和一个操作。我们可以通过多个输入来评估这个图,这些输入是通过使用 run 方法 的 feed_dict 参数将具体值 feed 给占位符:

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.]

在 TensorBoard,这图看起来是这样的:

TensorBoard screenshot

我们可以通过添加其他的操作来使得计算图更加的复杂,例如,

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

输出结果:

22.5

在TensorBoard中,上面的计算图如下所示:

TensorBoard screenshot

在机器学习中,我们通常需要一个可以计算任意输入的模型,比如上面的模型。为了使得模型可训练,我们需要能够修改图使得其具有相同的输入能得到新的输出。变量(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

当你调用tf.constant 时,常量就被初始化了,并且不能被修改。相比之下,当你调用tf.constant 的时候变量并没有被初始化。为了初始化TensorFlow里面的变量,你必须显式的调用下面的操作:

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

实现init 是TensorFlow子图初始化所有的全局变量的一个很重要的句柄。在我们调用sess.run 之前,变量是未初始化的。

由于x 是一个占位符,我们可以同时为多个x 评估linear_model :

print(sess.run(linear_model,  {x:  [1,  2,  3,  4]}))

输出结果:

[  0. 0.30000001 0.60000002 0.90000004]

我们创建了一个模型,但是我们不知道这个模型的好坏。为了评估训练数据的模型,我们需要一个y 占位符来提供期望值,并且我们需要写一个代价函数。

代价函数用于衡量当前模型与预期值之间的差距有多远。我们将使用线性回归的标准代价模型,其中代价是当前模型与期望值之间的差距的平方的总和。linear_model - y 创建一个每个元素与其对应实例的误差的向量。我们调用tf.square 来计算这个误差的平方。然后我们统计所有的平方差来创建一个标量,通过调用tf.reduce_sum 来抽象所有例子的错误:

y = tf.placeholder(tf.float32) 
squared_deltas = tf.square(linear_model - y) 
loss = tf.reduce_sum(squared_deltas)  
print(sess.run(loss,  {x:  [1,  2,  3,  4], y:  [0,  -1,  -2,  -3]}))

输出结果:

23.66

我们可以通过重新将Wb 分别赋值为-1和1来手动改进。一个变量可以通过tf.Variable 来初始化,也可以使用像tf.assign 的操作来改变。例如,W=-1b=1 就是我们这个模型的最优参数,我们可以对应改变 Wb 的值:

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

结果损失值为零。

0.0

我们能够猜测Wb 的最佳值,但是机器学习的重点是自动找到正确的模型参数。我们将在下一节展示如何完成这项工作。

tf.train API

对于机器学习的完整讨论已超出了本教程的范围。但是Tensorflow提供的优化器(optimizers) 可以逐步改变每个变量来逐步使得代价函数达到最小值。最简单的优化器是梯度下降(gradient descent) 。它根据相对于该变量的损失导数的大小来修改每个变量。一般来说,手动计算符号导数是繁琐而又容易出错的。所以只要使用tf.gradients 来描述模型 tensorflow 就可以自动计算导数。简单来说,优化器通常会自动为你做这件事,例如:

optimizer = tf.train.GradientDescentOptimizer(0.01) 
train = optimizer.minimize(loss)
sess.run(init)  # reset values to incorrect defaults.  
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)]

现在我们已经完成了一个实际的机器学习了!虽然这个简单的线性模型不需要太多的 tensorflow core 代码,但是使用更复杂的模型和方法给我们的模型 feed 数据则需要更多的代码。因此 tensorflow 为常见的模型,结构和功能提供更高级的抽象。我们将在下一节中学习如何使用这些抽象。

Complete program

完成可训练的线性回归模型如下所示:

import tensorflow as tf

# Model parameters
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
# Model input and output
x = tf.placeholder(tf.float32)
linear_model = W*x + b
y = tf.placeholder(tf.float32)

# loss
loss = tf.reduce_sum(tf.square(linear_model - y)) # sum of the squares
# optimizer
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)

# training data
x_train = [1, 2, 3, 4]
y_train = [0, -1, -2, -3]
# training loop
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init) # reset values to wrong
for i in range(1000):
  sess.run(train, {x: x_train, y: y_train})

# evaluate training accuracy
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x: x_train, y: y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))

运行后结果如下:

W:  [-0.9999969] b:  [  0.99999082] loss:  5.69997e-11

注意,loss 是一个非常小的数字(非常接近于零)。如果你运行这段代码,你的 loss 可能和上面的 loss 不完全一致,因为模型的初始化是使用伪随机值的。

在 tensorboard 仍然可以可视化非常复杂的程序。
TensorBoard final model visualization

tf.estimator

tf.estimator 是一个高级的 TensorFlow 库,它简化了机器学习的机制:

  • 运行训练循环
  • 运行评估循环
  • 管理数据集

tf.estimator 定义了许多常见的模型。

Basic usage

注意在 tf.estimator 里,线性回归将变得多么的简单:

# NumPy is often used to load, manipulate and preprocess data.  
import numpy as np 
import tensorflow as tf

# 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:  {'average_loss':  1.4833182e-08,  'global_step':  1000,  'loss':  5.9332727e-08}  eval metrics:  {'average_loss':  0.0025353201,  'global_step':  1000,  'loss':  0.01014128}

注意,不论我们评估的loss有多高,但它仍然接近与零。这意味这我们的学习是正确的。

A custom model

tf.estimator 不会限制你在预定义模型中。假设我们想要创建一个自定义的 TensorFlow 没有的模型。我们仍然可以使用 tf.estimator 来使用高度抽象的数据集,处理,训练。为了说明,我们将展示如何利用我们的知识使用低级的 TensorFlow API 来实现相同的线性回归模型。

为了定义一个使用tf.estimator 的自定义模型,我们需要使用 tf.estimator.Estimator 。实际上 tf.estimator.LinearRegressortf.estimator.Estimator 的一个子类。为了替代子类Estimator ,我们只需要提供 Estimator 的一个函数 model_fn 来告诉 tf.estimator 如何评估预测,训练步骤和损失。代码如下:

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() 函数的内容与我们从低级 API 得到的手动训练循环是非常相似的。

Next steps

现在你已经掌握了 TensorFlow 的基础知识。我们还有更多的教程助你了解学习更多。如果你是一个机器学习初学者,请查看 MNIST for beginners ,否则请查看 Deep MNIST for experts

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容