PyTorch : torch.nn.xxx 和 torch.nn.functional.xxx


PyTorch : torch.nn.xxx 和 torch.nn.functional.xxx

在寫 PyTorch 代碼時,我們會發現在 torch.nn.xxxtorch.nn.functional.xxx 中有一些功能重復的操作,比如卷積、激活、池化。這些操作有什么不同?各有什么用處?

首先可以觀察源碼:

eg:torch.nn.Conv2d

CLASS torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')

eg:torch.nn.functional

torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1) → Tensor

從中,我們可以發現,nn.Conv2d 是一個類,而 nn.functional.conv2d是一個函數。

換言之:

  • nn.Module 實現的 layer 是由 class Layer(nn.Module) 定義的特殊類
  • nn.functional 中的函數更像是純函數,由 def function(input) 定義

此外:

  1. 兩者的調用方式不同:調用 nn.xxx 時要先在里面傳入超參數,然后再將數據以函數調用的方式傳入 nn.xxx

    # torch.nn
    inputs =  torch.randn(64, 3, 244, 244)
    self.conv = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, padding=1)
    outputs = self.conv(inputs)
    
    # torch.nn.functional	需要同時傳入數據和 weight,bias等參數
    inputs =  torch.randn(64, 3, 244, 244)
    weight = torch.randn(64, 3, 3, 3)
    bias = torch.randn(64)
    outputs = nn.functinoal.conv2d(inputs, weight, bias, padding=1)
    
  2. nn.xxx 能夠放在 nn.Sequential里,而 nn.functional.xxx 就不行

  3. nn.functional.xxx 需要自己定義 weight,每次調用時都需要手動傳入 weight,而 nn.xxx 則不用

    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    
    # torch.nn 定義的CNN
    class CNN(nn.Module):
        def __init__(self):
            super(CNN, self).__init__()
            
            self.conv_1 = nn.Conv2d(1, 16, krenel_size=5, padding=0)
            self.relu_1 = nn.ReLU(inplace=True)
            self.maxpool_1 = nn.MaxPool2d(kernel_size=2)
    
            self.conv_2 = nn.Conv2d(16, 32, krenel_size=5, padding=0)
            self.relu_2 = nn.ReLU(inplace=True)
            self.maxpool_2 = nn.MaxPool2d(kernel_size=2)   
            
            self.linear = nn.Linear(4*4*32, 10)
          
        def forward(self, x):
            x = x.view(x.size(0), -1)
            out = self.maxpool_1(self.relu_1(self.conv_1(x)))
            out = self.maxpool_2(self.relu_2(self.conv_2(out)))
            out = self.linear(out.view(x.size(0), -1))
            return out
        
    # torch.nn.functional 定義一個相同的CNN
    class CNN(nn.Module):
        def __init__(self):
            super(CNN, self).__init__()
            
            self.conv_1_weight = nn.Parameter(torch.randn(16, 1, 5, 5))
            self.bias_1_weight = nn.Parameter(torch.randn(16))
            
            self.conv_2_weight = nn.Parameter(torch.randn(32, 16, 5, 5))
            self.bias_2_weight = nn.Parameter(torch.randn(32))
            
            self.linear_weight = nn.Parameter(torch.randn(4 * 4 * 32, 10))
            self.bias_weight = nn.Parameter(torch.randn(10))
          
        def forward(self, x):
            x = x.view(x.size(0), -1)
            out = F.conv2d(x, self.conv_1_weight, self.bias_1_weight)
            out = F.conv2d(out, self.conv_2_weight, self.bias_2_weight)
            out = F.linear(out.view(x.size(0), -1), self.linear_weight, self.bias_weight)
    
  4. 在使用Dropout時,推薦使用 nn.xxx。因為一般只有訓練時才使用 Dropout,在驗證或測試時不需要使用 Dropout。使用 nn.Dropout時,如果調用 model.eval() ,模型的 Dropout 層都會關閉;但如果使用 nn.functional.dropout,在調用 model.eval() 時,不會關閉 Dropout。

  5. 當我們想要自定義卷積核時,是不能使用torch.nn.ConvNd 的,因為它里面的權重都是需要學習的參數,沒有辦法自行定義。但是,我們可以使用 torch.nn.functional.conv2d()

References:

  1. pytorch:nn與nn.functional的區別——簡書


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM