重生之我在2024学Fine-tuning

一、Fine-tuning(微调)概述

        Fine-tuning(微调)是机器学习和深度学习中的一个重要概念,特别是在预训练模型的应用上。它指的是在模型已经通过大量数据训练得到一个通用的预训练模型后,再针对特定的任务或数据集进行进一步训练的过程。

        以下是Fine-tuning的一些关键点:

  1. 预训练模型:在Fine-tuning之前,模型已经在大规模的数据集上进行了训练,学习到了通用的特征和模式。例如,在自然语言处理(NLP)中,BERT(Bidirectional Encoder Representations from Transformers)就是一个预训练模型,它在大量的文本数据上训练,以理解语言的通用结构和语义。

  2. 特定任务:Fine-tuning通常是为了解决一个具体的任务,比如情感分析、问答系统、文本分类等。这些任务可能需要模型对特定类型的数据有更深入的理解。

  3. 数据集与调整参数:Fine-tuning需要一个针对特定任务的数据集,这个数据集可能远小于预训练时使用的数据集,但更专注于任务相关的数据。在Fine-tuning过程中,模型的大部分参数(通常是预训练模型的底层参数)会被保留,只有一小部分参数(如顶层的分类器)会被调整以适应新的任务。

  4. 训练过程与资源效率:Fine-tuning的过程通常比从头开始训练一个模型要快,因为模型已经学习了很多通用的知识,只需要对特定任务进行微调。Fine-tuning是一种资源效率较高的方法,因为它不需要从头开始训练一个大型模型,这样可以节省大量的计算资源和时间。

  5. 迁移学习与过拟合:Fine-tuning是迁移学习的一种形式,即将在一个领域学到的知识应用到另一个领域。由于Fine-tuning使用的数据集通常较小,所以存在过拟合的风险,即模型可能过于适应训练数据,而无法很好地泛化到未见过的数据。

        Fine-tuning是一种强大的技术,它使得模型能够快速适应新任务,同时利用预训练模型的强大能力。

二、大模型微调的底层原理

1.预训练与迁移学习

        大模型微调的基础是预训练模型,这些模型已经在大规模数据集上进行了训练,学习到了通用的特征和模式。微调过程实际上是迁移学习的一种应用,它将预训练模型的知识迁移到新的任务上。在这个过程中,模型的大部分参数(通常是底层参数)被保留,只有一小部分参数(如顶层的分类器或输出层)被调整以适应新任务。这种策略可以减少过拟合的风险,同时利用预训练模型在底层学到的通用特征。

2.参数更新与适应性调整

        在微调过程中,模型的参数更新策略是关键。通常,只有模型的顶层或部分层会被更新,而底层的参数保持不变。这种策略允许模型在保持其在预训练阶段学到的通用知识的同时,对特定任务进行适应性调整。通过这种方式,模型可以快速适应新任务,而无需从头开始训练,这大大减少了计算资源的需求。此外,微调过程中可能会调整学习率和其他超参数,以优化模型在新任务上的学习效率和性能。

3.低秩适应与参数效率

        为了进一步提高微调的参数效率,一些技术如LoRA(Low-Rank Adaptation)被提出。LoRA通过在模型的特定层引入低秩矩阵来模拟参数的改变量,从而以极小的参数量实现大模型的间接训练。这种方法假设预训练模型的权重变化可以通过低秩矩阵来近似,这意味着相对于直接微调所有模型参数,通过低秩矩阵的调整,可以用更少的参数达到近似效果。这种技术显著减少了微调过程中需要更新的参数数量,降低了计算成本,同时仍然能够使模型适应新任务。

三、常用的Fine-tuning方法

1.全量微调(Full Fine-tuning)

        这种方法涉及利用特定任务数据调整预训练模型的所有参数,以充分适应新任务。这种方法依赖大规模计算资源,但能有效利用预训练模型的通用特征,通常能够获得较好的性能提升。以下是一个使用PyTorch和Hugging Face的Transformers库进行全量微调的示例代码。这个例子中,我们将使用一个预训练的BERT模型来微调一个文本分类任务。

