2018/12/25

TensorFlow Regression

20 TensorFlow Regression
我們之前討討論過回歸在機器學習及統計領域裡佔有極其重要的角色,之前我們用scikit-learn 套件學習過回歸,這單元再度來討論回歸,但改用 tf 套件來處理。後續的單元中會碰到各種不同的 Loss function (誤失函數),這單元一開始先來探討幾種常見的 loss function。

🔶 Loss function (誤失函數)
是用量測真正的值和預測值之間的差,有時又稱cost function (成本函數),任何可以用來量測空間兩點間的不同的函數都可以做為誤失函數,一般要求是若是同一點則函數值為0,若而當兩點分得愈開函數值要變大。

■ Norm (範數)
之前已有討論過,這是最常用的度量之一,常用來表示距離。Norm 的定義是 $$ \left \|  \textbf{x}\right \| _p =\left (  \sum_i^n   \left |  x_i \right | ^p     \right )^{1/p}$$ 其中$p\geq 1$ 為一實數, 此定義稱 $l_p\mbox{-norm}$。當$p=1$ 時又稱 taxicab norm,$p=2$ 又稱 Euclidean norm,也是我們平時所說的歐氏距離,當$p$趨近於 $\infty$則是稱為infinity norm or maximum norm,定義成 $$\left \|  \textbf{x}\right \| _\infty:= \max_i \left | x_i \right |$$ 常見的三種norm在 $\mathbb{R}^2$ 中 norm 為1的集合如下圖
norm 為1的集合
圖中所畫線上的任何一點的$x-y$座標組成對應的Norm 其值為1。下列程式計算平面座點點 至原點的$l_1$- 及 $l_2$-norm
import matplotlib.pyplot as plt
import tensorflow as tf
sess = tf.Session()
x_vals = tf.linspace(-1., 1., 500)
target = tf.constant(0.)
l2_y_vals = tf.square(target - x_vals)
l2_y_out = sess.run(l2_y_vals)
l1_y_vals = tf.abs(target - x_vals)
l1_y_out = sess.run(l1_y_vals)
x_array = sess.run(x_vals)
plt.plot(x_array, l2_y_out, 'b-', label='l2 Norm')
plt.plot(x_array, l1_y_out, 'r--', label='l1 Norm')
plt.grid(True)
plt.ylim(-0.1, 0.4)
plt.legend(loc='lower right', prop={'size': 11})
plt.show()
L1, L2 Norm
■ Mean Square Error (MSE 均方誤差)
MSE 為$l_2$-norm 的延伸應用,計算$n$ 對$l_2$-norm 的平方再取平均,定義成
$${\textrm {MSE}} = \frac{1}{n}\sum_{i=1}^{n}\left (y_i-\hat {y}_i  \right )^2$$
其中$y_i$ 為真正的值而$\hat {y}_i $預測的值。MSE 為最基本的度量之一。這個度量有時分母的$n$會用2取代,用以消掉當微分時2階項所產生的2,如此可化簡神經元誤差後向傳播調整係數的計算。

■ Hinge loss function
此函數通常被用於最大邊界(maximum margin)演算法,而最大邊界又是SVM(支撐向量機)用到的重要演算法,此函數定義成 $$L= \max ({0, 1-y \cdot \hat y})$$ 其中$y \in {\{-1, +1}\}$, $\hat y \in \mathbb{R}$, 此函數的輸出當$y$和 $\hat y$同號,且$|\hat y|\geq 1$時為0。
import matplotlib.pyplot as plt
import matplotlib
import tensorflow as tf
sess = tf.InteractiveSession()
%matplotlib inline
myfont = matplotlib.font_manager.FontProperties(
    fname=r'C:/Windows/Fonts/msjh.ttf')
target2 = tf.constant(-1.)
target = tf.constant(1.)
x_vals = tf.linspace(-3., 3., 500)
hinge_y_vals = tf.maximum(0., 1. - tf.multiply(target, x_vals))
hinge_y_vals2 = tf.maximum(0., 1. - tf.multiply(target2, x_vals))
hinge_y_out = hinge_y_vals.eval()
hinge_y_out2 = hinge_y_vals2.eval()
x_array = x_vals.eval()
plt.plot(x_array, hinge_y_out, 'b-', label='y=1')
plt.plot(x_array, hinge_y_out2, 'r-', label='y=-1')
plt.ylim(-1.5, 3)
plt.legend(loc='lower right', prop={'size': 12})
plt.ylabel('輸出',fontproperties=myfont, size=14)
plt.xlabel('預測 y 值',fontproperties=myfont, size=14)
plt.grid()
sess.close()
Hinge loss function
■  Cross entropy loss (相互熵)定義成
$$L=-y\cdot \log_2 {\hat y}-y\cdot \log_2 {(1-\hat y)}$$ 其中$y$ 和 $\hat y$都是介於 $0\sim 1$.
import matplotlib.pyplot as plt
import matplotlib
import tensorflow as tf
sess = tf.InteractiveSession()
%matplotlib inline
x_vals = tf.linspace(-1., 2., 500)
target = tf.constant(1.)
target2 = tf.constant(0.5)
xentropy_y_vals = - tf.multiply(target, 
    tf.log(x_vals))-tf.multiply((1. - target), tf.log(1. - x_vals))
