首页 > 教程攻略 > ai资讯 >10G显存,使用Unsloth微调Qwen2并使用Ollama推理

10G显存,使用Unsloth微调Qwen2并使用Ollama推理

来源:互联网 时间:2026-08-24 14:35:25

之前在分享大模型微调实践时,不少朋友问到一个问题:手里的消费级显卡,显存只有10G左右,能不能跑得动7B级别的模型微调?答案是肯定的。今天就来聊聊在魔搭社区的免费算力上,如何借助Unsloth这个框架,基于Qwen2-7B打造一个自定义聊天机器人,再把它导出为GGUF文件,实现在PC端的本地推理。整个过程下来,显存占用控制在10G以内,对硬件的要求相当友好。

10G显存,使用Unsloth微调Qwen2并使用Ollama推理

在魔搭社区免费算力上,仅需要10G显存,使用Unsloth来微调Qwen2创建自定义聊天机器人,并创建GGUF文件,可以在PC端本地运行。

1 Unsloth是什么?

Unsloth是一个专注于预训练模型微调的框架。它最大的亮点是:针对Llama-3、Qwen2、Mistral这些主流模型,微调速度能提升2倍,显存占用可以减少70%。更关键的是,精度不会因此打折扣。

它有几个值得一提的特性:

  • 所有核心算子都用OpenAI的Triton语言编写,效率很高。
  • 准确度损失可以控制在0%,这一点在业界并不多见。
  • 支持4位和16位的QLoRA/LoRA微调,通过bitsandbytes实现。
  • 开源训练速度能提高5倍。
  • 当然,还有一张很酷的贴纸——所有基于Unsloth训练的模型都可以贴上它。

在本教程中,我们将在魔搭社区的免费GPU上,用10G显存来微调Qwen2-7B。

2 Ollama是什么?

Ollama是一款命令行工具,用来运行LLM极其简单,基本上一两条命令就能搞定。用它来构建AI应用,门槛非常低。本文就把Ollama作为最终的推理引擎。

3 环境安装

选择魔搭社区提供的镜像版本,然后安装Unsloth:

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

4 选择需要微调的模型

这次选的是Qwen2-7B。Qwen2是阿里的新一代大语言模型系列,在语言理解、生成、多语言能力、编程、数学、推理等多个基准测试中,整体表现超越了大多数开源模型,甚至在某些维度上可以跟专有模型掰掰手腕。

from unsloth import FastLanguageModel
import torch
from modelscope import snapshot_download

max_seq_length = 2048
dtype = torch.bfloat16
load_in_4bit = True

model_dir=snapshot_download("qwen/Qwen2-7B")
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = model_dir, 
    max_seq_length = max_seq_length,
    dtype = dtype,
    load_in_4bit = load_in_4bit,
)

这里几个参数需要简单说明一下:

max_seq_length = 2048

这个参数决定了模型能看到的上下文长度。Qwen2-7B理论上支持32K的上下文,通过yarn甚至可以扩展到128K。不过这次测试,我们把它设在2048,足够覆盖绝大多数对话场景。

dtype = torch.bfloat16

根据A10 GPU的特性,选择torch.bfloat16来平衡精度和显存。

load_in_4bit = True

这里启用了4位量化来微调。好处很明显——显存占用直接降到原来的四分之一。代价是精度会有所损失,大约1-2%。但对于我们这次对话机器人的场景来说,完全在可接受范围内。

5 微调参数

model = FastLanguageModel.get_peft_model(model,
    r = 16, # Choose any number > 0 ! Suggested 8, 16, 32, 64, 128
    target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",
                      "gate_proj", "up_proj", "down_proj",],
    lora_alpha = 16,
    lora_dropout = 0, # Supports any, but = 0 is optimized
    bias = "none",    # Supports any, but = "none" is optimized
    # [NEW] "unsloth" uses 30% less VRAM, fits 2x larger batch sizes!
    use_gradient_checkpointing = "unsloth", # True or "unsloth" for very long context
    random_state = 3407,
    use_rslora = False,  # We support rank stabilized LoRA
    loftq_config = None, # And LoftQ
)

