pytorch模型微调(Finetune)

Transfer Learning & Model Finetune

模型微调

**Transfer Learning:**机器学习分支,研究源域(source domain)的知识如何应用到目标域(target domain)。
迁移学习是一个很大的概念,它主要研究一系列源域的知识应用到目标域中,如何理解?
来自论文《A Survey on Transfer Learning》
上图左边是一个传统的机器学习任务的学习过程,传统的机器学习任务中对不同的任务分别进行训练和学习,得到称之为Learning System的模型,这里三个不同的任务就会得到三个不同的Learning System的模型;
而右边展示了迁移学习,它是怎么进行的呢?它就有不同的任务了,这个任务会划分为称之为Source Tasks(源任务)、Target Task(目标任务),这两个任务之间有一定的关联。首先,看右边的左边,先对Source Tasks进行学习,这里学习到的称之为Knowledge,而在右边的Target Task中,会利用在源任务中学习到的Knowledge进行学习进行训练,得到Learning System,这个过程叫做迁移学习。这个模型的训练不仅用到了Target Task的任务,以及还用到了Source Targets中的Knowledge,这就是迁移学习所要研究的问题。我们将源任务所学习到的知识用到目标任务当中,用来提升在目标任务里模型的性能。
深度学习模型训练当中的模型微调与迁移学习之间的关系?
训练一个模型就是不断更新它的权值,而整个模型当中最重要的东西也就是它的权值,这里的权值可以称之为知识,
可以把这些权值神经网络在特定任务当中学习到的知识,而这些知识是可以进行迁移的,将这些知识迁移到新任务当中,这样就完成了Transfer Learning,这就是模型微调。
在这里插入图片描述
为什么要采用Model Finetune这个trick呢?
这是由于在新任务中,数据量较小,不足以去训练一个较大的模型,因此就可以采用Model Finetune的方式来辅助我们在新任务当中去训练一个较好的模型,让我们的训练过程更快。这就类比于一个人如果学会了骑自行车,再去学骑电动车,这样就学的比较快。
神经网络该如何去迁移呢?
下面看一个卷积神经网络的示意图,卷积神经网络通常会划分为两个部分,将前面一系列的卷积、池化看作是features extractor,即特征提取,通过这些卷积、池化得到特征,后面会接上一系列的全连接层,将后面的全连接层称之为classifier,即分类器,这样就将一个卷积神经网络剖析成两个部分:特征提取、分类器。
对里面的一系列参数进行分析,哪些参数是有共性的,哪些参数又需要改变呢?会对卷积神经网络中的参数进行一个划分,将特征提取的部分认为是非常有共性的地方,可以原封不动的进行的进行迁移,而分类器的参数会与具体的任务有关,通常是需要进行改变的。
在这里插入图片描述

模型微调步骤

  • 1获取预训练模型参数(可以认为是源任务中学习到知识)
  • 2加载模型(load_state_dict)
  • 3修改输出层 ,以适应新的任务

模型微调训练方法

  • 1 固定预训练的参数(requires_grad = False;lr = 0)
    比如,图中的卷积神经网络,我们有时候会固定特征提取的部分,也就是这一系列卷积层的参数,固定它们不进行训练,这是因为有的时候,新任务的数据量比较小,我们不足以去训练那么多的参数,同时,我们也认为前面的特征提取的部分,它们的参数是非常有共性的,所以可以固定这些参数,让这些参数不更新,而这个具体的操作在pytorch中有两种方法:①可以设置requires_grad = False,也就是说这些参数不需要计算梯度,即不会再进行更新;②设置学习率lr为0,即更新的步伐为0,所以也不会去更新。这就完成了参数的固定。
  • 2 Features Extractor较小学习率(params_group)
    将特征提取这部分设置较小的学习率,这时就需要用到params_group(在优化器那部分介绍过),优化器可以对不同的参数组设置不同的超参数,这里就可以对不同的参数设置不同的学习率,让特征提取部分的学习率较小,而全连接层部分的学习率较大,这就实现了不同的参数设置不同的学习率。

【举例】
如何在pytorch中实现模型的finetune呢?下面的例子采用Resnet-18进行Finetune,用一个在image net训练好的Resnet-18,然后应用到新任务中,我们的目标任务(即新任务)是一个蚂蚁蜜蜂二分类任务。
蚂蚁蜜蜂二分类数据:

  • 训练集:各120~张
  • 验证集:各70~张
    可以看出这是一个数据量非常小的任务,将用一个Resnet-18进行Finetune。
    在这里插入图片描述
    查看Resnet-18的模型结构:
    在这里插入图片描述
    分析一下模型结构,然后要观察要在哪里改动。
    一般认为子模块‘conv1’、‘bn1’、‘relu’、‘maxpool’对图像进行初步的特征提取;‘layer1’、‘layer2’、‘layer3’、‘layer4’进行一系列的特征提取;‘avgpool’是对特征图进行一个池化操作;此处的‘fc’层是一个有1000个神经元的全连接层,1000类的分类任务。而新任务是二分类任务,所以需要将最后的fc层修改为一个只有两个神经元的全连接层。
    在这里插入图片描述
    采用model finetune与不采用model finetune,它们之间的训练情况
    不采用model finetune,即随机初始化一个Resnet-18,然后进行训练的情况:

    在这里插入图片描述
    代码实现如何进行Model Finetue?
