[特殊字符] 大模型对话风格微调项目实战——模型篇 [特殊字符]✨

📜 目录

  • 🎯 背景介绍

  • 🔍 这篇文章的任务

  • 🤖 模型选型

  • 📊 模型评测

  • ⚙️ 模型训练

  • 🔄 模型转换

  • 🧪 模型训练效果评估

  • 🎉 总结


🎯 背景介绍

本文是《大模型对话风格微调项目实战------数据工程篇》的后续文章,介绍了在该项目中如何进行模型的选择、评测、训练和效果评估。


🔍 这篇文章的任务

  1. 模型选型:选择合适的大模型,如GPT-3、BERT等,以及合适的任务,如文本生成、对话生成等。

  2. 模型评测:选择合适的评测指标,如BLEU、ROUGE等,以及合适的评测数据集,如WMT、MTBench等。

  3. 模型训练:对选择的模型进行训练,训练方法使用QLoRA微调,训练数据集使用《数据工程篇》中生成的数据集。

  4. 模型训练效果评估:对训练好的模型进行效果评估,评估方法使用OpenCompass评测框架。然后再进行主观评估。


🤖 模型选型

🧩 大模型选型原则

核心原则:

  • 选择适合任务的模型:根据任务的需求,选择合适的模型。例如,对于对话生成任务,选择适合的对话模型;对于数学推理任务,选择适合的数学模型。

  • 选择合适的语言模型:根据任务的需求,选择合适的语言模型。例如,对于中文任务,选择中文语言模型;对于英文任务,选择英文语言模型。

  • 选择合适的计算资源:根据计算资源的限制,选择合适的模型。例如,对于小批量任务,可以选择较小的模型;对于大规模任务,可以选择较大的模型。

🏆 大模型选型

任务需求分析:

  • 对话风格微调任务

    • 任务类型:对话风格迁移,保持对话内容的不变性,同时调整对话风格为"温柔"或者"毒舌"。

    • 语言要求:中文

  • 训练和推理资源限制

    • 目前可用的训练和推理资源有限

    • 训练显存:24GB

    • 推理显存:16GB

模型选择:基于任务需求和资源限制,选择如下候选模型

  1. qwen2.5-1.5B-Instruct(千问系列)

    • 核心能力:多语言对话与结构化输出

    • 参数规模:15亿参数

    • 突出特性:

      • 支持29种语言跨语言交互

      • 处理32K上下文并生成8K token对话

      • 擅长编程对话和数学推理场景

      • 稳定生成JSON等结构化响应

      • 系统提示适应性强的角色扮演

  2. internlm2_5-1_8b-chat(书生系列)

    • 核心能力:工具调用与复杂任务处理

    • 参数规模:18亿参数

    • 突出特性:

      • 支持多轮工具链式调用

      • 自主完成网页信息搜集与分析

      • MATH评测得分40.2(同量级领先)

      • 增强的指令理解与结果反思

      • 适合多步骤推理的智能体构建


📊 模型评测

🏗️ 评测框架

OpenCompass是一个开放的对话模型评估框架,用于评估对话模型的表现。OpenCompass提供了一系列的对话模型评估指标,包括BLEU、ROUGE、BERTScore等。

📚 评测数据集

根据任务需求,选择CLUE(中文理解)数据集进行模型评测。

  1. FewCLUE_bustm_gen 短文本分类数据集

    • 任务类型:中文自然语言推理(NLI)任务,属于句对分类任务范畴

    • 数据构成:包含160条标注样本及约2万条未标注数据,通过多模板Prompt增强小样本学习效果

    • 技术特征:采用对抗训练、对比学习和Mixup数据增强策略,专门测试模型在挑战性推理对上的表现

    • 应用目标:评估预训练模型在少量样本下的逻辑推理能力及泛化性能

  2. FewCLUE_ocnli_fc_gen 中文自然语言推理数据集

    • 任务类型:中文短文本匹配任务,属于二分类句对判断任务

    • 数据构成:遵循统一标准配置,包含等量的标注样本(160条)与未标注数据(约2万条)

    • 技术特征:应用相同的多模板Prompt框架,结合对抗训练提升模型鲁棒性

    • 应用目标:验证模型在极低资源场景下的语义匹配能力与迁移学习效果

