開始學習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中數據的中心單元。張量由原始值的集合組成通過變形爲多維矩陣。張量的等級是它的維度數量。這裏給出部分示例:
3 # 0 tensor
[1. ,2., 3.] # 1 tensor 3維
[[1., 2., 3.], [4., 5., 6.]] # 2 tensor 2*3維
[[[1., 2., 3.]], [[7., 8., 9.]]] # 3 tensor 2*1*3維
TensorFlow Core 教程
導入 TensorFlow
tensorFlow的import表達式一般長這個樣子:
import tensorflow as tf
import之後,就可以調用所有的TensorFlow類,方法,符號了。
The Computational Graph
TensorFlow Core程序由兩個分離的部分組成:
- 創建圖
- 運行圖
計算圖(computational graph)將一系列的TensorFLow操作排列成圖的節點。下面試着創建一個簡單的圖。每一個圖有0個或者多個tensor輸入,一個張量作爲輸出。節點的一種類型是常量,正如所有的TensorFlow常量一樣,這個常量沒有輸入,輸出的是它內部保存的值。下面創建了兩個浮點型張量 node1和node2:
node1 = tf.constant(3.0, 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.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:
[3.0, 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: 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
在TensorBroad中如下所示:
機器學習中,我們通常想要一個模型能夠接受任意參數作爲輸入。爲了使得模型可訓練,我們需要修改圖接收相同的輸入產生新的輸出。Variables允許我們給圖添加可訓練的參數,Variables僅通過初始值和類型構造:
W = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], 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]}))
輸出爲:
[ 0. 0.30000001 0.60000002 0.90000004]
到這裏,我們已經創建了一個模型,但是我們不知道他到底有多好。爲了在訓練數據基礎上評估這個模型,我們需要一個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:[1,2,3,4], y:[0,-1,-2,-3]}))
輸出的誤差爲:
23.66
我們可以手動的改進這個模型,通過調整W爲-1和b的值爲1得到完美的結果。通過給tf.Variable聲明的時候賦值來初始化一個變量,變量的值可以通過使用tf.assign
操作來改變。比如W=-1
和b=1
就是這個模型最優的結果:
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
這裏我們是通過猜測來找到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)]
以上就完成了簡單的機器學習的線性迴歸的例子。TensotFlow通過少量的代碼就完成了上述任務,當然了,複雜的模型和方法需要更多的代碼。TensorFlow提供更高等級的共同模式,結構,方法的抽象。在接下來的章節將介紹這些。
完整的代碼
import numpy as np
import tensorflow as tf
# Model parameters
W = tf.Variable([.3], tf.float32)
b = tf.Variable([-.3], 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
本例比之前的例子更復雜,但是也可以通過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=1)]
# 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([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,
batch_size=4,
num_epochs=1000)
eval_input_fn = tf.contrib.learn.io.numpy_input_fn(
{"x":x_eval}, y_eval, batch_size=4, num_epochs=1000)
# We can invoke 1000 training steps by invoking the method and passing the
# training data set.
estimator.fit(input_fn=input_fn, steps=1000)
# 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': 1000, 'loss': 1.9650059e-11}
自定義模型
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", [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))
# 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([1., 2., 3., 4.])
y = np.array([0., -1., -2., -3.])
input_fn = tf.contrib.learn.io.numpy_input_fn({"x": x}, y, 4, num_epochs=1000)
# train
estimator.fit(input_fn=input_fn, steps=1000)
# evaluate our model
print(estimator.evaluate(input_fn=input_fn, steps=10))
結果爲:
{'loss': 5.9819476e-11, 'global_step': 1000}
注意model()中的方法跟低等級的API的手寫的循環訓練的模型相似。
接下來
到這裏就完成了對TensorFlow基本的學習,下面將學習TensorFlow更多的知識。 初學者查看: MNIST for beginners, 非初學者查看: Deep MNIST for experts.
version 0.1 finished 20170331