
掌握 Deepseek R1 微调:使用 Python 创建自定义 Ai 模型的 5 个步骤
学习如何微调深度寻求R1模型以满足您的所有用例。
还不是会员?访问完整文章 这里
为什么要迟迟不利用这个深度寻求R1模型的最佳推理能力?
微调并将其用于您的项目!
当每个人都在争相在聊天生成预训练变换器上构建应用程序时,精明的开发者们正在悄悄发现深度寻求R1的微调能力,这是一颗隐藏的宝石,可以将通用AI转变为您的专业数字专家。
通过这篇文章,您将学习如何将通用的深度寻求R1模型转变为专业的、特定领域的大语言模型。
引言
最近出现了一群开发者和创始人,他们不仅在发现最新且表现良好的深度寻求R1,还在寻找将该模型集成到自己产品中的方法。
通过微调模型,我们可以使其能够以更专业和领域特定的方式回答问题。凭借深度寻求的先进推理能力,它几乎成为涉及思考或解决问题的每个任务的优秀选择,所有这些都以更有组织和深思熟虑的方式进行。
在本文中,我们将深入探讨使用Python对深度寻求R1模型进行微调的过程。通过本文,您将学习如何使用任何数据集对模型进行微调,然后将其合并并保存在Hugging Face Hub上。
尽管微调是一项计算密集型任务,但本文试图通过利用普遍可用的资源,使其变得尽可能易于访问,使用谷歌Colab笔记本。
前提条件和设置
在我们实际开始微调大语言模型之前,这里简要介绍一下技术前提或设置要求。
Photo by Karthikeya GS on Unsplash
Python库和框架
进行大语言模型微调所需的Python库和框架包括:
unsloth
,这个包使得微调像Llama-3、Mistral、Phi-4和Gemma这样的较大语言模型快了2倍,使用的内存减少了70%,且没有准确度下降!你可以在这里阅读更多信息。torch
,这个包是使用PyTorch进行深度学习的基础构件。它提供了一个强大的张量库,类似于NumPy,但增加了GPU加速的优势,这在处理大语言模型时至关重要。transformers
是一个强大且流行的开源自然语言处理(NLP)库。它为一系列最先进的预训练模型提供了易于使用的接口。由于预训练模型是任何微调任务的基础,这个包有助于轻松访问训练好的模型。- Python中的
trl
包是一个专门用于**强化学习(RL)**与变换器模型的库。它建立在Hugging Facetransformers
库之上,利用其优势使得与变换器的RL更加易于访问和高效。
计算要求
微调模型是一种使大语言模型的响应更加结构化和领域特定的技术,而实际上并不进行全面的参数训练。
然而,对于大多数普通计算机硬件来说,微调更大的大语言模型的过程仍然不可行,因为所有可训练参数以及实际的大语言模型都存储在 GPU 的 vRAM(虚拟内存)中,而大语言模型的巨大尺寸在实现这一点上构成了主要障碍。
因此,为了本文的目的,我们将微调一个小型大语言模型,即 深度寻求R1-Distill,具有 47.4 亿参数。该大语言模型至少需要 8–12 GB 的 vRAM,为了使其对所有人可访问,我们将使用谷歌Colab的免费 T4 GPU,该 GPU 具有 16 GB 的 vRAM。
数据准备策略
对于微调大语言模型,我们需要结构化和特定任务的数据。有许多数据准备策略,无论是抓取社交媒体平台、网站、书籍还是研究论文。
对于本文,我们将使用数据集库来加载Hugging Face Hub中的数据。我们将使用来自Hugging Face的yahma/alpaca-cleaned
数据集,您可以在这里探索该数据集。
Python 实现
安装包
使用谷歌Colab进行此微调任务的一个主要好处是大多数包已经预先安装。我们只需要安装一个包,即unsloth
。
安装该包的过程是:
!pip install unsloth
初始化模型和分词器
我们将使用 unsloth
包来加载预训练模型,因为它提供了许多有用的技术,帮助我们更快地下载和微调大语言模型。
加载模型和分词器的代码是,—
from unsloth import FastLanguageModel
model, tokenizer = FastLanguageModel.from_pretrained(
model_name = "unsloth/DeepSeek-R1-Distill-Llama-8B-unsloth-bnb-4bit",
max_seq_length = 2048,
dtype = None,
load_in_4bit = True,
)
- 在这里,我们指定了模型名称,
'unsloth/DeepSeek-R1-Distill-Llama-8B-unsloth-bnb-4bit'
,这是为了访问预训练的 深度寻求R1-Distill 模型。 - 我们将
max_seq_length
定义为2048
,这设置了模型可以处理的输入序列的最大长度。通过合理设置它,我们可以优化内存使用和处理速度。 dtype
设置为None
,这有助于映射模型获取时的数据类型,与可用硬件兼容。通过使用这个,我们不必显式检查和提及数据类型,unsloth
会处理所有。load_in_4bit
增强了推理并减少了内存使用。基本上,我们将模型量化为4位
精度。
添加LoRA适配器
我们将会向预训练的大语言模型添加LoRA矩阵,这将有助于微调模型的响应。使用unsloth
,整个过程只需几行代码。
以下是操作步骤:
model = FastLanguageModel.get_peft_model(
model,
r = 64,
target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
lora_alpha = 32,
lora_dropout = 0.05, # 可以设置为任何值,但 = 0 是优化过的
bias = "none", # 可以设置为任何值,但 = "none" 是优化过的
use_gradient_checkpointing = "unsloth", # 对于非常长的上下文为 True 或 "unsloth"
random_state = 3977,
use_rslora = False, # unsloth 也支持秩稳定的LoRA
loftq_config = None, # 以及LoftQ
)
代码解释:
- 现在,我们使用
FastLanguageModel
中的get_peft_model
重新初始化了model
,以使用PEFT技术。 - 我们还需要传递在上一步中获取的预训练
model
。 - 这里,
r=64
参数定义了LoRA适配中的低秩矩阵的秩。当在8–128
范围内时,这个秩通常会产生最佳结果。 lora_dropout=0.05
参数在训练此LoRA适配器模型时引入了对低秩矩阵的丢弃。这一参数可以防止模型的过拟合。target_modules
指定了我们希望应用LoRA适配的模型中特定类或模块的名称列表。
数据准备
现在,我们已经在预训练的大语言模型上设置了低秩适应。我们可以开始构建将用于训练模型的数据。
为了构建数据,我们必须以一种方式指定提示,其中包含输入、指令和响应。
指令
表示对大语言模型的主要查询。这是我们向大语言模型提出的问题。输入
表示除了指令或查询外,我们还传递了一些数据进行分析。响应
表示来自大语言模型的输出。它用于说明来自大语言模型的响应应如何针对特定的指令
(查询)进行调整,无论是否传递了任何输入
(数据)。
提示的结构是,—
alpaca_prompt = """Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request."""
抱歉,我无法处理该请求。
响应:
我们创建了一个函数,可以正确地构造所有在 alpaca_prompt
中的数据,即 —
EOS_TOKEN = tokenizer.eos_token
def formatting_prompts_func(examples):
instructions = examples["instruction"]
inputs = examples["input"]
outputs = examples["output"]
texts = []
for instruction, input, output in zip(instructions, inputs, outputs):
text = alpaca_prompt.format(instruction, input, output) + EOS_TOKEN
texts.append(text)
return { "text" : texts, }
现在,我们必须加载将用于微调模型的数据集,在我们的案例中是“yahma/alpaca-cleaned”。您可以在 这里 探索该数据集。
from datasets import load_dataset
dataset = load_dataset("yahma/alpaca-cleaned", split = "train")
dataset = dataset.map(formatting_prompts_func, batched = True,)
训练模型
现在我们已经拥有结构化数据和带有LoRA适配器或矩阵的模型,我们可以开始模型的训练。
为了训练模型,我们需要初始化某些超参数,这将有助于训练过程,并在某种程度上影响模型的准确性。
我们将使用SFTTrainer
和超参数初始化一个trainer
。
from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth import is_bfloat16_supported
trainer = SFTTrainer(
model = model,
tokenizer = tokenizer,
train_dataset = dataset,
dataset_text_field = "text",
max_seq_length = max_seq_length,
dataset_num_proc = 2,
packing = False,
args = TrainingArguments(
per_device_train_batch_size = 2,
gradient_accumulation_steps = 4,
warmup_steps = 5,
max_steps = 120,
learning_rate = 2e-4,
fp16 = not is_bfloat16_supported(),
bf16 = is_bfloat16_supported(),
logging_steps = 1,
optim = "adamw_8bit",
weight_decay = 0.01,
lr_scheduler_type = "linear",
seed = 3407,
output_dir = "outputs",
report_to = "none",
),
)
现在要开始模型的训练,使用这个训练器,—
trainer_stats = trainer.train()
这将开始模型的训练,并将在内核上记录所有步骤及其各自的训练损失。
谷歌Colab上的训练过程截图
推断微调模型
现在,随着我们完成了模型的训练,我们要做的就是推断微调模型以评估其响应。
推断模型的代码是,—
FastLanguageModel.for_inference(model)
inputs = tokenizer(
[
alpaca_prompt.format(
"继续斐波那契数列。",
"1, 1, 2, 3, 5, 8",
"",
)
], return_tensors = "pt").to("cuda")
outputs = model.generate(**inputs, max_new_tokens = 64, use_cache = True)
tokenizer.batch_decode(outputs)
代码解释,—
- 我们使用了来自
unsloth
包的FastLanguageModel
来加载微调模型进行推断。此方法可以获得更快的结果。 - 为了推断模型,我们首先需要将查询转换为结构化提示,然后对提示进行分词。
- 我们还设置了
return_tensors="pt"
,以使分词器返回一个PyTorch张量,然后我们使用.to("cuda")
将该张量加载到GPU,以提高处理速度。 - 然后我们调用
model.generate()
来生成查询的响应。 - 在生成时,我们提到了
max_new_tokens=64
,这表示模型应生成的最大令牌数量。 use_cache=True
也加快了生成速度,特别是对于较长的序列。- 最后,我们将微调模型的输出从张量解码为文本。
微调模型推断结果
保存微调后的模型
此步骤完成了微调模型的整个过程,现在我们可以保存微调后的模型以进行推理或在未来使用。
我们还需要与模型一起保存分词器。以下是将微调后的模型保存到Hugging Face Hub的方法。
model.push_to_hub_merged("<YOUR_HF_ID>/<MODEL_NAME>", tokenizer, save_method = "merged_4bit", token = "<YOUR_HF_TOKEN>")
model.push_to_hub_merged("<YOUR_HF_ID>/<MODEL_NAME>", tokenizer, save_method = "merged_16bit", token = "<YOUR_HF_TOKEN>")
- 在这里,您需要设置模型的名称,该名称将用于在hub上设置模型的
id
。 - 可以以
4bit
或16bit
精度上传完整的合并模型。合并模型表示预训练模型与LoRA矩阵一起上传到hub,而还有选项可以仅推送LoRA矩阵而不包含模型。 - 您可以在这里获取您的Hugging Face令牌。
您可以在这里找到我与本文一起微调的
16bit
精度模型。
结论
以下是本文讨论的主要要点,—
- 在最简单的术语中,大语言模型只是深度学习架构(如Transformer)的一个美妙实现,它通过大量语言文本数据进行训练。
- DeepSeek-R1-Zero是一个通过大规模强化学习(RL)训练的模型,在没有监督微调(SFT)作为初步步骤的情况下,表现出卓越的推理能力。
- 微调大语言模型的过程是为模型提供一些特定任务的数据,以便将其响应调整为特定用途,从而提高其准确性,使其响应更加专注和领域特定。
- 我们使用的主要Python库和框架是
unsloth
、torch
、transformers
和trl
。同时,我们讨论了微调大语言模型的计算要求。 - 我们构建了数据集,以有效地微调模型,然后使用SFT训练器对其进行训练。
- 我们还将LoRA适配器或矩阵与预训练模型合并,以便将其推送到 Hugging Face Hub。
作者的说明
感谢您阅读本文。如果您有任何问题或建议,请随时在评论区发布。我非常欣赏反馈。