xentropy_y_vals2 = - tf.multiply(target2, 
    tf.log(x_vals))-tf.multiply((1. - target2), tf.log(1. - x_vals))
xentropy_y_out = xentropy_y_vals.eval()
xentropy_y_out2 = xentropy_y_vals2.eval()
x_array =x_vals.eval()
plt.plot(x_array, xentropy_y_out, 'b-', label='y=1')
plt.plot(x_array, xentropy_y_out2, 'r-', label='y=0.5')
plt.ylim(-1.5, 3)
plt.legend(loc='lower right', prop={'size': 12})
plt.ylabel('L',size=14)
plt.xlabel('$\hat y$',size=14)
plt.grid()
sess.close()
相互熵
■  Sigmoid cross entropy loss (S 函數相互熵)$$L=-y\cdot \log_2 {f(\hat y)}-y\cdot \log_2 {(1-f(\hat y))}$$ 其中$f(\cdot)$ 為Sigmoid function.

🔶 使用反矩陣公式求回歸
我們在單元05 多重回歸中己討論過鮮公式直接求解,在此回顧一下,如果以一個特徵對一個目標為例(亦即在$x-y$平面求解),可將所有的$n$個實例寫成
$y_0=\beta _0+\beta _1x_{0}$
$y_1=\beta _0+\beta _1x_{1}$
$\cdots$
$y_{n-1}=\beta _0+\beta _1x_{n-1}$
進一用矩陣表示成
$\textbf{Y}=\textbf{X}\boldsymbol\beta$
其中$\textbf{Y}$為如下的 $n\times 1$ 矩陣,
$\textbf{Y}=\begin{bmatrix} y_0 \\  y_1 \\  \vdots  \\  y_{n-1}  \end{bmatrix}$
而 $\textbf{X}$為如下的$n\times 2$ 矩陣,
$\textbf{X}=\begin{bmatrix} 1& x_0 \\  1& x_1 \\  \vdots&\vdots  \\  1&  x_{n-1}  \end{bmatrix}$
$\boldsymbol\beta$為下列簡單的 $2\times 1$ 矩陣,
$\boldsymbol\beta=\begin{bmatrix} \beta_0 \\  \beta_1   \end{bmatrix}$,
表示成矩陣後,$\boldsymbol\beta$ 可由下列求得
 $\boldsymbol\beta = (\textbf{X}^T \textbf{X})^{-1}\textbf{X}^T\textbf{Y}$ 
之前我們曾用numpy解上式,下列程式則是用 tf 解
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
np.random.seed(101)
sess = tf.InteractiveSession()
%matplotlib inline
x_vals = np.linspace(0, 10, 50)
y_vals = x_vals + np.random.normal(0, 1, 50)
x_vals_column = np.transpose(np.matrix(x_vals))
ones_column = np.transpose(np.matrix(np.repeat(1, 50)))
A = np.column_stack((ones_column,x_vals_column))
b = np.transpose(np.matrix(y_vals))
A_tensor = tf.constant(A)
b_tensor = tf.constant(b)
tA_A = tf.matmul(tf.transpose(A_tensor), A_tensor)
tA_A_inv = tf.matrix_inverse(tA_A)
product = tf.matmul(tA_A_inv, tf.transpose(A_tensor))
beta_val = tf.matmul(product, b_tensor)
solution_eval = beta_val.eval()
print(solution_eval)
y_intercept = solution_eval[0]
slope = solution_eval[1]
print('slope: ',slope)
print('y_intercept: ', y_intercept)
best_fit = []
for i in x_vals:
  best_fit.append(slope*i+y_intercept)
plt.plot(x_vals, y_vals, 'o', label='Data')
plt.plot(x_vals, best_fit, 'r-', label='Best fit line', linewidth=2)
plt.legend(loc='lower right')
plt.ylabel('y values',size=14)
plt.xlabel('x value',size=14)
sess.close()
tf 回歸公式計算
程式是利用 linspace() 在0~10產生50個點,這些點的值加上一高斯隨機值就是$y$值,也就是目標值,第10行用 column_stack() 產生的矩陣就是文字說明中的 $\textbf{X}$。接著就是用反矩陣的公式計算,並把結果畫成圖。