import torch
from torch.utils.data import DataLoader, RandomSampler, SequentialSampler
from transformers import BertTokenizer, BertForSequenceClassification, AdamW, get_linear_schedule_with_warmup
from sklearn.metrics import accuracy_score# 检查是否有可用的GPU,如果有则使用GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 加载预训练的BERT模型和分词器
model_name = 'bert-base-uncased'
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertForSequenceClassification.from_pretrained(model_name)# 将模型移动到GPU上(如果可用)
model.to(device)# 假设我们有一些数据集,这里我们使用随机数据作为示例
# 你需要替换这些数据为你的实际数据集
train_data = [{'text': "I love using BERT for text classification.", 'label': 1},{'text': "BERT is not useful for my task.", 'label': 0},# ... 更多数据 ...
]# 将文本数据编码为模型可以理解的格式
input_ids = []
attention_masks = []
labels = []for data in train_data:encoded = tokenizer.encode_plus(data['text'],add_special_tokens=True,max_length=64,return_attention_mask=True,return_tensors='pt',)input_ids.append(encoded['input_ids'])attention_masks.append(encoded['attention_mask'])labels.append(data['label'])# 将数据转换为PyTorch张量
input_ids = torch.cat(input_ids, dim=0)
attention_masks = torch.cat(attention_masks, dim=0)
labels = torch.tensor(labels)# 创建DataLoader
train_data = torch.utils.data.TensorDataset(input_ids, attention_masks, labels)
train_sampler = RandomSampler(train_data)
train_dataloader = DataLoader(train_data, sampler=train_sampler, batch_size=8)# 设置优化器和学习率调度器
optimizer = AdamW(model.parameters(), lr=2e-5, eps=1e-8)
total_steps = len(train_dataloader) * 3  # 假设我们训练3个epoch
scheduler = get_linear_schedule_with_warmup(optimizer,num_warmup_steps=0,num_training_steps=total_steps
)# 训练模型
model.train()
for epoch in range(3):  # 训练3个epochfor batch in train_dataloader:batch = tuple(t.to(device) for t in batch)inputs = {'input_ids': batch[0],'attention_mask': batch[1],'labels': batch[2]}optimizer.zero_grad()outputs = model(**inputs)loss = outputs.lossloss.backward()optimizer.step()scheduler.step()# 评估模型(这里需要一个真实的测试集)
# 这里省略了评估代码,你需要根据你的数据集来实现评估逻辑# 保存模型
model.save_pretrained('./my_fine_tuned_bert_model')

请注意,这个代码是一个简化的示例,实际应用中你需要准备一个真实的数据集,并可能需要添加更多的训练逻辑,比如模型评估、早停(early stopping)、保存最佳模型等。此外,你还需要确保数据集的格式与模型输入的要求相匹配。

2.参数高效微调(Parameter-Efficient Fine-Tuning, PEFT)

这种技术旨在通过最小化微调参数的数量和计算复杂度,实现高效的迁移学习。它仅更新模型中的部分参数,显著降低训练时间和成本,适用于计算资源有限的情况。PEFT技术包括:

2.1 前缀调优(Prefix-tuning)

在输入前添加可学习的virtual tokens作为Prefix,仅更新Prefix参数,Transformer其他部分固定。

from transformers import AutoModelForCausalLM
from peft import PeftModel, PeftConfig# 加载预训练模型
model_name_or_path = "bert-base-uncased"
model = AutoModelForCausalLM.from_pretrained(model_name_or_path)# 创建PeftConfig配置
peft_config = PeftConfig.from_pretrained(model_name_or_path)# 应用前缀调优
peft_model = PeftModel.from_pretrained(model, peft_config, torch_dtype=torch.float16)# 打印可训练参数数量
peft_model.print_trainable_parameters()

这段代码首先加载了一个预训练的BERT模型,然后创建了一个PeftConfig配置,最后应用前缀调优并打印出可训练的参数数量。

2.2 提示调优(Prompt-tuning)

在输入层加入prompt tokens,简化版的Prefix Tuning,无需MLP调整。随着模型规模增大,效果接近full fine-tuning。

from transformers import AutoModelForCausalLM, AutoTokenizer# 加载预训练模型和分词器
model_name_or_path = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
model = AutoModelForCausalLM.from_pretrained(model_name_or_path)# 添加prompt tokens
prompt = tokenizer(["explain", "the", "concept", "of"], return_tensors="pt")
input_ids = torch.cat([prompt["input_ids"], torch.randint(0, 100, (1, 10))])  # 添加随机tokens# 将输入传递给模型
outputs = model(input_ids)

这段代码加载了一个预训练的BERT模型和分词器,然后添加了prompt tokens到输入中,并传递给模型。

