深度學習與Pytorch入門實戰(十)ResNet&nn.Module


摘抄

1. ResNet

2. nn.Module

  • 在PyTorch中nn.Module類是用於 定義網絡中 前向結構 的父類

  • 當要定義自己的網絡結構時就要繼承這個類

  • 現有的那些類式接口(如nn.Linearnn.BatchNorm2dnn.Conv2d等)也是繼承這個類的

  • nn.Module類可以嵌套若干nn.Module的對象,來形成網絡結構的嵌套組合

  • 下面記錄nn.Module的功能

3. 繼承nn.Module類的模塊

  • 使用其初始化函數創建對象,然后調用forward函數就能使用里面的前向計算過程。

  • 包括:Linear、ReLU、Sigmoid、Conv2d、ConvTransposed2d、Dropout...

4. 容器nn.Sequential()

  • nn.Sequential是一個Sequential容器

  • 模塊將按照 構造函數中傳遞的順序 添加到模塊中。

  • 通俗的說,就是根據自己的需求,把不同的函數組合成一個(小的)模塊使用 或者 把組合的模塊添加到自己的網絡中。

from torch import nn

conv_module = nn.Sequential(
          nn.Conv2d(1,20,5),
          nn.ReLU(),
          nn.Conv2d(20,64,5),
          nn.ReLU()
        )

# 具體的使用方法
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv_module = nn.Sequential(
          nn.Conv2d(1,20,5),
          nn.ReLU(),
          nn.Conv2d(20,64,5),
          nn.ReLU()
        )

    def forward(self, input):
        out = self.conv_module(input)
        return out

Tip:

  • 使用nn.Module,我們可以根據自己的需求改變傳播過程,如RNN等;

  • 如果需要快速構建或者不需要過多的過程,直接使用nn.Sequential

5. 模塊內部參數管理

可以用 .parameters() 或者 .named_parameters() 返回 其內的所有參數的迭代器:

from torch import nn

net = nn.Sequential(
      nn.Linear(4, 2),          # 輸入維度4,輸出維度2 的線性層
      nn.Linear(2, 2)
    )

print(list(net.parameters()))
# [Parameter containing:
# tensor([[-0.0829,  0.3424,  0.4514, -0.3981],
#         [-0.3401,  0.1429, -0.4525,  0.4991]], requires_grad=True),
# Parameter containing:
# tensor([-0.0321,  0.0872], requires_grad=True),
# Parameter containing:
# tensor([[ 0.0628,  0.3092],
#         [ 0.5135, -0.4738]], requires_grad=True),
# Parameter containing:
# tensor([-0.4249,  0.3921], requires_grad=True)]

print(dict(net.named_parameters()))
# {'0.weight': Parameter containing:
# tensor([[-0.0829,  0.3424,  0.4514, -0.3981],
#         [-0.3401,  0.1429, -0.4525,  0.4991]], requires_grad=True),
# '0.bias': Parameter containing:
# tensor([-0.0321,  0.0872], requires_grad=True),
# '1.weight': Parameter containing:
# tensor([[ 0.0628,  0.3092],
#         [ 0.5135, -0.4738]], requires_grad=True),
# '1.bias': Parameter containing:
# tensor([-0.4249,  0.3921], requires_grad=True)}

Tip:

  • 以第0層為例,weight.shape=[2,4],輸出維度在前,輸入維度在后,和Linear定義的時候相反;

  • 相比.parameters().named_parameters()能看到參數名,默認情況下會使用 所在的層數 + 參數類型 的方式,從0層開始編號;

  • 使用優化器時,可以直接調用 nn.Module 類定義的參數。

optimizer = optim.SGD(net.parameters(), lr=learning_rate)

6. 模塊樹形結構

  • 模塊之間通過 嵌套組合 會形成樹形結構,使用.children()可以 獲取其直接孩子結點

  • 使用.modules()可以 獲取其所有子結點。

from torch import nn

class BaseNet(nn.Module):
    
    def __init__(self):
#         super(BaseNet, self).__init__()  # python2寫法
        super().__init__()
        self.net = nn.Linear(4, 3)     # 輸入4維,輸出3維的線性層

    def forward(self, x):
        return self.net(x)
    
