TensorFlow 中的數據核心
由 TensorFlow 的名字我們就可以看出,其寓意表示張量(Tensor)流動(Flow)的意思。由此可見張量為 TensorFlow 的最核心的概念之一。 而這節課我們就來探究一下 TensorFlow 之中的數據核心概念:張量(Tensor)。
1. 什么是張量
“張量是具有統一類型(稱為 dtype )的多維數組 ———— TensorFlow 官方定義”
在 TensorFlow 之中,幾乎所有的數據都要轉換為張量進行運算,因此我們需要對張量有一定的了解。
簡單來說,我們可以將張量看作多維數組,因為是多維數組,因此可以包含三維或者三維以上的維度。就像一維數組可以理解為直線,二維數組可以理解為平面一樣。
張量是 TensorFLow 之中以數據核心,張量的主要組成要素包括:
- 名稱(name);
- 形狀(shape);
- 類型(dtype)。
名稱就是張量的唯一標識符,在 TensorFlow 中可以自動維護,我們一般不需要對名稱進行操作。其余的兩個概念我們可以通過以下例子來理解:
x = tf.ones((64, 28, 28, 3), dtype=tf.float32)
由此我們構建了一個四維張量,它的形狀是(64, 28, 28, 3),其中它的第一維是 64 個維度,第二維與第三維都是28個維度,第四維是 3 個維度。而它的類型是我們所指定的 tf.float32 類型,也就是 32 位浮點類型。
2. 張量的運算
在 TensorFlow 之中,如果我們想指定一個張量,我們可以通過如下操作實現:
x = tf.constant([1, 3, 5])
由此我們指定了一個形狀為(3),數據為[1, 3, 5]的一個張量,而默認的數據類型為int32 。
倘若我們需要指定全為 1 的張量,我們可以通過以下方式實現:
x1 = tf.ones([1, 3, 5])
相似的,如果我們需要指定全為 0 的向量,我們可以通過以下方式實現:
x2 = tf.zeros([1, 3, 5])
下面我們來看一下張量在TensorFlow中的基本運算。
2.1 加減乘除
在 TensorFlow 之中,我們可以使用內置的四則運算函數進行操作:
- tf.add:進行張量的加法;
- tf.subtract:進行張量的減法;
- tf.multiply:進行張量的乘法;
- tf.divid:進行張量的除法。
以乘法為例,我們可以看一下使用方法:
x1 = tf.constant([1, 3, 5])
x2 = tf.constant([1, 3, 5])
y = tf.multiply(x1, x2)
print(y)
我們可以得到如下結果:
tf.Tensor([ 1 9 25], shape=(3,), dtype=int32)
由此我們可以得到兩個張量相乘的結果。
但是 TensorFlow 已經對四則運算進行了重載,因此我們可以直接使用 + - * / 符號進行運算,比如:
y = x1 * x2
也可以得到相同的結果。
2.2 對數運算與指數運算
對于指數運算與對數運算,我們可以采用以下的函數:
- tf.pow:實現指數運算,可以使用 ** 代替;
- tf.exp:實現自然指數運算;
- tf.math.log:實現自然對數運算,與 tf.exp 剛剛相反。
例如,我們可以使用以下例子來進行指數與對數運算:
x = tf.constant([1, 3, 5])
print(tf.pow(x, 3))
x = tf.exp(2)
print(x)
print(tf.math.log(x))
由此我們可以得到運算之后的結果輸出:
tf.Tensor([ 1 27 125], shape=(3,), dtype=int32)
tf.Tensor(7.389056, shape=(), dtype=float32)
tf.Tensor(2.0, shape=(), dtype=float32)
2.3 使用張量進行矩陣運算
使用張量進行矩陣運算的條件為:
- 兩個張量形狀除了最后兩個維度外的所有形狀必須相同;
- 兩個張量形狀最后兩個維度需要符合 a * b 與 b * c的的格式。
在 TensorFlow 之中我們可以通過tf.matmul函數進行運算,具體示例如下:
a = tf.random.normal([3,4,5])
b = tf.random.normal([3,5,6])
print(tf.matmul(a, b))
其中a與b是固定形狀的隨機張量,因為兩者第一維形狀相同,而最后兩維形狀符合矩陣相乘的格式,因此可以進行矩陣運算,得到的結果為:
tf.Tensor(
[[[-0.41255787 0.2539668 -0.70357645 0.02980493 0.5546258
0.5286447 ]
[ 0.7544514 1.2061275 -0.8299564 -0.61776394 -2.0845695
0.55285174]
[ 4.9162273 0.23087293 0.6157658 -0.3430875 -3.9511528
0.2734207 ]
[-0.8638447 -0.48060232 -1.4220456 0.35801342 2.505946
2.7356615 ]]
[[ 2.260117 2.338372 -3.4372165 -0.2901526 0.12752411
-0.23638 ]
[ 0.14264594 -1.9469845 -5.1910253 2.5343626 -4.1282463
1.295904 ]
[ 0.5720302 1.6685274 2.1391735 -1.8491768 2.8305507
-1.1663995 ]
[-0.8750653 -3.5349839 -2.7755249 2.5702014 -3.525653
0.08906344]]
[[ 0.04434888 2.0841029 0.06953187 -2.3450966 -1.5517069
0.83987266]
[ 2.0700073 1.5478165 -0.07335746 -0.36860508 0.46835172
1.861287 ]
[-3.5253298 -1.5082629 -1.6806324 -1.2718723 -1.378425
-1.1990058 ]
[ 0.88312423 1.0631399 2.6772838 -1.0774231 -1.8299285
0.89358884]]], shape=(3, 4, 6), dtype=float32)
可以看到,我們的張量已經進行了矩陣的運算,并切形狀為我們期待的結果。
3. 張量的梯度
在機器學習中我們最經常使用的就是張量的梯度了,張量的梯度可以理解為張量的微分。因為在機器學習之中我們需要不斷地計算參數的導數來計算出參數的誤差,從而對參數進行調整。
在 TensorFlow 之中,計算張量的梯度是通過 tf.tf.GradientTape 來進行的,具體來說分為兩步:
- 在梯度帶中定義運算;
- 運算結束后從梯度帶中得到梯度。
下面我們以一個簡單的例子來展示一下如何求得梯度:
x = tf.Variable(5.0)
with tf.GradientTape() as tape:
y = x**2
dy_dx = tape.gradient(y, x)
print(dy_dx.numpy())
在上面的例子之中,我們首先定義了一個常量 x,然后我們在梯度帶中定義 y 為 x 的平方,然后我們便在記錄的梯度帶中求得 y 對于 x 的梯度,在這里就相當于導數。
因為 x * *2 的導數為 2 * x,因此我們得到的梯度應該是 2 * 5 = 10。
我們查看輸出,果然結果是6。
10.0
上面我們是通過一個常量來進行的演示,其實梯度可以應用于任意的張量,下面我們以一個張量來進行演示:
a = tf.Variable(tf.random.normal((3, 2)), name='a')
b = tf.Variable(tf.zeros(2), name='b')
x = [[1., 2., 3.]]
with tf.GradientTape(persistent=True) as tape:
y = tf.matmul(x, a) + b
loss = tf.reduce_mean(y**2) # 計算y**2的平均值
[dl_da, dl_db] = tape.gradient(loss, [a, b])
print(a)
print(dl_da, dl_db)
在這里我們定義了 a 和 b 兩個張量,并定義了一個常數 x;然后我們在梯度帶中計算了 y = a * x + b,然后又計算了 y 平方的平均值(賦值為 loss );計算結束后我們計算了 loss 對于 a 和 b 的梯度,并將其輸出。
我們可以得到以下結果,可以看到 TensorFlow 已經幫助我們計算了梯度:
<tf.Variable 'a:0' shape=(3, 2) dtype=float32, numpy=
array([[-0.16581778, -0.5726858 ],
[ 0.65533674, 0.8761684 ],
[ 0.7585775 , -1.0951476 ]], dtype=float32)>
tf.Tensor(
[[ 3.4205883 -2.1057918]
[ 6.8411765 -4.2115836]
[10.261765 -6.317375 ]], shape=(3, 2), dtype=float32) tf.Tensor([ 3.4205883 -2.1057918], shape=(2,), dtype=float32)
4. 小結
在該節之中,我們了解到了 TensorFlow 之中最基本的數據核心是張量,然后我們學習了張量的四則運算以及指數對數運算,最后我們學習了如何對張量進行梯度求解,而這將會是日后繼續研究的基礎。