??TensorFlow中關于張量的運算主要有:數學運算,矢量運算及矩陣運算,另外在實際的張量運算過程中,支也支持與numpy的廣播特性,不同維度的張量之間往往存在這低維張量向高維張量進行廣播的現象,這也稱之為張量的廣播機制。本文主要從數學運算、矢量運算、矩陣運算三個方面介紹張量運算相關的內容,最后我們在大致了解以下張量的廣播機制。
一、數學運算
??加減乘除、乘方開方、三角函數,指數對數以及邏輯運算等都是TensorFlow中比較常見的數學運算函數,TensorFlow提供了tf.math
包來實現這些數學運算,另外大部分數學運算還可以通過運算符重載的方式來實現 。這里我們簡單示例幾種常見的數學運算操作,同樣的,在正式進入代碼演示之前,先引入我們依賴的包,代碼如下:
import numpy as np
import tensorflow as tf
print("numpy.version:", np.__version__)
print("tensorflow.version:", tf.__version__)
結果如下:
numpy.version: 1.23.5
tensorflow.version: 2.11.0
??下面我們正式展示TensorFlow中的數學運算操作,代碼如下
# 定義兩個二維張量
a = tf.constant([[1.0, 2], [3, 4]])
b = tf.constant([[1.0, 0], [-1, 0]])
print("a:")
tf.print(a)
print("----------------------------------")
print("b:")
tf.print(b)
print("----------------------------------")
# 加法運算
print("a + b:")
tf.print(a + b)
print("----------------------------------")
# 減法運算
print("a - b:")
tf.print(a - b)
print("----------------------------------")
# 乘法運算
print("a * b:")
tf.print(a * b)
print("----------------------------------")
# 除法運算
print("a / b:")
tf.print(a / b)
print("----------------------------------")
# 乘方
print("b ** 2:")
tf.print(b ** 2)
print("----------------------------------")
# 開方
print("sqrt(a):")
tf.print(tf.sqrt(a))
print("----------------------------------")
# add運算符重載,a + 1等價于tf.math.add
print("a + 1:")
tf.print(a + 1)
print("tf.math.add(a, 1):")
tf.print(tf.math.add(a, 1))
print("----------------------------------")
# 邏輯運算
print("b > 0:")
tf.print(b > 0)
print("b == 0:")
tf.print(b == 0)
print("----------------------------------")
# 最大值
print("tf.maximum(a, b)")
tf.print(tf.maximum(a, b))
print("----------------------------------")
# 最小值
print("tf.minimum(a,b)")
tf.print(tf.minimum(a,b))
print("----------------------------------")
結果如下:
a:
[[1 2]
[3 4]]
----------------------------------
b:
[[1 0]
[-1 0]]
----------------------------------
a + b:
[[2 2]
[2 4]]
----------------------------------
a - b:
[[0 2]
[4 4]]
----------------------------------
a * b:
[[1 0]
[-3 0]]
----------------------------------
a / b:
[[1 inf]
[-3 inf]]
----------------------------------
b ** 2:
[[1 0]
[1 0]]
----------------------------------
sqrt(a):
[[1 1.41421354]
[1.73205078 2]]
----------------------------------
a + 1:
[[2 3]
[4 5]]
tf.math.add(a, 1):
[[2 3]
[4 5]]
----------------------------------
b > 0:
[[1 0]
[0 0]]
b == 0:
[[0 1]
[0 1]]
----------------------------------
tf.maximum(a, b)
[[1 2]
[3 4]]
----------------------------------
tf.minimum(a,b)
[[1 0]
[-1 0]]
----------------------------------
二、矢量運算
??矢量運算是指在一個特定軸上進行運算,將一個張量映射到一個標量或者另外一個低維張量。
許多矢量運算都以reduce開頭。下面分別從一維張量和多維張量的角度展示矢量運算的用法,代碼如下:
#一維張量的矢量運算
a = tf.range(1,6)
print("a:")
tf.print(a)
print("----------------------------------")
#求和
tf.print("reduce_sum:", tf.reduce_sum(a, axis = 0))
#如果只是一維張量,默認可以不指定axis
#求最大值
tf.print("reduce_max:", tf.reduce_max(a))
#求最小值
tf.print("reduce_min:", tf.reduce_min(a))
#求最均值
tf.print("reduce_mean:", tf.reduce_mean(a))
#求積
tf.print("reduce_prod:", tf.reduce_prod(a))
#按順序求每個位置累加和,類似于mysql中的窗口函數
tf.print("cumsum:", tf.math.cumsum(a))
#按順序求每個位置累積
tf.print("cumprod:", tf.math.cumprod(a))
print("----------------------------------")
c = tf.constant([True,True,True])
d = tf.constant([False,False,True])
print("c:")
tf.print(c)
print("----------------------------------")
print("d:")
tf.print(d)
print("----------------------------------")
tf.print("reduce_all(c):", tf.reduce_all(c))
tf.print("reduce_all(d):", tf.reduce_all(d))
tf.print("reduce_any(d):", tf.reduce_any(d))
print("----------------------------------")
#tf.math.top_k可以用于對張量取top k
a = tf.constant([1,3,6,6,4,6])
tf.print("a:",a)
values,indices = tf.math.top_k(a, 3, sorted=True)
print("top 3:")
tf.print("indices", indices, "values", values)
print("----------------------------------")
#多維張量的矢量運算
b = tf.random.uniform(shape=[3, 3, 3], minval=0, maxval=2, dtype=tf.int32)
print("b:")
tf.print(b)
print("----------------------------------")
tf.print("axis=0, reduce_sum:\n", tf.reduce_sum(b, axis=0, keepdims=True))
tf.print("axis=1, reduce_sum:\n", tf.reduce_sum(b, axis=1, keepdims=False))
tf.print("axis=2, reduce_sum:\n", tf.reduce_sum(b, axis=2, keepdims=False))
tf.print("no axis, reduce_sum:", tf.reduce_sum(b))
print("----------------------------------")
結果如下:
a:
[1 2 3 4 5]
----------------------------------
reduce_sum: 15
reduce_max: 5
reduce_min: 1
reduce_mean: 3
reduce_prod: 120
cumsum: [1 3 6 10 15]
cumprod: [1 2 6 24 120]
----------------------------------
c:
[1 1 1]
----------------------------------
d:
[0 0 1]
----------------------------------
reduce_all(c): 1
reduce_all(d): 0
reduce_any(d): 1
----------------------------------
a: [1 3 6 6 4 6]
top 3:
indices [2 3 5] values [6 6 6]
----------------------------------
b:
[[[0 0 1]
[1 1 0]
[0 0 0]]
[[0 1 1]
[0 0 1]
[1 1 0]]
[[1 1 0]
[0 0 1]
[0 0 0]]]
----------------------------------
axis=0, reduce_sum:
[[[1 2 2]
[1 1 2]
[1 1 0]]]
axis=1, reduce_sum:
[[1 1 1]
[1 2 2]
[1 1 1]]
axis=2, reduce_sum:
[[1 2 0]
[2 1 2]
[2 1 0]]
no axis, reduce_sum: 11
----------------------------------
三、矩陣運算
??矩陣運算主要是支持一些常規的線性代數中矩陣的計算,TensorFlow提供了tf.linalg
包來實現大部分和矩陣有關的運算,包括轉置、矩陣乘法、求逆、求跡、范數、行列式、求特征值以及矩陣分解等。下面通過代碼來展示常用的矩陣運算,代碼如下:
# 定義兩個二維張量來表示矩陣
a = tf.constant([[1, 2], [3, 4]], dtype=tf.float32)
b = tf.constant([[1, 0], [-1, 0]], dtype=tf.float32)
print("a:")
tf.print(a)
print("----------------------------------")
print("b:")
tf.print(b)
print("----------------------------------")
#矩陣轉置
tf.print("矩陣轉置:\n", tf.transpose(a))
print("----------------------------------")
#矩陣乘法
tf.print("矩陣乘法1:\n", tf.matmul(a, b))
tf.print("矩陣乘法2:\n", a @ b )
print("----------------------------------")
#矩陣求逆
tf.print("矩陣求逆:\n", tf.linalg.inv(a))
print("----------------------------------")
#矩陣求跡
tf.print("矩陣求跡:\n", tf.linalg.trace(a))
print("----------------------------------")
#矩陣特征值
tf.print("矩陣特征值:\n")
print( tf.linalg.eigvals(a))
print("----------------------------------")
#矩陣分解
s,u,v = tf.linalg.svd(a)
print("矩陣分解:\n")
tf.print(u,"\n")
tf.print(s,"\n")
tf.print(v,"\n")
tf.print(u @ tf.linalg.diag(s) @ tf.transpose(v))
print("----------------------------------")
結果如下
a:
[[1 2]
[3 4]]
----------------------------------
b:
[[1 0]
[-1 0]]
----------------------------------
矩陣轉置:
[[1 3]
[2 4]]
----------------------------------
矩陣乘法1:
[[-1 0]
[-1 0]]
矩陣乘法2:
[[-1 0]
[-1 0]]
----------------------------------
矩陣求逆:
[[-2.00000024 1.00000012]
[1.50000012 -0.50000006]]
----------------------------------
矩陣求跡:
5
----------------------------------
矩陣特征值:
tf.Tensor([-0.37228122+0.j 5.372281 +0.j], shape=(2,), dtype=complex64)
----------------------------------
矩陣分解:
[[0.404553503 -0.914514303]
[0.914514303 0.404553503]]
[5.46498537 0.365966141]
[[0.576048374 0.817415595]
[0.817415595 -0.576048374]]
[[0.999999583 1.99999964]
[2.99999976 4]]
----------------------------------
四、廣播機制
??在Numpy中,廣播機制(broad casting)指的是通過擴展低維度ndarray的維度來實現不同維度間ndarray的加減乘除等操作的機制。TensorFlow的廣播機制來源于Numpy,其針對張量運算的廣播規則和Numpy基本是一樣的,廣播規則如下:
- 如果張量的維度不同,對維度小的張量進行升維,直到兩個張量的維度一樣。
- 如果兩個張量在某個維度上的長度是相同的,或者其中一個張量在該維度上的長度為1,那么就認為這兩個張量在該維度上是相容的。
- 如果兩個張量在所有維度上均相容,它們之間就能應用廣播。
- 廣播后,每個維度的長度將取兩個張量在該維度長度的較大值。
- 在任何一個維度上,如果一個張量的長度為1,另一個張量長度大于1,那么在該維度上的廣播就是對第一個張量進行復制。
??TensorFlow中實現廣播有兩種方式,一種是使用tf.broadcast_to
顯式地講張量廣播至指定維度,還有一種就是在運算過程系統進行隱式的廣播。下面進行簡單的示例,代碼如下:
#定義兩個維度不同的張量
a = tf.constant([1, 1, 1])
b = tf.constant([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print("a:")
tf.print(a)
print("----------------------------------")
print("b:")
tf.print(b)
print("----------------------------------")
#顯式廣播
tf.print("顯式廣播:\n", tf.broadcast_to(a, b.shape))
print("----------------------------------")
#隱式廣播
tf.print("隱式廣播:\na + b:\n", a + b) #等價于 tf.broadcast_to(a, b.shape) + b
tf.print("隱式廣播:\na + 1:\n", a + 1)#等價于 a + tf.broadcast_to(1, a.shape)
print("----------------------------------")
#計算廣播后的shape
tf.print("廣播后的shape:", tf.broadcast_static_shape(a.shape, b.shape))
tf.print("廣播后的shape:", tf.broadcast_dynamic_shape(a.shape, b.shape))
print("----------------------------------")
結果如下:
a:
[1 1 1]
----------------------------------
b:
[[1 2 3]
[4 5 6]
[7 8 9]]
----------------------------------
顯式廣播:
[[1 1 1]
[1 1 1]
[1 1 1]]
----------------------------------
隱式廣播:
a + b:
[[2 3 4]
[5 6 7]
[8 9 10]]
隱式廣播:
a + 1:
[2 2 2]
----------------------------------
廣播后的shape: TensorShape([3, 3])
廣播后的shape: [3 3]
----------------------------------
??關于張量的運算,就簡單介紹到這里。