pytorch学习笔记(3) 动态调整学习率和hook函数的使用

pytorch学习笔记(3) 动态调整学习率和hook函数的使用.

动态调整学习率

def adjust_learning_rate(optimizer, epoch, params):
    lr = params["LEARNING_RATE"] * (0.1 **(epoch // 20))
    for param_group in optimizer.param_groups:
        # print("params", param_group)
        param_group['lr'] = lr

这个函数能够根据epoch动态的调整学习率,使用逻辑为:

optimizer = optim.SGD(model.parameters(), lr = params["learning_rate"], ...)
for i in range(epochs):
    adjust_learning_rate(optimizer, i, params)
    train(...)

如何提取CNN中间层的输出

使用场景为迁移学习. 针对不同的领域有不同的场景. 通常来说如果需要解决的问题数据集非常少,不足以训练一个大型神经网络,如果想要继续使用神经网络的特征提取能力,那么可以考虑微调一个已经训练好的模型.

  • 比如说先将网络在大型的数据集ImageNet上训练, 然后再用只包含猫和狗的小型数据集进行微调. 用来识别猫狗
  • 或者使用多任务的数据集来训练神经网络, 然后将这个迁移到其他与源任务相关的数据集用来做特征提取器,提取出来的特征用SVM这种高级分类器来进行分类, 这就是迁移学习.

今天笔者将在这里总结上面的第二个场景,如果使用已经训练好的网络模型进行任意卷积层的特征提取!

一共有三种方法.

  • 手动实现forward函数,也就是PyTorch论坛上提到的.
  • 使用hook函数勾取某一层的输出.
  • 在需要提取特征的地方定义一个变量.
手动实现forward函数

代码逻辑如下:

class Extract():
    def __init__(self, **params)
        self.model_path = params["model_path"] # 模型保存地址
        self.model = self.load_model() 
    def load_model(self):
        CNN = model.CNN_Net() # 初始化一个模型
        CNN.load_state_dict(torch.load(self.model_path)) # 加载训练好的参数
        return CNN
    def forward(self, input):
        x = input
        self.model.eval() # 这句非常重要
        with torch.no_grad():
            for name, module in self.model.cnn._module.items():
                x = module(x) # 一层一层地forward
                if name == '18': # 这里选取需要提取层的名字
                    return x # 这个x就是提取的特征向量,保存即可.

**然而,使用这种forward写法, 网络结构的定义最好使用torch.nn.Sequential().**这样会使得一层一层forward的时候不会乱.

使用hook函数勾取某一层的输出

hook函数会在每一次forward计算了一个输出之后调用.

代码逻辑如下

extract = Extract(**params) # 使用上面定义的类
model = extract.load_model() # 加载已经训练好的参数
model.eval() # 这一句非常重要
activation = {}
def get_activation(name):
    def hook(model, input, output):
        activation[name] = out.detach() # 保存输出
    return hook
model.cnn[19].register_forward_hook(get_activation('18')) # 在每一次forward计算一次输出之后调用hook函数.
for i in range(numbers_input):
    input = ...
    out = model(input)
    feature = activation['19'] # 勾取hook函数定义在那一层的输出
在需要提取特征的地方定义一个变量保存下来

代码逻辑如下: 在网络首先定义的地方加一个变量保存下来

class CNN_Net(nn.Module):
    def __init__(self):
        super(CNN_Net, self).__init__()
        self.cnn = nn.Sequential(
            # layer 1
            nn.Conv1d(128, 128, 4, padding=2),
            nn.BatchNorm1d(128),
            nn.ReLU(),
            nn.MaxPool1d(4),
            # layer 2
            nn.Conv1d(128, 128, 4, padding=2),
            nn.BatchNorm1d(128),
            nn.ReLU(),
            nn.MaxPool1d(4),
            # layer 3
            nn.Conv1d(128, 128, 4, padding=2),
            nn.BatchNorm1d(128),
            nn.ReLU(),
            nn.MaxPool1d(4),
            # layer 4
            nn.Conv1d(128, 128, 2, padding=2),
            nn.BatchNorm1d(128),
            nn.ReLU(),
            nn.MaxPool1d(2),
            # layer 5
            nn.Conv1d(128, 256, 2),
            nn.BatchNorm1d(256),
            nn.ReLU(),

            nn.Dropout(0.5)
        )
        self.fc = nn.Sequential(
            nn.Linear(256, 128),
            nn.ReLU(),
            nn.Linear(128,7),
            nn.ReLU(),
        )

    def forward(self, x):

        out = self.cnn(x)
        out = out.view(-1, 256)
        self.feature = out # 在这里!!!
        out = self.fc(out)
        return out

训练 ...

提取逻辑如下:

class Extract():
    def __init__(self, **params)
        self.model_path = params["model_path"] # 模型保存地址
        self.model = self.load_model() 
    def load_model(self):
        CNN = model.CNN_Net() # 初始化一个模型
        CNN.load_state_dict(torch.load(self.model_path)) # 加载训练好的参数
        return CNN
    def select_feature(self, input):
        x = input
        self.model.eval()
        with torch.no_grad():
            out = self.model(x)
            feature = self.model.feature # 非常简单,直接在此处提取特征.

但是这种写法,还是具有颇多不灵活之处,如果我要提取别的中间层的输出,又要修改,所以仅仅是投机取巧用用.

你可能感兴趣的:(深度学习,Python学习,Pytorch)