#step 2/5 模型

# 1/3 构建模型
resnet18_ft = models.resnet18()

# 2/3 加载参数
path_pretrained_model = os.path.join(BASEDIR, "..", "..", "data/resnet18-5c106cde.pth")
state_dict_load = torch.load(path_pretrained_model)
resnet18_ft.load_state_dict(state_dict_load)

# 法1:冻结卷积层
for param in resnet18_ft.parameters():
	param.requires_grad = False
print("conv1.weights[0, 0, ...]".format(resnet18_ft.conv1.weight[0, 0, ...]))

# 3/3 替换fc层(以适应新任务)
num_ftrs = resnet18_ft.fc.in_features
resnet18_ft.fc = nn.Linear(num_ftrs, classes)

# step 4/5 优化器
 #优化器中可以管理不同的参数组,为不同的参数组设置不同的超参数
# 法2:conv 小学习率
flag = 0
# flag = 1
if flag:
	#列表fc_params_id中的每一个元素对应fc层中的参数的地址
	fc_params_id = list(map(id, resnet18_ft.fc.parameters())) #返回的是parameters的内存地址
	# 将resnet18_ft中所有的参数过滤掉fc层,过滤条件就是采用内存地址,得到前面卷积层的参数
	base_params = filter(lambda p: id(p) not in fc_params_id, resnet18_ft.parameters())
	# 优化器设置不同的参数组
	optimizer = optim.SGD([
		{'params': base_params, 'lr': LR*0.1}, #0
		{'params': resnet18_ft.fc.parameters(), 'lr': LR}], momentum = 0.9)
else:
	optimizer = optim.SGD(resnet18_ft.parameters(), lr = LR, momentum = 0.9) #选择优化器

scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=lr_decay_step, gamma=0.1) #设置学习率

