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(...)
使用场景为迁移学习. 针对不同的领域有不同的场景. 通常来说如果需要解决的问题数据集非常少,不足以训练一个大型神经网络,如果想要继续使用神经网络的特征提取能力,那么可以考虑微调一个已经训练好的模型.
今天笔者将在这里总结上面的第二个场景,如果使用已经训练好的网络模型进行任意卷积层的特征提取!
一共有三种方法.
代码逻辑如下:
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函数会在每一次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 # 非常简单,直接在此处提取特征.
但是这种写法,还是具有颇多不灵活之处,如果我要提取别的中间层的输出,又要修改,所以仅仅是投机取巧用用.