2.3 Adapter调优(Adapter Tuning)

设计Adapter结构并嵌入Transformer中,仅对新增的Adapter结构进行微调,原模型参数固定。

from transformers import AutoModelForSequenceClassification, AdapterConfig# 加载预训练模型
model_name_or_path = "bert-base-uncased"
model = AutoModelForSequenceClassification.from_pretrained(model_name_or_path)# 创建AdapterConfig配置
adapter_config = AdapterConfig(r=1, lora_alpha=32, lora_dropout=0.1)# 应用Adapter调优
model.add_adapter(name="task_specific", config=adapter_config)# 打印可训练参数数量
model.print_trainable_parameters()

这段代码加载了一个预训练的BERT模型,创建了一个AdapterConfig配置,并应用Adapter调优。最后打印出可训练的参数数量。

3.冻结部分层进行微调

在Fine-tuning过程中,通常会冻结预训练模型中较低层级(靠近输入端)的参数不变,仅对较高层级(靠近输出端)的参数进行训练。这是因为底层特征通常更具通用性,而高层特征与特定任务关联更紧密。以下是一个使用PyTorch和Hugging Face的Transformers库进行这种微调策略的示例代码。这个例子中,我们将使用一个预训练的BERT模型来微调一个文本分类任务。

import torch
from torch.utils.data import DataLoader, Dataset
from transformers import BertTokenizer, BertForSequenceClassification, AdamW# 检查是否有可用的GPU,如果有则使用GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")# 加载预训练的BERT模型和分词器
model_name = 'bert-base-uncased'
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertForSequenceClassification.from_pretrained(model_name)# 将模型移动到GPU上(如果可用)
model.to(device)# 冻结预训练模型的底层参数
for param in model.bert.parameters():param.requires_grad = False# 仅对分类器头部的参数进行训练
for param in model.classifier.parameters():param.requires_grad = True# 假设我们有一些数据集,这里我们使用随机数据作为示例
# 你需要替换这些数据为你的实际数据集
class SimpleDataset(Dataset):def __init__(self, texts, labels):self.texts = textsself.labels = labelsdef __len__(self):return len(self.texts)def __getitem__(self, idx):text = self.texts[idx]label = self.labels[idx]encoding = tokenizer.encode_plus(text,add_special_tokens=True,max_length=64,return_attention_mask=True,return_tensors='pt',padding='max_length',truncation=True,)return {'input_ids': encoding['input_ids'].flatten(),'attention_mask': encoding['attention_mask'].flatten(),'labels': torch.tensor(label, dtype=torch.long)}# 创建数据集和数据加载器
texts = ["I love using BERT for text classification.", "BERT is not useful for my task."]
labels = [1, 0]  # 假设1是正面,0是负面
dataset = SimpleDataset(texts, labels)
dataloader = DataLoader(dataset, batch_size=2)# 设置优化器
optimizer = AdamW(model.classifier.parameters(), lr=5e-5)# 训练模型
model.train()
for epoch in range(3):  # 训练3个epochfor batch in dataloader:batch = {k: v.to(device) for k, v in batch.items()}inputs = {'input_ids': batch['input_ids'],'attention_mask': batch['attention_mask'],'labels': batch['labels']}optimizer.zero_grad()outputs = model(**inputs)loss = outputs.lossloss.backward()optimizer.step()# 保存模型
model.save_pretrained('./my_fine_tuned_bert_model')

在这个示例中,我们首先加载了一个预训练的BERT模型,并将其移动到GPU上(如果可用)。然后,我们冻结了BERT模型的底层参数,只允许分类器头部的参数进行训练。我们创建了一个简单的数据集和数据加载器,并设置了优化器。在训练过程中,我们只更新分类器头部的参数。最后,我们保存了微调后的模型。

4.微调全部层

虽然风险略高,但有时也会选择对整个预训练模型的所有参数进行微调。这在目标任务与预训练任务高度相关、数据量充足且计算资源允许的情况下较为有效。以下是一个示例代码,展示了如何在目标任务与预训练任务高度相关、数据量充足且计算资源允许的情况下,对整个预训练模型的所有参数进行微调。