⚙️ 进行评测

安装OpenCompass评测框架
复制代码
conda create -n opencompass python=3.10 -y
conda activate opencompass
git clone -c http.proxy=http://127.0.0.1:7890 https://github.com/open-compass/opencompass opencompass
cd opencompass
pip install -e .
下载模型
复制代码
# 下载qwen2.5-1.5b-instruct模型
modelscope download --model Qwen/Qwen2.5-1.5B-Instruct --cache_dir /mnt/model
​
# 下载internlm2_5-1_8b-chat模型
modelscope download --model Shanghai_AI_Laboratory/internlm2_5-1_8b-chat --cache_dir /mnt/model
运行评测
复制代码
python run.py \
    --models hf_qwen2_5_1_5b_instruct hf_internlm2_5_1_8b_chat \
    --datasets fewclue_bustm_gen fewclue_ocnli_fc_gen \
    --debug
​
# 推理框架加速模型评估(可选)
python run.py \
    --models lmdeploy_qwen2_5_1_5b_instruct lmdeploy_internlm2_5_1_8b_chat \
    --datasets fewclue_bustm_gen fewclue_ocnli_fc_gen \
    --debug

📈 评测结果

dataset version metric mode qwen2.5-1.5b-instruct-hf internlm2_5-1_8b-chat-hf
ocnli_fc-dev 51e956 accuracy gen 63.12 58.13
ocnli_fc-test 51e956 accuracy gen 60.60 58.06

从评测结果可以看出,qwen2.5-1.5b-instruct模型在FewCLUE_ocnli_fc_gen数据集上的表现比internlm2_5-1_8b-chat模型好。

🏆 模型选择

根据评测结果,选择qwen2.5-1.5b-instruct作为基座模型。


⚙️ 模型训练

🛠️ 微调框架选择

  1. Llama-factory

    • Llama-factory是一个开源的微调框架,用于微调大语言模型。

    • 提供了一系列的微调方法,包括QLoRA、P-Tuning、Prefix Tuning等。

  2. XTuner

    • XTuner是一个开源的微调框架,用于微调大语言模型。

    • 相对于Llama-factory,XTuner的微调方法更加灵活,支持更多的微调方法。

    • 可以在微调过程中直观的进行主观评估。

由于该项目对微调结果的评估方式主要为主观评估,所以选择XTuner作为微调框架。

📥 XTuner安装

复制代码
conda create -n xtuner python=3.10 -y
conda activate xtuner
git clone -c http.proxy=http://127.0.0.1:7890 https://github.com/InternLM/xtuner.git
cd xtuner/
pip install torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 --index-url https://download.pytorch.org/whl/cu121 --proxy=http://127.0.0.1:7890
pip install -e .

🔧 微调方法选择

  1. LoRA

    • 核心思想:低秩分解(Low-Rank Decomposition):将原始的大矩阵分解为两个低秩矩阵的乘积,其中一个矩阵的秩远小于原始矩阵的秩。
  2. QLoRA

    • 相对于LoRA,QLoRA在训练过程中进行了量化,减少了内存占用和计算量。

本项目中选择QLoRA作为微调方法。

📊 训练数据预处理

在《数据工程篇》生成的数据是csv格式,需要将其转换为XTuner支持的json格式。并且将其分为训练集、测试集和验证集。转换脚本如下:

复制代码
import csv
import json
import random
​
def convert_csv_to_json(csv_file_path, train_json_path, test_json_path, val_json_path):
    # 读取CSV文件
    with open(csv_file_path, 'r', encoding='utf-8') as csv_file:
        csv_reader = csv.DictReader(csv_file)
        data = list(csv_reader)
    
    # 随机打乱数据
    random.shuffle(data)
    
    # 分割数据集
    total = len(data)
    train_size = int(total * 0.8)
    remaining = total - train_size
    
    train_data = data[:train_size]
    test_data = data[train_size:train_size + remaining//2]
    val_data = data[train_size + remaining//2:]
    
    # 转换格式并保存训练集
    train_result = []
    for row in train_data:
        conversation = {
            "conversation": [
                {
                    "input": row["user"],
                    "output": f"{row['style']}\n{row['assistant']}"
                }
            ]
        }
        train_result.append(conversation)
    
    with open(train_json_path, 'w', encoding='utf-8') as json_file:
        json.dump(train_result, json_file, ensure_ascii=False, indent=2)
    
    # 转换格式并保存测试集
    test_result = []
    for row in test_data:
        conversation = {
            "conversation": [
                {
                    "input": row["user"],
                    "output": f"{row['style']}\n{row['assistant']}"
                }
            ]
        }
        test_result.append(conversation)
    
    with open(test_json_path, 'w', encoding='utf-8') as json_file:
        json.dump(test_result, json_file, ensure_ascii=False, indent=2)
    
    # 转换格式并保存验证集
    val_result = []
    for row in val_data:
        conversation = {
            "conversation": [
                {
                    "input": row["user"],
                    "output": f"{row['style']}\n{row['assistant']}"
                }
            ]
        }
        val_result.append(conversation)
    
    with open(val_json_path, 'w', encoding='utf-8') as json_file:
        json.dump(val_result, json_file, ensure_ascii=False, indent=2)
​
if __name__ == "__main__":
    input_csv = "style_chat_data.csv"
    train_json = "train.json"
    test_json = "test.json"
    val_json = "val.json"
    
    convert_csv_to_json(input_csv, train_json, test_json, val_json)
    print(f"转换完成,结果已保存到 {train_json}, {test_json}, {val_json}")

该脚本能够将style_chat_data.csv文件中的数据按80%训练集、10%测试集和10%验证集的比例分割,并转换为指定的JSON格式。脚本会生成train.json、test.json和val.json三个文件。转换后的json文件部分内容如下:

复制代码
[
  {
    "conversation": [
      {
        "input": "有家的感觉,喜欢!",
        "output": " 温柔\n 太好了呢!能给你带来温暖和安慰,我也很开心💖。有什么想聊的话题都可以和我分享哦。"
      }
    ]
  },
  {
    "conversation": [
      {
        "input": "有家的感觉,喜欢!",
        "output": " 温柔\n 太好了呢!我很高兴能给你带来温暖和安慰,如果有任何问题,随时告诉我哦~💖"
      }
    ]
  }
]

⚙️ 训练参数设置

模型设置

  • pretrained_model_name_or_path 模型路径:/mnt/model/Qwen/Qwen2___5-1___5B-Instruct

训练集设置

  • data_files 训练集路径:/mnt/datas/output.json

  • max_length 最大长度:256

训练参数设置

  • batch_size 批次大小:20

  • max_epochs 最大迭代次数:10000

验证问题设置

  • evaluation_inputs 验证问题设置(从验证集里随机选择10个问题):

    复制代码
    工作忙的没有私人时间,生活已经变得不会再幸福了。
    进医院你陪钱
    那个社长明信片还没收到么
    老林有对象我都替他开心
    静静的校园真美,羡慕
    穿这衣服,会被人领走的
    外星人还有台式呢?
    今天都没来道早安作业一大堆啊写死了
    居然有情人一起回去
    狗东西吃这么好

训练策略设置

  • quantization_config 量化配置:

    • load_in_4bit:False (禁用4位量化)

    • load_in_8bit:True (启用8位量化)

  • lora LoRA配置:

    • r:64

    • lora_alpha:128

数据配置

  • dataset 数据集配置:

    • type:load_dataset

    • path:json

    • data_files:data_files

  • dataset_map_fn 数据集映射函数配置:None

🚀 开始训练

将上面的参数保存到配置文件中,然后使用以下命令开始训练:

复制代码
xtuner train qwen2_5_1_5b_chat_qlora_alpaca_e3.py

下面内容分别显示训练前期,中期和后期的验证集测试效果:

训练前期:

复制代码
用户输入:穿这衣服,会被人领走的
模型输出:这衣服,会被人领走的,这句话可能是在提醒你注意自己的穿着,避免引起不必要的注意。如果你指的是某种特定的场合或环境,可能需要根据实际情况来决定是否穿得过于暴露或吸引人。在公共场合,保持适当和尊重他人的穿着是很重要的。
​
用户输入:外星人还有台式呢?
模型输出:外星人可能没有台式电脑,因为他们的科技水平和我们完全不同。他们可能使用更先进的设备,比如光子计算机或者量子计算机。不过,这只是一个假设,因为我们目前还没有发现外星人。
​
用户输入:今天都没来道早安作业一大堆啊写死了
模型输出:今天没来道早安作业,感觉好累啊。写得太多了,是不是有点超负荷了呢?别担心,慢慢来,休息一下,调整一下状态,明天继续加油哦!
​
用户输入:居然有情人一起回去
模型输出:起来像是在描述一段感情的结束,你是否需要一些安慰或建议?

此时模型的输出完全没有我们需要的风格,所以需要进行微调。

训练中期:

复制代码
用户输入:穿这衣服,会被人领走的
模型输出: 温柔
穿得这么漂亮,一定很自信呢!别担心,你很吸引人的。
​
用户输入:外星人还有台式呢?
模型输出: 外星人当然有台式电脑啦!他们可能有自己的科技,但人类的台式电脑也是他们了解我们文明的重要工具呢。你有没有什么关于外星人的有趣故事想分享呢?
​
用户输入:今天都没来道早安作业一大堆啊写死了
模型输出: 毒舌
6,你这是在用早安作业当早安吗?栓Q,别累着自己,早点休息,明天精神点!🔥
​
用户输入:居然有情人一起回去
模型输出: 毒舌
6,你这是在上演《情书》里的剧情吗?栓Q,别让爱情耽误了回家的路。

此时模型的输出已经有了我们需要的风格,但是还是有一些问题,所以需要继续微调。

训练后期:

复制代码
用户输入:穿这衣服,会被人领走的
模型输出: 温柔
 这句话听起来你有点担心自己的穿着哦。但重要的是你穿得开心啦!🌸你喜欢什么样的风格呀?
​
用户输入:外星人还有台式呢?
模型输出: 温柔
 外星人通常是指外星生物,它们的设计和外观可能与地球人不同,至于"台式"是哪个词呢?如果你感到困惑,我可以帮你查查相关信息哦。🤔💖
​
用户输入:今天都没来道早安作业一大堆啊写死了
模型输出: 温柔
 哎呀,听起来你今天真的很忙呢。工作虽然忙但记得也要照顾好自己哦,休息很重要。如果需要帮忙或者想聊聊天,我都在这里。加油!💖
​
用户输入:居然有情人一起回去
模型输出: 温柔
 那真是一件幸福的事情呢!希望你们之间的感情永远像现在一样美好哦~💖

此时模型的输出已经完全符合我们需要的风格,可以停止训练。

📉 训练loss曲线

可以看到在训练轮次达到2000左右时,模型的loss曲线开始收敛,并且loss值在0.07左右。

在训练过程中中断了一次,所以loss曲线有一个小的向上尖峰。


🔄 模型转换

XTuner训练的权重是pth格式的,需要将其转换为huggingface格式。

使用以下命令将模型转换为huggingface格式:

复制代码
xtuner convert pth_to_hf \
    /mnt/xtuner/qwen2_5_1_5b_chat_qlora_alpaca_e3.py \
    /mnt/xtuner/work_dirs/qwen2_5_1_5b_chat_qlora_alpaca_e3/iter_24500.pth \
    /mnt/xtuner/work_dirs/qwen2_5_1_5b_chat_qlora_alpaca_e3/iter_24500

🤝 合并模型

转换完成后,需要和基座模型进行合并,得到最终的模型。

使用以下命令合并模型:

复制代码
xtuner convert merge \
    /mnt/model/Qwen/Qwen2___5-1___5B-Instruct \
    /mnt/xtuner/work_dirs/qwen2_5_1_5b_chat_qlora_alpaca_e3/iter_24500 \
    /mnt/model/Qwen/Qwen2___5-1___5B-Instruct_Merge

🧪 模型训练效果评估

下面我们可以对微调后的模型进行测评。测评方法为主观评测。

先使用以下命令运行模型:

复制代码
lmdeploy chat \
  --chat-template /mnt/datas/chat_template.json \
  /mnt/model/Qwen/Qwen2___5-1___5B-Instruct_Merge

然后使从测试集内随机选择10个问题,进行测试。以下是部分测试结果:

复制代码
问:谢谢你,陪在我身边,一句好朋友。我们一起努力
答: 温柔
 谢谢你,我的朋友💖 我们都会一起加油,向着更好的未来前进!🌸
​
问:看看哪能淘个护士给你吧
答: 毒舌
 栓Q,你这是想把我培养成医院吉祥物啊?6到飞起!🔥蚌埠住了,其实医生太忙,需要休息。
​
问:和老师的发型显老
答: 温柔
 每个人的风格都有独特的韵味呢,不必太在意啦。老师的发型可能更添成熟魅力哦。💖
​
问:那个三色丸子是不是不好吃?
答: 毒舌
 好家伙,你吃的不是丸子,是悲伤的五彩斑斓球啊,栓Q,下次我请你去吃大当家。🥢🔥
​
问:走,去北极
答: 温柔
 哇,去北极探险听起来好刺激呀!但记得保暖哦,我没有耳朵的地方你可以想象一下。😊🌸

🎉 总结

本文详细介绍了大模型对话风格微调项目的完整流程,包括模型选型、评测、训练和效果评估。项目选用Qwen2-1.5B模型,通过XTuner框架进行QLoRA微调,成功实现了"温柔"和"毒舌"两种对话风格的迁移,并通过主观评测验证了微调效果。


💬 你对大模型对话风格微调有什么看法?欢迎在评论区留言讨论! 🎤

相关推荐
hello_ejb35 分钟前
聊聊Spring AI Alibaba的ObsidianDocumentReader
java·人工智能·spring
桥Dopey18 分钟前
Python常用的第三方模块之【jieba库】支持三种分词模式:精确模式、全模式和搜索引擎模式(提高召回率)
人工智能·python·分词模式
W流沙W18 分钟前
bert学习
人工智能·bert
想学好英文的ikun1 小时前
【MCP】第二篇:IDE革命——用MCP构建下一代智能工具链
ide·人工智能·python·ai·个人开发·mcp
袁袁袁袁满1 小时前
《巧用DeepSeek快速搞定数据分析》书籍分享
数据挖掘·数据分析
柏木乃一1 小时前
多态以及多态底层的实现原理
数据结构·c++·算法·stl·多态·虚函数表
码上飞扬1 小时前
深度剖析:GPT-3.5与GPT-4的主要区别及架构解析
人工智能
whuzhang161 小时前
3DGS之齐次坐标
人工智能·3d·自动驾驶
闭月之泪舞2 小时前
《深度神经网络之数据增强、模型保存、模型调用、学习率调整》
人工智能·学习·dnn
Aqua Cheng.2 小时前
25.4.22华为--算法真题整理(2025年4月22日)
java·算法·leetcode·华为·面试