<!-- {%hackmd QyTrHv3eTzWnFdMf54ouLw %} -->
6.5
===
[TOC]
# 典型神經網路結構
~~(歷史故事~~
- 1989年: Yann LeCun 用反向傳播演算法訓練多層神經網路辨識手寫郵遞區號-->LeNet
- 1998年: Yann LeCun 提出LeNet-5-->卷積神經網路正式誕生
:::info
但當時硬體運算資源有限,卷積神經訓練花太多時間和機器--->沒被廣泛應用
:::
- 2012年: Alex Krizhevsky用GPU實現AlexNet,獲得ImageNet冠軍-->深度卷積神經網路受重視,開始迅速發展
- 後續顏敬人員又提出了多種的神經網路結構 如VCG、inception、RNN、Transformer
## 6.5.1 Lenet-5
Lenet-5 採用先卷積再池化的模式,最後透過softmax函數取得結果
LaNet-5的結構: :arrow_down:
```python=
class LaNet_5(nn.Module): #inheritance from nn.Module
def __init__(self): #constructor
super(CNN,self).__init__() # call nn.Moudle's constructor
self.conv1=nn.Conv2d(1,6,5,1) #convolution layer, in channel=1(gray), out channel=6, kernal_size=5*5, stride=1
self.pool1=nn.AvgPool2d(2,stride=2) #max pooling, kernal size=2
self.conv2=nn.Conv2d(6,16,5,1) #convolution layer
self.pool2=nn.AvgPool2d(2,stride=2) # max pooling
self.fc1=nn.Linear(16*5*5,120) #fully connected layer, 16(16 channel),5*5(data size after pooling)
self.fc2=nn.Linear(120,84)
self.fc3(84,10)
def forward(self,x): #how data pass from different layer
#32*32*1
x=self.conv1(x) #28*28*6
x=self.pool1(x) #14*14*6
x=self.conv2(x) #10*10*16
x=self.pool2(x) #5*5*16
x=x.view(x.size(0),-1) #400*1
x=self.fc1(x) #120*1
x=self.fc2(x) #84*1
x=self.fc3(x) #10*1
output=F.softmax(x)
return torch.max(output,1)[1].cpu().data.numpy(),x
```
## 6.5.2 AlexNet
- 由Alex Krizhevsky提出,獲得2012年ImageNet冠軍,將Top-5錯誤率降低了 10多%
- 用CUDA GPU實現平行化的神經網路演算法,證明在**合理**的時間內訓練深度神經網路成為可能
AlexNet結構: :arrow_down:
```python=
class AlexNet(nn.Module): #inheritance from nn.Module
def __init__(self): #constructor
super(CNN,self).__init__() # call nn.Moudle's constructor
self.conv1=nn.Conv2d(3,96,11,4,2) #convolution layer, in channel=3(RGB), out channel=96, kernal_size=11*11, stride=4, padding=2(add 2 layer of "0")
self.pool1=nn.MaxPool2d(3,stride=2) #max pooling, kernal size=2
self.conv2=nn.Conv2d(96,256,5,1,2) #convolution layer
self.pool2=nn.MaxPool2d(3,stride=2) # max pooling
self.conv3=nn.Conv2d(256,384,3,1,1)
self.conv4=nn.Conv2d(256,384,3,1,1)
self.conv5=nn.Conv2d(294,256,3,1,1)
self.pool3 = nn.MaxPooling(3,stride=2)
self.fc1=nn.Linear(256*6*6,4096) #fully connected layer, 32(32 channel),7*7(data size after pooling)
self.fc2=nn.Linear(4096,4096)
self.fc3=nn.Linear(4096,1000)
def forward(self,x): #how data pass from different layer
#227*227*3
x=self.conv1(x) #96*55*55
x=nn.ReLU(x)
x=self.pool1(x) #96*27*27
x=self.conv2(x) #256*27*27
x=nn.ReLU(x)
x=self.pool2(x) #256*13*13
x=self.conv3(x) #384*13*13
x=nn.ReLU(x)
x=self.conv4(x) #384*13*13
x=nn.ReLU(x)
x=self.conv5(x) #256*13*13
x=nn.ReLU(x)
x=self.pool3(x) #256*6*6
x=x.view(x.size(0),-1) #9216*1
x=self.fc1(x) #4096*1
x=self.fc2(x) #4096*1
x=self.fc3(x) #1000*1
output=F.softmax(x)
return torch.max(output,1)[1].cpu().data.numpy(),x
```
- LeNat 有6萬個參數
- AlexNet有6000萬個參數
- 加了ReLU避免梯度消失
- 加了DropOut
- 加了局部歸一化層(batchNorm2d),後來發現用途不大
## 6.5.3 VCG
- 證明增加網路的深度可以一定程度的提高網路的性能
- 所有卷積層的kernal size都相同
- VCG-16: 卷積層+全連接層共有16層
~~層數太多,沒打code出來~~
## 6.5.4 殘差網路(Residual Network)
- 透過跳線的技巧(短路),打破逐層傳遞的結構,避免梯度爆炸、梯度消失的問題
- 反向求導可以直接跳線傳到頂層,從而避免梯度消失或梯度爆炸
- 可藉由跳線輕鬆地訓練1000層以上的神經網路
- 一堆殘差塊而非卷基層構成的網路
- 殘差塊(其中一種):

```python=
class Resblock(nn.Module): #inheritance from nn.Module
def __init__(self): #constructor
super(CNN,self).__init__()
self.conv1=nn.Conv2d()
self.act1=nn.ReLU()
self.conv2=nn.Conv2d()
self.act2=nn.ReLU()
def forward(self,x): #how data pass from different layer
c1=self.conv1(x)
a1=self.act1(c1)
c2=self.conv2(a1)
a2=self.act2(c1+x) ##重點在此
return a2
```
## 6.5.5 Inception 網路
- google提出
- 因較大的kernal適合捕捉大範圍的特徵,小kernal捕捉局部特徵-->如何決定
- 讓神經網路自己選擇合適的convolution kernal、pooling kernal

---

- 參數數量龐大
- 解法: 在kernal size>1的卷基層前加入kernal size=1的卷積層(輸出通道較少),減少輸入的特徵圖數量
## 6.5.6 NiN(Network in Network)
- 卷基層進行的是一般的線性卷積運算(加權和),再透過非線性的啟動函數輸出
- 用小的網路代替卷積層,增加非線性的能力


- 用全域平均池化代替全連接層-->每個特徵圖只有1個輸出值-->可以避免過擬合、過多參數的問題
- 全域池化層的輸入特徵圖數量==分類的數量
問題:
1.為什麼殘差網路(Residual Network)能夠有效解決梯度消失和梯度爆炸的問題?
2.AlexNet對卷積神經網路的發展產生了什麼重要影響?
3.簡述Inception 網路是如何處理不同尺度的特徵,以增強神經網路的性能?