check, initialize and freeze parameters

37291 ワード

https://stackoverflow.com/questions/63785319/pytorch-torch-no-grad-versus-requires-grad-false with torch.no_grad()requires_grad = Falseの違い(?)
基本的なcodeから逐次漸進する.
transfer learning=freezeはいくつかの階層だと思ってもいいです
基本的に,転移学習とは,いわゆる性能が良い,すなわち学習の良いparameterを持つことである.その後は特定のlayerのみを学習する(微調整と見なすことができる).私が欲しいデータセットによって交換すればいいです.これはなぜ良いのか、以下のように説明できると思います.
時間コストが急激に減少すると.これはかなりのメリットです.この概念を最初に知ったとき、他のデータセットや分類のトレーニングパラメータまでsegmenationで使われていると思っていたのですが、これはなぜうまくやっているのか逆に邪魔になるのでしょうか.CNNの役割は低-高画素認識であり、low parameterだけを持っていれば、うまく特徴抽出ができると考えられます.だから合理的だ.auto gradについては、すでに議論されています.

1.パラメータ確認

import torch
import torch.nn as nn
train_input.shape
----------------------------------------
torch.Size([64, 3, 224, 224])
class test_model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels = 3, out_channels = 30,
        kernel_size = 7, stride=2, padding=10, bias = False)
        self.conv2 = nn.Conv2d(in_channels = 30, out_channels = 30, 
        kernel_size = 3, stride=1, padding=10, bias = False)        
    def forward(self, inputs):
        feature_map1 = self.conv1(inputs)
        feature_map2 = self.conv2(feature_map1)        
        return feature_map2
モデル形状の確認
import pytorch_model_summary
from torchinfo import summary
model = test_model().to(device)
x = train_input
print(pytorch_model_summary.summary(model, x, show_input=True))
print('!@#'*40)
summary(model, input_size = x.shape )
パラメータのチェックと抽出
parameters={}
for n,i in enumerate(model.parameters()):
    parameters[n] = i
    print(n)
parameters.keys()
あるいは下の方が便利です
parameters={}
for n,i in model.named_parameters():
    parameters[n] = i
parameters.keys()
違いは、モデルクラスから定義された名前です.快適.
最も便利な方法
model.state_dict()
違いがあるだけです.state_dict()requires_grad = Falseです.

2. parameter initialize


大きく二つの段階に分かればいいです.
まずinitial関数を作成します.
def initialize_weight(m):
    if isinstance(m, nn.Conv2D):
        nn.init.kaiming_uniform_(m.weight.data,nonlinearity='relu')
次にこの関数をモデルに適用すればよい.
model.apply(initialize_weight)
このときapplyには、モデル内のlayerが回転していることがわかります.
つまり、ドアと見なすことができる.
  • 追加
  • len(model.state_dict())
    パラメータの合計
    model.state_dict().keys()
    検索しやすい
    model.conv1.weight.shape
    上のキーで確認
    parameter_test = torch.nn.parameter.Parameter(data = torch.zeros(32,1,3,3), requires_grad = True)
    model.conv1.weight = parameter_test
    parameterとして指定した場合、parameterに直接アクセスしてモデルを変更します.
    model.state_dict()
    変更の確認
    もうちょっと
    実際のモデルから初期化する方法.
    class Flatten(nn.Module):
        def forward(self, input):
            return input.view(input.size(0), -1)
    
    class test(nn.Module):
        def __init__(self):
            super().__init__()
            
            self.conv1 = conv_bn_relu(in_channel = 3, out_channel = 32, kernel = (3,3), s = (1,1), p = (1,1))
            self.pool1 = nn.MaxPool2d(kernel_size=(2, 2))
            
            self.conv2 = conv_bn_relu(in_channel = 32, out_channel = 32, kernel = (3,3), s = (1,1), p = (1,1))
            self.pool2 = nn.MaxPool2d(kernel_size=(2, 2)) 
            
            self.conv3 = conv_bn_relu(in_channel = 32, out_channel = 32, kernel = (3,3), s = (1,1), p = (1,1))
            self.pool3 = nn.MaxPool2d(kernel_size=(2, 2))
    
            self.conv4 = conv_bn_relu(in_channel = 32, out_channel = 32, kernel = (3,3), s = (1,1), p = (1,1))
            self.pool4 = nn.MaxPool2d(kernel_size=(2, 2))
            
            self.conv5 = conv_bn_relu(in_channel = 32, out_channel = 32, kernel = (3,3), s = (1,1), p = (1,1))
            self.pool5 = nn.MaxPool2d(kernel_size=(2, 2))
            
            self.flatten = Flatten()
            
            self.fc1 = nn.Linear(32*3*3, 10)
            self.fc2 = nn.Linear(10, 10)
            
            
        def forward(self, x):
            x = self.conv1(x)
            x = self.pool1(x)
            
            x = self.conv2(x)
            x = self.pool2(x)
            
            x = self.conv3(x)
            x = self.pool3(x)
            
            x = self.conv4(x)
            x = self.pool4(x)
            
            x = self.conv5(x)
            x = self.pool5(x)   
            
            x = self.flatten(x)
    
            return x
    上記のモデルを作成します.
    model = test()
    model.state_dict()
    パラメータを確認します.
    デフォルトの初期化が良いことがわかります.
    次に、applyを使用して関数を初期化します.
    def _initialize_weights(m):
        if isinstance(m, nn.Conv2d):
            nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
            if m.bias is not None:
                nn.init.constant_(m.bias, 0)
        elif isinstance(m, nn.BatchNorm2d):
            nn.init.constant_(m.weight, 1)
            nn.init.constant_(m.bias, 0)
        elif isinstance(m, nn.Linear):
            nn.init.normal_(m.weight, 0, 0.01)
            nn.init.constant_(m.bias, 0)
    テストがうまくいくかどうかをテストするためにconvのbias以外の部分だけを0にします.
    def _initialize_weights_test(m):
        if isinstance(m, nn.Conv2d):
            torch.nn.init.uniform_(m.weight, a=0.0, b=0.0)
            if m.bias is not None:
                nn.init.constant_(m.bias, 0)
        elif isinstance(m, nn.BatchNorm2d):
            nn.init.constant_(m.weight, 1)
            nn.init.constant_(m.bias, 0)
        elif isinstance(m, nn.Linear):
            nn.init.normal_(m.weight, 0, 0.01)
            nn.init.constant_(m.bias, 0)
    model.apply(_initialize_weights_test)
    model.state_dict()
    正確にはconvの重量分(biasを除く)だけが0になっています.
    すなわち,上記の関数を用いてモデルに適用することができる.

    3.freeze


    勾配の有無
    for n,i in enumerate(model.parameters()):
        print(i.requires_grad)
    gradを次のようにドラッグできます.
    for n,i in enumerate(model.parameters()):
        if n == 0:
            i.requires_grad = False
    for i,j in model.named_parameters():
        print(i,j.requires_grad)