unsloth微调Qwen3实现知识总结

最近在rk上玩了一下部署Qwen3-1.7B 实现知识点内容总结,效果勉强还看得过去。打算微调一下0.6B的模型,降低部署成本的同时得到更好的总结效果。

1. 数据准备

之前有一批ASR提取的视频语音文本数据,我把提取出的多个文本内容合并到一个json文件中大致结构如下图

剩下的就很简单了,找一个好一点的模型让它总结知识点作为输出。这里构建数据集采用的是Alpaca格式,然后用Go写了一个调用百炼api的代码,最后得到最终训练数据集。

go 复制代码
const (
    inFile       = "./all_texts.json"
    outFile      = "./ft_data.json"
    apiURL       = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions"
    token        = "百炼的api-key"
    model        = "qwen3-235b-a22b"
    systemPrompt = "你是一个内容知识点总结专家,你需要从大段文字中提炼出核心知识点内容并返回,请注意返回的内容不得超过20个字"
    apiKey       = "Bearer " + token
)
​
​
func post(text string) {
    userMessage := Message{Role: "user", Content: text}
    InstructionMessage := Message{Role: "system", Content: systemPrompt}
    query := Query{
        Model:          model,
        Messages:       []Message{InstructionMessage, userMessage},
        EnableThinking: false,
    }
    queryJSON, _ := json.Marshal(query)
    option := &grequests.RequestOptions{
        JSON:    queryJSON,
        Headers: Headers,
    }
​
    resp, err := grequests.Post(context.Background(), apiURL, grequests.FromRequestOptions(option))
    if resp.StatusCode == http.StatusOK {
        fmt.Println(resp)
        if err != nil {
            fmt.Println(err)
        }
​
        var result Response
        if err := json.Unmarshal(resp.Bytes(), &result); err != nil {
            fmt.Println(err)
        }
        output := OutItem{
            Instruction: systemPrompt,
            Input:       text,
            Output:      result.Choices[0].Message.Content,
        }
        outChannel <- output
    }
}
​
func main() {
    defer goPool.Release()
    var wg sync.WaitGroup
    for _, inText := range inTexts {
        wg.Add(1)
        _ = goPool.Submit(func() {
            defer wg.Done()
            post(inText.Text)
        })
    }
​
    go func() {
        wg.Wait()
        close(outChannel)
    }()
​
    var results []OutItem
    for o := range outChannel {
        results = append(results, o)
    }
​
    outRaw, _ := json.MarshalIndent(results, "", "  ")
    _ = os.WriteFile(outFile, outRaw, 0o644)
}

这里antsgoroutine池大小不能太大,不然会触发限流。总的来说请求响应还是很快的,最后得到了训练数据集,大概长这个样子

2. 利用unsloth微调

unsloth其实有非常好的文档来实现简单的QLora微调,可以参考示例。唯一美中不足的就是unsloth开源版本并不支持单机多卡训练,不过还好有些开源补丁或者开源分支实现了单机多卡训练,这里我就拿unsloth-multigpu举例(下文称为multi)。由于multi利用补丁实现,所以几乎不影响原本的unsloth微调代码,只需要引入multi的hook就可以实现多卡训练。但是就今天的使用来说,由于作者一直在更新,所以感觉api并不稳定,给出示例中的许多api和最新版本的貌似不匹配。不过家里也只有一张显卡,所以先用unsloth微调试试,等回公司再试试加上multi训练。微调的大致代码如下

ini 复制代码
model, tokenizer = FastLanguageModel.from_pretrained(
    "../Qwen3-0.6B",
    max_seq_length = 2048,
    dtype = torch.bfloat16,
    load_in_4bit = True
)
​
model = FastLanguageModel.get_peft_model(
    model,
    r=16,  # LoRA rank
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],
    lora_alpha=16,
    lora_dropout=0,
    bias="none",
    use_gradient_checkpointing="unsloth",
    random_state=2025,
    use_rslora=False,
    loftq_config=None,
)
​
training_args = TrainingArguments(
    output_dir="./runs",
    dataloader_num_workers=4,
    num_train_epochs=30,
    per_device_train_batch_size=8,
    gradient_accumulation_steps=1,
    learning_rate=1e-4,
    bf16=True,
    logging_steps=10,
    save_strategy="epoch",
    warmup_ratio=0.1,
    optim = "adamw_8bit",
    lr_scheduler_type = "linear",
    weight_decay=0.01,  # Weight decay
    max_grad_norm=1.0,  # Gradient clipping
    report_to = "tensorboard"
)
​
trainer = SFTTrainer(
    model=model,
    train_dataset=train_dataset,
    args=training_args,
)
​
logger.info("Starting training...")
trainer_stats = trainer.train()
logger.info("Training complete!")
logger.info(f"Training statistics: {trainer_stats}")
model.save_pretrained_merged("finetune_0.6B", tokenizer, save_method = "merged_16bit")