微调参数设置的目标是提高准确性,同时避免过拟合——过拟合意味着模型只是记住了训练数据,遇到新问题就抓瞎。我们希望模型真正学会“举一反三”。

r = 16, # Choose any number > 0 ! Suggested 8, 16, 32, 64, 128

这是微调过程中的秩(rank)。值越大,占用的内存越多、速度越慢,但复杂任务的准确度可能更高。通常建议从8(快速微调)起步,最高到128。但要注意,过大容易导致过拟合。

target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",
                  "gate_proj", "up_proj", "down_proj",],

这里对所有模块都进行了微调。当然,你可以删掉一些模块来减少内存和加速训练,不过强烈不建议这么做——信息通路被切断,效果多半会打折扣。

lora_alpha = 16,

这是微调的缩放因子。数值越大,微调对数据集的学习程度越深,但也越容易过拟合。一个经验法则是:让它等于秩r,或者翻倍。

lora_dropout = 0, # Supports any, but = 0 is optimized

保留为0,可以加快训练速度。虽然Dropout能防过拟合,但效果有限,这里就不用了。

bias = "none",    # Supports any, but = "none" is optimized

同样保留为none,既快又不容易过拟合。

use_gradient_checkpointing = "unsloth", # True or "unsloth" for very long context

TrueFalse"unsloth"三个选项。强烈推荐"unsloth",因为它能把显存占用再降30%,并且支持极长上下文的微调。

random_state = 3407,

设置随机种子,保证实验可复现。

use_rslora = False,  # We support rank stabilized LoRA

这是一个高级功能,可以自动设置lora_alpha = 16

loftq_config = None, # And LoftQ

另一个高级功能,能把LoRA矩阵初始化为权重的前r个奇异向量,一定程度提升准确度,但一开始会让显存飙升。

6 Prompt模板和数据集

这次使用Qwen-2的chatml格式来进行对话风格的微调。数据集用的是ShareGPT风格的Open Assistant对话数据集。

数据集链接:
https://modelscope.cn/datasets/OmniData/guanaco-sharegpt-style

使用get_chat_template函数来获取正确的聊天模板。这个函数目前支持zephyr、chatml、mistral、llama、alpaca、vicuna等多种模板。

注意,ShareGPT数据集的格式是{"from": "human", "value" : "Hi"},而不是标准的{"role": "user", "content" : "Hi"},所以需要用mapping做一层转换。

from unsloth.chat_templates import get_chat_template

tokenizer = get_chat_template(
    tokenizer,
    chat_template = "chatml", # Supports zephyr, chatml, mistral, llama, alpaca, vicuna, vicuna_old, unsloth
    mapping = {"role" : "from", "content" : "value", "user" : "human", "assistant" : "gpt"}, # ShareGPT style
)

def formatting_prompts_func(examples):
    convos = examples["conversations"]
    texts = [tokenizer.apply_chat_template(convo, tokenize = False, add_generation_prompt = False) for convo in convos]
    return { "text" : texts, }
pass

from modelscope.msdatasets import MsDataset
dataset =MsDataset.load('OmniData/guanaco-sharegpt-style', split = "train")
dataset = dataset.map(formatting_prompts_func, batched = True,)

可以对比一下mapping前后的数据集样式,变化非常直观。

7 训练模型

训练部分,我们使用huggingface的trl库:

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, # Can make training 5x faster for short sequences.
    args = TrainingArguments(
        per_device_train_batch_size = 2,
        gradient_accumulation_steps = 4,
        warmup_steps = 5,
        max_steps = 60,
        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",
    ),
)

大部分参数保持默认即可,但有几个值得专门提一下:

per_device_train_batch_size = 2,

如果想更充分地利用GPU,可以增加批大小。更大的batch通常让训练更稳定,也能减少过拟合的风险。