from transformers import BertForSequenceClassification, BertTokenizer, Trainer, TrainingArguments
import torch# 选择预训练模型
model_name = "bert-base-uncased"# 加载预训练模型和分词器
tokenizer = BertTokenizer.from_pretrained(model_name)
model = BertForSequenceClassification.from_pretrained(model_name, num_labels=2)# 准备训练和验证数据集
# 这里假设已经有了train_dataset和eval_dataset
# train_dataset = ...
# eval_dataset = ...# 设置训练参数
training_args = TrainingArguments(output_dir="./results",per_device_train_batch_size=16,per_device_eval_batch_size=64,num_train_epochs=3,evaluation_strategy="epoch",learning_rate=2e-5,save_total_limit=2,save_steps=500,load_best_model_at_end=True,  # 保存最佳模型metric_for_best_model="accuracy",  # 根据准确率选择最佳模型greater_is_better=True,push_to_hub=False,
)# 初始化Trainer
trainer = Trainer(model=model,args=training_args,train_dataset=train_dataset,eval_dataset=eval_dataset,tokenizer=tokenizer,
)# 开始训练
trainer.train()# 评估模型性能
results = trainer.evaluate()
print(results)

        这个示例展示了如何对整个预训练模型进行全量微调,适用于目标任务与预训练任务高度相关且计算资源允许的情况。通过这种方式,模型可以充分利用预训练阶段学到的知识,并针对新任务进行优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/905101.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络 4-2-1 网络层(IPv4)

2 IPv4分组 各协议之间的关系 IP协议(Internet Protocol, 网际协议)是互联网的核心&#xff01; ARP协议用于查询同一网络中的<主机IP地址&#xff0c;MAC地址>之间的映射关系 ICMP协议用于网络层实体之间相互通知“异常事件” IGMP协议用于实现IP组播 2.1 结构<首…

Docker中运行的Chrome崩溃问题解决

问题 各位看官是否在 Docker 容器中的 Linux 桌面环境&#xff08;如Xfce&#xff09;上启动Chrome &#xff0c;遇到了令人沮丧的频繁崩溃问题&#xff1f;尤其是在打开包含图片、视频的网页&#xff0c;或者进行一些稍复杂的操作时&#xff0c;窗口突然消失&#xff1f;如果…

K8S cgroups详解

以下是 Kubernetes 中 cgroups&#xff08;Control Groups&#xff09; 的详细解析&#xff0c;涵盖其核心原理、在 Kubernetes 中的具体应用及实践操作&#xff1a; 一、cgroups 基础概念 1. 是什么&#xff1f; cgroups 是 Linux 内核提供的 资源隔离与控制机制&#xff0c…

javaer快速从idea转战vscode

插件安装列表 在插市场安装下面插件 Extension Pack for JavaSpring Boot Tools 配置文件提示Database Client Database/No-SQL管理工具httpYac - Rest Client .http文件编辑、API测试工具 https://httpyac.github.io/guide/request.htmlGit Graph 图形化Git工具XML by Red H…

[项目总结] 抽奖系统项目技术应用总结

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

【赵渝强老师】TiDB SQL层的工作机制

TiDB节点的SQL层&#xff0c;即TiDB Server&#xff0c;它负责将SQL翻译成Key-Value操作&#xff0c;将其转发给共用的分布式Key-Value存储层TiKV&#xff0c;然后组装TiKV返回的结果&#xff0c;最终将查询结果返回给客户端。这一层的节点都是无状态的&#xff0c;节点本身并不…

性能远超SAM系模型,苏黎世大学等开发通用3D血管分割基础模型

如果把人的身体比作一座庞大的城市&#xff0c;那么血管无疑就是这座城市的「道路」&#xff0c;动脉、静脉以及毛细血管对应着高速公路、城市道路以及乡间小道&#xff0c;它们相互协作&#xff0c;通过血液将营养物质、氧气等输送到身体各处&#xff0c;从而维持着这座「城市…

git高效杀器——cz-customizable 搭配 commitlint

What is cz-customizable and commitlint? cz-customizable 一款可定制化的Commitizen插件(也可作为独立工具),旨在帮助创建如约定式提交规范的一致性提交消息。commitlint commitlint 是一个用于检查 Git 提交信息的工具,它可以帮助开发者保持提交信息的规范性和一致性。…

Spark 中RDD、Job,stage,task的关系

目录 1. 概念定义1.1 Job1.2 Stage1.3 Task 2. 关系总结3. 示例分析代码示例执行过程 4. Spark中的运行流程5. 关键点5.1 宽依赖和窄依赖5.2 并行度5.3 性能优化 **6. 总结****1. RDD的核心作用****1.1 什么是RDD&#xff1f;****1.2 RDD与Job、Stage、Task的关系** **2. Job、…