其中lora相关、epochs等训练参数都没怎么特殊设置,微调过程截图

3. 推理结果对比

输入相同的内容送入原始0.6B模型和0.6B微调后的模型分别进行推理,对比二者输出

swift 复制代码
[
    {
        "origin_outputs": "\n\n核心知识点提炼:电极反应式书写步骤(正负极判断、离子移动口诀、调频电荷、配平、总反应等)\n</think>\n\n电极反应式书写方法",
        "ft_outputs": "assistant\n<think>\n\n</think>\n\n电极反应式书写方法:正负极判断、电极反应架构书写、电荷移动及总反应式书写。"
    },
    {
        "origin_outputs": "\n\n好的,我需要将用户提供的关于二战的详细内容提炼出核心知识点,不超过20个字。首先,用户的内容涵盖了二战的起因、过程、关键事件和相关理论。核心点包括:德国在1939年入侵波兰,英法宣战,二战爆发,以及相关的历史事件和理论。\n\n需要确保提炼的内容准确且简洁,同时涵盖主要知识点。检查是否有重复或冗余的信息。例如,用户提到了丘吉尔的批评和慕尼黑协议,以及地理学理论的影响。但核心知识点应聚焦于时间线和关键事件",
        "ft_outputs": "\n\n</think>\n\n第二次世界大战爆发及转折点"
    },
    {
        "origin_outputs": "\n\n好的,用户发来的是关于酸碱中和滴定图像题的课程内容介绍。需要从大段文字中提炼核心知识点,不超过20个字。\n\n首先,用户提到"延续上一节课",说明这节课是继续之前的课程内容。接着提到"图像题",所以核心知识点应该是关于酸碱中和滴定图像题的内容。需要简明扼要地总结,确保不超过字数限制。\n\n可能的提炼是:"酸碱中和滴定图像题教学"。检查字数,刚好20个字,符合要求。确认没有冗余信息,",
        "ft_outputs": "assistant\n<think>\n\n</think>\n\n酸碱中和滴定图像题知识点总结。"
    },
    {
        "origin_outputs": "\n\n答案:\n20字\n</think>\n\n20字",
        "ft_outputs": "\n\n</think>\n\n借鉴名句修辞手法,增强文采与说服力。"
    }
]

我在apply_chat_template中已经设置了enable_thinking=False,但原始的0.6B还是会出现思考甚至莫名奇妙的答案,相比而言微调后的输出就正常许多。

相关推荐
数据科学作家2 小时前
学数据分析必囤!数据分析必看!清华社9本书覆盖Stata/SPSS/Python全阶段学习路径
人工智能·python·机器学习·数据分析·统计·stata·spss
CV缝合救星3 小时前
【Arxiv 2025 预发行论文】重磅突破!STAR-DSSA 模块横空出世:显著性+拓扑双重加持,小目标、大场景统统拿下!
人工智能·深度学习·计算机视觉·目标跟踪·即插即用模块
TDengine (老段)5 小时前
从 ETL 到 Agentic AI:工业数据管理变革与 TDengine IDMP 的治理之道
数据库·数据仓库·人工智能·物联网·时序数据库·etl·tdengine
蓝桉8025 小时前
如何进行神经网络的模型训练(视频代码中的知识点记录)
人工智能·深度学习·神经网络
星期天要睡觉6 小时前
深度学习——数据增强(Data Augmentation)
人工智能·深度学习
南山二毛7 小时前
机器人控制器开发(导航算法——导航栈关联坐标系)
人工智能·架构·机器人
大数据张老师7 小时前
【案例】AI语音识别系统的标注分区策略
人工智能·系统架构·语音识别·架构设计·后端架构
xz2024102****7 小时前
吴恩达机器学习合集
人工智能·机器学习
anneCoder7 小时前
AI大模型应用研发工程师面试知识准备目录
人工智能·深度学习·机器学习
骑驴看星星a7 小时前
没有深度学习
人工智能·深度学习