# **4.1.4~4.1.7** ## **1.多個樣本的正向計算** * 前面已經舉過單個樣本的正向計算,現在把它推到多個樣本 - - - 多個樣本(m個樣本$\mathbf{x}^{(i)}$)的資料特徵可以組成一個矩陣$X$: $$ \mathbf{X}=\begin{bmatrix} \begin{array}{} \mathbf{x}^{(1)}\\ \mathbf{x}^{(2)}\\ \vdots\\ \mathbf{x}^{(m)}\\ \end{array} \end{bmatrix} $$ 每個樣本所對應的層輸出向量 $\mathbf{z}^{(1)[l]}$、$\mathbf{a}^{(1)[l]}$的矩陣 $\mathbf{Z}^{(l)}$、$\mathbf{A}^{(l)}$可以表示成 $$ \textbf{Z}^{[l]}=\begin{bmatrix} \begin{array}{} \mathbf{z}^{(1)[l]}\\ \mathbf{z}^{(2)[l]}\\ \vdots\\ \mathbf{z}^{(m)[l]}\\ \end{array} \end{bmatrix} $$ $$ \textbf{A}^{[l]}=\begin{bmatrix} \begin{array}{} \mathbf{a}^{(1)[l]}\\ \mathbf{a}^{(2)[l]}\\ \vdots\\ \mathbf{a}^{(m)[l]}\\ \end{array} \end{bmatrix} $$ 其中,$\mathbf{z}^{(i)[l]}$、$\mathbf{a}^{(i)[l]}$分別是第$i$個樣本的第$l$層的加權和、啟動值,他們分別作為矩陣$\mathbf{Z}^{(l)}$、$\mathbf{A}^{(l)}$的第$i$行 把矩陣展開來寫: $$ \textbf{Z}^{[l]}=\begin{bmatrix} \begin{array}{} \mathbf{z}^{(1)[l]}\\ \mathbf{z}^{(2)[l]}\\ \vdots\\ \mathbf{z}^{(m)[l]}\\ \end{array} \end{bmatrix}= \begin{bmatrix} \begin{array}{} \mathbf{a}^{(1)[l-1]}\mathbf{W}^{[l]}+\mathbf{b}^{[l]}\\ \mathbf{a}^{(2)[l-1]}\mathbf{W}^{[l]}+\mathbf{b}^{[l]}\\ \vdots\\ \mathbf{a}^{(m)[l-1]}\mathbf{W}^{[l]}+\mathbf{b}^{[l]}\\ \end{array} \end{bmatrix} $$ 可以簡化成: $$\textbf{Z}^{[l]} = \textbf{A}^{[l-1]}\textbf{W}^{[l]} + \textbf{b}^{[l]}$$ 同樣的$\mathbf{A}^{(l)}$是$\mathbf{Z}^{(l)}$的啟動值: $$ \textbf{A}^{[l]}=\begin{bmatrix} \begin{array}{} \mathbf{a}^{(1)[l]}\\ \mathbf{a}^{(2)[l]}\\ \vdots\\ \mathbf{a}^{(m)[l]}\\ \end{array} \end{bmatrix}= \begin{bmatrix} \begin{array}{} \mathbf{g}^{[l]}\mathbf{z}^{(1)[l]}\\ \mathbf{g}^{[l]}\mathbf{z}^{(2)[l]}\\ \vdots\\ \mathbf{g}^{[l]}\mathbf{z}^{(m)[l]}\ \end{array} \end{bmatrix} $$ 可以簡化成: $$\textbf{A}^{[l]} = \textbf{g}^{[l]}(\textbf{Z}^{[l]})$$ ## **2.損失函數** * 損失函數:與真實值進行誤差評估(也可稱損失或者代價) *** ### **1.均方差損失函數** * 使用在一般的回歸問題 * 將所有預測值和真實值的差距平方取平均值作為誤差 * 公式:\ 真實值:$F=(f^{(1)},f^{(2)},\ \cdots ,f^{(m)})^T$\ \ 預測值:$Y=(y^{(1)},y^{(2)}\ , \ \cdots ,y^{(m)})^T$\ \ 均方差損失如下\ \ $$L(F,Y)=\frac{1}{m}\sum_{i=1}^{m}||f^{(i)}-y^{(i)}||^2$$ \ 為了讓求導梯度更好看,會將上式除以2,亦即 \ $$L(F,Y)=\frac{1}{2m}\sum_{i=1}^{m}||f^{(i)}-y^{(i)}||^2$$ *** ### **2.二分類交叉熵損失函數** * 使用在二分類問題 * 公式:\ \ 真實標籤:$F=(f^{(1)},f^{(2)},\ \cdots ,f^{(m)})^T$\ \ 預測機率:$Y=(y^{(1)},y^{(2)}\ , \ \cdots ,y^{(m)})^T$ $$L(f,y)=-\frac{1}{m}\sum_{i=1}^{m}[y^{(i)}log\ (f^{(i)})+(1-y^{(i)})\ log\ (1-f^{(i)})]$$ *** ### **3.多分類交叉熵損失函數** * 使用在多分類問題 * 公式:\ $f_c^{(i)}$表示第$i$個樣本屬於$c$類別的機率\ \ $y_c^{(i)}$用 $1$ or $0$ 表示第$i$個樣本是否屬於類別$c$ ( 即用 **one-hot** )\ \ 根據softmax回歸,多分類交叉熵損失函數的公式如下: $$L(\mathbf{f},\mathbf{y})=\frac{1}{m}\sum_{i=1}^{m}L_i(\mathbf{f}^{(i)},\mathbf{y}^{(i)})$$ $$=-\frac{1}{m}\sum_{i=1}^{m}\mathbf{y}^{(i)} \cdot log\ (\mathbf{f}^{(i)})$$ * 舉例 對於三分類問題,即$C=3$,某個樣本的$\mathbf{f}^{(i)}$和$\mathbf{y}^{(i)}$的值分別如下: $$\mathbf{f}^{(i)}= \begin{bmatrix} f_1^{(i)} & f_2^{(i)} & f_3^{(i)} \end{bmatrix}= \begin{bmatrix} 0.3 & 0.5 & 0.2 \end{bmatrix} $$ $$\mathbf{y}^{(i)}= \begin{bmatrix} y_1^{(i)} & y_2^{(i)} & y_3^{(i)} \end{bmatrix}= \begin{bmatrix} 0 & 0 & 1 \end{bmatrix} $$ 則交叉熵損失如下:\ $$-(0 \times log(0.3) + 0 \times log(0.5) + 1 \times log(0.2))=-log(0.2)$$ 可以看出交叉熵損失只取決於真實的類別所對應的那一項(1那一項) 我們也可以加入正則向避免參數過大 $$L(\mathbf{f},\mathbf{y})=\frac{1}{m}\sum_{i=1}^{m}L_i(\mathbf{f}^{(i)},\mathbf{y}^{(i)})+ \lambda\sum_{i=1}^{L}||\mathbf{W}^{[l]}||_2^2$$ *** ## **3.神經網路的訓練與實作** * 設神經元的數目為$n^{(l)}$,前一層的輸出值的數目是$n^{(l-1)}$,那麼該層的神經元泉質矩陣$W^{(l)}$是一個$n^{(l-1)}\times n^{(l)}$ 的矩陣 ```python= W1=np.random.randn(n_1_1,n_1)*0.01 ``` *** ### 1.製作一個兩層的神經網路,進行參數的初始化並return ```python= def initialize_parameters(nx, nh, no):#只有兩層 #nx:輸入的特徵數 #nh:中間層的神經元數 #no:輸出層的神經元數 np.random.seed(2) # 固定的種子,使每次運行這段程式時隨機數的值都是相同的 W1 = np.random.randn(nx, nh) * 0.01 b1 = np.zeros((1, nh)) W2 = np.random.randn(nh, no) * 0.01 b2 = np.zeros((1, no)) #檢驗是否符合,否的話停止執行 assert (W1.shape == (nx, nh)) assert (b1.shape == (1, nh)) assert (W2.shape == (nh, no)) assert (b2.shape == (1, no)) parameters = {"W1": W1, "b1": b1, "W2": W2, "b2": b2} return parameters nx, nh, no = 2, 4, 3 parameters = initialize_parameters(nx, nh, no) print("W1 = " + str(parameters["W1"])) print("b1 = " + str(parameters["b1"])) print("W2 = " + str(parameters["W2"])) print("b2 = " + str(parameters["b2"])) ``` ```python= #print W1 = [[-0.00416758 -0.00056267 -0.02136196 0.01640271] [-0.01793436 -0.00841747 0.00502881 -0.01245288]] b1 = [[0. 0. 0. 0.]] W2 = [[-1.05795222e-02 -9.09007615e-03 5.51454045e-03] [ 2.29220801e-02 4.15393930e-04 -1.11792545e-02] [ 5.39058321e-03 -5.96159700e-03 -1.91304965e-04] [ 1.17500122e-02 -7.47870949e-03 9.02525097e-05]] b2 = [[0. 0. 0.]] ``` *** ### 2.進行正向計算 * (第一層是進行$tanh(x)$,第二層是$sigmoid(x)$而這邊進行到將第二層加權過後的$\mathbf{Z}^{(2)}$輸出,沒有進行$sigmoid(x)$) ```python= def sigmoid(x): return 1 / (1 + np.exp(-x)) def forward_propagation(X, parameters): W1 = parameters["W1"] b1 = parameters["b1"] W2 = parameters["W2"] b2 = parameters["b2"] Z1 = np.dot(X, W1) + b1 # Z1 的形狀:(3, 2) (2, 4)+(1, 4) => (3, 4) A1 = np.tanh(Z1) Z2 = np.dot(A1, W2) + b2 # Z2 的形狀:(3, 4) (4, 3) + (1, 3) => (3, 3) # A2 = sigmoid(Z2),第二個神經元,這邊選擇不做 assert (Z2.shape == (X.shape[0], 3)) return Z2 X = np.array([[1., 2.], [3., 4.], [5., 6.]]) # 每一行對應於一個樣本 Z2 = forward_propagation(X, parameters) print("Z2=",Z2) ``` ```python= #print Z2= [[-1.36253581e-04 4.87491807e-04 -2.47960226e-05] [-1.64985210e-04 1.01574088e-03 -5.99877659e-05] [-1.96135525e-04 1.54048069e-03 -9.36558871e-05]] ``` *** ### 3.計算交叉熵 ```python= def softmax(Z): exp_Z = np.exp(Z - np.max(Z, axis=1, keepdims=True)) #減去最大的指數項,讓最大值的指數向=0 return exp_Z / np.sum(exp_Z, axis=1, keepdims=True) ``` ```python= def softmax_cross_entropy(Z, Y, onehot=False): m = len(Z) F = softmax(Z) if onehot: loss = -np.sum(Y * np.log(F)) / m else: y.flatten() log_Fy = -np.log(F[range(m), y]) loss = np.sum(log_Fy) / m return loss ``` ```python= def softmax_cross_entropy_reg(Z, Y, parameters, onehot=False, reg=1e-3): W1=parameter[0] W2=parameter[2] loss = softmax_cross_entropy(Z, Y, onehot) #損失 reg_term = reg * (np.sum(W1**2) + np.sum(W2**2)) #正則化向 L = loss + reg_term assert isinstance(L, float) #檢查是否為浮點數 return L ``` ```python= y = np.array([2, 0, 1]) # 每一行對應於一個樣本 loss = softmax_cross_entropy_reg(Z2, y, parameters) print(loss) ``` ```python= #print 1.098427770814438 ``` * 包起來讓我們只輸入資料和目標值就可以計算交叉熵 ```python= def compute_loss_reg(f, loss, X, Y, parameters, reg=1e-3): Z2 = f(X, parameters) return loss(Z2, Y, parameters, reg) reg = 1e-3 L = compute_loss_reg(forward_propagation, softmax_cross_entropy_reg, X, y, parameters, reg) print(L) ``` *** ### 4.製作一個丟入f和parameters就能返回的權重的函數 * 這在2.4章節實作過,但他預設是使用lambda函數,所以需要適時調整 ```python= def numerical_gradient(f, params, eps=1e-6): numerical_grads = [] # 儲存數值梯度的列表 for x in params: grad = np.zeros(x.shape) # 初始化梯度為零陣列 # 創建用於遍歷 x 的迭代器,設定返回多維索引和可讀寫操作的標誌 it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite']) # 簡單來說就是對每個x去算他的梯度 # 遍歷每個元素 while not it.finished: idx = it.multi_index # 當前元素的多維索引 old_value = x[idx] # 儲存原始值 # 對該元素進行微小變化,計算函數在新值下的變化 x[idx] = old_value + eps fx_plus = f() # 計算 f(x + eps) x[idx] = old_value - eps fx_minus = f() # 計算 f(x - eps) # 根據數值變化計算該元素的數值偏導數 grad[idx] = (fx_plus - fx_minus) / (2 * eps) x[idx] = old_value # 恢復原始值 it.iternext() # 移動到下一個元素 numerical_grads.append(grad) # 將該參數的數值梯度加入列表 return numerical_grads # 返回數值梯度列表 #計算權重值 def f(): return compute_loss_reg (forward_propagation, softmax_cross_entropy_reg, X, y, parameters,reg) num_grads = numerical_gradient (f, parameters) print(num_grads[0]) print(num_grads[3]) #在這邊應該要用 #print(num_grads["W1"])我不清楚他單純是忘記前面用dict還是想表達使用list或numpy的狀況... #print(num_grads["W2"]) ``` *** ### 5.簡單的梯度下降優化器 ```python= def max_abs(grads):#取最大的梯度 return max(np.max(np.abs(grad)) for grad in grads) def gradient_descent_ANN(f, X, y, parameters, reg=0.0, alpha=0.01, iterations=100, gamma=0.8, epsilon=1e-8): losses = [] for i in range(iterations): loss = f() # 計算當前損失 grads = numerical_gradient(f, parameters) # 計算梯度 if max_abs(grads) < epsilon: print("Gradient is small enough!") print("Number of iterations:", i) break for param, grad in zip(parameters, grads): #zip:把將 parameters和grads 中的對應元素分別配對 param -= alpha * grad # 更新模型參數 losses.append(loss) # 儲存當前損失值 return parameters, losses ``` 題目 : 代表預測值跟真實值的誤差叫什麼函數?