# Deep Learning Presentation 0408
*Time: 0407*
*Editor: Wang Xuan-Wei*
*Chapter 6*
---
:::danger
OUTLINE
* **Standardize** an image dataset
* train a model to predict **rock, paper, scissors** poses from hand images
* use **dropout layers** to ***regularize*** the model
* learn how to **find a learning rate** to train the model
* understand how the ***Adam optimizer*** uses adaptive learning rates
* **capture gradients and parameters** to visualize their *evolution* during training
* understand how **momentum** and **Nesterov momentum** work
* use **scedulers** to implement learning rate changes during training
:::
## Sources
Coding Source: [Google Colab](https://colab.research.google.com/github/dvgodoy/PyTorchStepByStep/blob/master/Chapter06.ipynb)
You can also use Jupyter notebook to open up the coding files.
The rock, paper, scissors' dataset can be found in the textbook Step-by-Step, or one can follow the coding sources.
Note: we will not show too many code here, the coding details can be found in the website above or the text book Step-by-Step.
## 1. Data Preparation
:::info
In this section, we will learn:
* ImageFolder() function
* Standardization of the data
* How does the real dataset look like
:::
### ImageFolder() from PyTorch
當圖片資料原本用資料夾分門別類時,要調取圖片資料就可以使用`torchvision.datasets`中的`ImageFolder()`。
而使用`ImageFolder()`時也可以利用下面三種不同的參數:
1. *root* : 指定儲存圖片的路徑,這邊的範例用的是 'rps'。
2. *transform* : 返回轉換後的圖片,可以指定用前面章節提過的data augmentation transformations方法。
3. *target_transform* : 為一個函數,輸入target、輸出對其的轉換。但這邊不適用,因為這邊的數據target是integers(適用的條件是target也要是圖片才行)。
5. *loader* : 一個從指定路徑加載圖片的函數。
6. *is_valid_file* : 檢查file是否corrupted。
我們便可以檢視我們的圖片資料,從以下可以看出每個資料都是$28\times 28$ pixels,然後分成3個channels (RGB)。

### Standardization of the data
這步必須先知道pixels 的 mean value, standard deviation(/per channels)。
在建立完 `statistics_per_channel(images, labels)` function之後,我們便可以知道3個channel分別對應到的 data points 數量、mean value以及 sdv。以下是針對first mini-batch做的統計資料:

輸出其實是這樣的意思:
| | R | G | B |
| -------- | -------- | -------- | -------- |
| #'s of data points | 16.0000|16.0000 |16.0000 |
|mean |13.8748 |13.3048 |13.1962 |
|sdv |3.0507 |3.8268 |3.9754 |
然後我們針對全部的資料作統計,再使用`StepByStep.make_normalizer()`函數對所有數據做常態標準化。

可以從最後輸出看見PyTorch把數據都轉成$[0,1]$之間的值,其輸出的數據解讀是這樣的:
| | R | G | B |
| -------- | -------- | -------- | -------- |
|mean |0.8502 |0.8215 |0.8116 |
|sdv |0.2089 |0.2512 |0.2659 |
**Note** : **永遠**都使用**training set**做standardization的統計計算!
### How does the real dataset look like
讓原本剪刀石頭布的影像作做standardization之後(省略code細節),看起來會像這樣:

可以看見因為標準化之後pixels的色彩都發生了變化,這是正常現象,係減少了data的complexity跟variability,使得可以改善image processing algorithm的速度及效率。接下來在下個section中會探討標準化後的圖像做捲積的效應。
## 2. Three Channel Convolution
做捲積的理由是因為可以讓影像過濾掉不必要的資訊、保留可辨別的特徵。但如何挑選過濾器(filter)又是另一門學問,這邊先不討論(會涉及到傅立葉轉換等等的原理),只講述大致的計算過程。
> 每個filter的channel數與他進行的捲積圖像一樣多。
以上是這裏的小重點之一,我們可以看看下面例子:

其計算的原理是像下圖一樣:

當然,也可以考慮有兩組filters:

所以結論是你可以有很多組不同的filters,去跟每個channel做捲積,但在一組裡面filter的數量必須跟原本要被捲積的資料channels數量一樣多。這邊有RGB三個channels, 那filters一次就要有三個。最後,如果有n組filters,那麼最後output就會有n個channels。
## 3. Fancier model
接下來會做一個新的model出來,這個模型有兩個input parameters:
1. *n_filters* : model的兩個捲積塊的輸出通道數
2. *p* : dropout 某些 input values 的機率 (詳細內容見下個section)
然後建一個 `class CNN2(nn.Module)`,內建三個函數:
**1.**

可以看見有兩個convolutional layers跟兩個linear layers (hidden layer `fc1`, output layer`fc2` )
**2.**

因為model的屬性較低、層數少不可再hook,導致無法capture activate function跟 max pooling的輸出值了,所以這邊只取用了功能性的 activation function `F.relu()`以及max pooling 函數`F.max_pool2d()`。
**3.**

這裡用hidden layer 跟output layer 去做classfier。並且,每個liner layer前面都存在一個**dropout layer**,以機率p捨棄input values。
以上三個functions都構造完之後,再來就是一個forward函數執行:

也就是這個model流程是:
```mermaid
graph LR;
inputs-->feauturizer-->calssifier;
```
## 4. Dropout
在深度學習過程中,除了常見的underfitting問題之外,處理overfitting也是重要的議題。當訓練誤差很低時,在訓練資料的表現很好,但是卻在在測試集上無法獲得較好的結果,則會稱這種情況為過擬合(Overfitting)。可以想像這樣的問題可能是因為模型容量不適當或是因為資料量多寡造成的,除了從這兩個方面改善以外,也可以利用**正則化regularization**的方法解決。
這裡的Dropout就是一種regularization的方法。他透過randomly捨棄features的方式,強迫model生出不同方式去接近target(optimized point),這雖然讓整個訓練過程變得比較難,但也變得generalization了。
來看看dropout function的細節。
我們建立以下dropping model with dropout probability $p=0.5$:

接著平均灑一些點:

對這些點用dropping_model:

從這裡我們發現一些重點:
* 使用 train mode 執行這個model
* 因為這個model沒有weights,所以可以很清楚的看見是drop "**inputs**"而非"weights"
* 這次實驗只drop掉 4 個elements
* 而殘留的elements的值都不一樣了!
然後其餘數值必須都乘上一個$1/p$的factor,也就是$1/0.5=2$倍,這個調整的手段是為了保持在遭受dropout layer 之後輸出的整體水平。稍微計算一下會發現:
* 未drop平均值為 $6.6$
* drop後平均值為 $4.7$
* 調整後平均值為 $9.4$
事實上factor調整了平均丟棄的元素數量,如果這時候設$p=0.45$,會捨棄掉一半的數據,但調整後平均值會是$6.4$。我們來看看drop,會捨棄掉一半的數據,但調整後平均值會是$6.4$。我們來看看drop實驗1000次之後,調整後輸出的值的分布:

上面的圖表顯示了,對於這組輸入,我們帶有dropout的簡單線性層的輸出不再是確切的$6.6$,而是介於$0$和$12$之間的值。然而,所有場景的平均值都非常接近$6.6$。並且需要知道,dropout的概率決定了輸出的分布範圍有多廣。

考慮最左邊的圖,當$p=0.1$的時候,幾乎沒有dropout,則調整後輸出更緊密分布在原本平均值周圍;相反地,在最右圖中當$p=0.9$的時候,幾乎dropout所有值,分布就變得極端,而且$0$的位置有很高的柱狀。
> 輸出分佈的variance隨著dropout概率的增加而增加。
> 較高的dropout概率使模型更難學習──這就是正則化的作用。
### Two Dimensional Dropout
可以對convolution layer 做dropout嗎?可以,雖然概念一樣但相對於剛才對**個別輸入**的捨棄,他是**丟棄整個channels / filters**。比方說如果一個convolution layer產生了$10$個filters,一個概率為$0.5$的 2D dropout將丟棄$5$個過濾器(平均而言),而剩餘的filters將保留其所有的像素值不變。
如果考慮像剛才的例子一樣在這邊選擇丟棄個別的pixels (Regular Dropout),這樣作用不大,因為相鄰的像素間有強關聯性,隨機被丟棄的pixel可以用相鄰的pixel填補;但如果對於整個channel / filter做丟棄的話 (Two-Dimensional Dropout),顏色就會改變,像下圖右邊一樣會是我們希望的結果。

當然如果今天若不是以圖像作為學習對象,channel跟顏色不再有對應,但每個通道仍然都有一些特徵,通過隨機丟棄一些channel,Two-Dimensional Dropout就實現了其所需的正則化。
## 5. Model Configuration
:::info
我們創建一個model、一個loss function 和一個optimizer。
* model : 使用先前創建的`CNN2 class`:
* $5$ 個 filters
* $0.3$ 的 dropout probaility
* 使用`nn.CrossEntropyLoss()`(它將接收我們模型產生的三個logits)。
接下來在這個section,我們將簡單提及使用的optimizer,以及learning rate。
:::
### Optimizer
我們除了先前提及的SGD優化器以外,可以考慮使用**Adam**優化器。
> ***Adaptive moment estimation (Adam)*** 為每個參數計算learning rate。每一步都會跟前一步的gradient比較,如果梯度方向相同,梯度亮就增強;反之減弱。故同向加速越快,使得Adam收斂速度快,是好的優化器之一。詳細內容第7個section會再提及。
### Learning Rate
另一件我們需要牢記的事情是:$0.1$的學習率已經不夠了因為當學習率太高時損失不會下降,甚至會上升!所以我們需要降低學習率。對於這個例子,我們使用$3\times 10^{-4}$,即 *Karpathy's Constant*。

## 6. Model Training
先針對以上的設定做model訓練,並且計算loss:


### Accuracy
我們利用以下code計算出每個channel的正確數量以及總資料數:

也就是,我們針對validation set 有$313/372=0.841$的正確率,這是不錯的一次回測。
### Regularizing Effect
接下來我們比較做dropout前後的loss差別:

我們有兩個重要結論:
1. **Training loss在dropout後更高** - 畢竟 dropout使訓練變得更加困難。
2. **Validation loss在使用dropout後更低** - 這意味著模型更好地generalizing,並在未見過的數據上取得更好的性能,這正是使用像dropout這樣的正則化方法的整個目的。
且有以下的表格結果:
| | No Dropout | After Dropout |
| ------------------- |:----------:|:-------------:|
| Training accuracy | $99.92$ % | $99.36$ % |
| Validation accuracy | $78.76$ % | $84.13$ % |
所以沒有dropout的模型看起來有點*overfitting*了,相較之下有dropout的模型訓練得比較好──因為training accuracy 跟validation accuracy 有較小的gap!
### Visualizing Filters
| | #'s of filters | #'s of output channels | filter size |
| ------------- |:--------------:|:----------------------:|:-----------:|
| Conv. layer 1 | $5$ | $3$ | $3\times3$ |
| Conv. layer 2 | $5$ | $5$ | $3\times3$ |
>**Converlution Layer 1:**

>**Converlution Layer 2:**

---
Continuing part -> [Click me](https://hackmd.io/@tOcOYk2uSKyDq-IaFI8RNQ/ryr7KxggA)