深度学习:从零开始的DeepSeek-R1-Distill有监督微调训练实战(SFT)
原文链接:从零开始的DeepSeek微调训练实战(SFT)
微调参考示例:由unsloth官方提供https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen2.5_(7B)-Alpaca.ipynbhttps://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen2.5_(7B)-Alpaca.ipynb
本文使用modelscope社区提供的免费GPU示例进行复现。
魔搭社区汇聚各领域最先进的机器学习模型,提供模型探索体验、推理、训练、部署和应用的一站式服务。https://www.modelscope.cn/my/overview
基础概念
预训练模型 (Pre-trained Model): 预训练模型是指在大规模数据集上(如Wikipedia、书籍、网页等)进行过训练的模型。这些模型学习到了通用的语言知识和模式。你可以把它们想象成已经掌握了基本语法和常识的“学生”。常见的预训练模型有BERT、GPT、Llama、DeepSeek等。
微调 (Fine-tuning): 微调是指在预训练模型的基础上,使用特定任务的数据集继续训练模型,使其适应特定任务或领域。就像让一个已经掌握基本知识的学生,学习特定专业的知识。
为什么需要微调?: 预训练模型虽然强大,但它们是通用的。对于特定任务(如医疗问答、代码生成、情感分析等),预训练模型可能表现不佳。微调可以让模型更好地适应特定任务,提高性能。
SFT (Supervised Fine-Tuning): SFT是一种微调方法,它使用带有标签的数据集进行训练。例如,在医疗问答任务中,数据集会包含问题和对应的正确答案。模型通过学习这些问题和答案之间的关系,来提高在特定任务上的表现。
SFT vs. RLHF:
- SFT (Supervised Fine-tuning): 使用标注好的数据集进行训练。模型学习输入和输出之间的直接映射。简单高效,但依赖于高质量的标注数据。
- RLHF (Reinforcement Learning from Human Feedback): 通过人类反馈来训练模型。首先使用SFT,然后通过人类对模型输出进行打分,并使用强化学习算法来优化模型。可以更好地捕捉人类偏好,但更复杂,成本更高。
- 总结: SFT是基础,RLHF是进阶。通常先进行SFT,再根据需要进行RLHF。
高效微调 (Efficient Fine-tuning): 高效微调是指在有限的计算资源下,对大型模型进行微调的方法。例如,LoRA(Low-Rank Adaptation)只微调模型中的部分参数,从而减少计算量和内存需求。
环境准备
unsloth
-
Unsloth 是什么?
Unsloth 是一个专为大型语言模型(LLM)微调和推理设计的框架。它的主要目标是提高训练速度和降低内存消耗,让用户能够在有限的硬件资源上更高效地进行 LLM 的操作。
-
Unsloth 的主要特点
-
速度快:Unsloth 通过各种优化技术(如 Flash Attention、量化等)显著提高了 LLM 的训练和推理速度。在某些情况下,速度提升可达数倍。
-
内存占用低:Unsloth 通过优化内存使用,使得在较小显存的 GPU 上也能微调大型模型。
-
易于使用:Unsloth 提供了简洁的 API,方便用户快速上手。
-
支持多种模型:Unsloth 支持多种流行的 LLM,如 Llama、Mistral、Phi、Qwen 等。
-
-
Unsloth 的安装
-
直接使用pip命令安装即可
-
pip install unsloth pip install --force-reinstall --no-cache-dir --no-deps git+https://github.com/unslothai/unsloth.git
-
WandB (Weights & Biases) 安装
-
WandB 是什么?
WandB 是一个用于机器学习实验跟踪、可视化和协作的平台。它可以帮助你记录实验的各种指标、超参数、模型权重、数据集等,并提供交互式的可视化界面,方便你分析实验结果和比较不同实验的表现。
-
WandB 的主要特点
-
实验跟踪:记录实验的各种指标(如损失、准确率、学习率等)、超参数、代码版本、数据集等。
-
可视化:提供交互式的图表,方便你分析实验结果。
-
协作:支持多人协作,方便团队成员共享实验结果和讨论。
-
超参数优化:支持自动超参数搜索,帮助你找到最佳的超参数组合。
-
模型管理:可以保存和版本控制模型权重。
-
报告生成:可以自动生成实验报告。
-
-
WandB 的安装和注册
-
安装:使用 pip 安装 WandB:
-
pip install wandb
- 注册:
-
访问 WandB 官网(https://wandb.ai/site)并注册账号。
-
注册后,在你的个人设置页面找到 API Key,复制它。
-
WandB 在环境准备中的作用
在 SFT 环境准备中,WandB 主要用于:
-
监控训练过程:在训练过程中,WandB 会自动记录各种指标,如损失、学习率等,并提供实时更新的图表。
-
记录超参数:WandB 会记录你使用的超参数,方便你后续复现实验和比较不同超参数的效果。
-
保存模型:你可以使用 WandB 保存训练过程中的模型权重,方便后续加载和使用。
-
分析实验结果:WandB 提供了丰富的可视化工具,可以帮助你分析实验结果,找出最佳的模型和超参数。
-
-
-
模型下载
ModelScope模型地址:https://www.modelscope.cn/models/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B
创建DeepSeek-R1-Distill-Qwen-7B文件夹,用于保存下载的模型权重:
-
mkdir ./DeepSeek-R1-Distill-Qwen-7B
创建成功后,可使用如下命令下载模型:
-
modelscope download --model deepseek-ai/DeepSeek-R1-Distill-Qwen-7B --local_dir ./DeepSeek-R1-Distill-Qwen-7B
- 模型权重文件
- config.json
- 内容: 这个文件包含了模型的配置信息,它是一个 JSON 格式的文本文件。这些配置信息定义了模型的架构、层数、隐藏层大小、注意力头数等。
- 重要性: 这是模型的核心配置文件,加载模型时会读取这个文件来构建模型的结构。
{"architectures": ["Qwen2ForCausalLM" // 指定模型的架构类型为 Qwen2ForCausalLM,这是一个用于因果语言建模(生成文本)的 Qwen2 模型。],"attention_dropout": 0.0, // 在注意力机制中使用的 dropout 比率。设置为 0.0 表示不使用 dropout。Dropout 是一种正则化技术,用于防止过拟合。"bos_token_id": 151646, // 句子开头标记(Beginning of Sentence)的 ID。在分词器中,每个词或标记都有一个唯一的 ID。"eos_token_id": 151643, // 句子结束标记(End of Sentence)的 ID。"hidden_act": "silu", // 隐藏层的激活函数。SiLU(Sigmoid Linear Unit)是一种激活函数。"hidden_size": 3584, // 隐藏层的大小(维度)。"initializer_range": 0.02, // 用于初始化模型权重的标准差。"intermediate_size": 18944, // 前馈网络(Feed-Forward Network)中间层的大小。"max_position_embeddings": 131072, // 模型可以处理的最大序列长度(位置嵌入的数量)。"model_type": "qwen2", // 模型类型为 qwen2。"num_attention_heads": 28, // 注意力机制中注意力头的数量。"num_hidden_layers": 28, // 模型中隐藏层(Transformer 层)的数量。"num_key_value_heads": 4, // 键值头的数量。用于分组查询注意力(Grouped-Query Attention, GQA)。如果该值小于`num_attention_heads`,则表示启用了GQA, 否则为多头注意力(Multi-Head Attention, MHA)。"rms_norm_eps": 1e-06, // RMSNorm(Root Mean Square Layer Normalization)中使用的 epsilon 值,用于防止除以零。"rope_theta": 10000.0, // RoPE(Rotary Positional Embeddings)中使用的 theta 值。RoPE 是一种位置编码方法。"tie_word_embeddings": false, // 是否将词嵌入矩阵和输出层的权重矩阵绑定(共享)。设置为 `false` 表示不绑定。"torch_dtype": "bfloat16", // 模型使用的默认数据类型。`bfloat16` 是一种 16 位浮点数格式,可以提高计算效率并减少内存占用。"transformers_version": "4.48.3", // 使用的 Transformers 库的版本。"use_cache": true, // 是否使用缓存机制来加速推理。设置为 `true` 表示使用缓存。"vocab_size": 152064 // 词汇表的大小(不同词或标记的数量)。
}
- configuration.json
- 内容: 这个文件和 config.json 类似,通常包含模型的配置信息。在某些模型中,这两个文件可能是同一个文件,或者 configuration.json 包含了更详细的配置。对于 DeepSeek-R1-Distill-7B 模型,你可以认为它和 config.json 作用相同。
- generation_config.json
- 内容: 这个文件包含模型生成文本时的配置参数,例如解码方法(beam search、top-k sampling 等)、最大生成长度、温度系数等。
{"_from_model_config": true, // 表示这些配置中的大部分是从模型的配置文件(config.json)中继承的。"bos_token_id": 151646, // 句子开头标记(Beginning of Sentence)的 ID。"eos_token_id": 151643, // 句子结束标记(End of Sentence)的 ID。"do_sample": true, // 是否使用采样(sampling)方法生成文本。如果设置为 `false`,则使用贪婪解码(greedy decoding)。"temperature": 0.6, // 温度系数。温度系数用于控制生成文本的随机性。值越高,生成的文本越随机;值越低,生成的文本越确定。"top_p": 0.95, // Top-p 采样(nucleus sampling)的阈值。Top-p 采样只从概率最高的、累积概率超过 `top_p` 的词中进行采样。"transformers_version": "4.39.3" // 使用的 Transformers 库的版本。(原文档中是4.39.3,这与之前config.json里的版本号不同,但通常情况下,版本号应当以config.json里的为准)
}
-
LICENSE
内容: 这是一个文本文件,包含了模型的许可证信息。许可证规定了你可以如何使用、修改和分发模型。 -
model-00001-of-00002.safetensors 和 model-00002-of-00002.safetensors
内容: 这些文件是模型权重文件,它们以 Safetensors 格式存储。Safetensors 是一种安全且高效的张量存储格式。由于模型很大,权重被分成了多个文件。 -
model.safetensors.index.json
内容: 这是一个索引文件,用于指示哪些权重存储在哪个 .safetensors 文件中。当模型权重被分成多个文件时,需要这个索引文件来正确加载权重。 -
README.md
内容: 这是一个 Markdown 格式的文本文件,通常包含模型的介绍、使用说明、示例代码等。 -
tokenizer_config.json
内容: 包含分词器(Tokenizer)的配置信息。
{"add_bos_token": true, // 是否在输入序列的开头添加句子开头标记(BOS token)。设置为 `true` 表示添加。"add_eos_token": false, // 是否在输入序列的结尾添加句子结束标记(EOS token)。设置为 `false` 表示不添加。"__type": "AddedToken", //这是一个内部使用的类型标记,表示这是一个"添加的token""content": "<|begin of sentence|>", // 这是一个特殊标记的内容,表示句子的开始"lstrip": false, //在处理这个token时,是否移除左侧的空白符"normalized": true, // 是否对这个token进行标准化处理"rstrip": false, //是否移除右边的空白符"single_word": false, // 是否将此token视为单个词"clean_up_tokenization_spaces": false, // 是否清理分词过程中的空格。设置为 `false` 表示不清理。"__type": "AddedToken","content": "<|end of sentence|>","lstrip": false,"normalized": true,"rstrip": false,"single_word": false,"legacy": true, // 是否使用旧版(legacy)的分词器行为。这里设置为`true`可能表示兼容旧版本。"model_max_length": 16384, // 模型可以处理的最大序列长度。"__type": "AddedToken","content": "<|end of sentence|>","lstrip": false,"normalized": true,"rstrip": false,"single_word": false,"sp_model_kwargs": {}, // SentencePiece 模型的相关参数(这里为空)。"unk_token": null, // 未知词标记(unknown token)。设置为 `null` 表示没有专门的未知词标记。"tokenizer_class": "LlamaTokenizerFast", // 分词器的类名。`LlamaTokenizerFast` 表示这是一个快速版本的 Llama 分词器。"chat_template": "{% if not add_generation_prompt is defined %}{% set add_generation_prompt = false %}{% endif %}{% set ns = namespace(is_first=false, is_tool=false, is_output_first=true, system_prompt='') %}{%- for message in messages %}{%- if message['role'] == 'system' %}{% set ns.system_prompt = message['content'] %}{%- endif %}{%- endfor %}{{bos_token}}{{ns.system_prompt}}{%- for message in messages %}{%- if message['role'] == 'user' %}{%- set ns.is_tool = false -%}{{'<|User|>' + message['content']}}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is none %}{%- set ns.is_tool = false -%}{%- for tool in message['tool_calls']%}{%- if not ns.is_first %}{{'<|Assistant|><|tool calls begin|><|tool call begin|>' + tool['type'] + '<|tool sep|>' + tool['function']['name'] + '\n' + '```json' + '\n' + tool['function']['arguments'] + '\n' + '```' + '<|tool call end|>'}}{%- set ns.is_first = true -%}{%- else %}{{'\n' + '<|tool call begin|>' + tool['type'] + '<|tool sep|>' + tool['function']['name'] + '\n' + '```json' + '\n' + tool['function']['arguments'] + '\n' + '```' + '<|tool call end|>'}}{{'<|tool calls end|><|end of sentence|>'}}{%- endif %}{%- endfor %}{%- endif %}{%- if message['role'] == 'assistant' and message['content'] is not none %}{%- if ns.is_tool %}{{'<|tool outputs end|>' + message['content'] + '<|end of sentence|>'}}{%- set ns.is_tool = false -%}{%- else %}{% set content = message['content'] %}{% if '</think>' in content %}{% set content = content.split('</think>')[-1] %}{% endif %}{{'<|Assistant|>' + content + '<|end of sentence|>'}}{%- endif %}{%- endif %}{%- if message['role'] == 'tool' %}{%- set ns.is_tool = true -%}{%- if ns.is_output_first %}{{'<|tool outputs begin|><|tool output begin|>' + message['content'] + '<|tool output end|>'}}{%- set ns.is_output_first = false %}{%- else %}{{'\n<|tool output begin|>' + message['content'] + '<|tool output end|>'}}{%- endif %}{%- endif %}{%- endfor -%}{% if ns.is_tool %}{{'<|tool outputs end|>'}}{% endif %}{% if add_generation_prompt and not ns.is_tool %}{{'<|Assistant|><think>\n'}}{% endif %}"// ↑这是一个 Jinja2 模板,定义了对话的格式。它根据消息的角色(用户、助手、工具)和内容,构建最终的输入文本。}
数据集准备
推理模型与通用模型相比,输出的回答包括了一段思考过程(Chain of Thoughts 思维链)。这个思考过程本质也是通过预测下一个token进行实现的,只不过DeepSeek系列模型输出时,会将思考过程放在一对特殊token <think>...</think>之间,</think>标签后的内容作为回答的正文。
微调推理模型时,同样需要包含思维链和最终回答两部份。因此,在围绕DeepSeek R1 Distill模型组进行微调的时候,微调数据集的回复部分文本也需要是包含推理 和最终回复两部分内容,才能使得DeepSeek R1模型组在保持既定回复风格的同时,强化模型能力,反之则会导致指令消融问题(模型回复不再包含think部分)。
modelscope社区提供了多样的推理数据集供开发者使用 。
原文采取由深圳大数据研究院发布的HuatuoGPT-o1模型的微调数据集—medical-o1-reasoning-SFT,地址:https://www.modelscope.cn/datasets/AI-ModelScope/medical-o1-reasoning-SFT。
本数据集将数据分为:
- Question:医疗问题
- Complex_CoT:进行诊疗的思维链
- Response:最终的答复
数据集中所有内容均为英文
模型演示
在进行微调前,我们可以了解一下模型的基本用法。
1. 加载已经下载到本地的模型
max_seq_length = 2048 # 指定输出的最大长度
dtype = None # 不指定模型精度,由unsloth框架自动检测
load_in_4bit = False # 采用int4量化,减少显存占用,但是会降低模型性能# 加载模型和分词器
model, tokenizer = FastLanguageModel.from_pretrained(model_name="./DeepSeek-R1-Distill-Qwen-7B", # 待微调的模型名称max_seq_length=max_seq_length, # 模型可以处理的最长序列长度dtype=dtype, # 限定模型浮点精度load_in_4bit=False # 是否使用int量化
)
2. 通过unsloth框架配置待微调的LoRA模型
'''
LoRA 的核心思想是,对于预训练模型的权重矩阵 W,不直接对其进行更新,
而是添加一个低秩分解矩阵 ΔW = A * B,
其中 A 和 B 是两个较小的矩阵。在微调过程中,只更新 A 和 B 的参数,而 W 的参数保持不变。
这样可以大大减少需要微调的参数数量,降低计算成本。
'''
model = FastLanguageModel.get_peft_model(model,r=8, # lora微调的秩 # 较小的 `r` 值会减少需要微调的参数数量,降低计算成本,但也可能降低模型的表达能力。# 较大的 `r` 值会增加参数数量,提高模型的表达能力,但也会增加计算成本。# 通常需要根据实际情况进行实验,选择合适的 `r` 值。一般来说,8、16、32、64 是常用的值。target_modules = ["q_proj", "k_proj", "v_proj", # 指定要应用 LoRA 的模块。这些模块通常是 Transformer 模型中的线性层。"o_proj", "gate_proj", "up_proj", "down_proj"], # 这里分别应用了注意力机制中的Wq, Wk, Wv, Wo线性投影层,FFN中的线性层lora_alpha=8, # lora缩放因子,决定模型权重的更新程度,建议设置为r或r的倍数lora_dropout=0,bias="none", # 不为LoRA层添加偏置use_gradient_checkpointing="unsloth", # 是否设置梯度检查点,# 梯度检查点是一种以时间换空间的技术,可以减少内存占用,但会增加计算时间。random_state=3407, # 设置随机种子,保证实验可以浮现use_rslora=False, # 是否使用Rank-Stabilized LoRA(rslora)。rslora 是一种改进的 LoRA 方法,可以自动调整 `lora_alpha`。loftq_config=None # 是否使用QLoRA,即将LoRA与量化技术结合
)
3. 进行简单推理
# 将模型切换为推理模式,可以进行简单的对话
FastLanguageModel.for_inference(model)question = "请介绍一下你自己!"
# 对输入进行分词
# 传入待分词的文本列表,最后返回一个PyTorch张量
input_ids = tokenizer([question], return_tensors="pt").to("cuda")
# input_ids返回token对应词表中的id,即将一个句子映射为一个token id序列
# attention_mask用于表示input_ids中哪些是为了填充序列长度而通过<pad>填充的token,1表示所有的 token 都是实际的词或标记,没有填充。
input_ids# 调用模型生成答复
'''
是否使用缓存机制来加速生成过程。设置为 True 表示使用缓存。缓存机制会存储先前计算的键/值对(key/value pairs),避免重复计算,从而提高生成速度。在自回归生成(逐个 token 生成)中,缓存机制非常有用。
'''
outputs_ids = model.generate(input_ids=input_ids.input_ids,max_new_tokens=1024,use_cache=True
)
# 模型的直接输出同样为token ids,需要通过tokenizer进行解码
outputs_idsresponse = tokenizer.batch_decode(outputs_ids)
print(response[0])
可以在prompt中添加<think>标签对引导模型进行思考。
question = "你好,好久不见!"
# 更完善的prompt
prompt_style_chat = """请写出一个恰当的回答来完成当前对话任务。### Instruction:
你是一名助人为乐的助手。### Question:
{}### Response:
"""# 使用tokenizer处理prompt
input_ids = tokenizer([prompt_style_chat.format(questionm '')], return_tensors="pt").to("cuda")outputs = model.generate(input_ids=input_ids.input_ids,use_cache=True,do_sample=True, # 启用采样temperature=0.7, # 较高的温度top_p=0.9, # Top-p 采样repetition_penalty=1.2, # 重复惩罚max_new_tokens=1024, # 最大新token数量
)response = tokenizer.batch_decode(outputs, skip_special_tokens=True)[0]
print(response)
未添加<think>标签,模型有概率不思考。
prompt_style_chat = """请写出一个恰当的回答来完成当前对话任务。### Instruction:
你是一名助人为乐的助手。### Question:
{}### Response:
<think>{}
"""
question = "请你分析李朗笛和朗朗以及李云迪之间的关系"# 使用tokenizer处理prompt
input_ids = tokenizer([prompt_style_chat.format(question, "")], return_tensors="pt").to("cuda")outputs = model.generate(input_ids=input_ids.input_ids,use_cache=True,do_sample=True, # 启用采样temperature=0.7, # 较高的温度top_p=0.95, # Top-p 采样repetition_penalty=1.2, # 重复惩罚max_new_tokens=1024, # 最大新token数量
)response = tokenizer.batch_decode(outputs, skip_special_tokens=False)[0]
print(response)
添加<think>标签作为引导,模型更容易进行思考。
微调实操
微调请重新开一个notebook,清空缓存,从头进行。
1. 倒入依赖
# 导入依赖
from modelscope.msdatasets import MsDataset # modelscope数据集类
from trl import SFTTrainer # 微调训练器配置类
from transformers import TrainingArguments # 微调参数配置类
from unsloth import FastLanguageModel, is_bfloat16_supported # 检查GPU是否支持bf16
import wandb # 微调数据可视化
2. 定义模板
因为数据集是英文的,所以promt也采用英文,保证语言一致性。
# 1. 定义prompt模板
finetune_template = '''Below is an instruction that describes a task, paired with an input that provides further context.
Write a response that appropriately completes the request.
Before answering, think carefully about the question and create a step-by-step chain of thoughts to ensure a logical and accurate response.### Instruction:
You are a medical expert with advanced knowledge in clinical reasoning, diagnostics, and treatment planning.
Please answer the following medical question. ### Question:
{}### Response:
<think>
{}
</think>
{}'''prompt_style_zh = '''以下是一个任务说明,配有提供更多背景信息的输入。
请写出一个恰当的回答来完成该任务。
在回答之前,请仔细思考问题,并按步骤进行推理,确保回答逻辑清晰且准确。### Instruction:
您是一位具有高级临床推理、诊断和治疗规划知识的医学专家。
请回答以下医学问题。### 问题:
{}### 问题:
<think>{}'''
3. 加载模型
# 2. 加载模型
model, tokenizer = FastLanguageModel.from_pretrained(model_name="./DeepSeek-R1-Distill-Qwen-7B",max_seq_length=2048,dtype=None,load_in_4bit=False
)
EOS_TOKEN = tokenizer.eos_token
4. 加载数据集
# 在模型微调时,给微调数据集加上 EOS_TOKEN 非常重要。它可以明确文本边界、保持训练目标一致性、控制生成过程、处理多轮对话,以及更好地利用 CoT 数据集。
EOS_TOKEN = tokenizer.eos_token# 格式话训练数据
def formatting_prompts_func(examples):inputs = examples["Question"]cots = examples["Complex_CoT"]outputs = examples["Response"]texts = []for input, cot, output in zip(inputs, cots, outputs):text = finetune_template.format(input, cot, output) + EOS_TOKENtexts.append(text)return {"text": texts,}ds = MsDataset.load('AI-ModelScope/medical-o1-reasoning-SFT', split = "train")
dataset = ds.map(formatting_prompts_func, batched = True,)
print(dataset["text"][0])
5. 配置微调模型
将LoRA模块加入模型,为微调做准备
'''
LoRA 的核心思想是,对于预训练模型的权重矩阵 W,不直接对其进行更新,
而是添加一个低秩分解矩阵 ΔW = A * B,
其中 A 和 B 是两个较小的矩阵。在微调过程中,只更新 A 和 B 的参数,而 W 的参数保持不变。
这样可以大大减少需要微调的参数数量,降低计算成本。
'''
model = FastLanguageModel.get_peft_model(model,r=16, # lora微调的秩 # 较小的 `r` 值会减少需要微调的参数数量,降低计算成本,但也可能降低模型的表达能力。# 较大的 `r` 值会增加参数数量,提高模型的表达能力,但也会增加计算成本。# 通常需要根据实际情况进行实验,选择合适的 `r` 值。一般来说,8、16、32、64 是常用的值。target_modules = ["q_proj", "k_proj", "v_proj", # 指定要应用 LoRA 的模块。这些模块通常是 Transformer 模型中的线性层。"o_proj", "gate_proj", "up_proj", "down_proj"], # 这里分别应用了注意力机制中的Wq, Wk, Wv, Wo线性投影层,FFN中的线性层lora_alpha=16, # lora缩放因子,决定模型权重的更新程度,建议设置为r或r的倍数lora_dropout=0,bias="none", # 不为LoRA层添加偏置use_gradient_checkpointing="unsloth", # 是否设置梯度检查点,# 梯度检查点是一种以时间换空间的技术,可以减少内存占用,但会增加计算时间。random_state=3407, # 设置随机种子,保证实验可以浮现use_rslora=False, # 是否使用Rank-Stabilized LoRA(rslora)。rslora 是一种改进的 LoRA 方法,可以自动调整 `lora_alpha`。loftq_config=None # 是否使用QLoRA,即将LoRA与量化技术结合
)
6. 配置微调参数
# 5. 配置微调参数
trainer = SFTTrainer(model=model,tokenizer=tokenizer,train_dataset=dataset,dataset_text_field="text", # 数据集中包含文本的字段的名称。# dataset_text_field="text", # 说明text列对应的是微调数据集max_seq_length=2048, # 模型能处理的最长序列dataset_num_proc=2, # 用于预处理数据的进程数。args=TrainingArguments(per_device_train_batch_size=2, # mini-batch-sizegradient_accumulation_steps=4, # 梯度累积,用于模型batch_size=2*4=8的情况,模型实际上经过 2 * 4 = 8 个batch之后才会更新参数(一个step),能缓解GPU无法放下大batch的问题num_train_epochs=3, # 训练轮数# max_steps = 60 # 如果要进行迅速严重微调可行性,可以只训练60个steps,训练的总步数(参数更新次数)。warmup_steps=5, # 模型热身步数,学习率会从 0 逐渐增加到设定的学习率。lr_scheduler_type="linear", # 学习率调度器类型。这里使用线性调度器,学习率会线性下降。learning_rate=2e-4, # 学习率fp16=not is_bfloat16_supported(), # 是否使用 FP16(16 位浮点数)混合精度训练。如果 GPU 不支持 bfloat16,则使用 fp16。bf16=is_bfloat16_supported(),logging_steps=10, # 多少个step打印一次信息optim="adamw_8bit", # 指定优化器weight_decay=0.01, # 权重衰退seed=3407, # 随机种子,保证结果可以复现output_dir="outputs" # 保存训练结果(模型、日志等)的目录。)
)
7. 进行微调
# 6. 进行微调
wandb.init()
trainer_stats = trainer.train()
看到如下输出即表示微调正在运行中。
8. 将LoRA权重与原始矩阵合并,保存微调后的模型
# LoRA微调完成后,保存微调模型并合并矩阵
new_model_local = "DeepSeek-R1-Qwen-7B-Medical-Full" # 定义一个字符串变量,表示保存模型的本地路径。
model.save_pretrained(new_model_local) # 保存微调后的模型(包括 LoRA 权重)。
tokenizer.save_pretrained(new_model_local) # 保存分词器。
model.save_pretrained_merged(new_model_local, tokenizer, save_method="merged_16bit") # 合并 LoRA 权重到基础模型中,并保存合并后的模型。
相关文章:
深度学习:从零开始的DeepSeek-R1-Distill有监督微调训练实战(SFT)
原文链接:从零开始的DeepSeek微调训练实战(SFT) 微调参考示例:由unsloth官方提供https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Qwen2.5_(7B)-Alpaca.ipynbhttps://colab.research.google.com/git…...
JavaScript |(五)DOM简介 | 尚硅谷JavaScript基础实战
学习来源:尚硅谷JavaScript基础&实战丨JS入门到精通全套完整版 笔记来源:在这位大佬的基础上添加了一些东西,欢迎大家支持原创,大佬太棒了:JavaScript |(五)DOM简介 | 尚硅谷JavaScript基础…...
模型整合-cherry studio+mysql_mcp_server服务配置
一、什么是MCP MCP(Model Context Protocol)是模型上下文协议,它允许大型语言模型(LLM)通过协议与外部工具或服务交互,动态获取实时数据或执行操作。简单来说,它让模型不再局限于静态知识库&…...
【QA】装饰模式在Qt中有哪些运用?
在Qt框架中,装饰模式(Decorator Pattern)主要通过继承或组合的方式实现,常见于IO设备扩展和图形渲染增强场景。以下是Qt原生实现的装饰模式典型案例: 一、QIODevice装饰体系(继承方式) 场景 …...
window 设置自动开启/关闭程序(分享)
打开计算机管理 winr 输入 compmgmt.msc 找到任务计划程序创建任务 设置开启任务 常规:添加名称与描述 触发器:新建触发时间与次数 操作:新建执行程序 添加任务对应的位置 以便修改 设置关闭任务 添加批处理文件,写完后吧 .…...
QT布局笔记
在 Qt 中,如果你希望将一个 QGroupBox 放置在水平布局(QHBoxLayout)的上方,可以通过将它们添加到一个垂直布局(QVBoxLayout)中来实现。垂直布局会将子布局或子控件按垂直顺序排列,因此 QGroupBo…...
【LLM大模型】LangChain学习
大模型对话 from langchain.chat_models import ChatOpenAI # 内置对话模型 from langchain.schema import HumanMessage, SystemMessage, AIMessage # 用户提示词,系统提示词, AI响应chat ChatOpenAI(temperature0.7, openai_api_keyxxxxxxxxxxxx) #…...
SpringBoot实战(三十二)集成 ofdrw,实现 PDF 和 OFD 的转换、SM2 签署OFD
目录 一、OFD 简介 1.1 什么是 OFD?1.2 什么是 版式文档?1.3 为什么要用 OFD 而不是PDF? 二、ofdrw 简介 2.1 定义2.2 Maven 依赖2.3 ofdrw 的 13 个模块 三、PDF/文本/图片 转 OFD(ofdrw-conterver) 3.1 介绍…...
SolidWorks使用显卡教程
操作步骤: 打开注册表编辑器 按下键盘上的 Win R 组合键,输入 regedit 并按回车键,打开注册表编辑器。 导航到显卡信息路径 在注册表中依次展开以下路径: plaintext HKEY_CURRENT_USER\Software\SolidWorks\SOLIDWORKS 2021\Per…...
mysql 查询进程查看并释放
在MySQL中,查看和管理进程(例如查询、连接等)是数据库维护和性能调优的重要部分。以下是一些常用的方法来查看MySQL进程并释放它们。 1. 查看进程 你可以使用SHOW PROCESSLIST命令来查看当前MySQL服务器上的所有进程。这个命令会显示正在执…...
C++代码2-多目标算法求解车辆路径规划
为了解决车辆路径规划问题,我们需要在同一模型中同时考虑多个目标,其中一个目标是降低运营总成本,而另一个目标是降低总的碳排放量。使用组合算法,包括人工蜂群算法(Artificial Bee Colony, ABC)、模拟退火算法(Simulated Annealing, SA)、以及多目标优化算法MODAD(Mu…...
JAVA学习*接口
接口 在生活中我们常听说USB接口,那接口是什么呢? 在Java中,接口相当于多个类的一种公共规范,是一种引用数据类型。 定义接口 public interface IUSB {public static final String SIZE "small";public abstract vo…...
Matplotlib
一、Matplotlib快速入门 学习目标 了解什么是matplotlib 为什么要学习matplotlib matplotlib简单图形的绘制 1、什么是Matplotlib 是专门用于开发2D图表(包括3D图表) 以渐进、交互式方式实现数据可视化 2、为什么要学习Matplotlib 可视化是在整个数据挖掘的关键辅助工…...
新版frp-0.61.0 实现泛解析域名穿透 以及 https启用
需要在公网服务器的域名解析平台 泛域名 *.aa.com 解析到frp 公网服务器的ip x.x.x.x 对于frpc.toml 文件的 serverAddr 绑定的ip 需要公网服务器放行 bindPort 对于的端口 frpc.toml serverPort 对于的的是 frps.toml bindPort 端口 frps.toml bindPort 7000 vhostHTTPP…...
HTTPS 加密过程详解
HTTPS 详解及其加密过程流程框架 HTTPS(Hypertext Transfer Protocol Secure)是一种基于 HTTP 协议的安全通信协议,通过 SSL/TLS 协议对传输数据进行加密和身份验证,解决了 HTTP 明文传输的安全隐患。以下是其核心原理和加密流程的…...
lua垃圾回收
lua垃圾回收 lua 垃圾回收 lua 垃圾回收 collectgarbage(“count”)获取当前lua脚本占用内存字节数(单位为KB)。 collectgarbage(“collect”)执行一次垃圾回收。 xxxnil 将变量置为空,会释放内存。 lua中的机制和c#中回收机制很类似 解除羁绊(置为空)。 --垃圾回…...
springboot继承使用mybatis-plus举例相关配置,包括分页插件以及封装分页类
以下是使用 MyBatis-Plus 分页插件的完整配置和封装步骤,包括日志输出、驼峰转下划线、逻辑删除以及分页属性类的封装。 1. 引入依赖 确保在 pom.xml 中已经引入 MyBatis-Plus 的依赖: <XML> <dependency><groupId>com.baomidou<…...
智能汽车以太网系统测试:聚焦ETH链路高负载性能表现
引言 在智能汽车高速发展的今天,车载以太网作为车辆信息交互的“神经网络”,承担着传输海量数据的关键使命。它不仅能够满足车辆对高带宽、低延迟和高可靠性的通信需求,还为自动驾驶、智能座舱等复杂功能提供了强大的技术支持。然而…...
学习笔记:黑马程序员JavaWeb开发教程(2025.3.21)
10.7 案例-员工管理-分页查询-分析 形参的默认值可以使用注解来设置:RequestParam(default “1”) 10.8 案例-员工管理-分页查询-PageHelper插件 分页插件PageHelper帮助完成有关分页的所有操作,我们只要正常使用查询语句就可以了。插件会自动…...
计算机网络精讲day1——计算机网络的性能指标(上)
性能指标1:速率 概念1:比特 英文全称是binary digit,意思是一个二进制数字,因此一个比特就是二进制数字中的1或0,比特也是信息论中使用的信息量单位。 概念2:速率 网络中的速率指的是数据的传送速率&#…...
gin-路由handler封装思路
约束handler入参和返回为func(ctx, req) (resp, error)。通过反射,封装handler,在调用前后写入入参和返回的处理。 package testingimport ("context""fmt""reflect""strings""testing" )type ReqPa…...
【实战案例】用STAR+3W模型拆解电商支付系统设计文档
各位开发者朋友,上次分享了结构化写作的黄金公式后,很多同学反馈需要更具象的落地方法。今天通过真实电商支付系统案例,手把手教你用STAR3W模型写出可执行的设计文档! 结构化写作的「黄金公式」 STAR原则 3W模型 Situation&…...
计算机组成原理和计算机网络常见单位分类及换算
计算机组成原理(主要用于存储、内存、缓存等) 计算机网络(主要用于传输速率) 直观对比...
线性筛法求素数
时间复杂度 o(n) int cnt, primes[N];//cnt用来记录素数的下标 bool st[N];//用来标记合数 int minp[N];//最小质因数 void get_primes(int n) {for(int i 2;i < n;i )//从2开始找数 {if(!st[i])//如果这个数没有被筛出去过,说明是一…...
触动精灵对某东cookie读取并解密--记lua调用C语言
在Mac上构建Lua扩展模块:AES解密与Base64解码实战 今天我要分享一个实用技术:如何在Mac系统上为Lua编写和编译C扩展模块,特别是实现一个某东iOS PIN码解密功能的扩展。这对于需要在Lua环境中执行高性能计算或使用底层系统功能的开发者非常有…...
GEO:在AI时代抢占DeepSeekC位?
前言:当SEO遇见AGI——一场静默的流量革命 在生成式AI日均处理53亿次查询的今天,传统SEO的「关键词-排名-点击」逻辑正在崩塌。DeepSeek、ChatGPT、豆包等大模型用动态生成的答案,悄然截流了68%的搜索需求。更残酷的是:当用户问&q…...
【设计模式】策略模式
以下是格式优化后的Markdown文档,仅调整代码缩进,保持内容不变: 四、策略模式 策略(Strategy) 模式是一种行为型模式,其实现过程与模板方法模式非常类似——都 是以扩展的方式支持未来的变化。本章通过对一个具体范例的逐步重构…...
第J6周:ResNeXt-50实战解析
文章目录 一、前期准备1.设置GPU2.导入数据3.查看数据 二、数据预处理1.加载数据2.可视化数据3.再次检查数据4.配置数据集 四、模型复现1. 分组卷积模块2. 定义残差模块3. 堆叠残差单元4. 搭建ResNext-50网络5. 查看模型摘要 五、训练模型六、结果可视化总结: &…...
调试 ResNet18 cpp实现中的段错误(SIGSEGV)问题
调试 ResNet18 cpp实现中的段错误(SIGSEGV)问题 问题分析 您的程序在运行时遇到了段错误(SIGSEGV),GDB显示错误发生在main()函数的第一行(resnet18_allo_test.cpp:33)。这种情况看起来很奇怪&…...
详细介绍IDI_APPLICATION和IDC_ARROW
书籍:《windows程序设计(第五版)》 环境:visual studio 2022 内容:HELLOWIN程序 说明:以下内容大部分来自腾讯元宝。 IDI_APPLICATION 与 IDC_ARROW 详解 1. IDC_ARROW(光标资源标识符) 定义与…...
curl库+openssl库windows编译
一、工具准备 Visual Studio 2008:确保安装了 C 开发工具。 Git:用于克隆 cURL 的源码。 Perl:可以从 ActiveState Perl 下载并安装。 NASM(可选):如果需要汇编优化,可以从NASM 官方网站 下载并…...
今日行情明日机会——20250321
后续投资机会分析 结合2025年3月21日盘面数据(涨停56家,跌停31家),市场呈现结构性分化行情,海洋经济成为绝对主线,机器人概念局部活跃,人工智能表现较弱。以下是具体方向与策略建议:…...
repo init 错误 Permission denied (publickey)
一、已经生成ssh-key并设置到gerrit上 二、已经设置.gitconfig (此步骤是公司要求,设置gerrit地址为一个别名之类的,有的公司不需要) 然后出现下面的错误,最后发现忘记设置git的用户名和邮箱 1. git config --globa…...
STM32 模拟SPI 模式0
SPI 模式 0 的时钟极性(CPOL)为 0,时钟相位(CPHA)为 0。CPOL 0 意味着时钟信号空闲时为低电平,CPHA 0 表示在时钟信号的第一个跳变沿(上升沿)进行数据采样。 #include "stm3…...
MySQL实现全量同步和增量同步到SQL Server或其他关系型库
在将MySQL中的两张表同步到SQL Server的过程中,全量同步和增量同步各有其优缺点。全量同步简单直接但可能耗时较长且资源消耗大,而增量同步则更加高效但需要额外的逻辑来处理数据的变更。以下是对这两种同步方式的详细解释及代码示例的完善。 完整代码示…...
详细解析GetOpenFileName()
书籍:《Visual C 2017从入门到精通》的2.3.8 Win32控件编程 环境:visual studio 2022 内容:【例2.34】打开文件对话框和另存为。 说明:以下内容大部分来自腾讯元宝。 GetOpenFileName() 是 Windows API 中用于显示标准文件打开…...
FPGA----完美解决Windows下[XSIM 43-3409][XSIM 43-3915]错误
大家好久不见,今天开始又要重操旧业了!最近会更新很多关于petalinux的踩坑日记,敬请期待! 先更新一个常见问题,使用Vivado仿真时C编译器报错问题。如下所示 ERROR: [XSIM 43-3409] Failed to compile generated C fi…...
LeetCode Hot100 刷题路线(Python版)
目录 1. LeetCode Hot100 刷题笔记(1)—— 哈希、双指针、滑动窗口 2. LeetCode Hot100 刷题笔记(2)—— 子串、普通数组、矩阵 3. LeetCode Hot100 刷题笔记(3)—— 链表 4. LeetCode Hot100 刷题笔记&…...
宇树科技纯技能要求总结
一、嵌入式开发与硬件设计 核心技能 嵌入式开发: 精通C/C,熟悉STM32、ARM开发熟悉Linux BSP开发及驱动框架(SPI/UART/USB/FLASH/Camera/GPS/LCD)掌握主流平台(英伟达、全志、瑞芯微等) 硬件设计:…...
Docker学习笔记(十)搭建Docker私有仓库
一、环境配置 1、宿主机系统:macOS Sequoia(版本15.2) 2、虚拟机VMware Fusion版本:专业版 13.6.2 (24409261) 3、虚拟机系统:AlmaLinux-9-latest-x86_64-boot.iso 二、安装Harbor开源企业级Docker镜像 Harbor 是一个开源的企业级 Docker…...
FastAPI WebSocket 无法获取真实 IP 错误记录
FastAPI WebSocket 无法获取真实 IP 错误记录 问题描述 在使用 FastAPI WebSocket 服务时,发现无法获取设备的真实 Remote IP,所有连接均显示为内网地址 10.x.x.1。以下是完整的排查过程及解决方案。 排查步骤 1. 基础信息检查 • 现象复现࿱…...
DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例4,TableView15_04导出当前页数据示例
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例4,TableView15_04导出当…...
【Linux】快速上手Makeflie CMake
🦄个人主页:修修修也 🎏所属专栏:Linux ⚙️操作环境:Xshell (操作系统:Ubuntu 22.04 server 64bit) 目录 📌快速上手Makefile 基本结构 变量 自动变量 常用目标 📌快速上手CMake CMake与Makefile的关系 CMake的使用步骤 常用命令…...
Python连接数据库进行增删改查
更多优质文章 _>_>_>_>_>✍✈✉戳我 目录 1.导入相关库 2.创建连接 3.插入数据 4.删除数据 5.修改数据 6.查询数据 7.更多干货 1.导入相关库 import pymysql -----pip install pymysql #下载库 2.创建连接 conn pymysql.connect(hostlocalho…...
数据库的两种模式
数据库的 严格模式(Strict Mode) 和 宽松模式(Non-Strict Mode) 是数据库管理系统(DBMS)中用于控制数据验证和处理方式的两种不同模式。它们的主要区别在于对数据完整性、一致性和错误处理的严格程度。 1. …...
【css酷炫效果】纯CSS实现立体旋转立方体
【css酷炫效果】纯CSS实现立体旋转立方体 缘创作背景html结构css样式完整代码效果图 想直接拿走的老板,链接放在这里:https://download.csdn.net/download/u011561335/90492014 缘 创作随缘,不定时更新。 创作背景 刚看到csdn出活动了&am…...
Cursor与Coze结合开发电影推荐系统:一次高效的技术实践
1 项目背景 有个想法,和朋友打算一起看电影,但是不知道看什么(吃饭也是),于是在豆瓣高分电影榜单中选择出来一些感兴趣的电影,随机挑选一部“天意之选”。为此,我尝试结合Cursor(智…...
【总结篇】java多线程,新建线程有几种写法,以及每种写法的优劣势
java多线程 新建线程有几种写法,以及每种写法的优劣势 [1/5]java多线程 新建线程有几种写法–继承Thread类以及他的优劣势[2/5]java多线程-新建线程有几种写法–实现Runnable接口以及他的优劣势[3/5]java多线程 新建线程有几种写法–实现Callable接口结合FutureTask使用以及他的…...
idea问题(三)pom文件显示删除线
一、问题 1、现象 2、原因 分析原因和出现的流程:创建子模块的时候因为名称错误了,并且通过修改模块模块名称后,又删除了模块,因删除不干净。再次建立了同名模块,会让IDEA认为你再次新建的项目是已经被删除的项目。 …...
python爬虫概述
0x00 python爬虫概述 以豆瓣的选电影模块为例,当查看源代码搜索猫猫的奇幻漂流瓶是搜不到的 这时服务器的工作方式应该是这样的 客户端浏览器第一次访问其实服务器端是返回的一个框架(html代码) 当客户端浏览器第二次通过脚本等方式进行访问时服务器端才返回的数据…...