本地微调大模型实践

710 阅读4分钟

背景

大型语言模型LLM是指包含数百亿(或更多)参数的Transformer语言模型。例如GPT-3、PaLM、Galactica和LLaMA。包括缩放定律、 新兴能力和关键技术。

1、LLM的缩放定律

在模型大小、数据大小和总计算量方面大幅度缩放(数量级),缩放可以大大提高LLM的模型容量。如KM缩放定律、Chinchilla缩放定律。

2、LLM的新兴能力

定义为“在小型模型中不存在但在大型模型中出现的能力”。用于区分LLM与PLM。具体为上下文学习ICL、指令跟随、逐步推理。

3、LLM的关键技术

1)缩放:Transformer语言模型存在明显的缩放效应。如GPT-3和PaLM通过将模型大小分别增加到175B和540B来探索缩放极限。

2)训练:使用分布式训练算法来学习LLM的网络参数,联合使用各种并行策略。

3)能力引发:设计适当的任务指令或特定的上下文学习策略,激发作为通用任务求解器的潜在能力。

4)对齐微调:将LLM与人类价值观对齐,例如有益、诚实和无害。

5)工具操作:利用外部工具来弥补LLM无法捕捉最新信息不足。如外部插件。

方案

本文微调大模型基础:

实现方案

引入unsloth包

%%capture

# Installs Unsloth, Xformers (Flash Attention) and all other packages!

!pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"

!pip install --no-deps "xformers<0.0.27" "trl<0.9.0" peft accelerate bitsandbytes

加载大模型

from unsloth import FastLanguageModel

import torch

max_seq_length = 2048

dtype = None

load_in_4bit = True

model,tokenizer = FastLanguageModel.from_pretrained(

    model_name = "Qwen/Qwen2-1.5B-Instruct",

    max_seq_length = max_seq_length,

    dtype = dtype,

    load_in_4bit = load_in_4bit,

)

Dingtalk_20240817131249.jpg

微调前测试

# 微调前测试

alpaca_prompt="""

下面是描述一个任务,以一个输入然后提供一个回复

### Instruction:

{}

### Input:

{}

### Response:

{}

"""

FastLanguageModel.for_inference(model)

inputs = tokenizer(

    [

        alpaca_prompt.format(

            "", # instruction

            "我花了500块做了个智商测试怎么测出来只有30?", # input

            "", # output

        )

    ], return_tensors = "pt").to("cuda")

from transformers import TextStreamer

text_streamer = TextStreamer(tokenizer)

# _ = model.generate(**inputs, streamer = text_streamer, max_new_tokens = 128)

_ = model.generate(**inputs, streamer = text_streamer, max_new_tokens = 128)

Dingtalk_20240817131257.jpg

准备数据集

# 准备微调数据集

EOS_TOKEN = tokenizer.eos_token # 必须添加 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):

    # 必须添加EOS_TOKEN,否则无限生成

    text = alpaca_prompt.format(instruction, input, output) + EOS_TOKEN

    texts.append(text)

  return {"text":texts,}

pass

from datasets import load_dataset

dataset = load_dataset("logicChen/llama3-test", split="train")

dataset = dataset.map(formatting_prompts_func, batched=True,)

Dingtalk_20240817131307.jpg

设置训练参数

#设置训练参数

from trl import SFTTrainer

from transformers import TrainingArguments

model = FastLanguageModel.get_peft_model(

    model,

    r = 16, # 建议8,16,32,64,128

    target_modules = ["q_proj","k_proj","v_proj","o_proj","gate_proj", "up_proj","down_proj",], # 调整那些层

    lora_alpha = 32,

    lora_dropout = 0.1,

    bias = "none",

    use_gradient_checkpointing = "unsloth", # 检查点,长上下文长度

    random_state = 3407,

    use_rslora = False,

    loftq_config = None,

)

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, # 可以让短序列的训练速度提高5倍

    args = TrainingArguments(

        per_device_train_batch_size = 2,

        gradient_accumulation_steps = 8,

        warmup_steps = 50,

        max_steps = 100, # 微调步数,根据自己的需要设置

        learning_rate = 4e-5, # 学习率 可以调整该值看损失值

        fp16 = not torch.cuda.is_bf16_supported(),

        bf16 = torch.cuda.is_bf16_supported(),

        logging_steps = 5,

        optim = "adamw_8bit",

        weight_decay = 0.01,

        lr_scheduler_type = "cosine",# 根据自己的需要设置不同的值

        seed = 3407,

        output_dir = "outputs",

    ),

)

执行训练

trainer_stats = trainer.train()

2e-4的损失值: Dingtalk_20240817130934.jpg

4e-5的损失值:

Dingtalk_20240817131620.jpg

测试微调后的模型

#测试微调后的模型

FastLanguageModel.for_inference(model)

input_0 = tokenizer(

    [

        alpaca_prompt.format(

            "", # instruction

            "我花了500块做了个智商测试怎么测出来只有30?", # input

            "", # output

        )

    ], return_tensors = "pt").to("cuda")

from transformers import TextStreamer

text_streamer = TextStreamer(tokenizer)


_ = model.generate(**input_0, streamer=text_streamer,max_new_tokens=128)

Dingtalk_20240817132145.jpg 测试结果不尽如意

保存模型

# 保存LoRA模型

model.save_pretrained("lora_model")

#合并模型并量化成4位gguf保存

model.save_pretrained_gguf("model",tokenizer, quantization_method="q4_k_m")

保存到谷歌云盘

from google.colab import drive

  

# Mount your Google Drive.

drive.mount('/content/drive')

  

# Copy the file to your Google Drive.

!cp ./model/unsloth.Q4_K_M.gguf /content/drive/MyDrive

总结

以上就是本地微调大模型的方案,微调后的模型可以下载在本地通过ollama验证测试。

引用