TensorFlow 2 簡介
TensorFlow 是由谷歌在 2015 年 11 月發布的深度學習開源工具,我們可以用它來快速構建深度神經網路,并訓練深度學習模型,運用 TensorFlow 及其他開源框架的主要目的,就是為我們提供一個更利于搭建深度學習網路的模塊工具箱,使開發時能夠簡化代碼,最終呈現出的模型更加簡潔易懂,
2019 年,TensorFlow 推出了 2.0 版本,也意味著 TensorFlow 從 1.x 正式過度到 2.x 時代,根據 TensorFlow 官方 介紹內容 顯示,2.0 版本將專注于簡潔性和易用性的改善,主要升級方向包括:
- 使用 Keras 和 Eager Execution 輕松構建模型,
- 在任意平臺上實作穩健的生產環境模型部署,
- 為研究提供強大的實驗工具,
- 通過清理廢棄的 API, 和減少重復來簡化 API,
當然,如果你對 TensorFlow 1.x 本來就不熟悉,可能無法看明白這些升級的內容,不用擔心,本次課程將直接對 TensorFlow 2 進行學習,我們不再回首過去,直接展望未來,
安裝 TensorFlow 2
pip install -U tensorflow
接下來,我們將從 TensorFlow 基礎概念語法入手,一步一步學習 TensorFlow 的使用,
張量
首先,你應該知道什么是向量和矩陣,我們把 1 維的陣列稱之為向量, 2 維的陣列稱之為矩陣,那么,現在告訴你張量其實代表著更大的范圍,你也可以把其看作是N 維陣列,
所以,如果現在重新描述向量和矩陣,就可以是:一階張量為向量,二階張量為矩陣,當然,零階張量也就是標量,而更重要的是 N 階張量,也就是 N 維陣列,


所以,張量并不是什么晦澀難懂的概念,如果不嚴謹的講,張量就是 NN 維陣列,前面提到的向量、矩陣,也是張量,
后面將學習到的大多數深度學習框架都會使用張量的概念,這樣做的好處是統一對資料的定義,NumPy 中,資料都使用 Ndarray 多維陣列進行定義,TensorFlow 中,資料都會用張量進行表述,
下面就來學習 TensorFlow 中對張量的定義,在 TensorFlow 中,每一個 Tensor 都具備兩個基礎屬性:資料型別(默認:float32)和形狀,
其中,資料型別大致如下表所示:

另外,TensorFlow 通過三種符號約定來描述張量維度:階,形狀和維數,三者之間的關系如下:

值得注意的是,上表中的示例都是形容張量的形狀,例如 [3, 4] 指的張量的形狀為 [3, 4],而不是張量 [3, 4],
根據不同的用途,TensorFlow 中主要有 2 種張量型別,分別是:
- tf.Variable :變數 Tensor,需要指定初始值,常用于定義可變引數,例如神經網路的權重,
- tf.constant :常量 Tensor,需要指定初始值,定義不變化的張量,
我們可以通過傳入串列或 NumPy 陣列來新建變數和常量型別的張量:
代碼示例:
import tensorflow as tf
tf.__version__
輸出
'2.0.0'
v = tf.Variable([[1, 2], [3, 4]]) # 形狀為 (2, 2) 的二維變數
v
輸出
<tf.Variable 'Variable:0' shape=(2, 2) dtype=int32, numpy=
array([[1, 2],
[3, 4]], dtype=int32)>
c = tf.constant([[1, 2], [3, 4]]) # 形狀為 (2, 2) 的二維常量
c
輸出
<tf.Tensor: id=9, shape=(2, 2), dtype=int32, numpy=
array([[1, 2],
[3, 4]], dtype=int32)>
仔細觀察,你會發現輸出包含了張量的 3 部分屬性,分別是形狀 shape,資料型別 dtype,以及對應的 NumPy 陣列,
你還可以直接通過 .numpy() 輸出張量的 NumPy 陣列,
c.numpy()
輸出
array([[1, 2],
[3, 4]], dtype=int32)
上面我們已經介紹了常量張量,這里再列舉幾個經常會用到的新建特殊常量張量的方法:
- tf.zeros:新建指定形狀且全為 0 的常量 Tensor
- tf.zeros_like:參考某種形狀,新建全為 0 的常量 Tensor
- tf.ones:新建指定形狀且全為 1 的常量 Tensor
- tf.ones_like:參考某種形狀,新建全為 1 的常量 Tensor
- tf.fill:新建一個指定形狀且全為某個標量值的常量 Tensor
c = tf.zeros([3, 3]) # 3x3 全為 0 的常量 Tensor
c
輸出
<tf.Tensor: id=12, shape=(3, 3), dtype=float32, numpy=
array([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]], dtype=float32)>
tf.ones_like(c) # 與 c 形狀一致全為 1 的常量 Tensor
輸出
<tf.Tensor: id=15, shape=(3, 3), dtype=float32, numpy=
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], dtype=float32)>
tf.fill([2, 3], 6) # 2x3 全為 6 的常量 Tensor
輸出
<tf.Tensor: id=18, shape=(2, 3), dtype=int32, numpy=
array([[6, 6, 6],
[6, 6, 6]], dtype=int32)>
除此之外,我們還可以創建一些序列,例如:
- tf.linspace:創建一個等間隔序列,
- tf.range:創建一個數字序列,
tf.linspace(1.0, 10.0, 5, name="linspace")
輸出
<tf.Tensor: id=22, shape=(5,), dtype=float32, numpy=array([ 1\. , 3.25, 5.5 , 7.75, 10\. ], dtype=float32)>
tf.range(start=1, limit=10, delta=2)
輸出
<tf.Tensor: id=26, shape=(5,), dtype=int32, numpy=array([1, 3, 5, 7, 9], dtype=int32)>
實際上,如果你熟悉 NumPy 的話,你會發現這與 NumPy 中創建各式各樣的多維陣列方法大同小異,資料型別是一切的基礎,了解完張量我們就可以繼續學習張量的運算了,
Eager Execution
TensorFlow 2 帶來的最大改變之一是將 1.x 的 Graph Execution(圖與會話機制)更改為 Eager Execution(動態圖機制),在 1.x 版本中,低級別 TensorFlow API 首先需要定義資料流圖,然后再創建 TensorFlow 會話,這一點在 2.0 中被完全舍棄,TensorFlow 2 中的 Eager Execution 是一種命令式編程環境,可立即評估操作,無需構建圖,
所以說,TensorFlow 的張量運算程序可以像 NumPy 一樣直觀且自然了,接下來,我們以最簡單的加法運算為例:
c + c # 加法計算
輸出
<tf.Tensor: id=27, shape=(3, 3), dtype=float32, numpy=
array([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]], dtype=float32)>
如果你接觸過 1.x 版本的 TensorFlow,你要知道一個加法運算程序十分復雜,我們需要初始化全域變數 → 建立會話 → 執行計算,最終才能列印出張量的運算結果,
init_op = tf.global_variables_initializer() # 初始化全域變數
with tf.Session() as sess: # 啟動會話
sess.run(init_op)
print(sess.run(c + c)) # 執行計算
Eager Execution 帶來的好處顯而易見,其進一步降低了 TensorFlow 的入門門檻,之前的 Graph Execution 模式,實際上讓很多人在入門時都很郁悶,因為完全不符合正常思維習慣,
TensorFlow 中提供的數學計算,包括線性代數計算方面的方法也是應有盡有,十分豐富,下面,我們再列舉一個示例,
a = tf.constant([1., 2., 3., 4., 5., 6.], shape=[2, 3])
b = tf.constant([7., 8., 9., 10., 11., 12.], shape=[3, 2])
c = tf.linalg.matmul(a, b) # 矩陣乘法
c
輸出
<tf.Tensor: id=34, shape=(2, 2), dtype=float32, numpy=
array([[ 58., 64.],
[139., 154.]], dtype=float32)>
tf.linalg.matrix_transpose(c) # 轉置矩陣
輸出
<tf.Tensor: id=36, shape=(2, 2), dtype=float32, numpy=
array([[ 58., 139.],
[ 64., 154.]], dtype=float32)>
你應該能夠感覺到,這些常用 API 都能在 NumPy 中找到對應的方法,這也就是課程需要你預先熟悉 NumPy 的原因,由于函式實在太多太多,一般來講,除了自己經常使用到的,都會在需要某種運算的時候,查閱官方檔案,
所以說,你可以把 TensorFlow 理解成為 TensorFlow 式的 NumPy + 為搭建神經網路而生的 API,
自動微分
在數學中,微分是對函式的區域變化率的一種線性描述,雖然微分和導數是兩個不同的概念,但是,對一元函式來說,可微與可導是完全等價的,如果你熟悉神經網路的搭建程序,應該明白梯度的重要性,而對于復雜函式的微分程序是及其麻煩的,為了提高應用效率,大部分深度學習框架都有自動微分機制,
TensorFlow 中,你可以使用 tf.GradientTape 跟蹤全部運算程序,以便在必要的時候計算梯度,
w = tf.Variable([1.0]) # 新建張量
with tf.GradientTape() as tape: # 追蹤梯度
loss = w * w
grad = tape.gradient(loss, w) # 計算梯度
grad
輸出
<tf.Tensor: id=52, shape=(1,), dtype=float32, numpy=array([2.], dtype=float32)>
上面,我們演示了一個自動微分程序,它的數學求導程序如下:

所以,當 w 等于 1 時,計算結果為 2,
tf.GradientTape 會像磁帶一樣記錄下計算圖中的梯度資訊,然后使用 .gradient 即可回溯計算出任意梯度,這對于使用 TensorFlow 低階 API 構建神經網路時更新引數非常重要,
常用模塊
上面,我們已經學習了 TensorFlow 核心知識,接下來將對 TensorFlow API 中的常用模塊進行簡單的功能介紹,對于框架的使用,實際上就是靈活運用各種封裝好的類和函式,由于 TensorFlow API 數量太多,迭代太快,所以大家要養成隨時 查閱官方檔案 的習慣,
- tf.:包含了張量定義,變換等常用函式和類,
- tf.data:輸入資料處理模塊,提供了像 tf.data.Dataset 等類用于封裝輸入資料,指定批量大小等,
- tf.image:影像處理模塊,提供了像影像裁剪,變換,編碼,解碼等類,
- tf.keras:原 Keras 框架高階 API,包含原 tf.layers 中高階神經網路層,
- tf.linalg:線性代數模塊,提供了大量線性代數計算方法和類,
- tf.losses:損失函式模塊,用于方便神經網路定義損失函式,
- tf.math:數學計算模塊,提供了大量數學計算函式,
- tf.saved_model:模型保存模塊,可用于模型的保存和恢復,
- tf.train:提供用于訓練的組件,例如優化器,學習率衰減策略等,
- tf.nn:提供用于構建神經網路的底層函式,以幫助實作深度神經網路各類功能層,
- tf.estimator:高階 API,提供了預創建的 Estimator 或自定義組件,
在構建深度神經網路時,TensorFlow 可以說提供了你一切想要的組件,從不同形狀的張量、激活函式、神經網路層,到優化器、資料集等,一應俱全,由于 TensorFlow 包含的介面太多,每個都拿出來練習變得不切實際,關于TensorFlow 2.0 的基礎內容就到這里!
想要了解新特性的詳細內容,請學習課程:
《TensorFlow 2.0 新特性快速入門?》
想要進行實戰專案,請學習課程:
《TensorFlow 2 深度學習入門與實踐》?
知乎專欄同步:https://zhuanlan.zhihu.com/p/88829655
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/65628.html
標籤:其他
