在自定义合成数据上微调 SmolLM

社区文章 发布于 2025 年 1 月 5 日

image/png

SmolLM2 是一个紧凑型语言模型系列,有三种大小:1.35 亿、3.6 亿和 17 亿参数。它们能够解决各种任务,同时足够轻量级,可以在设备上运行。微调像 SmolLM 这样的语言模型涉及多个步骤,从设置环境到训练模型和保存结果。以下是基于提供的 Notebook 文件的详细分步指南。

笔记本 链接
SmolLM-FT-360M SmolLM-FT-360M.ipynb
SmolLM-FT-135M (类型 2) SmolLM-FT-135M-T2.ipynb
SmolLM2 演示 SmolLM2 Demo.ipynb

Hugging Face 访问令牌

image/png

别忘了在运行时添加或替换你自己的 Hugging Face 访问令牌,以便访问受限的轻量级模型


步骤 1:设置环境

在深入微调之前,你需要使用必要的库和工具设置你的环境。

  1. 安装所需的库:

    • 使用 pip 安装必要的 Python 库。其中包括 transformersdatasetstrltorchacceleratebitsandbyteswandb
    • 这些库对于使用 Hugging Face 模型、数据集和训练循环至关重要。
    !pip install transformers datasets trl torch accelerate bitsandbytes wandb
    
  2. 导入必要的模块:

    • 从已安装的库中导入所需的模块。其中包括 AutoModelForCausalLMAutoTokenizerTrainingArgumentspipelineload_datasetSFTTrainer
    from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, pipeline
    from datasets import load_dataset
    from trl import SFTConfig, SFTTrainer, setup_chat_format
    import torch
    import os
    
  3. 检测设备(GPU、MPS 或 CPU):

    • 检测可用的硬件(GPU、MPS 或 CPU),以确保模型在最有效的设备上运行。
    device = (
        "cuda"
        if torch.cuda.is_available()
        else "mps" if torch.backends.mps.is_available() else "cpu"
    )
    

步骤 2:加载预训练模型和分词器

接下来,加载预训练的 SmolLM 模型及其对应的分词器。

  1. 加载模型和分词器:

    • 使用 AutoModelForCausalLMAutoTokenizer 从 Hugging Face 加载 SmolLM 模型和分词器。
    model_name = "HuggingFaceTB/SmolLM2-360M"
    model = AutoModelForCausalLM.from_pretrained(pretrained_model_name_or_path=model_name)
    tokenizer = AutoTokenizer.from_pretrained(pretrained_model_name_or_path=model_name)
    
  2. 设置聊天格式:

    • 使用 setup_chat_format 函数准备模型和分词器,以执行基于聊天的任务。
    model, tokenizer = setup_chat_format(model=model, tokenizer=tokenizer)
    
  3. 测试基础模型:

    • 使用一个简单的提示测试基础模型,以确保其正常工作。
    prompt = "Explain AGI ?"
    pipe = pipeline("text-generation", model=model, tokenizer=tokenizer, device=0 if device == "cuda" else -1)
    print(pipe(prompt, max_new_tokens=200))
    
  4. 如果:遇到:

    • 分词器中已添加聊天模板,这表示分词器已有一个预定义的聊天模板,这会阻止 setup_chat_format() 再次修改它。
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline

model_name = "HuggingFaceTB/SmolLM2-1.7B-Instruct"
model = AutoModelForCausalLM.from_pretrained(pretrained_model_name_or_path=model_name)
tokenizer = AutoTokenizer.from_pretrained(pretrained_model_name_or_path=model_name)

tokenizer.chat_template = None

from trl.models.utils import setup_chat_format
model, tokenizer = setup_chat_format(model=model, tokenizer=tokenizer)

prompt = "Explain AGI?"
pipe = pipeline("text-generation", model=model, tokenizer=tokenizer, device=0)
print(pipe(prompt, max_new_tokens=200))

📍 否则跳过此部分 [ 步骤 4 ]!


步骤 3:加载和准备数据集

微调需要数据集。在这种情况下,我们使用一个名为 Deepthink-Reasoning 的自定义数据集。

image/png

  1. 加载数据集:

    • 使用 load_dataset 函数从 Hugging Face 加载数据集。
    ds = load_dataset("prithivMLmods/Deepthink-Reasoning")
    
  2. 分词数据集:

    • 定义一个分词函数,以批处理方式处理数据集。此函数将聊天模板应用于每个提示-响应对并对文本进行分词。
    def tokenize_function(examples):
        prompts = [p.strip() for p in examples["prompt"]]
        responses = [r.strip() for r in examples["response"]]
        texts = [
            tokenizer.apply_chat_template(
                [{"role": "user", "content": p}, {"role": "assistant", "content": r}],
                tokenize=False
            )
            for p, r in zip(prompts, responses)
        ]
        return tokenizer(texts, truncation=True, padding="max_length", max_length=512)
    
  3. 应用分词:

    • 将分词函数应用于数据集。
    ds = ds.map(tokenize_function, batched=True)
    