🔶 使用Cholesky 分解求回歸
矩陣反轉的公式求解 $\boldsymbol\beta$ 當矩陣很大時,在數值的運算很沒有效率,較可行的方法是利用Cholesky 分解,將$\textbf{X}^T \textbf{X}$分解成一個下三角和一個上三角矩陣相乘,寫成
$\textbf{X}^T \textbf{X}= \textbf{L} \textbf{U}$
則解最佳係數的問題變成解
 $\textbf{L} \textbf{U} \boldsymbol\beta = \textbf{X}^T\textbf{Y}$
可先令
$ \textbf{U} \boldsymbol\beta =\boldsymbol\alpha$
並解出
 $\textbf{L}\boldsymbol\alpha = \textbf{X}^T\textbf{Y}$
中的的$\boldsymbol\alpha $,再將其值帶入$ \textbf{U} \boldsymbol\beta =\boldsymbol\alpha$中解出$\boldsymbol\beta$,如此可避開求反矩陣。
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
np.random.seed(101)
sess = tf.InteractiveSession()
%matplotlib inline
x_vals = np.linspace(0, 10, 50)
y_vals = x_vals + np.random.normal(0, 1, 50)
x_vals_column = np.transpose(np.matrix(x_vals))
ones_column = np.transpose(np.matrix(np.repeat(1, 50)))
A = np.column_stack((ones_column,x_vals_column))
b = np.transpose(np.matrix(y_vals))
A_tensor = tf.constant(A)
b_tensor = tf.constant(b)
tA_A = tf.matmul(tf.transpose(A_tensor), A_tensor)
L = tf.cholesky(tA_A)
tA_b = tf.matmul(tf.transpose(A_tensor), b)
alpha = tf.matrix_solve(L, tA_b)
beta_val = tf.matrix_solve(tf.transpose(L), alpha)
beta_val = tf.matmul(product, b_tensor)
solution_eval = beta_val.eval()
print(solution_eval)
y_intercept = solution_eval[0]
slope = solution_eval[1]
print('slope: ',slope)
print('y_intercept: ', y_intercept)
best_fit = []
for i in x_vals:
  best_fit.append(slope*i+y_intercept)
plt.plot(x_vals, y_vals, 'o', label='Data')
plt.plot(x_vals, best_fit, 'r-', label='Best fit line', linewidth=2)
plt.legend(loc='lower right')
plt.ylabel('y values',size=14)
plt.xlabel('x value',size=14)
sess.close()
因使用相同的seed,解出來的結果會和直接求反陣的結果相同。一點需注意的是第16行中傳回的只有下三角矩,將此矩陣轉置就是分解所需的上三角。

 🔶 使用tf Optimizer (佳化器)求回歸
上面用反矩陣或矩陣分解的方式求回歸都是直接用數學運算求解,並沒有使用到機器學習中學習的特性。下面的例子我們要用學習的方法求解,先前我們用scikit-learn求解時的主要的步驟約略是
  • 讀進或產生資料
  • 產生Optimizer的實例
  • 使用Optimizer的method fit()去調適參數
  • 使用predict() method 去預測
  • 最後求性能並檢視結果
而在tf 中主要的步驟也很相似
  • 讀進或產生資料
  • 產生placeholder 變數用以饋入資料
  • 建立系統的模型及定義lost (cost) function
  • 產生Optimizer的實例
  • 建立sess及啟始變數
  • 訓練
  • 預測
  • 最後求性能並檢視結果
以下是一個簡單的 tf 學習的例子
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
np.random.seed(101)
learning_rate = 0.0001
training_epochs = 1000
x_train = np.linspace(1, 10, 50)
y_train = x_train + np.random.normal(0, 1, 50)
X = tf.placeholder("float")
Y = tf.placeholder("float")
w = tf.Variable(0.1)
b = tf.Variable(0.1)
y_model = tf.multiply(X, w) + b
cost = tf.reduce_mean(tf.square(Y-y_model))
train_op = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
for epoch in range(training_epochs):
    for (x, y) in zip(x_train, y_train):
        sess.run(train_op, feed_dict={X: x, Y: y})
w_val = sess.run(w)
b_val = sess.run(b)
sess.close()
y_learned = x_train*w_val+b_val
print('w_val: ',w_val)
print('b_val: ', b_val)
plt.plot(x_train,  y_train, 'o',label='Data')
plt.plot(x_train, y_learned, 'r',label='Best fit line', linewidth=2)
plt.legend(loc='lower right')
plt.ylabel('y values',size=14)
plt.xlabel('x value',size=14);
Optimizer learning
由結果可看出學習結果的係數很接近直接用數學求解的結果

沒有留言:

張貼留言