建立張量與變數

張量

  • 引入 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)
    
    • 均勻分布
    # 亂數從 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 的差異在於,TensorFlow 的張量為常數 ,無法修改。
  • 將 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/    t=1.0s, h=4.9m, v=9.8m/s, a=9.8m/    t=2.0s, h=19.6m, v=19.6m/s, a=9.8m/    t=3.0s, h=44.1m, v=29.4m/s, a=9.8m/