gradient_accumulation_steps = 4,

这相当于在不增加内存消耗的前提下,把有效批大小翻了几倍。如果你发现训练损失曲线震荡得厉害,增加这个值通常能解决问题。

max_steps = 60, # num_train_epochs = 1,

这里为了快速演示,只跑了60步。如果是完整的训练,建议注释掉max_steps,改用num_train_epochs = 1。通常数据集跑1到3个epoch就够了,再多就容易过拟合。

learning_rate = 2e-4,

想让训练更稳但更慢?调低学习率。这里的典型尝试范围是2e-4、1e-4、5e-5、2e-5。

trainer_stats = trainer.train()

显存占用(使用Unsloth):

8. 推理/运行模型

训练完成后,直接运行模型来看看效果。

from unsloth.chat_templates import get_chat_template

tokenizer = get_chat_template(
    tokenizer,
    chat_template = "chatml", # Supports zephyr, chatml, mistral, llama, alpaca, vicuna, vicuna_old, unsloth
    mapping = {"role" : "from", "content" : "value", "user" : "human", "assistant" : "gpt"}, # ShareGPT style
)

FastLanguageModel.for_inference(model) # Enable native 2x faster inference

messages = [
    {"from": "human", "value": "杭州的省会在哪里?"},
]
inputs = tokenizer.apply_chat_template(
    messages,
    tokenize = True,
    add_generation_prompt = True, # Must add for generation
    return_tensors = "pt",
).to("cuda")

outputs = model.generate(input_ids = inputs, max_new_tokens = 64, use_cache = True)
tokenizer.batch_decode(outputs)

同时也支持流式输出:

FastLanguageModel.for_inference(model) # Enable native 2x faster inference

messages = [
    {"from": "human", "value": "杭州的省会在哪里?"},
]
inputs = tokenizer.apply_chat_template(
    messages,
    tokenize = True,
    add_generation_prompt = True, # Must add for generation
    return_tensors = "pt",
).to("cuda")

from transformers import TextStreamer
text_streamer = TextStreamer(tokenizer, skip_prompt = True)
_ = model.generate(input_ids = inputs, streamer = text_streamer, max_new_tokens = 128, use_cache = True)

9. 保存模型

把微调好的模型保存起来——它会被存成一个约100MB的LoRA小文件。

model.sa ve_pretrained("lora_model") # Local sa ving
tokenizer.sa ve_pretrained("lora_model")

10. 导出至Ollama

最后一步,也是最关键的一步:把微调后的模型导出为GGUF格式。这里选择的量化方法是q4_k_m。想了解更多GGUF的信息,可以看看llama.cpp的官方文档。

if True: model.sa ve_pretrained_gguf("model", tokenizer, quantization_method = "q4_k_m")

11. 自动创建Modelfile

Unsloth在导出GGUF时,会自动生成Ollama所需的Modelfile文件,里边包含了模型路径和微调时使用的聊天模板。可以打印出来看看:

print(tokenizer._ollama_modelfile)

12. 使用Ollama创建和推理模型

Linux环境使用

Linux用户可以直接用魔搭镜像环境安装,非常方便:

git clone https://www.modelscope.cn/modelscope/ollama-linux.git
cd ollama-linux
sudo chmod 777 ./ollama-modelscope-install.sh
./ollama-modelscope-install.sh

启动Ollama服务

ollama serve

创建自定义模型

使用ollama create命令创建自定义模型:

!ollama create unsloth_qwen2 -f /mnt/workspace/model/Modelfile

多轮对话测试

在终端中运行GGUF模型:

ollama run unsloth_qwen2

可以测试一下多轮对话效果,看看模型能否记住上下文。

至此,你已经成功用Unsloth微调了Qwen2基础模型,让它具备了多轮对话能力,并顺利导出到Ollama,可以在本地PC上运行。整个过程显存占用不到10G,在魔搭社区的免费算力上就能轻松完成。