人工智能專欄限時打折中
以下幾個專欄限時打折中,歡迎訂閱
正文
為方便用戶使用,PyTorch實現了神經網絡中絕大多數的layer,這些layer都繼承於nn.Module,封裝了可學習參數parameter,並實現了forward函數,且很多都專門針對GPU運算進行了CuDNN優化,其速度和性能都十分優異。
如nn.Linear(in_features, out_features, bias),需關注這三個參數的作用。
如nn.Linear中有weight和bias兩個可學習參數輸入輸出的形狀,如nn.linear的輸入形狀是(N, input_features),輸出為(N,output_features),N是batch_size。
在PyTorch裡面編寫神經網絡,所有的層結構和損失函數都來自於torch.nn,所有的模型構建都是從這個基類 nn.Module 繼承的,於是有了下面這個模板。
class net_name(nn.Moudle) :
def __init__ (self,other_ments) :
super(net_name,self). __init__()
self.conv1=nn.Conv2d(in_channels, out_channels, kernel_size)
# other network l ayer 其它網絡層
def forward(self, x):
x=self.conv1(x)
return x
這樣就建立了一個計算圖 ,並且這個結構可以複用多次,每次調用就相當於用該計算圖定義的相同參數做一次前向傳播,這得益於 PyTorch 的自動求導功能,所以我們不需要自己編寫反向傳播,而所有的網絡層都是由 nn 這個包得到的,比如線性層nn.Linear,等之後使用的時候我們可以詳細地介紹每一種網絡對應的結構,以及如何調用。
定義完模型之後 ,我們需要通過nn這個包來定義損失函數。 常見的損失函數都已經定義在了nn巾,比如均方誤差 、多分類的交叉熵,以及二分類的交叉熵,等等,調用這些已經定義好的損失函數也很簡單:
criterion = nn.CrossEntropyLoss( )
loss = criterion(output, target)
這樣就能求得我們的輸出和真實目標之間的損失函數了
常見的神經網絡層:
卷積層conv = nn.Conv2d(1, 1, (3, 3), 1, bias=False)
池化層pool = nn.AvgPool2d(2,2)
Linear:全連接層linear = nn.Linear(3, 4)
BatchNorm:批規範化層bn = nn.BatchNorm1d(4)
Dropout:dropout層dropout = nn.Dropout(0.5)#0.5的概率捨棄
激活函數relu = nn.ReLU(True)
# Embedding層,有4個詞,每個詞用5維的向量表示
embedding = nn.Embedding(4, 5)
搭建網絡的兩種方式
我們在搭建神經網絡的時候,可以將多個神經網絡層組合在一起,我們可以使用Sequential和ModuleList這兩種方式。
我們先來看一下Sequential,它我們可以看作是一個module
# Sequential的三種寫法
寫法一:為每一個神經網絡層添加一個名字
net1 = nn.Sequential()
net1.add_module('conv', nn.Conv2d(3, 3, 3))
net1.add_module('batchnorm', nn.BatchNorm2d(3))
net1.add_module('activation_layer', nn.ReLU())
因為有名字,所以我們可以根據名字來取出神經網絡的每一層
net1.conv
net1.batchnorm
前向傳播out=net1(input)
寫法二:
net2 = nn.Sequential(
nn.Conv2d(3, 3, 3),
nn.BatchNorm2d(3),
nn.ReLU()
)
這個沒有名字,我們可以通過索引取出Sequential中神經網路的每一層
net2[0]
前向傳播out=net2(input)
寫法三:使用OrderedDict將神經網絡層封裝為一個字典,然後傳遞到Sequential中
from collections import OrderedDict
net3= nn.Sequential(OrderedDict([
('conv1', nn.Conv2d(3, 3, 3)),
('bn1', nn.BatchNorm2d(3)),
('relu1', nn.ReLU())
]))
可以根據名字取出神經網絡的每一層
net3.conv1
前向傳播
方式一:output = net3(input)
方式二:output = net3.relu1(net1.batchnorm(net1.conv(input)))
ModuleList的使用方式,注意ModuleList在Module中使用它的時候(在實現nn.Module的__init__()方法中使用的時候),才能自動識別為子module。
class Net4(nn.Module):
def __init__(self):
super(Net4, self).__init__()
self.module_list = nn.ModuleList([nn.Conv2d(3, 3, 3), nn.ReLU()])
def forward(self):
model = MyModule()
ModuleList其實就是一個List,只不過在Module中它會自動識別為module,識別為module的好處就是它會作為整個module的一個整體,在反向傳播中跟新其參數。
除ModuleList之外還有ParameterList,其是一個可以包含多個parameter的類list對象。我們如果要是在init中用到list,我們應該用ModuleList或ParameterList,而不是使用list。
class MyLinear(nn.Module):
def __init__(self, inp, outp):
super(MyLinear, self).__init__()
# requires_grad = True
self.w = nn.Parameter(torch.randn(outp, inp))
self.b = nn.Parameter(torch.randn(outp))
def forward(self, x):
x = x @ self.w.t() + self.b
return x
這個表示建立一個全連接層,w和b就是全連接層的權重參數,其中w的維度是(輸出,輸入)
nn.Parameter中會自帶梯度求梯度功能
獲取參數
Net.parameters()表示獲取net的所有參數
List表示轉換為列表形式,此時這個列表應該是[w0,b0,w1,b1]
遍歷所有的模型的參數,其中name表示模型的參數,注意這個名字中沒有net.1,這是因為nn.ReLU是模型的第二層,但是這裡並沒有參數,所以net.0之後沒有net.1,而直接是net.2
Named——children表示獲取net的網絡的孩子結點
獲取所有結點,從子結點開始逐漸到孫子結點
自定義展開層
class Flatten(nn.Module):
def __init__(self):
super(Flatten, self).__init__()
def forward(self, input):
return input.view(input.size(0), -1)
class TestNet(nn.Module):
def __init__(self):
super(TestNet, self).__init__()
self.net = nn.Sequential(nn.Conv2d(1, 16, stride=1, padding=1),
nn.MaxPool2d(2, 2),
Flatten(),
nn.Linear(1*14*14, 10))
def forward(self, x):
return self.net(x)
閱讀更多 幻風的AI之路 的文章