建立張量與變數
張量
- 引入 tensorflow
import tensorflow as tf
- 建立張量並以 0 作為初始值
x = tf.ones(shape=(2,1))
print(x)
>>> tf.Tensor(
[[1.]
[1.]], shape=(2, 1), dtype=float32)
- 建立張量並以 1 作為初始值
y = tf.zeros(shape=(2,1))
print(y)
>>> tf.Tensor(
[[0.]
[0.]], shape=(2, 1), dtype=float32)
- 建立張量,並以常數初始化
a = tf.constant(((1.,4.),(9.,16.)))
print(a)
>>> tf.Tensor(
[[ 1. 4.]
[ 9. 16.]], shape=(2, 2), dtype=float32)
- 建立由亂數組成的張量
- 常態分佈
# 亂數從平均值 0、標準差 1 的常態分佈中抽取出來 # 等同於 np.random.normal(size=(3,1), loc=0., scale=1.) z = tf.random.normal(shape=(3,1), mean=0., stddev=1.) print(z) >>> tf.Tensor( [[-1.1859674 ] [ 0.3267818 ] [ 0.11066005]], shape=(3, 1), dtype=float32)
- 均勻分布
NumPy 與 TensorFlow 的差異在於,TensorFlow 的張量為常數 ,無法修改。# 亂數從 0 到 1 之間均勻分布抽取出來 # 等同於 np.random.uniform(size=(3,1), low=0., high=1.) k = tf.random.uniform(shape=(3,1), minval=0., maxval=1.) print(k) >>> tf.Tensor( [[0.97643256] [0.13791454] [0.7854562 ]], shape=(3, 1), dtype=float32)
- 將 numpy 轉換成 tensorflow
x = np.ones((2,2))
x[0, 0] = 0
y = tf.convert_to_tensor(x)
print(y)
>>> tf.Tensor(
[[0. 1.]
[1. 1.]], shape=(2, 2), dtype=float64)
變數
- 創建變數
- 直接用 tuple 初始化
v = tf.Variable(((3.,1.,3.),(2.,3.,2.))) print(v) >>> <tf.Variable 'Variable:0' shape=(2, 3) dtype=float32, numpy=array( [[3., 1., 3.], [2., 3., 2.]], dtype=float32)>
- 用隨機值初始化
v = tf.Variable(initial_value=tf.random.normal(shape=(3,1))) print(v) >>> <tf.Variable 'Variable:0' shape=(3, 1) dtype=float32, numpy=array( [[2.1368823 ], [0.8101084 ], [0.47075817]], dtype=float32)>
- 變數賦值
- 透過
assign()
方法對變數賦值
v.assign(tf.ones(shape=(3,1))) >>> <tf.Variable 'UnreadVariable' shape=(3, 1) dtype=float32, numpy=array( [[1.], [1.], [1.]], dtype=float32)>
- 對變數局部賦值
v[0,0].assign(0) >>> <tf.Variable 'UnreadVariable' shape=(2, 3) dtype=float32, numpy=array( [[0., 1., 3.], [2., 3., 2.]], dtype=float32)>
- 透過
- 變數運算
- 加法
v.assign_add(tf.ones((2,3))) >>> <tf.Variable 'Variable:0' shape=(2, 3) dtype=float32, numpy=array( [[1., 2., 4.], [3., 4., 3.]], dtype=float32)>
- 減法
v.assign_sub(2*tf.ones((2,3))) >>> <tf.Variable 'UnreadVariable' shape=(2, 3) dtype=float32, numpy=array( [[-1., 0., 2.], [ 1., 2., 1.]], dtype=float32)>
張量操作
基本數學運算
- 初始化
a = tf.constant(((1.,4.),(9.,16.)))
>>> tf.Tensor(
[[ 1. 4.]
[ 9. 16.]], shape=(2, 2), dtype=float32)
- 平方
a = tf.square(a)
print(a)
>>> tf.Tensor(
[[ 1. 16.]
[ 81. 256.]], shape=(2, 2), dtype=float32)
- 平方根
a = tf.sqrt(a)
print(a)
>>> tf.Tensor(
[[ 1. 4.]
[ 9. 16.]], shape=(2, 2), dtype=float32)
- 加法(逐元素相加)
b = tf.ones((2,2))
print(a+b)
>>> tf.Tensor(
[[ 2. 5.]
[10. 17.]], shape=(2, 2), dtype=float32)
- 點積
b = tf.constant(((1.,-1.),(-1.,1.)))
c = tf.matmul(a,b)
print(c)
>>> tf.Tensor(
[[-3. 3.]
[-7. 7.]], shape=(2, 2), dtype=float32)
- 相乘(逐元素相乘)
d = a*b
print(d)
>>> tf.Tensor(
[[ 1. -4.]
[-9. 16.]], shape=(2, 2), dtype=float32)
微分
計算一階梯度
- 試算 \(\text{y}=\text{2x}^2+\text{3x}+\text{1}\)
- \(\text{y}’|_\text{x=3}=\text{4x}+3=\text{15}\)
import tensorflow as tf x = tf.Variable(3.) # 在 with 子句中定義函式 f(x) with tf.GradientTape() as tape: y = 2 * x ** 2 + 3*x + 1 gradient = tape.gradient(y, x) print(gradient) >>> tf.Tensor(15.0, shape=(), dtype=float32)
未來會大量的使用自動微分來處理 \(\frac{\partial L}{\partial W}\) (損失值對權重的梯度)
- 系統預設只會追縱 GradientTape 區塊中的可訓練變數(trainable variable),對常數張量需要用
tape.watch()
進行指定追縱。x = tf.constant(3.) with tf.GradientTape() as tape: tape.watch(x) # 忽略這行輸出會是 None y = 2 * x ** 2 + 3*x + 1 gradient = tape.gradient(y, x) print(gradient) >>> tf.Tensor(15.0, shape=(), dtype=float32)
計算二階梯度
- 試算一個自由落體運動
- 令 \(\text{h}=\frac{1}{2}\text{gt}^2\),其中 \(\text{g}=9.8\)
def free_fall(time): t = tf.Variable(time) with tf.GradientTape() as outer_tape: with tf.GradientTape() as inner_tape: h = 0.5 * 9.8 * t ** 2 v = inner_tape.gradient(h, t) a = outer_tape.gradient(v, t) print(f"t={time:.1f}s, h={h.numpy():.1f}m, v={v.numpy():.1f}m/s, a={a.numpy():.1f}m/s²") free_fall(0.) free_fall(1.) free_fall(2.) free_fall(3.) >>> t=0.0s, h=0.0m, v=0.0m/s, a=9.8m/s² t=1.0s, h=4.9m, v=9.8m/s, a=9.8m/s² t=2.0s, h=19.6m, v=19.6m/s, a=9.8m/s² t=3.0s, h=44.1m, v=29.4m/s, a=9.8m/s²