步骤 4:配置训练参数

设置训练参数以控制微调过程。

  1. 定义训练参数:

    • 使用 TrainingArguments 指定批大小、学习率、步数和优化设置等参数。
    use_bf16 = torch.cuda.is_bf16_supported()
    training_args = TrainingArguments(
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        warmup_steps=5,
        max_steps=60,
        learning_rate=2e-4,
        fp16=not use_bf16,
        bf16=use_bf16,
        logging_steps=1,
        optim="adamw_8bit",
        weight_decay=0.01,
        lr_scheduler_type="linear",
        seed=3407,
        output_dir="outputs",
        report_to="wandb",
    )
    

步骤 5:初始化训练器

使用模型、分词器、数据集和训练参数初始化 SFTTrainer

trainer = SFTTrainer(
    model=model,
    processing_class=tokenizer,
    train_dataset=ds["train"],
    args=training_args,
)

步骤 6:开始训练

通过调用训练器的 train 方法开始微调过程。

trainer.train()

步骤 7:保存微调模型

训练完成后,将微调模型和分词器保存到本地目录。

  1. 保存模型和分词器:

    • 使用 save_pretrained 方法保存模型和分词器。
    save_directory = "/content/my_model"
    model.save_pretrained(save_directory)
    tokenizer.save_pretrained(save_directory)
    
  2. 压缩并下载模型:

    • 压缩保存的目录并下载以备将来使用。
    import shutil
    shutil.make_archive(save_directory, 'zip', save_directory)
    
    from google.colab import files
    files.download(f"{save_directory}.zip")
    

模型与量化

项目 链接
模型 SmolLM2-CoT-360M
量化版本 SmolLM2-CoT-360M-GGUF

结论

微调 SmolLM 涉及设置环境、加载模型和数据集、配置训练参数以及运行训练循环。通过遵循这些步骤,你可以将 SmolLM 调整到你的特定用例,无论是用于推理任务、基于聊天的应用程序还是其他 NLP 任务。

此过程高度可定制,因此请随意尝试不同的数据集、超参数和训练策略,以获得项目的最佳结果。


社区

大家好,感谢这个教程!只有一个问题,如何使用 LM Studio 等工具正确格式化输出?目前,它似乎不会在响应结束时停止,并输出大量无意义的内容。

停止序列令牌可能存在问题。<|endoftext|> 停止令牌可能未包含在训练流中。相反,请初始化正确的停止短语,例如 [END]。此外,请尝试在 LM Studio 中使用最大令牌控制来限制响应长度。你需要尝试不同的值才能找到适合你用例的最佳值。

为了更好的格式化并解决漏洞问题,请访问 Giskard 输出格式化,了解正确的格式化技术/其他! @chrisvnz

谢谢!

运行 trainer.train() 时出现以下错误

Traceback (most recent call last):
  File "/smollm2/train.py", line 63, in 
    trainer.train()
  File "/smollm2/smol-env/lib/python3.12/site-packages/transformers/trainer.py", line 2238, in train
    return inner_training_loop(
           ^^^^^^^^^^^^^^^^^^^^
  File "/smollm2/smol-env/lib/python3.12/site-packages/transformers/trainer.py", line 2582, in _inner_training_loop
    tr_loss_step = self.training_step(model, inputs, num_items_in_batch)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/smollm2/smol-env/lib/python3.12/site-packages/trl/trainer/sft_trainer.py", line 904, in training_step
    return super().training_step(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/smollm2/smol-env/lib/python3.12/site-packages/transformers/trainer.py", line 3796, in training_step
    loss = self.compute_loss(model, inputs, num_items_in_batch=num_items_in_batch)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/smollm2/smol-env/lib/python3.12/site-packages/trl/trainer/sft_trainer.py", line 886, in compute_loss
    correct_predictions = (predictions == shift_labels) & mask
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: The size of tensor a (2) must match the size of tensor b (4) at non-singleton dimension 0
·
文章作者

@ep5000
请参阅此 Notebook。如果遇到相同的错误,请再次联系我并提供脚本。

Notebook:https://huggingface.co/datasets/prithivMLmods/Finetune-Colab-Nb/blob/main/SmolLM-FT-Type2/SmolLM-FT-135M-T2.ipynb

检查你的数据集,确保每个样本的 input_ids 长度与 labels 长度匹配。验证没有样本具有不同的序列长度或填充不当的 labels。此外,检查过时的软件包,并在必要时升级它们,以避免兼容性问题。

#upgarde to
%%capture
!pip install git+https://github.com/huggingface/trl.git
!pip install git+https://github.com/huggingface/transformers.git
!pip install git+https://github.com/huggingface/accelerate.git
!pip install git+https://github.com/huggingface/peft
!pip install huggingface_hub sentencepiece
!pip install datasets==4.0.0 torch
!pip install hf_xet numpy bitsandbytes 

注册登录 以评论