下图为使用Model Finetune的情况:
在这里插入图片描述

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: PyTorch 是一个基于 Python 的科学计算库,它有着一些非常方便的特性,使得它成为了深度学习领域的开发者们的首选。而 pkuseg 是一个由北大自然语言处理实验室开发的中文分词工具,是目前效果最好的中文分词工具之一。在使用 PyTorch 微调 pkuseg 模型时,我们需要先了解一些基本的原理。 pkuseg 模型是基于 BERT 进行 fine-tune 的,因此我们需要先加载预训练好的 BERT 模型。然后,我们需要将 pkuseg 的数据转换成 BERT 的输入格式,即 tokenization 和 padding。接着,我们可以将这些数据输入到已经加载好的 BERT 模型中,并微调一些特定的层,使其适应我们的任务。最后,我们可以使用训练好的模型进行分词。 具体步骤如下: 1. 加载预训练的 BERT 模型 ```python from transformers import BertModel, BertTokenizer bert_model = BertModel.from_pretrained('bert-base-chinese') tokenizer = BertTokenizer.from_pretrained('bert-base-chinese') ``` 2. 加载 pkuseg 数据集并转换为 BERT 的输入格式 ```python from pkuseg import pkuseg seg = pkuseg() text = '我爱自然语言处理' tokens = tokenizer.tokenize(text) # 将 pkuseg 分词后的结果转换为 BERT 的输入格式 input_ids = tokenizer.convert_tokens_to_ids(tokens) input_ids = tokenizer.build_inputs_with_special_tokens(input_ids) segment_ids = [0] * len(input_ids) input_mask = [1] * len(input_ids) # padding max_length = 128 padding_length = max_length - len(input_ids) if padding_length > 0: input_ids += [0] * padding_length segment_ids += [0] * padding_length input_mask += [0] * padding_length else: input_ids = input_ids[:max_length] segment_ids = segment_ids[:max_length] input_mask = input_mask[:max_length] # 转换为 PyTorch Tensor input_ids = torch.tensor([input_ids]) segment_ids = torch.tensor([segment_ids]) input_mask = torch.tensor([input_mask]) ``` 3. 微调 pkuseg 模型 ```python import torch.nn as nn import torch.optim as optim class PkusegModel(nn.Module): def __init__(self, bert_model): super().__init__() self.bert = bert_model self.fc = nn.Linear(768, 4) # 分类数为4 def forward(self, input_ids, segment_ids, input_mask): _, pooled_output = self.bert(input_ids, token_type_ids=segment_ids, attention_mask=input_mask) output = self.fc(pooled_output) return output model = PkusegModel(bert_model) criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=0.0001) # 训练模型 for epoch in range(10): running_loss = 0.0 for inputs, labels in dataloader: optimizer.zero_grad() outputs = model(*inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() print('Epoch: %d, Loss: %.4f' % (epoch+1, running_loss/len(dataloader))) ``` 4. 使用训练好的模型进行分词 ```python def pkuseg_tokenize(text): tokens = tokenizer.tokenize(text) input_ids = tokenizer.convert_tokens_to_ids(tokens) input_ids = tokenizer.build_inputs_with_special_tokens(input_ids) segment_ids = [0] * len(input_ids) input_mask = [1] * len(input_ids) input_ids = torch.tensor([input_ids]) segment_ids = torch.tensor([segment_ids]) input_mask = torch.tensor([input_mask]) with torch.no_grad(): outputs = model(input_ids, segment_ids, input_mask) _, predicted = torch.max(outputs.data, 1) predicted = predicted.cpu().numpy().tolist() labels = [tokenizer.convert_ids_to_tokens([i])[0] for i in predicted] words = [] for i in range(len(tokens)): if labels[i].startswith('B'): words.append(tokens[i]) elif labels[i].startswith('I'): words[-1] += tokens[i][2:] else: words.append(tokens[i]) return words text = '我爱自然语言处理' words = pkuseg_tokenize(text) print(words) ``` 以上就是使用 PyTorch 微调 pkuseg 模型的基本原理和步骤。 ### 回答2: PyTorch是一个开源的机器学习框架,可以用于搭建、训练和调优深度学习模型。而pkuseg是一个基于深度学习的中文分词工具,它能够将一段中文文本进行分词处理。使用PyTorch微调pkuseg模型的原理如下: 1. 准备数据集:为了微调pkuseg模型,首先需要准备一个包含大量中文文本的数据集。这个数据集应该包含已经正确切分好的分词结果。 2. 加载模型:使用PyTorch加载pkuseg的预训练模型。这个预训练模型是在大规模的中文语料库上进行训练得到的,可以实现良好的中文分词效果。 3. 冻结参数:为了避免已经训练好的权重被破坏,我们需要冻结模型中的一些参数,例如卷积层的权重。冻结这些参数后,我们只对一部分需要微调的层进行训练。 4. 定义微调层:在pkuseg模型中,我们可以选择微调一些层,例如最后几个全连接层。这些层的参数可以通过训练进行调优,以适应特定的分词任务。 5. 更新梯度:使用已准备好的数据集,通过反向传播算法更新微调层的权重。根据模型的输出和标签数据之间的差距,调整权重来最小化损失函数。 6. 评估性能:在微调过程中,使用一部分数据作为验证集,用于评估模型的性能。可以使用一些指标,如Precision、Recall和F1-score来衡量模型的分词效果。 7. 迭代微调:如果模型的性能不够理想,可以多次迭代进行微调,使用不同的参数组合和数据子集。通过反复迭代的方式,逐渐提高模型在特定分词任务上的性能。 通过以上步骤,我们可以使用PyTorch对pkuseg模型进行微调,使其适应特定的中文分词任务,提高分词的准确性和性能。 ### 回答3: 使用PyTorch微调pkuseg模型的原理如下: 首先,pkuseg是一个基于深度学习的中文分词工具,采用了LSTM-CRF模型微调是指在已经训练好的模型基础上,通过修改部分参数或者加入新的数据集来进行再训练,以提高模型性能。 在进行微调pkuseg模型时,首先需要加载预训练的模型参数。这可以通过使用PyTorch提供的模型加载函数进行实现。加载模型参数后,可以固定部分参数,如LSTM层的参数,以防止它们在微调过程中被修改。 接下来,我们可以选择一些新的数据集来进行微调。这些数据集通常是与原始数据集相似或相关的,例如来自相同领域或主题的数据。通过将新数据集与原始数据集进行合并,可以扩大训练数据规模,有助于提高模型的泛化能力。 在微调过程中,可以使用PyTorch提供的优化器,如随机梯度下降(SGD),来更新模型的参数。可以通过设定不同的学习率、权重衰减等来调整优化器的参数,以达到更好的微调效果。 微调过程中,需要选择合适的损失函数来度量模型的训练误差,通常选择交叉熵损失函数。在每个训练迭代中,通过计算损失函数的梯度,更新模型中可训练参数的数值,以降低损失函数的值。 微调过程需要进行多个训练迭代,直到达到预定的停止条件为止。在每个迭代中,可以通过计算模型在验证集上的性能指标,如准确率、召回率等,来评估模型的表现,并根据评估结果进行调整。 最后,可以保存微调后的模型参数,以备后续使用。这些模型参数可以用于分词任务,通过对输入文本进行切分,得到分词结果。 综上所述,使用PyTorch微调pkuseg模型的原理就是加载预训练模型参数,固定部分参数,选择合适的损失函数和优化器,通过迭代更新模型参数,评估模型性能,并保存微调后的模型参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值