機器學習-tensorflow建立和操控張量
學習目標:
- 初始化 TensorFlow
Variable
並賦值 - 建立和操控張量
- 回憶線性代數中的加法和乘法知識(如果這些內容對您來說很陌生,請參閱矩陣加法和乘法簡介)
- 熟悉基本的 TensorFlow 數學和陣列運算
from __future__ import print_function import tensorflow as tf try: tf.contrib.eager.enable_eager_execution() print("TF imported with eager execution!") except ValueError: print("TF already imported with eager execution!")
向量加法
您可以對張量執行很多典型數學運算 (TF API)。以下程式碼會建立下列向量(一維張量),所有向量都正好有六個元素:
- 一個包含質數的
primes
向量。 - 一個值全為
1
的ones
向量。 - 一個通過對前兩個向量執行元素級加法而建立的向量。
- 一個通過將
primes
向量中的元素翻倍而建立的向量。
primes = tf.constant([2, 3, 5, 7, 11, 13], dtype=tf.int32) print("primes:", primes) # 建立 tf.ones 方法建立全部為0 ones = tf.ones([6], dtype=tf.int32) print("ones:", ones) # tf.add 兩個向量執行元素級加法 just_beyond_primes = tf.add(primes, ones) print("just_beyond_primes:", just_beyond_primes) twos = tf.constant([2, 2, 2, 2, 2, 2], dtype=tf.int32) primes_doubled = primes * twos print("primes_doubled:", primes_doubled) #輸出如下: primes: tf.Tensor([ 2 3 5 7 11 13], shape=(6,), dtype=int32) ones: tf.Tensor([1 1 1 1 1 1], shape=(6,), dtype=int32) just_beyond_primes: tf.Tensor([ 3 4 6 8 12 14], shape=(6,), dtype=int32) primes_doubled: tf.Tensor([ 4 6 10 14 22 26], shape=(6,), dtype=int32)
輸出張量不僅會返回其值,還會返回其形狀(將在下一部分中討論)以及儲存在張量中的值的型別。呼叫張量的 numpy
方法會返回該張量的值(以 NumPy 陣列形式):
some_matrix = tf.constant([[1, 2, 3], [4, 5, 6]], dtype=tf.int32) print(some_matrix) print("\nvalue of some_matrix is:\n", some_matrix.numpy()) #輸出如下: tf.Tensor( [[1 2 3] [4 5 6]], shape=(2, 3), dtype=int32) value of some_matrix is: [[1 2 3] [4 5 6]]
張量形狀
形狀用於描述張量維度的大小和數量。張量的形狀表示為 list
,其中第 i
個元素表示維度 i
的大小。列表的長度表示張量的階(即維數)。
有關詳情,請參閱 TensorFlow 文件。
以下是一些基本示例:
# A scalar (0-D tensor).
scalar = tf.zeros([])
# A vector with 3 elements.
vector = tf.zeros([3])
# A matrix with 2 rows and 3 columns.
matrix = tf.zeros([2, 3])
print('scalar has shape', scalar.get_shape(), 'and value:\n', scalar.numpy())
print('vector has shape', vector.get_shape(), 'and value:\n', vector.numpy())
print('matrix has shape', matrix.get_shape(), 'and value:\n', matrix.numpy())
#輸出:
scalar has shape () and value:
0.0
vector has shape (3,) and value:
[0. 0. 0.]
matrix has shape (2, 3) and value:
[[0. 0. 0.]
[0. 0. 0.]]
廣播
在數學中,您只能對形狀相同的張量執行元素級運算(例如,相加和等於)。不過,在 TensorFlow 中,您可以對張量執行傳統意義上不可行的運算。TensorFlow 支援廣播(一種借鑑自 NumPy 的概念)。利用廣播,元素級運算中的較小陣列會增大到與較大陣列具有相同的形狀。例如,通過廣播:
-
如果運算需要大小為
[6]
的張量,則大小為[1]
或[]
的張量可以作為運算數。 -
如果運算需要大小為
[4, 6]
的張量,則以下任何大小的張量都可以作為運算數:[1, 6]
[6]
[]
-
如果運算需要大小為
[3, 5, 6]
的張量,則以下任何大小的張量都可以作為運算數:[1, 5, 6]
[3, 1, 6]
[3, 5, 1]
[1, 1, 1]
[5, 6]
[1, 6]
[6]
[1]
[]
注意:當張量被廣播時,從概念上來說,系統會複製其條目(出於效能考慮,實際並不複製。廣播專為實現效能優化而設計)。
有關完整的廣播規則集,請參閱簡單易懂的 NumPy 廣播文件。
以下程式碼執行了與之前一樣的張量運算,不過使用的是標量值(而不是全包含 1
或全包含 2
的向量)和廣播。
primes = tf.constant([2, 3, 5, 7, 11, 13], dtype=tf.int32)
print("primes:", primes)
one = tf.constant(1, dtype=tf.int32)
print("one:", one)
just_beyond_primes = tf.add(primes, one)
print("just_beyond_primes:", just_beyond_primes)
two = tf.constant(2, dtype=tf.int32)
primes_doubled = primes * two
print("primes_doubled:", primes_doubled)
#輸出:
primes: tf.Tensor([ 2 3 5 7 11 13], shape=(6,), dtype=int32)
one: tf.Tensor(1, shape=(), dtype=int32)
just_beyond_primes: tf.Tensor([ 3 4 6 8 12 14], shape=(6,), dtype=int32)
primes_doubled: tf.Tensor([ 4 6 10 14 22 26], shape=(6,), dtype=int32)
練習 1:向量運算。
執行向量運算以建立一個“just_under_primes_squared”向量,其中第 i
個元素等於 primes
中第 i
個元素的平方減 1。例如,第二個元素為 3 * 3 - 1 = 8
。
使用 tf.multiply
或 tf.pow
操作可求得 primes
向量中每個元素值的平方。
# 方法一 使用 tf.multiply 和 tf.add 方法
def solution(primes):
primes_squared = tf.multiply(primes, primes)
neg_one = tf.constant(-1, dtype=tf.int32)
just_under_primes_squared = tf.add(primes_squared, neg_one)
return just_under_primes_squared
# 方法二 使用 tf.pow 和 tf.subtract 方法
def alternative_solution(primes):
primes_squared = tf.pow(primes, 2)
one = tf.constant(1, dtype=tf.int32)
just_under_primes_squared = tf.subtract(primes_squared, one)
return just_under_primes_squared
primes = tf.constant([2, 3, 5, 7, 11, 13], dtype=tf.int32)
just_under_primes_squared = solution(primes)
print("just_under_primes_squared:", just_under_primes_squared)
輸出:
just_under_primes_squared: tf.Tensor([ 3 8 24 48 120 168], shape=(6,), dtype=int32)
矩陣乘法
線上性代數中,當兩個矩陣相乘時,第一個矩陣的列數必須等於第二個矩陣的行數。
3x4
矩陣乘以4x2
矩陣是**有效**的,可以得出一個3x2
矩陣。4x2
矩陣乘以3x4
矩陣是*無效**的。
# A 3x4 matrix (2-d tensor).
x = tf.constant([[5, 2, 4, 3], [5, 1, 6, -2], [-1, 3, -1, -2]],
dtype=tf.int32)
# A 4x2 matrix (2-d tensor).
y = tf.constant([[2, 2], [3, 5], [4, 5], [1, 6]], dtype=tf.int32)
# Multiply `x` by `y`; result is 3x2 matrix.
matrix_multiply_result = tf.matmul(x, y)
print(matrix_multiply_result)
輸出:
tf.Tensor(
[[35 58]
[35 33]
[ 1 -4]], shape=(3, 2), dtype=int32)
張量變形
由於張量加法和矩陣乘法均對運算數施加了限制條件,TensorFlow 程式設計者需要頻繁改變張量的形狀。
您可以使用 tf.reshape
方法改變張量的形狀。
例如,您可以將 8x2 張量變形為 2x8 張量或 4x4 張量:
# Create an 8x2 matrix (2-D tensor).
matrix = tf.constant(
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14], [15, 16]],
dtype=tf.int32)
reshaped_2x8_matrix = tf.reshape(matrix, [2, 8])
reshaped_4x4_matrix = tf.reshape(matrix, [4, 4])
print("Original matrix (8x2):")
print(matrix.numpy())
print("Reshaped matrix (2x8):")
print(reshaped_2x8_matrix.numpy())
print("Reshaped matrix (4x4):")
print(reshaped_4x4_matrix.numpy())
輸出:
Original matrix (8x2):
[[ 1 2]
[ 3 4]
[ 5 6]
[ 7 8]
[ 9 10]
[11 12]
[13 14]
[15 16]]
Reshaped matrix (2x8):
[[ 1 2 3 4 5 6 7 8]
[ 9 10 11 12 13 14 15 16]]
Reshaped matrix (4x4):
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]
[13 14 15 16]]
此外,您還可以使用 tf.reshape
更改張量的維數(“階”)。
例如,您可以將 8x2 張量變形為三維 2x2x4 張量或一維 16 元素張量。
# Create an 8x2 matrix (2-D tensor).
matrix = tf.constant(
[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14], [15, 16]],
dtype=tf.int32)
reshaped_2x2x4_tensor = tf.reshape(matrix, [2, 2, 4])
one_dimensional_vector = tf.reshape(matrix, [16])
print("Original matrix (8x2):")
print(matrix.numpy())
print("Reshaped 3-D tensor (2x2x4):")
print(reshaped_2x2x4_tensor.numpy())
print("1-D vector:")
print(one_dimensional_vector.numpy())
輸出:
Original matrix (8x2):
[[ 1 2]
[ 3 4]
[ 5 6]
[ 7 8]
[ 9 10]
[11 12]
[13 14]
[15 16]]
Reshaped 3-D tensor (2x2x4):
[[[ 1 2 3 4]
[ 5 6 7 8]]
[[ 9 10 11 12]
[13 14 15 16]]]
1-D vector:
[ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]
練習 2:改變兩個張量的形狀,使其能夠相乘。
下面兩個向量無法進行矩陣乘法運算:
a = tf.constant([5, 3, 2, 7, 1, 4])
b = tf.constant([4, 6, 3])
請改變這兩個向量的形狀,使其成為可以進行矩陣乘法運算的運算數。
然後,對變形後的張量呼叫矩陣乘法運算。
請注意,當兩個矩陣相乘時,第一個矩陣的列數必須等於第二個矩陣的行數。
一個可行的解決方案是,將 a
變形為 2x3 矩陣,並將 b
變形為 3x1 矩陣,從而在相乘後得到一個 2x1 矩陣:
還有一個解決方案是,將 a
變形為 6x1 矩陣,並將 b
變形為 1x3 矩陣,從而在相乘後得到一個 6x3 矩陣。
# Task: Reshape two tensors in order to multiply them
a = tf.constant([5, 3, 2, 7, 1, 4])
b = tf.constant([4, 6, 3])
reshaped_a = tf.reshape(a, [2, 3])
reshaped_b = tf.reshape(b, [3, 1])
c = tf.matmul(reshaped_a, reshaped_b)
print("reshaped_a (2x3):")
print(reshaped_a.numpy())
print("reshaped_b (3x1):")
print(reshaped_b.numpy())
print("reshaped_a x reshaped_b (2x1):")
print(c.numpy())
輸出:
reshaped_a (2x3):
[[5 3 2]
[7 1 4]]
reshaped_b (3x1):
[[4]
[6]
[3]]
reshaped_a x reshaped_b (2x1):
[[44]
[46]]
變數、初始化和賦值
到目前為止,我們執行的所有運算都針對的是靜態值 (tf.constant
);呼叫 numpy()
始終返回同一結果。在 TensorFlow 中可以定義 Variable
物件,它的值是可以更改的。
建立變數時,您可以明確設定一個初始值,也可以使用初始化程式(例如分佈):
# Create a scalar variable with the initial value 3.
v = tf.contrib.eager.Variable([3])
# Create a vector variable of shape [1, 4], with random initial values,
# sampled from a normal distribution with mean 1 and standard deviation 0.35.
w = tf.contrib.eager.Variable(tf.random_normal([1, 4], mean=1.0, stddev=0.35))
print("v:", v.numpy())
print("w:", w.numpy())
輸出:
v: [3]
w: [[1.1244123 0.24574566 1.0949733 1.1712703 ]]
要更改變數的值,請使用 assign
操作:
v = tf.contrib.eager.Variable([3])
print(v.numpy())
tf.assign(v, [7])
print(v.numpy())
v.assign([5])
print(v.numpy())
輸出:
[3]
[7]
[5]
向變數賦予新值時,其形狀必須和之前的形狀一致:
v = tf.contrib.eager.Variable([[1, 2, 3], [4, 5, 6]])
print(v.numpy())
try:
print("Assigning [7, 8, 9] to v")
v.assign([7, 8, 9])
except ValueError as e:
print("Exception:", e)
輸出:
[[1 2 3]
[4 5 6]]
Assigning [7, 8, 9] to v
Exception: Shapes (2, 3) and (3,) are incompatible
練習 3:模擬投擲兩個骰子 10 次。
建立一個骰子模擬,在模擬中生成一個 10x3
二維張量,其中:
- 列
1
和2
均儲存一個六面骰子(值為 1-6)的一次投擲值。 - 列
3
儲存同一行中列1
和2
的值的總和。
例如,第一行中可能會包含以下值:
- 列
1
儲存4
- 列
2
儲存3
- 列
3
儲存7
我們將投擲骰子得到的值分別放入兩個 10x1 矩陣中,即 die1
和 die2
。兩次投擲骰子得到的值的總和將儲存在 dice_sum
中,然後,將三個 10x1 矩陣連線成一個矩陣,從而建立一個 10x3 矩陣。
或者,我們可以將投擲骰子得到的值放入一個 10x2 矩陣中,但將同一矩陣的不同列相加會更加複雜。我們還可以將投擲骰子得到的值放入兩個一維張量(向量)中,但這樣做需要轉置結果。
# Task: Simulate 10 throws of two dice. Store the results in a 10x3 matrix.
die1 = tf.contrib.eager.Variable(
tf.random_uniform([10, 1], minval=1, maxval=7, dtype=tf.int32))
die2 = tf.contrib.eager.Variable(
tf.random_uniform([10, 1], minval=1, maxval=7, dtype=tf.int32))
dice_sum = tf.add(die1, die2)
resulting_matrix = tf.concat(values=[die1, die2, dice_sum], axis=1)
print(resulting_matrix.numpy())
輸出:
[[ 2 3 5]
[ 3 1 4]
[ 1 6 7]
[ 4 2 6]
[ 6 5 11]
[ 2 6 8]
[ 4 3 7]
[ 4 2 6]
[ 6 4 10]
[ 6 4 10]]
random_uniform(
shape,
minval=0,
maxval=None,
dtype=tf.float32,
seed=None,
name=None
)
引數:
shape:一維整數張量或 Python 陣列。輸出張量的形狀。
minval:dtype 型別的 0-D 張量或 Python 值;生成的隨機值範圍的下限;預設為0。
maxval:dtype 型別的 0-D 張量或 Python 值。要生成的隨機值範圍的上限。如果 dtype 是浮點,則預設為1 。
dtype:輸出的型別:float16、float32、float64、int32、orint64。
seed:一個 Python 整數。用於為分佈建立一個隨機種子。檢視 tf.set_random_seed 行為。
name:操作的名稱(可選)。
返回:
用於填充隨機均勻值的指定形狀的張量。
tf.concat
第一個引數values:就是兩個或者一組待連線的tensor了
第二個引數axis:必須是一個數,表明在哪一維上連線
如果axis是0,那麼在某一個shape的第一個維度上連,對應到實際,就是疊放到列上
t1 = [[1, 2, 3], [4, 5, 6]]
t2 = [[7, 8, 9], [10, 11, 12]]
tf.concat([t1, t2],0) == > [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
如果concat_dim是1,那麼在某一個shape的第二個維度上連
t1 = [[1, 2, 3], [4, 5, 6]]
t2 = [[7, 8, 9], [10, 11, 12]]
tf.concat([t1, t2],1) ==> [[1, 2, 3, 7, 8, 9], [4, 5, 6, 10, 11, 12