# 類神經網路的 ReLU 及其常數時間實作 > 資料整理: [jserv](https://wiki.csie.ncku.edu.tw/User/jserv) ## 類神經網路的激勵函數 ReLU 全名為 Rectified Linear Unit,中譯為「修正線性單元」,是種類神經網路中激勵函數 (activation function,也可翻譯為活化函數)。所謂的激勵函數,用意是增加類神經網路裡頭的非線性特徵。早期尚未發展出深層網路時,時常被拿來做資料預測的演算法是[線性回歸法](https://en.wikipedia.org/wiki/Linear_regression) (linear regression),正如字面上的意義,線性回歸法只能用來預測呈線性分佈的資料,非線性的關係就難以用這樣的函數來描述。但現實生活中大部分的現象都是非線性,例如[美國人的收入與年齡之間的關係呈曲線分佈](https://www.reddit.com/r/dataisbeautiful/comments/1dqsxn/us_total_money_income_distribution_by_age_2012/),這樣要給定一個年紀的人,去預測他的收入,就顯然難以利用線性回歸。因此,為解決更複雜的問題,人們就發展出了帶有非線性特徵的 [Logistic Regression](https://medium.com/@chih.sheng.huang821/%E6%A9%9F%E5%99%A8-%E7%B5%B1%E8%A8%88%E5%AD%B8%E7%BF%92-%E7%BE%85%E5%90%89%E6%96%AF%E5%9B%9E%E6%AD%B8-logistic-regression-aff7a830fb5d),開始可解決簡單的二分法問題。 然而一個 Logistic Regression 的能力還是有限,[即便是二分法都有無法正確分類的狀況](https://youtu.be/hSXFuypLukA?list=PLJV_el3uVTsPy9oCRY30oBPNLCo89yu49&t=3388),因此為了得到更強大的函數,數學家嘗試串接多個 Logistic Regression,形成初步的類神經網路。 > 對照參閱台大電機系[李宏毅](https://speech.ee.ntu.edu.tw/~tlkagk/)教授的[機器學習線上課程](https://www.youtube.com/c/HungyiLeeNTU/playlists)。 ReLU 定義如下: $$ ReLU(x) = \begin{cases} x & \text{if } x \geq 0 \newline 0 & \text{if } x \lt 0 \end{cases} $$ ReLU 計算量小,只要判斷輸入是否大於 `0`,沒有指數運算。  ## 常數時間度 ReLU 實作 思路:由於 ReLU 函數要判斷輸入數值的正負,但浮點數的操作成本較高,於是我們可引入 union,讓 float 和 int (有號整數) 共用同一段記憶體空間 (針對 LP64 data model): ```c float ReLU(float x) { union { float f; int32_t i; } out = { .f = x }; ... } ``` 首先我們回顧有號整數的表達方式,為了方便圖解,下列圖示以 8 位元的整數 (即對應到 C 語言的 `int8_t`,定義於 `<stdint.h>` 標頭檔)  > sign bit 為 `0` 時,表示該數值為「正」,數值為 $0 \times 2^0$ (最右邊的位元) + $0 \times 2^1$ (右邊數來第二個位元) + $1 \times 2^2$ (右邊數來第三個位元) = 4 (十進位)  > sign bit 為 `1` 時,表示該數值為「負」,右側 7 個位元表示數值 $2^7 - 4 = 124$,這編碼採用[二補數](https://hackmd.io/@sysprog/binary-representation) [二補數](https://hackmd.io/@sysprog/binary-representation)看似不直觀,但可縮減運算的成本。例如十進位的 $-4$ 和 $-1$ 相加,透過[二補數](https://hackmd.io/@sysprog/binary-representation)運作如下:  從上圖右方起逐位元進行加法運算,連帶 sign bit 也可運算,超過 8 位元能表達的位元 (即上圖左下的 `1`) 就直接捨棄,這樣就讓電路設計變得單純。 另外,在[二補數](https://hackmd.io/@sysprog/binary-representation)系統中,對有號數的位移 (shift) 概念上也跟無號整數相同,但為了確保最終結果的正負號一致,需要額外的運算規則:  > 當你將有號整數右移,需要在左側填補一致的 sign bit 知曉[二補數](https://hackmd.io/@sysprog/binary-representation)系統及有號整數右移的規則後,我們考慮 `~(out.i >> 31)` 這個表示方式,其實相當於取參數 `x` 的 sign bit,分為以下兩種狀況: * 若 $x < 0$,則 `~(out.i >> 31)` 得到運算結果是 `000...00` (32-bits) * 若 $x >= 0$,則 `~(out.i >> 31)` 得到運算結果是 `111...11` (32-bits) 再將 `x` 和上述 `~(out.i >> 31)` 進行 AND 運算,即為 ReLU 函數的定義。 程式碼列表如下: ```c #include <stdint.h> // 當輸入 x 大於等於 0 時,回傳 x,否則回傳 0 float ReLU(float x) { /* 宣告一個 union,由兩個 field 組成 * 一個型態為 float,用以儲存原本的資料 * 一個型態為 int,用以進行位移運算 * 由於 union 中的所有欄位共用同一份記憶體 * 且 float 和 int32_t 都佔四個 byte * 因此對 i 操作時等同於在變更 f 的值 */ union { float f; int32_t i; } out = {.f = x}; /* 將資料存入 union */ /* 由於 int32_t 是有號數型態,因此位移時是採用算術位移(帶號) * 將此數向右位移 31 次,會使 4 個 byte 被 sign 值填滿 * (若非負則為 0,否則為 1) * 將其反相後,即成為 & 運算的遮罩 * 以此遮罩與原本的資料做 & 運算,若非負則內容不變 * 否則會全部變成 0 */ out.i &= ~(out.i >> 31); /* 將處理完的結果以 float 的型態回傳 */ return out.f; } ``` ## ReLU 與其他激勵函數的比較  [Sigmoid function](https://en.wikipedia.org/wiki/Sigmoid_function) 作為 Logistic Regression 的激勵函數,是這個算式當中非線性特徵的由來。由於 Logistic Regression 的目的是做分類,其輸出是一個機率值,故其值域會介於 $[0, 1]$ 之間。在[反向傳播演算法](https://www.youtube.com/watch?v=ibJpTrp5mcE&list=PLJV_el3uVTsPy9oCRY30oBPNLCo89yu49&index=12) (Backpropagation) 發明後,人們發現在計算神經網路中每一層結點的參數時,由於 Sigmoid 會把 $(- \infty , \infty)$ 的輸入映射到 $[0, 1]$ 之間,會造成在反向傳播參數時每一層的數字愈算愈小,到最後幾層的數字全都是 0 的梯度消失 (Gradient Vanishing) 現象。後來出現的 [Hyperbolic tangent function (tanh)](https://en.wikipedia.org/wiki/Hyperbolic_function)(長高的 Sigmoid,其值域在 $[-1, 1]$ 之間)也有類似的問題。 因此,在 Yoshua Bengio 等人的論文〈[Deep Sparse Rectifier Neural Networks](http://proceedings.mlr.press/v15/glorot11a/glorot11a.pdf)〉(第 318 頁),提到以 ReLU 取代其它激勵函數的好處: > The rectifier activation function allows a network to easily obtain sparse representations. > ... > Apart from being more biologically plausible, sparsity also leads to mathematical advantages (see previous section). > ... > Computations are also cheaper: there is no need for computing the exponential function in activations, and sparsity can be exploited. 統整論文的描述: * ReLU 較容易使得神經網路的結構變得稀疏,因為算出來參數為負的結點被視為沒有貢獻,因此輸出為 0,相當於是從神經網路中被拿掉了 * ReLU 的行為比較符合生物學當中觀察到的神經活化現象(全有全無律,也就是在刺激不夠大的時候,神經根本不會有反應回饋出現的現象) * ReLU 的計算量比較小  > 在神經生理方面,當刺激未達一定的強度時,神經元不會興奮,因此不會產生神經衝動。如果超過某個強度,才會引起神經衝動。ReLU 較好捕捉這個生物神經元的特徵。 因此, ReLU 成為現代訓練類神經網路時,常用的激勵函數之一。 延伸閱讀: * [深度學習:使用激勵函數的目的、如何選擇激勵函數](https://mropengate.blogspot.com/2017/02/deep-learning-role-of-activation.html)
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.