本指南介紹如何在TensorFlow中編程。在使用本指南之前,請安裝TensorFlow。為了充分利用本指南,您應該了解以下內容:
- 如何使用Python編程。
- 了解什麽是數組。
- 理想的條件,了解機器學習。但是,如果您對機器學習知之甚少,那麽這仍然可以是您應該閱讀的一本指南。
TensorFlow提供了多個API,其中最底層的API ———— TensorFlow核心 – 為您提供完整的編程控製。TensorFlow Core適用於機器學習研究人員和其他需要對模型進行精細控製的開發者。更高層次的API建立在TensorFlow核心之上。這些更高級別的API通常比TensorFlow Core更容易學習和使用。另外,更高級別的API使得不同用戶之間的重複任務更容易和更一致。像tf.estimator這樣的high-level API可以幫助您管理數據集,評估,訓練和推理。
本指南從TensorFlow Core教程開始。稍後,我們演示如何在tf.estimator中實現相同的模型。了解TensorFlow核心原則將給你一個很好的思維模型,即當你使用更緊湊的更高級別的API時,知道模型內部工作是如何工作的。
張量
TensorFlow中的數據中心單位是張量。一個張量由一組任意維數的原始值組成。張量的秩(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教程
導入Tensorflow
TensorFlow程序的規範導入語句如下所示:
import tensorflow as tf
這使得Python可以訪問所有TensorFlow的類,方法和符號。大多數文檔假定您已經完成了這個工作。
計算圖
你可能會想到TensorFlow核心程序由兩個獨立的部分組成:
- 構建計算圖。
- 運行計算圖。
一個計算圖是一係列排列成節點圖的TensorFlow操作。下麵我們來構建一個簡單的計算圖。每個節點將零個或多個張量作為輸入,並產生一個張量作為輸出。一種類型的節點是一個常量,像所有的TensorFlow常量一樣,它不需要輸入,並輸出一個內部存儲的值。我們可以創建兩個浮點數張量node1
和node2
如下:
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.0
和4.0
,這跟你想的可能不太一樣。相反,它們是在評估時分別產生3.0和4.0的節點。為了實際評估節點,我們必須在一個Session(會話)內部運行計算圖。會話封裝了TensorFlow運行時的控製和狀態。
以下代碼創建一個Session
對象,然後調用它的run
方法運行足夠的計算圖來評估node1
和node2
。通過在會話中運行計算圖如下:
sess = tf.Session()
print(sess.run([node1, node2]))
我們看到了3.0和4.0的預期值:
[3.0, 4.0]
我們可以通過組合具有操作的Tensor
節點(操作也是節點)來構建更複雜的計算。例如,我們可以求和我們的兩個常量節點,並產生一個新的圖形如下:
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如何將圖形可視化:
就目前來看,這張圖並不特別有趣,因為它總是會產生一個不變的結果。圖形可以參數化來接受外部輸入,稱為占位符。一個占位符是稍後提供特定值的聲明。
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b # + provides a shortcut for tf.add(a, b)
前麵的三行有點像一個函數或lambda,我們在其中定義兩個輸入參數(a和b),然後對它們進行操作。我們可以通過使用feed_dict參數來給run方法傳入多個值,從而評估計算圖:
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中,圖形如下所示:
我們可以通過添加另一個操作來使計算圖更加複雜。例如,
add_and_triple = adder_node * 3.
print(sess.run(add_and_triple, {a: 3, b: 4.5}))
產生輸出
22.5
在TensorBoard中,上麵的計算圖如下所示:
在機器學習中,我們通常需要一個可以進行任意輸入的模型,比如上麵的模型。為了使模型可訓練,我們需要能夠修改圖形以獲得具有相同輸入的新輸出。變量允許我們將可訓練參數添加到圖形中。變量可以通過一個類型和初始值構造:
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.Variable
。要初始化TensorFlow程序中的所有變量,您必須顯式調用一個特殊的操作,如下所示:
init = tf.global_variables_initializer()
sess.run(init)
意識到這一點很重要:init
是初始化所有全局變量的TensorFlow sub-graph句柄。直到我們調用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
我們可以通過重新賦值來手動改進W
和b
到-1和1的完美值。一個變量被初始化為提供的值tf.Variable
但可以使用類似的操作進行更改tf.assign
。例如,W=-1
和b=1
是我們模型的最佳參數。我們可以改變W
和b
因此:
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]}))
最後的print顯示現在的損失是零。
0.0
我們猜到了W
和b
的完美值,但是機器學習的重點是自動找到正確的模型參數。我們將在下一節展示如何完成這個目標。
tf.train API
機器學習的完整討論超出了本教程的範圍。TensorFlow提供了優化器用於緩慢地改變每個變量以使損失函數最小化。最簡單的優化器是梯度下降。它根據相對於該變量的損失導數的大小來修改每個變量。一般來說,手動計算符號導數是非常繁瑣的,而且容易出錯。因此,TensorFlow可以自動生成導數,僅使用該函數對模型進行描述tf.gradients
。為了簡單起見,優化器通常會為您執行此操作。例如,
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核心代碼,但是更複雜的模型和方法將數據提供給模型需要更多的代碼。因此,TensorFlow為常見的模式,結構和功能提供更高層次的抽象。我們將在下一節學習如何使用這些抽象。
完整的程序
完成的可訓練線性回歸模型如下所示:
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
請注意,損失是非常小的數字(非常接近零)。如果你運行這個程序,你的損失可能與上述損失不完全一樣,因為模型是用偽隨機值初始化的。
這個更複雜的程序仍然可以在TensorBoard中可視化
tf.estimator
tf.estimator
是一個high-level TensorFlow庫,簡化了機器學習的機製,包括以下內容:
- 運行訓練循環
- 運行評估循環
- 管理數據集
tf.estimator定義了許多常見的模型。
基本用法
注意使用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}
請注意我們的評估數據是如何有更高的損失,但仍然接近於零。這意味著我們正在正確地學習。
自定義模型
tf.estimator
不會將您鎖定在預定義的模型中。假設我們想創建一個沒有內置到TensorFlow中的自定義模型。我們仍然可以保留tf.estimator
的數據集,feeding,訓練等的高層次抽象。下麵我們將展示如何實現我們自己的等效模型————LinearRegressor
使用我們對低級別TensorFlow API的知識。
定義一個適用的自定義模型tf.estimator
,我們需要使用tf.estimator.Estimator
。tf.estimator.LinearRegressor
實際上是tf.estimator.Estimator
的子類,而不是sub-classingEstimator
,我們隻是提供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手動模型訓練循環非常相似。
下一步
現在您已經掌握了TensorFlow的基礎知識。我們還有更多的教程可供您了解更多信息。如果你是機器學習的初學者,請參閱MNIST初學者版,否則請看深度MNIST專家版。