CS224d-Day 2:
在 Day 1 里,先了解了一下 NLP 和 DP 的主要概念,對它們有了一個大體的印象,用向量去表示研究對象,用神經網絡去學習,用 TensorFlow 去訓練模型,基本的模型和算法包括 word2vec,softmax,RNN,LSTM,GRU,CNN,大型數據的 seq2seq,還有未來比較火熱的研究方向 DMN,還有模型的調優。
今天先不直接進入理論學習,而是先學習一下 TensorFlow,在原課程里,這部分在第7講,但是我覺得最高效地學習算法的方式,就是一邊學理論,一邊寫代碼,實踐中才能理解更深刻。
Day 2 先認識 TensorFlow,了解一下基本用法,下一次就寫代碼來訓練模型算法,以問題為導向,以項目為驅動。
本文結構:
- 1. TensorFlow 是什么
- 2. 為什么需要 TensorFlow
- 3. TensorFlow 的優點
- 4. TensorFlow 的工作原理
- 5. 安裝
-
6. TensorFlow 基本用法
- 要點
- 例子
- 概念
- 圖
- 張量
- 會話
1. TensorFlow 是什么
是一個深度學習庫,由 Google 開源,可以對定義在 Tensor(張量)上的函數自動求導。
Tensor(張量)意味著 N 維數組,Flow(流)意味著基于數據流圖的計算,TensorFlow即為張量從圖的一端流動到另一端。
它的一大亮點是支持異構設備分布式計算,它能夠在各個平臺上自動運行模型,從電話、單個CPU / GPU到成百上千GPU卡組成的分布式系統。
支持CNN、RNN和LSTM算法,是目前在 Image,NLP 最流行的深度神經網絡模型。
2. 為什么需要 TensorFlow 等庫
深度學習通常意味著建立具有很多層的大規模的神經網絡。
除了輸入X,函數還使用一系列參數,其中包括標量值、向量以及最昂貴的矩陣和高階張量。
在訓練網絡之前,需要定義一個代價函數,常見的代價函數包括回歸問題的方差以及分類時候的交叉熵。
訓練時,需要連續的將多批新輸入投入網絡,對所有的參數求導后,代入代價函數,從而更新整個網絡模型。
這個過程中有兩個主要的問題:1. 較大的數字或者張量在一起相乘百萬次的處理,使得整個模型代價非常大。2. 手動求導耗時非常久。
所以 TensorFlow 的對函數自動求導以及分布式計算,可以幫我們節省很多時間來訓練模型。
3. TensorFlow 的優點
第一,基于Python,寫的很快并且具有可讀性。
第二,在多GPU系統上的運行更為順暢。
第三,代碼編譯效率較高。
第四,社區發展的非常迅速并且活躍。
第五,能夠生成顯示網絡拓撲結構和性能的可視化圖。
4. TensorFlow 的工作原理
TensorFlow是用數據流圖(data flow graphs)技術來進行數值計算的。
數據流圖是描述有向圖中的數值計算過程。
有向圖中,節點通常代表數學運算,邊表示節點之間的某種聯系,它負責傳輸多維數據(Tensors)。
節點可以被分配到多個計算設備上,可以異步和并行地執行操作。因為是有向圖,所以只有等到之前的入度節點們的計算狀態完成后,當前節點才能執行操作。
5. 安裝
極客學院有官方文檔翻譯版,講的很清楚,有各種安裝方式的講解。
我選擇基于 Anaconda 的安裝,因為這個很方便。
Anaconda 是一個集成許多第三方科學計算庫的 Python 科學計算環境,用 conda 作為自己的包管理工具,同時具有自己的計算環境,類似 Virtualenv。
安裝 Anaconda
我之前已經安裝過 Anaconda 了,直接從下面進行:建立一個 conda 計算環境
# 計算環境名字叫 tensorflow:
# Python 2.7
$ conda create -n tensorflow python=2.7
- 激活環境,使用 conda 安裝 TensorFlow
$ source activate tensorflow
(tensorflow)$ # Your prompt should change
# Mac OS X, CPU only:
(tensorflow)$ pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0rc0-py2-none-any.whl
安裝成功后,每次使用 TensorFlow 的時候需要激活 conda 環境
conda 環境激活后,你可以測試是否成功,在終端進入 python,輸入下面代碼,沒有提示錯誤,說明安裝 TensorFlow 成功:
$ python
...
>>> import tensorflow as tf
>>> hello = tf.constant('Hello, TensorFlow!')
>>> sess = tf.Session()
>>> print(sess.run(hello))
Hello, TensorFlow!
>>> a = tf.constant(10)
>>> b = tf.constant(32)
>>> print(sess.run(a + b))
42
>>>
- 當你不用 TensorFlow 的時候,關閉環境:
(tensorflow)$ source deactivate
$ # Your prompt should change back
- 再次使用的時候再激活:
$ source activate tensorflow
(tensorflow)$ # Run Python programs that use TensorFlow.
...
(tensorflow)$ source deactivate
在 Jupyter notebook 里用 TensorFlow
我在 (tensorflow)$ 直接輸入 jupyter notebook 后,輸入 import tensorflow as tf 是有錯誤的,可以參考這里。
6. TensorFlow 基本用法
接下來按照官方文檔中的具體代碼,來看一下基本用法。
你需要理解在TensorFlow中,是如何:
- 將計算流程表示成圖;
- 通過Sessions來執行圖計算;
- 將數據表示為tensors;
- 使用Variables來保持狀態信息;
- 分別使用feeds和fetches來填充數據和抓取任意的操作結果;
先看個栗子:
例1,生成三維數據,然后用一個平面擬合它:
# (tensorflow)$ python 用 Python API 寫 TensorFlow 示例代碼
import tensorflow as tf
import numpy as np
# 用 NumPy 隨機生成 100 個數據
x_data = np.float32(np.random.rand(2, 100))
y_data = np.dot([0.100, 0.200], x_data) + 0.300
# 構造一個線性模型
b = tf.Variable(tf.zeros([1]))
W = tf.Variable(tf.random_uniform([1, 2], -1.0, 1.0))
y = tf.matmul(W, x_data) + b
# 最小化方差
loss = tf.reduce_mean(tf.square(y - y_data))
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)
# 初始化變量
init = tf.initialize_all_variables()
# 啟動圖 (graph)
sess = tf.Session()
sess.run(init)
# 擬合平面
for step in xrange(0, 201):
sess.run(train)
if step % 20 == 0:
print step, sess.run(W), sess.run(b)
# 輸出結果為:
0 [[-0.14751725 0.75113136]] [ 0.2857058]
20 [[ 0.06342752 0.32736415]] [ 0.24482927]
40 [[ 0.10146417 0.23744738]] [ 0.27712563]
60 [[ 0.10354312 0.21220125]] [ 0.290878]
80 [[ 0.10193551 0.20427427]] [ 0.2964265]
100 [[ 0.10085492 0.201565 ]] [ 0.298612]
120 [[ 0.10035028 0.20058727]] [ 0.29946309]
140 [[ 0.10013894 0.20022322]] [ 0.29979277]
160 [[ 0.1000543 0.20008542]] [ 0.29992008]
180 [[ 0.10002106 0.20003279]] [ 0.29996923]
200 [[ 0.10000814 0.20001261]] [ 0.29998815]
注意這幾條代碼:
W = tf.Variable(tf.random_uniform([1, 2], -1.0, 1.0))
y = tf.matmul(W, x_data) + b
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)
sess.run(train)
print step, sess.run(W), sess.run(b)
接下來看具體概念:
- TensorFlow 用圖來表示計算任務,圖中的節點被稱之為operation,縮寫成op。
- 一個節點獲得 0 個或者多個張量 tensor,執行計算,產生0個或多個張量。
- 圖必須在會話(Session)里被啟動,會話(Session)將圖的op分發到CPU或GPU之類的設備上,同時提供執行op的方法,這些方法執行后,將產生的張量(tensor)返回。
1. 構建圖
例2,計算矩陣相乘:
import tensorflow as tf
# 創建一個 常量 op, 返回值 'matrix1' 代表這個 1x2 矩陣.
matrix1 = tf.constant([[3., 3.]])
# 創建另外一個 常量 op, 返回值 'matrix2' 代表這個 2x1 矩陣.
matrix2 = tf.constant([[2.],[2.]])
# 創建一個矩陣乘法 matmul op , 把 'matrix1' 和 'matrix2' 作為輸入.
# 返回值 'product' 代表矩陣乘法的結果.
product = tf.matmul(matrix1, matrix2)
默認圖有三個節點, 兩個 constant() op, 和一個 matmul() op. 為了真正進行矩陣相乘運算, 并得到矩陣乘法的結果, 你必須在會話里啟動這個圖.
2. 張量 Tensor
從向量空間到實數域的多重線性映射(multilinear maps)(v是向量空間,v*是對偶空間)
例如代碼中的 [[3., 3.]],Tensor 可以看作是一個 n 維的數組或列表。在 TensorFlow 中用 tensor 數據結構來代表所有的數據, 計算圖中, 操作間傳遞的數據都是 tensor。
3. 在一個會話中啟動圖
創建一個 Session 對象, 如果無任何創建參數, 會話構造器將啟動默認圖。
會話負責傳遞 op 所需的全部輸入,op 通常是并發執行的。
# 啟動默認圖.
sess = tf.Session()
# 調用 sess 的 'run()' 方法, 傳入 'product' 作為該方法的參數,
# 觸發了圖中三個 op (兩個常量 op 和一個矩陣乘法 op),
# 向方法表明, 我們希望取回矩陣乘法 op 的輸出.
result = sess.run(product)
# 返回值 'result' 是一個 numpy `ndarray` 對象.
print result
# ==> [[ 12.]]
# 任務完成, 需要關閉會話以釋放資源。
sess.close()
交互式使用
在 Python API 中,使用一個會話 Session 來 啟動圖, 并調用 Session.run() 方法執行操作.
為了便于在 IPython 等交互環境使用 TensorFlow,需要用 InteractiveSession 代替 Session 類, 使用 Tensor.eval() 和 Operation.run() 方法代替 Session.run()。
例3,計算 'x' 減去 'a':
# 進入一個交互式 TensorFlow 會話.
import tensorflow as tf
sess = tf.InteractiveSession()
x = tf.Variable([1.0, 2.0])
a = tf.constant([3.0, 3.0])
# 使用初始化器 initializer op 的 run() 方法初始化 'x'
x.initializer.run()
# 增加一個減法 sub op, 從 'x' 減去 'a'. 運行減法 op, 輸出結果
sub = tf.sub(x, a)
print sub.eval()
# ==> [-2. -1.]
變量 Variable
上面用到的張量是常值張量(constant)。
變量 Variable,是維護圖執行過程中的狀態信息的. 需要它來保持和更新參數值,是需要動態調整的。
下面代碼中有 tf.initialize_all_variables
,是預先對變量初始化,
Tensorflow 的變量必須先初始化,然后才有值!而常值張量是不需要的。
下面的 assign() 操作和 add() 操作,在調用 run() 之前, 它并不會真正執行賦值和加和操作。
例4,使用變量實現一個簡單的計數器:
# -創建一個變量, 初始化為標量 0. 初始化定義初值
state = tf.Variable(0, name="counter")
# 創建一個 op, 其作用是使 state 增加 1
one = tf.constant(1)
new_value = tf.add(state, one)
update = tf.assign(state, new_value)
# 啟動圖后, 變量必須先經過`初始化` (init) op 初始化,
# 才真正通過Tensorflow的initialize_all_variables對這些變量賦初值
init_op = tf.initialize_all_variables()
# 啟動默認圖, 運行 op
with tf.Session() as sess:
# 運行 'init' op
sess.run(init_op)
# 打印 'state' 的初始值
# 取回操作的輸出內容, 可以在使用 Session 對象的 run() 調用 執行圖時,
# 傳入一些 tensor, 這些 tensor 會幫助你取回結果.
# 此處只取回了單個節點 state,
# 也可以在運行一次 op 時一起取回多個 tensor:
# result = sess.run([mul, intermed])
print sess.run(state)
# 運行 op, 更新 'state', 并打印 'state'
for _ in range(3):
sess.run(update)
print sess.run(state)
# 輸出:
# 0
# 1
# 2
# 3
上面的代碼定義了一個如下的計算圖:
Ok,總結一下,來一個清晰的代碼:
過程就是:建圖->啟動圖->運行取值
計算矩陣相乘:
import tensorflow as tf
# 建圖
matrix1 = tf.constant([[3., 3.]])
matrix2 = tf.constant([[2.],[2.]])
product = tf.matmul(matrix1, matrix2)
# 啟動圖
sess = tf.Session()
# 取值
result = sess.run(product)
print result
sess.close()
上面的幾個代碼介紹了基本用法,通過觀察,有沒有覺得 tf 和 numpy 有點像呢。
TensorFlow和普通的Numpy的對比
在cs224d的課件中有下面這個代碼,來看一下二者之間的區別:
eval()
在 Python 中定義完 a 后,直接打印就可以看到 a。
In [37]: a = np.zeros((2,2))
In [39]: print(a)
[[ 0. 0.]
[ 0. 0.]]
但是在 Tensorflow 中需要顯式地輸出(evaluation,也就是說借助eval()函數)!
In [38]: ta = tf.zeros((2,2))
In [40]: print(ta)
Tensor("zeros_1:0", shape=(2, 2), dtype=float32)
In [41]: print(ta.eval())
[[ 0. 0.]
[ 0. 0.]]
**通過幾個例子了解了基本的用法,feed 在上面的例子中還沒有寫到,下一次就能用到了,其他的可以查詢這里。 **
Day 1 宏觀了解了 NLP,Day 2 搞定了工具,下次要直接先進入實戰,訓練模型,先從 Logistic 和 NN 開始,一邊看模型一邊寫代碼一邊思考模型原理,這樣理解才會更深刻!
[cs224d]
Day 1. 深度學習與自然語言處理 主要概念一覽
Day 2. TensorFlow 入門
Day 3. word2vec 模型思想和代碼實現
Day 4. 怎樣做情感分析
Day 5. CS224d-Day 5: RNN快速入門
Day 6. 一文學會用 Tensorflow 搭建神經網絡
Day 7. 用深度神經網絡處理NER命名實體識別問題
Day 8. 用 RNN 訓練語言模型生成文本
Day 9. RNN與機器翻譯
Day 10. 用 Recursive Neural Networks 得到分析樹
Day 11. RNN的高級應用