深度學習軟件
(這一部分去看tensorflow和pytorch的筆記)
(見專欄)
-
tensorflow和pytorch區別
tensorflow,我們先構建顯示的圖,然后重復運行它
pytorch,我們每次做前向傳播時,都構建一個新的圖
卷積神經網絡CNN 結構
-
LeNet-5
比較經典的用于數字識別的cnn
from torch import nn import torch from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Tanhclass LeNet(nn.Module):def __init__(self):super(LeNet,self).__init__()self.model1 = nn.Sequential(#input:32x32x1#conv1:28x28x6Conv2d(1, 6, 5, 1, 0),Tanh(),#poo1:14x14x6MaxPool2d(2, 2),#conv2:10x10x16Conv2d(6,16,5,1,0),Tanh(),#poo2:5x5x16MaxPool2d(2,2),Flatten(),Linear(400,120),Tanh(),Linear(120,84),Tanh(),Linear(84,10))def forward(self,x):x = self.model1(x)return xlenet = LeNet()
-
AlexNet
很小的計算量,但是耗費存儲也很多,比較低的acc
但是,實際上AlexNet 的輸入圖片尺寸為 224×224(這里是227×227)
import torch from torch import nn from torch.nn import Flatten, Linearclass AlexNet(nn.Module):def __init__(self):super(AlexNet,self).__init__()self.model1 = nn.Sequential(#input:227x227x3#conv1:55x55x96nn.Conv2d(3,96,11,4,0),#pool1:27x27x96nn.MaxPool2d(3,2),nn.ReLU(),#conv2:27x27x256nn.Conv2d(96,256,5,1,2),#pool2:13x13x256nn.MaxPool2d(3,2),nn.ReLU(),#conv3:13x13x384nn.Conv2d(256,384,3,1,1),#conv4:13x13x384nn.Conv2d(384,384,3,1,1),#conv5:13x13x256nn.Conv2d(384,256,3,1,1),#pool3:6x6x256nn.MaxPool2d(3,2),nn.Flatten(),#9216=6x6x256nn.Linear(9216,4096),nn.Linear(4096,1000),nn.Linear(1000,10))def forward(self,x):x = self.model1(x)return xalexnet = AlexNet()
-
ZFNet
注意:計算輸出圖尺寸是下取整(輸入尺寸-卷積核尺寸+2*padding)/stride + 1
import torch from torch import nnclass ZFNet(nn.Module):def __init__(self):super(ZFNet,self).__init__()self.model1 = nn.Sequential(#input:224x224x3#conv1:110x110x96nn.Conv2d(3,96,7,2,1),#pool1:55x55x96nn.MaxPool2d(3,2),#conv2:26x26x256nn.Conv2d(96,256,5,2,0),#pool2:13x13x256nn.MaxPool2d(3,2),#conv3:13x13x384nn.Conv2d(256,384,3,1,1),#conv4:13x13x384nn.Conv2d(384,384,3,1,1),#conv5:13x13x256nn.Conv2d(384,256,3,1,1),#pool5:6x6x256nn.MaxPool2d(3,2),nn.Flatten(),#6*6*256nn.Linear(6*6*256,4096),nn.Linear(4096,4096),nn.Linear(4096,1000))def forward(self,x):x = self.model1(x)return xzfnet = ZFNet()
-
VGGNet
耗費最高的存儲,最多的操作
import torch from torch import nnclass VGG16Net(nn.Module):def __init__(self):super(VGG16Net,self).__init__()self.model1 = nn.Sequential(#input:224x224x3nn.Conv2d(3,64,3,1,1),nn.Conv2d(64,64,3,1,1),nn.MaxPool2d(2,2),nn.Conv2d(64,128,3,1,1),nn.Conv2d(128,128,3,1,1),nn.MaxPool2d(2,2),nn.Conv2d(128,256,3,1,1),nn.Conv2d(256,256,3,1,1),nn.Conv2d(256,256,3,1,1),nn.MaxPool2d(2,2),nn.Conv2d(256,512,3,1,1),nn.Conv2d(512, 512, 3, 1, 1),nn.Conv2d(512, 512, 3, 1, 1),nn.MaxPool2d(2,2),nn.Conv2d(512,512,3,1,1),nn.Conv2d(512, 512, 3, 1, 1),nn.Conv2d(512, 512, 3, 1, 1),nn.MaxPool2d(2,2),nn.Flatten(),nn.Linear(7*7*512,4096),nn.Linear(4096,4096),nn.Linear(4096,1000))def forward(self,x):x = self.model1(x)return xvgg16 = VGG16Net()
-
GoogLeNet
最高效
efficient Inception module:設計一個良好的本地網絡拓撲結構(網絡中的網絡)然后將這些模塊堆疊在彼此之上
沒有全連接層
對來自前一層的輸入應用并行filter操作
但是這樣就會計算的很復雜,解決辦法:采用1x1卷積來降低特征深度的“瓶頸”層
四個并行分支:1x1 卷積、1x1→3x3 卷積、1x1→5x5 卷積、3x3 池化→1x1 卷積實現:
class Inception(nn.Module):"""Inception模塊:并行處理不同尺度的特征"""def __init__(self, in_channels, c1, c2, c3, c4):super(Inception, self).__init__()# 分支1:1x1卷積(降維或保持維度)self.branch1 = nn.Sequential(Conv2d(in_channels, c1, kernel_size=1),BatchNorm2d(c1),ReLU(inplace=True))# 分支2:1x1卷積(降維)-> 3x3卷積self.branch2 = nn.Sequential(Conv2d(in_channels, c2[0], kernel_size=1),BatchNorm2d(c2[0]),ReLU(inplace=True),Conv2d(c2[0], c2[1], kernel_size=3, padding=1),BatchNorm2d(c2[1]),ReLU(inplace=True))# 分支3:1x1卷積(降維)-> 5x5卷積self.branch3 = nn.Sequential(Conv2d(in_channels, c3[0], kernel_size=1),BatchNorm2d(c3[0]),ReLU(inplace=True),Conv2d(c3[0], c3[1], kernel_size=5, padding=2),BatchNorm2d(c3[1]),ReLU(inplace=True))# 分支4:3x3池化 -> 1x1卷積(降維)self.branch4 = nn.Sequential(MaxPool2d(kernel_size=3, stride=1, padding=1), # 保持尺寸的池化Conv2d(in_channels, c4, kernel_size=1),BatchNorm2d(c4),ReLU(inplace=True))def forward(self, x):# 四個分支的輸出在通道維度拼接b1 = self.branch1(x)b2 = self.branch2(x)b3 = self.branch3(x)b4 = self.branch4(x)return torch.cat([b1, b2, b3, b4], dim=1) # dim=1表示通道維度拼接
-
ResNet
模型效率中等,準確度最高
使用殘差連接的非常深的網絡(152層)
這是ResNet(殘差網絡)中最基礎的 殘差塊(Residual Block) 結構示意圖,用來解決深度神經網絡訓練時的梯度消失、模型難以收斂問題,核心是 “殘差連接(跳躍連接)”設計。
下面拆解每個部分:
-
基礎流程(從下往上看)
- 輸入
X
: 代表網絡某一層的輸入特征(比如是圖像經過前面卷積后的特征圖,包含空間維度和通道維度)。 - 主路徑(計算
F(X)
): - 先過一個3x3 conv
(3×3 卷積層),接著relu
(ReLU 激活函數),再過第二個3x3 conv
。這一系列操作對輸入X
做特征變換,輸出F(X)
(F
表示“殘差函數”,學習輸入與輸出的殘差關系 )。 - 殘差連接(
X
直接跳連): 輸入X
不經過主路徑的卷積,直接“抄近道”加到主路徑輸出上(圖里的⊕
是逐元素相加,要求X
和F(X)
維度匹配 )。 - 前向傳播:因為這個分支僅進行簡單的恒等映射或少量維度調整操作,計算量小,傳播速度更快,雖然X跳連和主路徑并行啟動計算,但是完成時間有差異,最終會在加法操作處等待最慢的分支完成后再繼續傳播。
- 反向傳播:在殘差塊反向傳播過程中,來自后續層的梯度到達 (F(x) + x) 的加法操作位置時,會按照加法求導規則,同時分配到 “identity” 分支和 (F(x)) 分支。雖然 identity 分支的梯度計算簡單,可能先傳播到前面的層,但前面的層等待的是兩個分支的梯度都傳播過來后進行融合。只有當 (F(x)) 分支的梯度也傳播過來后,將兩個分支的梯度相加,得到總的梯度,才會用于對前面層的參數更新 。
- 輸出(
F(X)+X
過relu
): 相加后的結果F(X)+X
再經過一個relu
,作為整個殘差塊的最終輸出,傳遞給下一層。
- 輸入
-
核心設計意義
殘差連接 - 解決梯度消失:傳統深層網絡訓練時,梯度回傳易衰減。殘差連接讓梯度能“走捷徑”直接反向傳播,讓深層網絡更易訓練。
學習殘差更高效:網絡不直接學“從
X
到最終輸出”的復雜映射,而是學“殘差F(X) = 最終輸出 - X
”。殘差通常更簡單,模型收斂更快、更穩定。
-
-
其他的一些CNN結構
-
Network in Network (NiN)
帶有“微網絡”的Mlpconv層,在每個卷積層內部計算局部圖像塊,更高層次的特征抽象
微網絡采用多層感知機(全連接層,即1x1卷積層)
作為GoogLeNet和ResNet “瓶頸層”的前身 -
Identity Mappings in Deep Residual Networks
-
Wide Residual Networks
-
Aggregated Residual Transformations for Deep Neural Networks (ResNeXt)
-
Deep Networks with Stochastic Depth
-
FractalNet: Ultra-Deep Neural Networks without Residuals
采用分形結構設計 -
Densely Connected Convolutional Networks
DenseNet:通過特征拼接增強層間連接 -
SqueezeNet: AlexNet-level Accuracy With 50x Fewer Parameters and <0.5Mb Model Size
-