Pytorch学习(二)—— nn模块
torch.nn
- nn.Module
- 常用的神經(jīng)網(wǎng)絡(luò)相關(guān)層
- 損失函數(shù)
- 優(yōu)化器
- 模型初始化策略
- nn和autograd
- nn.functional
- nn和autograd的關(guān)系
- hooks簡介
- 模型保存
- GPU計算
Pytorch nn模塊提供了創(chuàng)建和訓(xùn)練神經(jīng)網(wǎng)絡(luò)的各種工具,其專門為深度學(xué)習(xí)設(shè)計,核心的數(shù)據(jù)結(jié)構(gòu)是Module。Module是一個抽象的概念,既可以表示神經(jīng)網(wǎng)絡(luò)中的某個層,也可以表示一個包含很多層的神經(jīng)網(wǎng)絡(luò)。
nn.Module
nn.Module基類構(gòu)造函數(shù):
def __init__(self):self.training = Trueself._parameters = OrderedDict()self._buffers = OrderedDict()self._backward_hooks = OrderedDict()self._forward_hooks = OrderedDict()self._forward_pre_hooks = OrderedDict()self._state_dict_hooks = OrderedDict()self._load_state_dict_pre_hooks = OrderedDict()self._modules = OrderedDict()其中對部分屬性的解釋如下:
- training: 對于一些在訓(xùn)練和測試階段采用策略不同的層如Dropout和BathNorm,通過training值決定前向傳播策略。
- _parameters: 用來保存用戶直接設(shè)置的parameter。
- _buffers: 緩存。
- *_hooks: 存儲管理hooks函數(shù),用來提取中間變量。
- _modules: 子module。
實際使用中,最常見的做法是繼承nn.Module來撰寫自定義的網(wǎng)絡(luò)層,需要注意以下幾點:
- 自定義層必須繼承nn.Module,并且在其構(gòu)造函數(shù)中需要調(diào)用nn.Module的構(gòu)造函數(shù)。
- 必須在構(gòu)造函數(shù)__init__中定義可學(xué)習(xí)參數(shù)。
- 使用forward函數(shù)實現(xiàn)前向傳播過程。
- 無須寫反向傳播函數(shù),nn.Module能夠利用autograd自動實現(xiàn)反向傳播。
- Moudle中的可學(xué)習(xí)參數(shù)可以通過named_parameters()或者parameters()返回迭代器。
借助nn.Moudle實現(xiàn)簡單的全連接層和多層感知機網(wǎng)絡(luò):
# -*- coding: utf-8 -*- # create on 2021-06-29 # author: yangimport torch from torch import nn# 全連接層 class Linear(nn.Module):def __init__(self, in_features, out_features):super(Linear, self).__init__() # or nn.Module.__init__(self)self.w = nn.Parameter(torch.randn(in_features, out_features))self.b = nn.Parameter(torch.randn(out_features))def forward(self, x):x = x.mm(self.w)return x + self.b.expand_as(x)# 多層感知機 class Perceptron(nn.Module):def __init__(self, in_features, hidden_features, out_features):nn.Module.__init__(self)self.layer1 = Linear(in_features, hidden_features)self.layer2 = Linear(hidden_features, out_features)def forward(self, x):x = self.layer1(x)x = torch.sigmoid(x)return self.layer2(x)if __name__ == '__main__':layer = Linear(4, 3)for name, parameter in layer.named_parameters():print(name, parameter)preceptron = Perceptron(3, 4, 1)for name, parameter in preceptron.named_parameters():print(name, parameter)常用的神經(jīng)網(wǎng)絡(luò)相關(guān)層
nn模塊中已經(jīng)封裝好了許多神經(jīng)網(wǎng)絡(luò)相關(guān)層,包括卷積、池化、激活等,實際使用時可借助ModuleList和Sequential簡化網(wǎng)絡(luò)構(gòu)建過程:
# Sequential # eg1: net1 = nn.Sequential() net1.add_module('conv', nn.Conv2d(3, 3, 3)) net1.add_module('batchnorm', nn.BatchNorm2d(3)) net1.add_module('relu', nn.ReLU())# eg2: net2 = nn.Sequential(nn.Conv2d(3, 3, 3),nn.BatchNorm2d(3),nn.ReLU()) # eg3: from collections import OrderedDict net3 = nn.Sequential(OrderedDict([('conv1', nn.Conv2d(3, 3, 3)),('batchnorm', nn.BatchNorm2d(3)),('relu', nn.ReLU())]))# ModelList modelist = nn.ModuleList([nn.Conv2d(3, 4), nn.BatchNorm2d(3), nn.ReLU()])損失函數(shù)
深度學(xué)習(xí)中要用到各種各樣的損失函數(shù),這些損失函數(shù)可以看作是一些特殊的layer,Pytorch將這些損失函數(shù)實現(xiàn)為nn.Module的子類。
以交叉熵損失CrossEntropyLoss為例:
# Loss Function score = torch.randn(3, 2) label = torch.Tensor([1, 0, 1]).long() criterion = nn.CrossEntropyLoss() loss = criterion(score, label)優(yōu)化器
torch.optim中封裝了許多深度學(xué)習(xí)中常用的優(yōu)化方法,所有的優(yōu)化方法都繼承自基類optim.Optimizer,并實現(xiàn)了自己的優(yōu)化步驟,以最基本的優(yōu)化方法——隨機梯度下降法(SGD)舉例說明:
模型初始化策略
深度學(xué)習(xí)中參數(shù)的初始化非常重要,良好的初始化能夠讓模型更快收斂,達到更好的性能。Pytorch中nn.Module模塊參數(shù)都采取了比較合理的初始化策略,我們也可以用自定義的初始化代替系統(tǒng)默認的初始化。nn.init模塊專門為初始化設(shè)計,并實現(xiàn)了常用的初始化策略。
借助init實現(xiàn)xavier高斯初始化:
from torch.nn import initlinear = nn.Linear(3, 4) torch.manual_seed(1) init.xavier_normal_(linear.weight) print(linear.weight.data)nn和autograd
nn.functional
在介紹nn和autograd之間的關(guān)系前,先來介紹nn中另一個很常用的模塊:nn.functional。nn中實現(xiàn)的大多數(shù)layer在functional中都有一個與之相對應(yīng)的函數(shù)。nn.functional與nn.Module的主要區(qū)別在于:nn.Module實現(xiàn)的layer是一個特殊的類,由class Layer(nn.Module)定義,會自動提取可學(xué)習(xí)的參數(shù);而nn.functional中的函數(shù)更像是純函數(shù),由def function(input) 定義。
當某一層有可學(xué)習(xí)參數(shù)時,如Conv,BathNorm等,最好使用nn.Module;由于激活、池化等層沒有可學(xué)習(xí)的參數(shù),因此可以使用對應(yīng)的functional函數(shù)替代,二者在性能上沒有太大的差異。在模型構(gòu)建中,可以搭配使用nn.Module和nn.functional:
from torch.nn import functional as F class Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(3, 6, 5)self.conv2 = nn.Conv2d(6, 16, 5)self.fc1 = nn.Linear(16 * 5 * 5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 100)def forward(self, x):x = F.max_pool2d(F.relu(self.conv1(x)), 2)x = F.max_pool2d(F.relu(self.conv2(x)), 2)x = x.view(-1, 16 * 5 * 5)x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return x有可學(xué)習(xí)參數(shù)的層,也可以使用functional代替,只不過實現(xiàn)起來較為煩瑣,需要手動定義參數(shù):
class MyLinear(nn.Module):def __init__(self):super(MyLinear, self).__init__()self.weight = nn.Parameter(torch.zeros(4, 3))self.bias = nn.Parameter(torch.zeros(4))def forward(self, x):x = F.linear(x, self.weight, self.bias)return xnn和autograd的關(guān)系
nn是建立在autograd之上的模塊,主要的工作是實現(xiàn)前向傳播。nn.Module對輸入的Tensor進行的各種操作,本質(zhì)上都用到了autograd技術(shù)。
autograd.Function和nn.Module之間的區(qū)別如下:
- autograd.Function利用Tensor對autograd技術(shù)的擴展,為autograd實現(xiàn)新的運算op
- nn.functional是autograd操作的集合,是經(jīng)過封裝的函數(shù)。
- nn.Module利用autograd,對nn的功能進行擴展,構(gòu)建網(wǎng)絡(luò)時,使用nn.Module作為基本元,nn.Module通常包裹autograd.Function作為真正實現(xiàn)的部分。 例如:
nn.ReLU = nn.functional.relu()
nn.functional.relu()類型為Function,再往下真正完成計算的部分通常使用C++實現(xiàn)。 - 如果某個操作在autograd中尚未支持,則需要利用Function手動實現(xiàn)對應(yīng)的前向傳播反向傳播
hooks簡介
hooks了解的不多,簡單認為是一種獲取模型中間結(jié)果(包括前向傳播的輸出和反向傳播的梯度)的方法,前向傳播的hooks函數(shù)有如下形式:hook(module, input, output) -> None,反向傳播則具有如下形式:hook(module, input, output) -> Tensor or None,hooks函數(shù)不應(yīng)修改輸入和輸出,并且在使用后應(yīng)當及時刪除,避免增加運行負載。
from torchvision import modelsmodel = models.resnet34() features = torch.Tensor()def hooks(module, input, output):features.copy_(output.data)handle = model.layer8.register_forward_hook(hooks) output = model(input) handle.remove()模型保存
在Pytorch中,所有Module對象都具有state_dict()函數(shù),返回當前Module的所有狀態(tài)數(shù)據(jù)。將這些狀態(tài)數(shù)據(jù)保存后,下次是用模型時即可利用load_state_dict()函數(shù)將狀態(tài)加載進來。
# save model torch.save(net.state_dict(), 'net.pth')# load model net2 = Net() net2.load_state_dict(torch.load('net.pth'))還有另外一種保存模型的方法:
torch.save(net, 'net_all.pth') net2 = torch.load('net_all.pth')目前,pytorch提供了onnx借口,可將pth模型導(dǎo)出為onnx模型。
GPU計算
將Module放在GPU上運行:
Pytorch提供了兩種方式,可在多個GPU上并行計算,二者參數(shù)十分相似,通過device_ids指定在哪些GPU上進行優(yōu)化,output_device指定輸出到那個GPU。不同之處在于nn.parallel.data_parallel直接利用多GPU并行計算得出結(jié)果,nn.DataParallel返回一個新的module,能夠自動在多GPU上進行并行加速。
# GPU 并行計算 '''DataParallel并行的方式是將輸入一個batch的數(shù)據(jù)均分成多份,分別送到對應(yīng)的GPU進行計算,然后將各個GPU得到的梯度相加。與Module相關(guān)的所有數(shù)據(jù)也會以淺拷貝的方式復(fù)制多份 ''' # method 1 new_net = nn.DataParallel(net, device_ids=[0, 1])# method 2 output = nn.parallel.data_parallel(net, input, device_ids=[0, 1])總結(jié)
以上是生活随笔為你收集整理的Pytorch学习(二)—— nn模块的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 沉痛悼念“中国航天之父”、我校创始人之一
- 下一篇: 计算机研讨会通讯录,江苏学会网 中国力学