Kubernetes基础(三十二):Worker节点启动全解析

Worker节点是Kubernetes集群的"肌肉"&#xff0c;负责实际运行业务负载。本文将深入剖析Worker节点的完整启动流程&#xff0c;并揭秘生产环境中的关键优化点。 一、启动流程全景图 二、核心启动阶段详解 1. 系统初始化&#xff08;0-30秒&#xff09; 关键任务&a…

matlab实现模型预测控制

考虑扩展状态空间形式 缩写为 对于未来的预测&#xff0c;这里要注意&#xff0c;默认了最小预测时域为1&#xff0c;如果不为1&#xff0c;从k1到k最小预测时域的x的预测为0 模型预测控制matlab运行代码&#xff0c;可实现模型预测控制。 StateMPC是按照钱积新版《预测控制》…

Python_day22

DAY 22 复习日 复习日 仔细回顾一下之前21天的内容&#xff0c;没跟上进度的同学补一下进度。 作业&#xff1a; 自行学习参考如何使用kaggle平台&#xff0c;写下使用注意点&#xff0c;并对下述比赛提交代码 kaggle泰坦里克号人员生还预测 一、Kaggle 基础使用步骤 注册与登录…

【软件测试】基于项目驱动的功能测试报告(持续更新)

目录 一、项目的介绍 1.1 项目背景 二、测试目标 2.1 用户服务模块 2.1.1 用户注册模块 2.1.1.1 测试点 2.1.1.2 边界值分析法(等价类+边界值) 2.1.1.2.1 有效等价类 2.1.1.2.2 无效等价类 2.1.1.2.3 边界值 2.1.1.2.4 测试用例设计 2.1.2 用户登录 2.1.2.1 测试…

QT中多线程的实现

采用官方推荐的 QObject::moveToThread 方式实现&#xff08;相比继承 QThread 更灵活&#xff09;&#xff0c;包含耗时任务执行、主线程通信、线程安全退出等核心功能。 环境说明 Qt 版本&#xff1a;Qt 5.15 或 Qt 6&#xff08;兼容&#xff09;项目类型&#xff1a;GUI …

从知识图谱到精准决策:基于MCP的招投标货物比对溯源系统实践

前言 从最初对人工智能的懵懂认知&#xff0c;到逐渐踏入Prompt工程的世界&#xff0c;我们一路探索&#xff0c;从私有化部署的实际场景&#xff0c;到对DeepSeek技术的全面解读&#xff0c;再逐步深入到NL2SQL、知识图谱构建、RAG知识库设计&#xff0c;以及ChatBI这些高阶应…

maven如何搭建自己的私服(LINUX版)?

环境准备 安装 JDK &#xff1a;确保系统已安装 JDK 8 或更高版本。可以通过以下命令安装 JDK&#xff1a; 安装 OpenJDK &#xff1a;sudo apt update && sudo apt install openjdk-11-jdk 安装 Oracle JDK &#xff1a;需要添加第三方仓库&#xff0c;例如 WebUpd8 …

armv7 backtrace

ref&#xff1a; ARM Cortex-M3/M4/M7 Hardfault异常分析_arm hardfault-CSDN博客

探索 C++23 的 views::cartesian_product

文章目录 一、背景与动机二、基本概念与语法三、使用示例四、特点与优势五、性能与优化六、与 P2374R4 的关系七、编译器支持八、总结 C23 为我们带来了一系列令人兴奋的新特性&#xff0c;其中 views::cartesian_product 是一个非常实用且强大的功能&#xff0c;它允许我们轻…

SHAP分析!Transformer-BiLSTM组合模型SHAP分析,模型可解释不在发愁!

SHAP分析&#xff01;Transformer-BiLSTM组合模型SHAP分析&#xff0c;模型可解释不在发愁&#xff01; 目录 SHAP分析&#xff01;Transformer-BiLSTM组合模型SHAP分析&#xff0c;模型可解释不在发愁&#xff01;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 基于SH…

牛客周赛 Round 92-题解

牛客周赛 Round 92-题解 A-小红的签到题 code #include<iostream> #include<string> using namespace std; string s; int main() {int n;cin >> n;cout << "a_";for (int i 0; i < n - 2; i )cout << b;return 0; }B-小红的模…