Introduction to TensorFlow
深度學習框架簡介
爲什麼要用成熟的框架,而不是從頭寫一個:
- 這些深度學習框架有助於擴展機器學習代碼
- 可以自動計算梯度(Gradients)!(使得我們可以把重點放在高層次的數學上)
- 標準化機器學習應用,方便共享交流
- 多種算法、理念、抽象、編程語言等的融合
- 提供GPU並行運算的接口
TF是什麼?
Tenorflow是谷歌開發的一個使用流式圖進行數值計算的開源軟件庫。
It’s just a deep learning framework, an open source software library for numerical computation using flow graphs from Google.
TF的工作原理和基本範例
-
最核心的思想
將數值計算表示爲圖的形式(express a numeric computation as a graph)
- 圖的節點是某種運算,支持任意數量的輸入和輸出
- 圖的邊是tensor(張量,n維數組),在節點之間流動
-
擁有一個隱藏層的神經網絡的例子
其在TensorFlow中的計算圖如下:
- 其中ReLU是一個表示修正線性單元的激活函數,我們在線性輸入上加入一些非線性函數,能夠賦予神經網絡一定的表達能力。ReLU表示在你的輸入和0之間取最大值,即max(input,0)。
- 而只是一個placeholder(佔位符),只在執行的時候填充輸入,編程的時候指定大小即可。
構建運算圖
要描述這樣的graph flow,只需要編寫代碼:
import tensorflow as tf
# 定義一個變量b初始化爲0 大小爲100維; w是一個服從[-1,1]的均勻分佈
b = tf.Varable(tf.Zeros((100,)))
w = tf.Varable(tf.random_uniform((784,100),-1,1))
# x是一個佔位符,並沒有被初始化爲任何值,編程時只需要指定它:僅接收32位浮點數的數據類型,接收一個(100,784)的shape
x = tf.placeholder(tf.float32,(100,784))
# actually build our flow graph
h = tf.nn.relu(tf.matmul(x,w) +b)
這段代碼只是構建了運算圖,連輸入都沒有,自然無法馬上獲取h的值。上述代碼並沒有顯式地聲明節點和邊,TensorFlow根據數學表達式自動構造了運算圖。
如何得到輸出(Getting output)
到目前爲止,我們只定義了一張圖,如何執行它呢?我們可以通過session將這張圖部署到某個執行環境(CPU、GPU、Google的TensorProcessingUnit……)上去。session就是支持圖中所有操作的執行的硬件環境。
sess.run(fetches,feeds)
-
建立一個會話對象(session object)
-
調用兩個參數fetches和feeds
- fetches:圖結點列表,返回這些結點的輸出結果
- feeds:將圖結點映射至具體值的字典(Dictionary)
# 創建一個會話對象 sess = tf.Session() # sess.run 初始化所有變量 sess.run(tf.initialize_all_variables()) sess.run(h,{x: np.random.random(100,784)})
如何訓練模型
-
對於優化過程而言,如何定義損失?
# prediction是在網絡結束時的預測值,是對神經網絡頂層進行softmax函數計算,輸出一個概率向量,這是一個迴歸過程 prediction = tf.nn.softmax(...) # label是我們真實標記的佔位符,我們的模型根據它來訓練 label = tf.placeholder(tf.float32,[100,10]) # 創建交叉熵結點 cross_entropy = -tf.reduce_sum(label * tf.log(prediction), axis=1)
-
如何計算梯度
# 創建一個優化器 train_step = tf.teain.GradientDescentOptimizer(0.5).minimize(cross_entropy)
Tensorflow中有一個通用的抽象類叫優化器(optimizer),在這個類中的每一個子類都是針對特定學習算法的優化器。
train_step這一步驟實際上在模型上對所有的變量進行梯度的計算,因爲.minimize函數在這裏做了兩件事:
- 第一件是計算參數的梯度,本案例中參數爲交叉熵,它和我們圖中定義的所有變量相關。然後它會對這些變量根據梯度進行更新。
- Q:我們是如何計算梯度的呢?
- A:TensorFlow的工作方式是:每一個圖節點都有一個附加的梯度操作,都有相對於輸入預先構建的輸出梯度。因此,當我們在計算交叉熵相對於所有參數的梯度時,通過圖使用鏈式法則利用反向傳播計算是非常簡單的。
- 第一件是計算參數的梯度,本案例中參數爲交叉熵,它和我們圖中定義的所有變量相關。然後它會對這些變量根據梯度進行更新。
創建一個迭代的學習計劃(Building training schedule)
# 建立一個字典,將值傳給我們之前定義好的兩個佔位符,x和label是圖中的結點,即字典中的關鍵字是圖中的結點,對應的項是Numpy數據
for i in range(1000):
batch_x, batch_label = data.next_batch()
sess.run(train_step,feed_dict={x: batch_x,
label: batch_label })
變量共享
Q:有時候我們想要生成一張圖的多個實例,或者在多機多個GPU上訓練同一個模型,就會帶來同一個變量在不同位置出現。如何在不同位置共享同一個變量呢?
A:
-
一種樸素的想法是:
在代碼頂端創建這個變量的字典。把一些字符串的字典放到它們所代表的變量中。
variable_dict = {
"weights":tf.Variable(tf.random_normal([782,100])),
"biases":tf.Variable(tf.zeros([100]),name="biases")
}
這種做法的缺點在於:破壞了封裝性!(No good for encapsulation!)
-
更成熟一些的做法:
-
Variable_scope()提供了一個簡單的命名空間方案來避免衝突
-
Get_variable() 如果一個具備特定名字的向量不存在的話,該函數會爲你創建一個變量
否則,如果發現它存在,將訪問該變量
-
總結
TF的用法總結如下:
- 創建圖
a 前向傳播/預測
b 優化操作 - 初始化session
- 在session中執行
從線性迴歸來熟悉TensorFlow
現場vim敲代碼環節[撒花🎉]
首先初始程序框架如下,我們需要完成linear_regression()函數來擬合我們的數據分佈
# linear regression
# Author: Nishith Khandwala ([email protected])
# Adapted from https://github.com/hans/ipython-notebooks/
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
import matplotlib
matplotlib.use('TKAgg')
from matplotlib import pyplot as plt
'''
Good ole linear regression: find the best linear fit to our data
'''
def generate_dataset():
# data is generated by y = 2x + e
# where 'e' is sampled from a normal distribution
x_batch = np.linspace(-1, 1, 101)
y_batch = 2 * x_batch + np.random.randn(*x_batch.shape) * 0.3
return x_batch, y_batch
def linear_regression():
return NotImplementedError
def run():
pass
x_batch, y_batch = generate_dataset()
plt.figure(1)
plt.scatter(x_batch, y_batch)
plt.plot(x_batch, y_pred_batch)
plt.savefig('plot.png')
if __name__ == '__main__':
run()
小哥幾乎是敲一句解釋一句,把之前對tensorflow編程流程的講解很好地融入了進來,代碼的完成版如下:
# linear regression
# Author: Nishith Khandwala ([email protected])
# Adapted from https://github.com/hans/ipython-notebooks/
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
import matplotlib
matplotlib.use('TKAgg')
from matplotlib import pyplot as plt
'''
Good ole linear regression: find the best linear fit to our data
'''
def generate_dataset():
# data is generated by y = 2x + e
# where epsilon 'e' is sampled from a normal distribution :e是從正態分佈採樣得到的
x_batch = np.linspace(-1, 1, 101)
y_batch = 2 * x_batch + np.random.randn(*x_batch.shape) * 0.3
return x_batch, y_batch
# 我們將用圖來實現線性迴歸
def linear_regression():
# 首先定義流式圖 flow graph -> 第一步創建佔位符
# 我們創建x類型爲浮點數,希望形狀更通用,設置shape爲(None),意味着你可以動態改變每一批次數據的數量,然後把它們送進網絡中
x = tf.placeholder(tf.float32, shape=(None,), name="x")
y = tf.placeholder(tf.float32, shape=(None,), name="y")
# 定義變量作用域
with tf.variable_scope("lreg") as scope:
w = tf.Variable(np.random.normal(),name="w")
y_pred = tf.multiply(w,x)
loss = tf.reduce_mean(tf.square(y_pred - y))
return x, y, y_pred, loss
def run():
x_batch, y_batch = generate_dataset()
x,y,y_pred, loss=linear_regression()
#優化器 定義學習率爲0.1,最小化模型的損失
optimizer = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
init = tf.global_variables_initializer()
with tf.Session() as session:
session.run(init)
feed_dict = {x: x_batch,y: y_batch}
for _ in range(30):
loss_val, _= session.run([loss,optimizer], feed_dict)
print('loss_val:',loss_val.mean())
y_pred_batch = session.run(y_pred,{x: x_batch})
plt.figure(1)
plt.scatter(x_batch, y_batch)
plt.plot(x_batch, y_pred_batch)
plt.savefig('plot.png')
plt.show()
if __name__ == '__main__':
run()
實驗運行結果:
在terminal打印loss值:
loss_val: 0.6620599
loss_val: 0.587803
loss_val: 0.5233017
…
loss_val: 0.10778806
loss_val: 0.10634918
繪製出圖形如下: