# ANN 理論 ## Activation Function (激勵函數) 讓資料可以被微分 [Activation Function List](https://en.wikipedia.org/wiki/Activation_function) ## Backpropagation (反向傳播) 利用更新 權重 來影響 ANN 的結果 (看 [SDG](#SGD-隨機梯度下降法)) ![反向](https://i.imgur.com/MBbiUmW.gif) ### Cost Function (成本函數) #### MSE (均方誤差) 基本上是變異數 $$Error=(\hat{X}-X)$$ $$MSE=\frac{1}{n}\sum_{i=1}^{n}(Error_{i})^2$$ $\hat{X}$是AI預期值 $X$是真實輸出值 $n$是觀察的數目 ### SGD (隨機梯度下降法) ![](https://i.imgur.com/Qr7PnJE.png) 梯度下降常會遇到卡在 Local Minmum ,因為其原則是 ==如果斜率是負的就繼續==,但在遇到 Local Minmum 就會卡住,所以要用Momentum SGD 公式 $$W_x^{t+1}=W_x^t-a\nabla f(W_x^t)$$ $a$是Learning Rate (學習率) $W_x^{t+1}$是新的權重 $W_x^t$是舊的權重 $t$是更新次數 <!-- Momentum 公式 --> 將$Error$對$Weight_{i}$微分: $\frac{dError}{dWeight_{i}}=\frac{\sum (x_i-f(x_i))^2}{dWeight_{i}}=\frac{\sum x_i^2+f(x_i)^2-2x_if(x_i)}{dWeight_{i}}$ $=(\sum\frac{x_i^2+f(x_i)^2-2x_if(x_i)}{df(x_i)})*\frac{df(x_i)}{dWeight_{i}}=\sum(2f(x_i)-2)*\frac{df(x_i)}{dWeight_{i}}$ 其中對每一次的batch而言,$\sum(2f(x_i)-2*x_i)$是常數。 $\frac{df(x_i)}{dWeight_{i}}$可以透過自動微分快速取得。 ## 自動微分 如果假設 $$e=(a+b)(b+1)$$ 那他等於 $c=a+b$ $d=b+1$ $e=cd$ 轉成樹會長這樣 ![](https://i.imgur.com/QDcWpoc.png) 帶入值($a=2,b=1$)會長這樣 ![](https://i.imgur.com/bct9Qp8.png) 使用前向模式微分 公式是 $\Sigma子節點\times邊$ ![](https://i.imgur.com/nDprToZ.png) 使用後向模式微分 公式是 $\Sigma父節點\times邊$ ![](https://i.imgur.com/kIXOESf.png) 實作 `nodes.go` ```go= package gmath type calcPartial func(float64, float64) (float64, float64) type calcValue func(float64, float64) float64 type Node struct { // is (left side value,right side value)(left side partial,right side partial) calcPartial calcPartial // is (left side value,right side value)(this value) calcValue calcValue // diff partial float64 // calc number & const number value value float64 rSide, lSide *Side } type Side struct { // child node node *Node // diff partial float64 } func Const(value float64) *Node { return &Node{ value: value, } } func Varible(value float64) *Node { return &Node{ value: value, } } func (s *Node) Calc() { s.forward() s.partial = 1 s.backward() } func (s *Node) Set(value float64) *Node { s.value = value return s } func (s *Node) Partial() float64 { return s.partial } func (s *Node) forward() float64 { if s.calcValue != nil { s.value = s.calcValue(s.lSide.node.forward(), s.rSide.node.forward()) } if s.calcPartial != nil { s.lSide.partial, s.rSide.partial = s.calcPartial(s.lSide.node.value, s.rSide.node.value) } return s.value } func (s *Node) backward() { if s.rSide != nil { s.rSide.node.partial += s.partial * s.rSide.partial s.rSide.node.backward() } if s.lSide != nil { s.lSide.node.partial += s.partial * s.lSide.partial s.lSide.node.backward() } } func newNode(calcValue calcValue, calcPartial calcPartial) *Node { return &Node{ calcPartial: calcPartial, calcValue: calcValue, } } func newSide(value *Node) *Side { return &Side{ node: value, } } ``` `math.go` ```go= package gmath import "math" func Add(value ...*Node) *Node { return buildOP(valueAdd, partialAdd, value...) } func Sub(value ...*Node) *Node { return buildOP(valueSub, partialSub, value...) } func Mult(value ...*Node) *Node { return buildOP(valueMult, partialMult, value...) } func Div(value ...*Node) *Node { return buildOP(valueDiv, partialDiv, value...) } func buildOP(calcValue calcValue, calcPartial calcPartial, value ...*Node) *Node { node := newNode(calcValue, calcPartial) for _, v := range value { if node.rSide == nil { node.rSide = newSide(v) continue } if node.lSide == nil { node.lSide = newSide(v) continue } newnode := newNode(calcValue, calcPartial) newnode.rSide, node = newSide(node), newnode } return node } func partialAdd(lvalue float64, rvalue float64) (float64, float64) { return 1, 1 } func partialSub(lvalue float64, rvalue float64) (float64, float64) { return -1, -1 } func partialMult(lvalue float64, rvalue float64) (float64, float64) { return rvalue, lvalue } func partialDiv(lvalue float64, rvalue float64) (float64, float64) { return -math.Pow(lvalue, -2) * math.Pow(rvalue, -1), -math.Pow(rvalue, -2) * math.Pow(lvalue, -1) } func valueAdd(lvalue float64, rvalue float64) float64 { return lvalue + rvalue } func valueSub(lvalue float64, rvalue float64) float64 { return -lvalue - rvalue } func valueMult(lvalue float64, rvalue float64) float64 { return lvalue * rvalue } func valueDiv(lvalue float64, rvalue float64) float64 { return 1 / (lvalue * rvalue) } ``` 使用 ```go= a := Varible(2) b := Varible(3) c := Add(Mult(a, b), a) c.Calc() // 4 2 print(a.Partial(), b.Partial()) ``` ## 基本數學概念 ### 微分 假設有一個函數$f(x)=x^{n}$,將它微分完會變成$f'(x)=nx^{n-1}$ 範例 $f(x)=x^{5}$ 會變成 $f'(x)=5x^{4}$ $f'$代表微分一次,$f''$是兩次,以此類推 ### 偏微分 偏微分是選擇曲面中的一條切線,並求出它的斜率 假設$f(x,y)=x^2+2xy+y^2$, $$\frac{\partial f}{\partial y}=2x+2y$$ 意思是指將$y$當成自變量,而$x$當成常數的微分結果 將$y$當成自變量,$x$當成常數的函數標示為$f_x(y)=\cdots$ ### 向量 敘述一個空間的基本元素 ~~空間角可以用內積公式取得~~ <!-- 貌似不行,但cos theta確定可以 --> $\vec{x}$=($x_{1}$,$x_{2}$,$x_{3},...)$ $|\vec{x}|=\sqrt{x_{1}^{2}+x_{2}^{2}+x_{3}^{2}+\cdots}$ <!-- 以下省略 --> $\cos\theta$=$\frac{\vec{x}\vec{y}}{|\vec{x}||\vec{y}|}$ $\cos\theta$又稱相關係數 ### 向量微分 先跟Nabla說聲好 $$\nabla f(x)$$ 一維度的向量x的梯度$f'(x)$ 多維度的向量x的梯度用$\nabla f(x)$ <!-- 我不懂... --> <!-- +1 by Hugo --> <!-- working on it --> ### 矩陣 這是一個矩陣 $$ \begin{bmatrix} a & b \\ c & d \end{bmatrix} $$ 方陣 二階方陣 $$ \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix} $$ 矩陣裡只有加減乘,不一定能除 除的話要乘以其-1次方 $A^1*A^{-1}=方陣$ 這是轉置矩陣(上面有個T),如果轉置2次等於沒轉置 $$ \begin{bmatrix} a & b \\ c & d \end{bmatrix}^T= \begin{bmatrix} a & c \\ b & d \end{bmatrix} $$ $$ \begin{bmatrix} a_1 \\ a_2 \end{bmatrix} \begin{bmatrix} b_1 b_2 \end{bmatrix} = \begin{bmatrix} a_1*b_1+a_2*b_2 \end{bmatrix} $$ ![轉置](https://i.imgur.com/82IbDU3.gif) ### exp $exp(x)=e^x=2.71828182846...^x$ e是一個實數無理數,e=2.71828182846... 推導如下: 假設銀行年利率為1,一年算一次利息,設總金額為$x$,則$f(time)=x*2^{time}$ 那如果改為每極短時間記一次利息,且時間反比於利息。 則新年利率為 $$\lim_{n\to\infty}(1+\frac{1}{n})^n$$ e在微積分時十分便利。 ## 參考資料 - [build artificial neural network scratch part 1](https://www.kdnuggets.com/2019/11/build-artificial-neural-network-scratch-part-1.html) - [偏微分](https://zh.wikipedia.org/wiki/%E5%81%8F%E5%AF%BC%E6%95%B0) - [梯度最佳解相關算法](https://chih-sheng-huang821.medium.com/%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-%E5%9F%BA%E7%A4%8E%E6%95%B8%E5%AD%B8-%E4%B8%89-%E6%A2%AF%E5%BA%A6%E6%9C%80%E4%BD%B3%E8%A7%A3%E7%9B%B8%E9%97%9C%E7%AE%97%E6%B3%95-gradient-descent-optimization-algorithms-b61ed1478bd7) - [梯度下降](https://chih-sheng-huang821.medium.com/%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-%E5%9F%BA%E7%A4%8E%E6%95%B8%E5%AD%B8-%E4%BA%8C-%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D%E6%B3%95-gradient-descent-406e1fd001f) - [自動微分](https://blog.csdn.net/aws3217150/article/details/70214422) - [Backpropagation | Brilliant Math & Science Wiki](https://brilliant.org/wiki/backpropagation/) - [矩陣](https://zh.wikipedia.org/wiki/%E7%9F%A9%E9%98%B5) - [backprop](http://galaxy.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html) - [機器學習](https://medium.com/%E9%9B%9E%E9%9B%9E%E8%88%87%E5%85%94%E5%85%94%E7%9A%84%E5%B7%A5%E7%A8%8B%E4%B8%96%E7%95%8C/%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92ml-note-sgd-momentum-adagrad-adam-optimizer-f20568c968db) - [error function](https://stackoverflow.com/questions/22601258/error-function-in-artificial-neural-network-trained-using-backpropogation) - [backpropagation](https://brilliant.org/wiki/backpropagation/) - [自動微分](http://fancyerii.github.io/books/autodiff/) *[Local Minmum]:區域最小值 *[ANN]:人工神經網路 *[權重]:W