class MyNet(nn.Module):
    
    def __init__(self):
        super(MyNet, self).__init__()  # 使用Seq容器組合了三個模塊
        self.net = nn.Sequential(
            BaseNet(), 
            nn.ReLU(),
            nn.Linear(3, 2)
        )
    
    def forward(self, x):
        return self.net(x)
    
my_net = MyNet()

print(list(my_net.children()))   # 直接孩子
# [Sequential(
#   (0): BaseNet(
#     (net): Linear(in_features=4, out_features=3, bias=True)
#   )
#   (1): ReLU()
#   (2): Linear(in_features=3, out_features=2, bias=True)
# )]

print(list(my_net.modules()))   # 所有孩子
# [MyNet(
#   (net): Sequential(
#     (0): BaseNet(
#       (net): Linear(in_features=4, out_features=3, bias=True)
#     )
#     (1): ReLU()
#     (2): Linear(in_features=3, out_features=2, bias=True)
#   )
# ), 
# Sequential(
#   (0): BaseNet(
#     (net): Linear(in_features=4, out_features=3, bias=True)
#   )
#   (1): ReLU()
#   (2): Linear(in_features=3, out_features=2, bias=True)
# ), 
# BaseNet(
#   (net): Linear(in_features=4, out_features=3, bias=True)
# ), 
# Linear(in_features=4, out_features=3, bias=True), ReLU(), Linear(in_features=3, out_features=2, bias=True)]
  • .children()只返回自己的直系孩子列表,在這里也就是一個nn.Sequential容器。

  • 而使用.modules()獲取的所有孩子是包括自己的。

7. 設備

  • 使用.to(device)可以在具體的CPU/GPU上切換,這會將其所有子模塊也一起轉移過去運行。
device = torch.device('cuda')

net = Net()

net.to(device)

Tip:

  • 模塊的.to(device)是原地操作並返回自己的引用

  • 而Tensor的 .to(device) 不會在當前Tensor上操作,返回的 才是在目標設備上對應創建的Tensor

    • 所以net = MLP().to(device)

8. 加載和保存

  • 使用torch.load()載入檢查點文件,然后傳入net.load_state_dict()網絡模型設置參數

  • 把當前類所有狀態net.state_dict()傳入torch.save()保存到文件中去。

  • 在訓練過程中,每隔一定的迭代次數可以保存一下檢查點,將當前網絡模型的狀態傳進去。

  • eg. ckpt.mdl是網絡的一個中間狀態

net.load_state_dict(torch.load('ckpt.mdl'))

# train...

torch.save(net.state_dict(), 'ckpt.mdl')

9. 訓練和測試模式

  • 前面的學習中提到DropoutBatch Normalization在訓練和測試中的行為不同

  • 需要對每一個nn.Module()模塊 單獨設置訓練狀態和測試狀態

  • 可以直接為網絡使用方法.train() 切換到訓練模式,使用.eval()方法 切換到測試模式

# train
net.train()
...
# test
net.eval()
...

10. 實現自定義的類

10.1 nn.Sequential用法

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)

Tip:

  • 只有類才能寫到Sequential里面,比如F.relu不可以,要重新定義nn.ReLU

  • 如,Flatten類,Reshape類都需要自己實現!

10.2 nn.Parameters 和 .parameters()

  • 如果在繼承nn.Module類來實現模塊時,出現需要操作Tensor的部分,那么應當使用nn.Parameters(注意這里P大寫) 將其包裝起來

  • 如果直接使用Tensor,那么就不能用.parameters()(注意這里p小寫)獲取到所有參數,也就不能直接傳給優化器去記錄要優化的這些參數了。

class MyLinear(nn.Module):
    def __init__(self, inp, outp):
        super(MyLinear, self).__init__()
        # 線性層的參數w和b,對w而言輸出維度放在前面
        # requires_grad = True
        self.w = nn.Parameter(torch.randn(outp, inp))   # w: [n^l, n^{l-1}]
        self.b = nn.Parameter(torch.randn(outp))

    def forward(self, x):
        x = x @ self.w.t() + self.b
        return x

Tip:

  • 上述MyLinear 和 pytorch自帶的Linear類效果一樣

  • 使用nn.Parameter()包裝Tensor時,自動設置了requires_grad=True

  • 即默認情況下認為它是反向傳播優化的參數。


免責聲明!

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



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