原文連結
開始學習TensorFlow
在學習本文之前,需要首先安裝Tensorflow。本文介紹以下知識:
- 如何使用Python程式設計
- 關于矩陣的一些知識
- 關于機器學習的一些知識
TensorFlow提供多種多樣的API。最底層的API是Tensorflow Core,提供完全的程式控制。我們推薦機器學習研究者以及其他想要對他們的模型有更良好的控制能力的這類人使用TensorFLow Core。更進階的API是建構在Tensorflow Core基礎之上的。這些更高等級的API減少重複性工作并且能在不同的使用者之間保持一緻性。比如tf.contrib.learn協助管理資料集,估計,訓練和接口。值得注意的是一些高等級的API方法名字包含contrib的是在開發版本。這意味着一些contrib方法有可能在接下來的版本中過時或者改變。
本文使用Tensorflow Core作為入門。接着介紹了如何使用tf.contrib.learn實作相同的模型。了解Tensorflow Core的規則将使得你能夠在心裡明白使用更進階的API時模型内部是如何工作的。
張量(Tensor)
tensor(張量)是TensorFlow中資料的中心單元。張量由原始值的集合組成通過變形為多元矩陣。張量的等級是它的次元數量。這裡給出部分示例:
# 0 tensor
[ ,, ] # 1 tensor 3維
[[, , ], [, , ]] # 2 tensor 2*3維
[[[, , ]], [[, , ]]] # 3 tensor 2*1*3維
TensorFlow Core 教程
導入 TensorFlow
tensorFlow的import表達式一般長這個樣子:
import之後,就可以調用所有的TensorFlow類,方法,符号了。
The Computational Graph
TensorFlow Core程式由兩個分離的部分組成:
- 建立圖
- 運作圖
計算圖(computational graph)将一系列的TensorFLow操作排列成圖的節點。下面試着建立一個簡單的圖。每一個圖有0個或者多個tensor輸入,一個張量作為輸出。節點的一種類型是常量,正如所有的TensorFlow常量一樣,這個常量沒有輸入,輸出的是它内部儲存的值。下面建立了兩個浮點型張量 node1和node2:
node1 = tf.constant(, tf.float32)
node2 = tf.constant() # also tf.float32 implicitly
print(node1, node2)
輸出:
Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32)
注意,這裡的最終輸出并不是3.4和4.0,而是當評估他們的時候将分别輸出3.0和4.0.為了最終評估節點,必須在一個session裡面運作圖。一個session封裝tensorflow運作時的控制和狀态。
下面将建立一個sesion對象,之後調用它的run方法來通過運作圖來評估node1和node2.如下示範了如何在session中運作圖:
sess = tf.Session()
print(sess.run([node1, node2]))
可以看到最終的輸出是3.0 and 4.0:
[, ]
我們可以通過組合多個張量節點以及操作(操作也是節點)來完成更複雜的計算。比如,将兩個常量節點相加,生成一個新的圖:
node3 = tf.add(node1, node2)
print("node3: ", node3)
print("sess.run(node3): ",sess.run(node3))
最後兩句表達式的輸出如下:
node3: Tensor("Add_2:0", shape=(), dtype=float32)
sess.run(node3): 7.0
TensorFlow提供一個很實用的稱為TensorBoard的工具,它可以可視化一個圖。這裡給出一個TensorBoard可視化圖之後的結果:

圖中并沒有什麼特别值得注意的東西,因為它僅僅生成一個常量結果。圖可以通過參數化來接受外部的輸入,稱為placeholder。一個placeholder預示着它将提供數值。
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b #tf.add(a, b)的快速實作
上面的三行代碼像一個方法或者lambda表達式,定義了兩個輸入以及一個操作。我們可以通過使用feed_dict為tensor中的placeholder指定輸入參數來評估圖。
print(sess.run(adder_node, {a: , b:}))
print(sess.run(adder_node, {a: [,], b: [, ]}))
輸出為:
[ ]
在TensorBoard中顯示如下:
我們可以用圖來完成更複雜的操作:
add_and_triple = adder_node * 3.
print(sess.run(add_and_triple, {a: 3, b:4.5}))
輸入如下:
22.5
在TensorBroad中如下所示:
機器學習中,我們通常想要一個模型能夠接受任意參數作為輸入。為了使得模型可訓練,我們需要修改圖接收相同的輸入産生新的輸出。Variables允許我們給圖添加可訓練的參數,Variables僅通過初始值和類型構造:
W = tf.Variable([], tf.float32)
b = tf.Variable([-], 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子圖的一個操作,用來初始化所有的全局變量。直到調用了
sess.run
,變量才會被初始化。
既然x是一個placeholder,我們可以同時給x取多個值來評估linear_model。
print(sess.run(linear_model, {x:[1,2,3,4]}))
輸出為:
[ ]
到這裡,我們已經建立了一個模型,但是我們不知道他到底有多好。為了在訓練資料基礎上評估這個模型,我們需要一個placeholder類型的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:[,,,], y:[,-,-,-]}))
輸出的誤差為:
23.66
我們可以手動的改進這個模型,通過調整W為-1和b的值為1得到完美的結果。通過給tf.Variable聲明的時候指派來初始化一個變量,變量的值可以通過使用
tf.assign
操作來改變。比如
W=-1
和
b=1
就是這個模型最優的結果:
fixW = tf.assign(W, [-])
fixb = tf.assign(b, [])
sess.run([fixW, fixb])
print(sess.run(loss, {x:[,,,], y:[,-,-,-]}))
最後的輸出顯示損失值為:
0.0
這裡我們是通過猜測來找到W和b的值,但是在機器學習中找到正确的模型參數是自動進行的。本文将在接下來介紹如何實作。
tf.train API
TensorFlow提供優化器通過慢慢的改變每一個變量的值來最小化損失函數。最簡單的優化器就是梯度下降,根據損失函數對變量求得的導數大小來改變每一個變量。TensorFlow能夠使用tf.gradients方法對模型自動求導。簡單的來說,優化器通常自動的完成這個任務,比如:
optimizer = tf.train.GradientDescentOptimizer()
train = optimizer.minimize(loss)
sess.run(init) # reset values to incorrect defaults.
for i in range():
sess.run(train, {x:[,,,], y:[,-,-,-]})
print(sess.run([W, b]))
模型參數的結果:
[array([-], dtype=float32), array([ ],
dtype=float32)]
以上就完成了簡單的機器學習的線性回歸的例子。TensotFlow通過少量的代碼就完成了上述任務,當然了,複雜的模型和方法需要更多的代碼。TensorFlow提供更高等級的共同模式,結構,方法的抽象。在接下來的章節将介紹這些。
完整的代碼
import numpy as np
import tensorflow as tf
# Model parameters
W = tf.Variable([], tf.float32)
b = tf.Variable([-], 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()
train = optimizer.minimize(loss)
# training data
x_train = [,,,]
y_train = [,-,-,-]
# training loop
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init) # reset values to wrong
for i in range():
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))
最後的輸出如下:
本例比之前的例子更複雜,但是也可以通過TensorFlowBroad可視化。
tf.contrib.learn
tf.contrib.learn是一個高等級的TensorFlow類,它使得機器學習變得簡單,包括:
- 循環進行訓練
- 循環進行評估
- 管理資料集
- 管理回報
tf.contrib.learn定義了很多公共模型。
基本用法
tf.contrib.learn使得線性回歸變得更加簡單:
import tensorflow as tf
# NumPy is often used to load, manipulate and preprocess data.
import numpy as np
# Declare list of features. We only have one real-valued feature. There are many
# other types of columns that are more complicated and useful.
features = [tf.contrib.layers.real_valued_column("x", dimension=)]
# An estimator is the front end to invoke training (fitting) and evaluation
# (inference). There are many predefined types like linear regression,
# logistic regression, linear classification, logistic classification, and
# many neural network classifiers and regressors. The following code
# provides an estimator that does linear regression.
estimator = tf.contrib.learn.LinearRegressor(feature_columns=features)
# 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([, , , ])
y_train = np.array([, -, -, -])
x_eval = np.array([, , , ])
y_eval = np.array([-, -, -, ])
input_fn = tf.contrib.learn.io.numpy_input_fn({"x":x_train}, y_train,
batch_size=,
num_epochs=)
eval_input_fn = tf.contrib.learn.io.numpy_input_fn(
{"x":x_eval}, y_eval, batch_size=, num_epochs=)
# We can invoke 1000 training steps by invoking the method and passing the
# training data set.
estimator.fit(input_fn=input_fn, steps=)
# Here we evaluate how well our model did.
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)
最終的結果:
{'global_step': , 'loss': e-}
自定義模型
tf.contrib.learn 并沒有限定模型. 如果想要建立一個TensorFlow中沒有建立的模型,我們依然可以保持tf.contrib.learn的高度抽象的資料集、回報、訓練等。接下來,我們将展示如何實作TensorFlow中LinearRegressor相等的模型,而僅僅使用TensorFlow 低等級API知識。
為了使用tf.contrib.learn定義一個自定義模型,我們需要使用的tf.contrib.learn.Estimator和tf.contrib.learn.LinearRegressor事實上是tf.contrib.learn.Estimator的一個子類。這裡傳遞給Estimator一個函數模型model_fn聲明 tf.contrib.learn需要如何評估預測, 訓練步驟和損耗,而不是使用子類。代碼如下:
import numpy as np
import tensorflow as tf
# Declare list of features, we only have one real-valued feature
def model(features, labels, mode):
# Build a linear model and predict values
W = tf.get_variable("W", [], dtype=tf.float64)
b = tf.get_variable("b", [], 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()
train = tf.group(optimizer.minimize(loss),
tf.assign_add(global_step, ))
# ModelFnOps connects subgraphs we built to the
# appropriate functionality.
return tf.contrib.learn.ModelFnOps(
mode=mode, predictions=y,
loss=loss,
train_op=train)
estimator = tf.contrib.learn.Estimator(model_fn=model)
# define our data set
x = np.array([, , , ])
y = np.array([, -, -, -])
input_fn = tf.contrib.learn.io.numpy_input_fn({"x": x}, y, , num_epochs=)
# train
estimator.fit(input_fn=input_fn, steps=)
# evaluate our model
print(estimator.evaluate(input_fn=input_fn, steps=))
結果為:
{'loss': e-, 'global_step': }
注意model()中的方法跟低等級的API的手寫的循環訓練的模型相似。
接下來
到這裡就完成了對TensorFlow基本的學習,下面将學習TensorFlow更多的知識。 初學者檢視: MNIST for beginners, 非初學者檢視: Deep MNIST for experts.
version 0.1 finished 20170331