承接上一篇:PyTorch 入門實戰(三)——Dataset和DataLoader
PyTorch入門實戰
1.博客:PyTorch 入門實戰(一)——Tensor
2.博客:PyTorch 入門實戰(二)——Variable
3.博客:PyTorch 入門實戰(三)——Dataset和DataLoader
4.博客:PyTorch 入門實戰(四)——利用Torch.nn構建卷積神經網絡
5.博客:待更新...
目錄
一、概念
1.需要聲明的是構建卷積神經網絡需要有一定的面向對象基礎,因爲所有建立的模型結構都是繼承自nn.Module這個基類所完成的
2.我們需要新建一個子類,並且構造函數和前向傳播等方法需要被重寫才能實現自己編寫的網絡
3.我們還需要知道torch中卷積層,池化層,全連接層等部分的編寫方法和拼接方式
二、使用nn.Module創建一個網絡框架
1.聲明一個類,並繼承自nn.Module:
class testNet(nn.Module):
2.定義構造函數,例如我們建立一個用於分類的網絡,類別數是10:
class testNet(nn.Module):
def __init__(self, num_classes=10):
3.初始化方法使用父類的方法即可,super這裏指的就是nn.Module這個基類,第一個參數是自己創建的類名:
class testNet(nn.Module):
def __init__(self, num_classes=10):
super(testNet, self).__init__()
#定義自己的網絡
4.我們還需要定義自己的前向傳播函數,注意forward函數需要有返回值:
class testNet(nn.Module):
def __init__(self, num_classes=10):
super(testNet, self).__init__()
#定義自己的網絡
def forward(self,x):
#定義自己的前向傳播方式
return x
5.到目前爲止,我們基本上算是搭了一個具體的框架,但是裏面沒有“肉”,接下來就講解如何填“肉”~
三、利用PyTorch卷積模塊填充網絡框架
1.卷積層nn.Con2d()
常用參數:
- in_channels:輸入通道數(深度)
- out_channels:輸出通道數(深度)
- kernel_size:濾波器(卷積核)大小,寬和高相等的卷積核可以用一個數字表示,例如kernel_size=3;否則用不同數字表示,例如kernel_size=(5,3)
- stride:表示濾波器滑動的步長
- padding:是否進行零填充,padding=0表示四周不進行零填充,padding=1表示四周進行1個像素點的零填充
- bias:默認爲True,表示使用偏置
- groups:groups=1表示所有輸入輸出是相關聯的;groups=n表示輸入輸出通道數(深度)被分割爲n份,並分別對應,且需要被groups整除
- (dilation:卷積對輸入的空間間隔,默認爲dilation=1)
舉個例子,構建一個輸入通道爲3,輸出通道爲64,卷積核大小爲3x3,四周進行1個像素點的零填充的conv1層:
class testNet(nn.Module):
def __init__(self, num_classes=10):
super(testNet, self).__init__()
#定義自己的網絡
self.conv1 = nn.Conv2d(3,64,kernel_size=3,padding=1)
def forward(self,x):
#定義自己的前向傳播方式
return x
除此之外,我們還需要在forward函數裏使用conv1構建傳播方法:
class testNet(nn.Module):
def __init__(self, num_classes=10):
super(testNet, self).__init__()
#定義自己的網絡
self.conv1 = nn.Conv2d(3,64,kernel_size=3,padding=1)
def forward(self,x):
#定義自己的前向傳播方式
out = self.conv1(x)
return out
這樣一個只含有一個卷積層的網絡就搭建好了。
2.池化層——最大值池化nn.MaxPool2d()和均值池化nn.AvgPool2d(),
常用參數:
- kernel_size、stride、padding、dilation在卷積層部分定義和這裏一致
- return_indices:表示是否返回最大值的下標,默認爲False,即不返回
- ceil_mode:默認爲False,即不使用方格代替層結構
- (均值池化函數中)count_include_pad:默認爲True,表示包含零填充
舉個例子,構建一個卷積核大小爲2x2,步長爲2的pool1層,並且加入到forward中:
class testNet(nn.Module):
def __init__(self, num_classes=10):
super(testNet, self).__init__()
#定義自己的網絡
self.conv1 = nn.Conv2d(3,64,kernel_size=3,padding=1)
self.pool1 = nn.MaxPool2d(kernel_size=2,stride=2)
def forward(self,x):
#定義自己的前向傳播方式
out = self.conv1(x)
out = self.pool1(out)
return out
事實上,池化層可以不必緊跟在卷積層之後,中間可以加入激活層和BatchNorm層,甚至可以在多個卷積操作後添加池化操作
3.加快收斂速度一一批標準化層nn.BatchNorm2d()
常用參數爲:
- num_features:輸入通道數(深度)
- eps:爲數值穩定性而添加到分母的值, 默認值爲1e-5
- momentum:用於running_mean和running_var計算的值;對於累積移動平均值(即簡單平均值),可以設置爲“無”。 默認值爲0.1
- affine:當設置爲True時,該模塊具有可學習的仿射參數。 默認爲True
- track_running_stats:當設置爲True時,該模塊跟蹤運行的均值和方差,當設置爲False時,該模塊不跟蹤這樣的統計數據,並且總是在訓練和評估模式。 默認爲True
舉個例子,構建一個輸入通道爲64的BN1層,與卷積層輸出通道數64對應,並加入到forward中:
class testNet(nn.Module):
def __init__(self, num_classes=10):
super(testNet, self).__init__()
#定義自己的網絡
self.conv1 = nn.Conv2d(3,64,kernel_size=3,padding=1)
self.BN1 = nn.BatchNorm2d(64)
self.pool1 = nn.MaxPool2d(kernel_size=2,stride=2)
def forward(self,x):
#定義自己的前向傳播方式
out = self.conv1(x)
out = self.BN1(out)
out = self.pool1(out)
return out
4.增加網絡的非線性——激活函數nn.ReLU(True)
參數:
- inplace:可以選擇就地進行操作。 默認值爲False
因此設置爲True的意義就是改變當前的原始對象
ReLU,線性整流函數(Rectified Linear Unit),定義如下:
舉個例子,在卷積層(或BN層)之後,池化層之前,添加激活函數,並加入到forward中:
class testNet(nn.Module):
def __init__(self, num_classes=10):
super(testNet, self).__init__()
#定義自己的網絡
self.conv1 = nn.Conv2d(3,64,kernel_size=3,padding=1)
self.BN1 = nn.BatchNorm2d(64)
self.relu1 = nn.ReLU(True)
self.pool1 = nn.MaxPool2d(kernel_size=2,stride=2)
def forward(self,x):
#定義自己的前向傳播方式
out = self.conv1(x)
out = self.BN1(out)
out = self.relu1(out)
out = self.pool1(out)
return out
5.利用nn.Sequential()按順序構建網絡
(1)利用add_module()函數添加層,第一個參數是層名,第二個參數是實現方法
layer2 = nn.Sequential()
layer2.add_module('conv2', nn.Conv2d(64,64,kernel_size=3,padding=1))
layer2.add_module('BN2',nn.BatchNorm2d(64))
layer2.add_module('relu2',nn.ReLU(True))
layer2.add_module('pool2',nn.MaxPool2d(kernel_size=2,stride=2))
self.layer2 = layer2
可以看到layer2裏有四個部分:卷積層conv2,批標準化層BN2,激活函數relu2和最大池化層pool2
不要忘記forward函數裏添加,只不過變得簡單了,其實博主也建議利用Sequential()的方式
class testNet(nn.Module):
def __init__(self, num_classes=10):
super(testNet, self).__init__()
#定義自己的網絡
self.conv1 = nn.Conv2d(3,64,kernel_size=3,padding=1)
self.BN1 = nn.BatchNorm2d(64)
self.relu1 = nn.ReLU(True)
self.pool1 = nn.MaxPool2d(kernel_size=2,stride=2)
layer2 = nn.Sequential()
layer2.add_module('conv2', nn.Conv2d(64,64,kernel_size=3,padding=1))
layer2.add_module('BN2',nn.BatchNorm2d(64))
layer2.add_module('relu2',nn.ReLU(True))
layer2.add_module('pool2',nn.MaxPool2d(kernel_size=2,stride=2))
self.layer2 = layer2
def forward(self,x):
#定義自己的前向傳播方式
out = self.conv1(x)
out = self.BN1(out)
out = self.relu1(out)
out = self.pool1(out)
out = self.layer2(out)
return out
(2)直接在Sequential()裏寫:
self.layer3 = nn.Sequential(
nn.Conv2d(64,128,kernel_size=3,padding=1),
nn.BatchNorm2d(128),
nn.ReLU(True),
)
forward函數不要忘記加上
class testNet(nn.Module):
def __init__(self, num_classes=10):
super(testNet, self).__init__()
#定義自己的網絡
self.conv1 = nn.Conv2d(3,64,kernel_size=3,padding=1)
self.BN1 = nn.BatchNorm2d(64)
self.relu1 = nn.ReLU(True)
self.pool1 = nn.MaxPool2d(kernel_size=2,stride=2)
layer2 = nn.Sequential()
layer2.add_module('conv2', nn.Conv2d(64,64,kernel_size=3,padding=1))
layer2.add_module('BN2',nn.BatchNorm2d(64))
layer2.add_module('relu2',nn.ReLU(True))
layer2.add_module('pool2',nn.MaxPool2d(kernel_size=2,stride=2))
self.layer2 = layer2
self.layer3 = nn.Sequential(
nn.Conv2d(64,128,kernel_size=3,padding=1),
nn.BatchNorm2d(128),
nn.ReLU(True),
)
def forward(self,x):
#定義自己的前向傳播方式
out = self.conv1(x)
out = self.BN1(out)
out = self.relu1(out)
out = self.pool1(out)
out = self.layer2(out)
out = self.layer3(out)
return out
6.線性分類器(全連接層)——線性迴歸函數nn.Linear()
y=wx+b
四個屬性:
- in_features: 上層神經元個數
- out_features:本層神經元個數
- weight:權重, 形狀
[
out_features,
in_features] - bias:偏置, 形狀[out_features]
三個參數:
- in_features:上層網絡神經元的個數
- out_features: 該網絡層神經元的個數
- bias: 網絡層是否有偏置,默認爲True,且維度爲[out_features]
其實Linear是一個類,在linear.py中有定義,裏面的構造函數就告訴了我們一樣的信息:
def __init__(self, in_features, out_features, bias=True):
super(Linear, self).__init__()
self.in_features = in_features
self.out_features = out_features
self.weight = Parameter(torch.Tensor(out_features, in_features))
if bias:
self.bias = Parameter(torch.Tensor(out_features))
else:
self.register_parameter('bias', None)
self.reset_parameters()
舉個例子,我們設計一個分類器,in_features爲128,out_features可以爲我們的類別數num_classes=10
self.classifier = nn.Sequential(
nn.Linear(128,num_classes),
)
注意在forward中一般需要將之前的結果,即多維度的Tensor展平成一維以便分類,可參看博主博客:
torch x = x.view(x.size(0),-1)的理解
代碼爲:
out = out.view(out.size(0), -1)
out = self.classifier(out)
最終一個簡單的分類網絡如下:
class testNet(nn.Module):
def __init__(self, num_classes=10):
super(testNet, self).__init__()
#定義自己的網絡
self.conv1 = nn.Conv2d(3,64,kernel_size=3,padding=1)
self.BN1 = nn.BatchNorm2d(64)
self.relu1 = nn.ReLU(True)
self.pool1 = nn.MaxPool2d(kernel_size=2,stride=2)
layer2 = nn.Sequential()
layer2.add_module('conv2', nn.Conv2d(64,64,kernel_size=3,padding=1))
layer2.add_module('BN2',nn.BatchNorm2d(64))
layer2.add_module('relu2',nn.ReLU(True))
layer2.add_module('pool2',nn.MaxPool2d(kernel_size=2,stride=2))
self.layer2 = layer2
self.layer3 = nn.Sequential(
nn.Conv2d(64,128,kernel_size=3,padding=1),
nn.BatchNorm2d(128),
nn.ReLU(True),
)
self.classifier = nn.Sequential(
nn.Linear(128,num_classes),
)
def forward(self,x):
#定義自己的前向傳播方式
out = self.conv1(x)
out = self.BN1(out)
out = self.relu1(out)
out = self.pool1(out)
out = self.layer2(out)
out = self.layer3(out)
out = out.view(out.size(0), -1)
out = self.classifier(out)
return out
7.防止過擬合——nn.Dropout()
參數:
- p:元素歸零的概率。 默認值爲0.5
- inplace:如果設置爲True,將就地執行此操作。 默認值爲False
函數功能的解釋爲:
在訓練期間,使用伯努利分佈的樣本隨機地將輸入張量的一些元素歸零:p使得在每個前向呼叫中隨機化零元素。
事實證明,這是一種有效的正則化技術,可以防止神經元的共同適應,如“通過阻止特徵檢測器的共同適應改善神經網絡”所述。
通俗易懂地,就是使神經元部分失活,即在不同的訓練過程中隨機扔掉一部分神經元。也就是讓某個神經元的激活值以一定的概率p,讓其停止工作,本次訓練過程中不更新權值,也不參與神經網絡的計算,但是它的權重得保留下來。
實際上,分類器如果想達到好的效果,可以加上多個激活層和Dropout的組合操作,再得出結果,例如:
self.classifier = nn.Sequential(
nn.Linear(128,256),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(256, 256),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(256,num_classes),
)
最終的網絡爲:
class testNet(nn.Module):
def __init__(self, num_classes=10):
super(testNet, self).__init__()
#定義自己的網絡
self.conv1 = nn.Conv2d(3,64,kernel_size=3,padding=1)
self.BN1 = nn.BatchNorm2d(64)
self.relu1 = nn.ReLU(True)
self.pool1 = nn.MaxPool2d(kernel_size=2,stride=2)
layer2 = nn.Sequential()
layer2.add_module('conv2', nn.Conv2d(64,64,kernel_size=3,padding=1))
layer2.add_module('BN2',nn.BatchNorm2d(64))
layer2.add_module('relu2',nn.ReLU(True))
layer2.add_module('pool2',nn.MaxPool2d(kernel_size=2,stride=2))
self.layer2 = layer2
self.layer3 = nn.Sequential(
nn.Conv2d(64,128,kernel_size=3,padding=1),
nn.BatchNorm2d(128),
nn.ReLU(True),
)
self.classifier = nn.Sequential(
nn.Linear(128,256),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(256, 256),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(256,num_classes),
)
def forward(self,x):
#定義自己的前向傳播方式
out = self.conv1(x)
out = self.BN1(out)
out = self.relu1(out)
out = self.pool1(out)
out = self.layer2(out)
out = self.layer3(out)
out = out.view(out.size(0), -1)
out = self.classifier(out)
return out
四、自己寫一個VGG-16帶有BatchNorm層的網絡
1.VGG-16(含有BN層)的網絡架構:
VGG16(
(features): Sequential(
(0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(2): ReLU(inplace)
(3): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(5): ReLU(inplace)
(6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(7): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(8): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(9): ReLU(inplace)
(10): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(12): ReLU(inplace)
(13): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(14): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(15): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(16): ReLU(inplace)
(17): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(18): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(19): ReLU(inplace)
(20): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(21): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(22): ReLU(inplace)
(23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(24): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(25): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(26): ReLU(inplace)
(27): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(28): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(29): ReLU(inplace)
(30): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(31): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(32): ReLU(inplace)
(33): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(34): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(35): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(36): ReLU(inplace)
(37): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(38): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(39): ReLU(inplace)
(40): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(41): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(42): ReLU(inplace)
(43): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(44): AvgPool2d(kernel_size=1, stride=1, padding=0)
)
(classifier): Sequential(
(0): Linear(in_features=512, out_features=4096, bias=True)
(1): ReLU(inplace)
(2): Dropout(p=0.5)
(3): Linear(in_features=4096, out_features=4096, bias=True)
(4): ReLU(inplace)
(5): Dropout(p=0.5)
(6): Linear(in_features=4096, out_features=10, bias=True)
)
)
2.其實這個是print出來的。那麼我們想得到這樣的結構,需要寫出這樣一個網絡結構,博主的代碼如下:
import torch.nn as nn
class VGG16(nn.Module):
def __init__(self, num_classes=10):
super(VGG16, self).__init__()
self.features = nn.Sequential(
#1
nn.Conv2d(3,64,kernel_size=3,padding=1),
nn.BatchNorm2d(64),
nn.ReLU(True),
#2
nn.Conv2d(64,64,kernel_size=3,padding=1),
nn.BatchNorm2d(64),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
#3
nn.Conv2d(64,128,kernel_size=3,padding=1),
nn.BatchNorm2d(128),
nn.ReLU(True),
#4
nn.Conv2d(128,128,kernel_size=3,padding=1),
nn.BatchNorm2d(128),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
#5
nn.Conv2d(128,256,kernel_size=3,padding=1),
nn.BatchNorm2d(256),
nn.ReLU(True),
#6
nn.Conv2d(256,256,kernel_size=3,padding=1),
nn.BatchNorm2d(256),
nn.ReLU(True),
#7
nn.Conv2d(256,256,kernel_size=3,padding=1),
nn.BatchNorm2d(256),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
#8
nn.Conv2d(256,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
#9
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
#10
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
#11
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
#12
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
#13
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
nn.AvgPool2d(kernel_size=1,stride=1),
)
self.classifier = nn.Sequential(
#14
nn.Linear(512,4096),
nn.ReLU(True),
nn.Dropout(),
#15
nn.Linear(4096, 4096),
nn.ReLU(True),
nn.Dropout(),
#16
nn.Linear(4096,num_classes),
)
#self.classifier = nn.Linear(512, 10)
def forward(self, x):
out = self.features(x)
out = out.view(out.size(0), -1)
out = self.classifier(out)
return out
3.創建VGG16類對象再打印即可:
if __name__ == '__main__':
import torch
#使用gpu
use_cuda = torch.cuda.is_available()
device = torch.device("cuda" if use_cuda else "cpu")
net = VGG16().to(device)
print(net)
代碼整體爲:
import torch.nn as nn
class VGG16(nn.Module):
def __init__(self, num_classes=10):
super(VGG16, self).__init__()
self.features = nn.Sequential(
#1
nn.Conv2d(3,64,kernel_size=3,padding=1),
nn.BatchNorm2d(64),
nn.ReLU(True),
#2
nn.Conv2d(64,64,kernel_size=3,padding=1),
nn.BatchNorm2d(64),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
#3
nn.Conv2d(64,128,kernel_size=3,padding=1),
nn.BatchNorm2d(128),
nn.ReLU(True),
#4
nn.Conv2d(128,128,kernel_size=3,padding=1),
nn.BatchNorm2d(128),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
#5
nn.Conv2d(128,256,kernel_size=3,padding=1),
nn.BatchNorm2d(256),
nn.ReLU(True),
#6
nn.Conv2d(256,256,kernel_size=3,padding=1),
nn.BatchNorm2d(256),
nn.ReLU(True),
#7
nn.Conv2d(256,256,kernel_size=3,padding=1),
nn.BatchNorm2d(256),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
#8
nn.Conv2d(256,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
#9
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
#10
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
#11
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
#12
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
#13
nn.Conv2d(512,512,kernel_size=3,padding=1),
nn.BatchNorm2d(512),
nn.ReLU(True),
nn.MaxPool2d(kernel_size=2,stride=2),
nn.AvgPool2d(kernel_size=1,stride=1),
)
self.classifier = nn.Sequential(
#14
nn.Linear(512,4096),
nn.ReLU(True),
nn.Dropout(),
#15
nn.Linear(4096, 4096),
nn.ReLU(True),
nn.Dropout(),
#16
nn.Linear(4096,num_classes),
)
#self.classifier = nn.Linear(512, 10)
def forward(self, x):
out = self.features(x)
out = out.view(out.size(0), -1)
out = self.classifier(out)
return out
class testNet(nn.Module):
def __init__(self, num_classes=10):
super(testNet, self).__init__()
#定義自己的網絡
self.conv1 = nn.Conv2d(3,64,kernel_size=3,padding=1)
self.BN1 = nn.BatchNorm2d(64)
self.relu1 = nn.ReLU(True)
self.pool1 = nn.MaxPool2d(kernel_size=2,stride=2)
layer2 = nn.Sequential()
layer2.add_module('conv2', nn.Conv2d(64,64,kernel_size=3,padding=1))
layer2.add_module('BN2',nn.BatchNorm2d(64))
layer2.add_module('relu2',nn.ReLU(True))
layer2.add_module('pool2',nn.MaxPool2d(kernel_size=2,stride=2))
self.layer2 = layer2
self.layer3 = nn.Sequential(
nn.Conv2d(64,128,kernel_size=3,padding=1),
nn.BatchNorm2d(128),
nn.ReLU(True),
)
self.classifier = nn.Sequential(
nn.Linear(128,256),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(256, 256),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(256,num_classes),
)
def forward(self,x):
#定義自己的前向傳播方式
out = self.conv1(x)
out = self.BN1(out)
out = self.relu1(out)
out = self.pool1(out)
out = self.layer2(out)
out = self.layer3(out)
out = out.view(out.size(0), -1)
out = self.classifier(out)
return out
if __name__ == '__main__':
import torch
#使用gpu
use_cuda = torch.cuda.is_available()
device = torch.device("cuda" if use_cuda else "cpu")
net = VGG16().to(device)
print(net)
結果爲:
五、總結
1.nn.Module是一個基類,需要派生一個子類構造自己的網絡,需要改寫的方法有__init__,forward等,nn.Sequential()函數按照定義順序構建網絡。
2.nn中各種模塊的使用需要注意輸入輸出的銜接以及順序。
3.forward函數中的層層之間的輸入輸出的大小也要注意匹配