ChatGLM3-6B-128K模型微调实战:从零开始训练专属模型

1. 引言

想不想让AI模型真正懂你的业务?当你发现通用大模型回答不了专业问题,或者总是给出不太对劲的回复时,模型微调就是你的解决方案。今天我们就来手把手教你如何用自定义数据训练一个专属的ChatGLM3-6B-128K模型。

ChatGLM3-6B-128K是ChatGLM系列中的长文本专家,特别擅长处理长达128K上下文的复杂对话。这意味着它不仅能记住更多的对话历史,还能理解更长的文档内容。通过微调,你可以让这个强大的模型学会你的专业术语、业务逻辑和回答风格。

不需要高深的机器学习知识,跟着本文的步骤,你就能训练出属于自己的智能助手。我们将从数据准备开始,一步步带你完成整个微调过程,最后还会教你如何评估模型效果。

2. 环境准备与快速部署

2.1 硬件要求

在开始之前,先确认你的设备是否满足基本要求。ChatGLM3-6B-128K对硬件的要求相对友好:

  • 内存:至少16GB RAM(推荐32GB)
  • 显存:至少13GB(RTX 4080 16GB或同等级别显卡)
  • 存储:20GB可用空间(用于存储模型和训练数据)

如果你没有足够的本地资源,也可以考虑使用云平台提供的GPU实例,很多平台都预装了深度学习环境,开箱即用。

2.2 环境配置

首先我们需要安装必要的Python包。建议使用conda创建独立的虚拟环境:

conda create -n chatglm_finetune python=3.10
conda activate chatglm_finetune

然后安装核心依赖:

pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install transformers datasets peft accelerate

这些包分别负责深度学习计算、模型加载、数据处理和高效训练。如果你在使用云平台,这些环境可能已经预装好了。

2.3 模型下载

接下来下载ChatGLM3-6B-128K的模型文件。你可以从Hugging Face模型库获取:

from transformers import AutoModel, AutoTokenizer

model_path = "THUDM/chatglm3-6b-128k"
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
model = AutoModel.from_pretrained(model_path, trust_remote_code=True)

首次运行时会自动下载模型文件,大小约12GB,下载时间取决于你的网络速度。如果下载中断,可以设置resume_download=True来续传。

3. 数据准备与格式化

3.1 数据格式要求

训练数据的质量直接决定微调效果。ChatGLM3-6B-128K需要特定格式的训练数据,通常使用JSONL文件(每行一个JSON对象):

{"prompt": "用户问题或指令", "response": "期望的模型回答"}
{"prompt": "另一个问题", "response": "对应的回答"}

每个样本包含一个prompt(输入)和response(输出)。prompt可以是问题、指令或对话上下文,response是你期望模型生成的理想回答。

3.2 数据收集建议

根据你的使用场景,收集合适的数据:

  • 客服场景:收集历史客服对话记录
  • 专业知识:整理常见问题与标准答案
  • 创意写作:准备范文和写作提示
  • 代码生成:收集代码片段和对应描述

数据量不需要很大,通常100-1000个高质量样本就能看到明显效果。质量远比数量重要,确保每个回答都是准确、专业的。

3.3 数据预处理

使用以下代码将你的数据转换为训练格式:

import json

def prepare_data(input_file, output_file):
    with open(input_file, 'r', encoding='utf-8') as fin, \
         open(output_file, 'w', encoding='utf-8') as fout:
        
        for line in fin:
            # 根据你的数据格式进行解析
            data = json.loads(line)
            prompt = data['question']  # 根据实际字段名调整
            response = data['answer']
            
            # 转换为标准格式
            formatted_data = {
                "prompt": prompt,
                "response": response
            }
            fout.write(json.dumps(formatted_data, ensure_ascii=False) + '\n')

# 使用示例
prepare_data('raw_data.jsonl', 'formatted_data.jsonl')

记得检查生成的文件,确保格式正确且没有乱码。

4. 训练参数配置

4.1 基础参数设置

微调的核心是找到合适的训练参数。下面是一个推荐的配置:

from transformers import TrainingArguments

training_args = TrainingArguments(
    output_dir="./chatglm3-finetuned",
    per_device_train_batch_size=2,
    gradient_accumulation_steps=8,
    learning_rate=2e-5,
    num_train_epochs=3,
    logging_steps=10,
    save_steps=500,
    fp16=True,
    remove_unused_columns=False,
)

这些参数的含义:

  • per_device_train_batch_size:每个设备的批次大小,根据显存调整
  • gradient_accumulation_steps:梯度累积步数,模拟更大的批次
  • learning_rate:学习率,微调时通常设置较小
  • num_train_epochs:训练轮数,3-5轮通常足够

4.2 关键参数详解

学习率选择

  • 太大:可能导致训练不稳定,损失震荡
  • 太小:训练过慢,可能无法充分学习
  • 推荐范围:1e-5到5e-5

批次大小调整: 如果遇到显存不足,可以减小per_device_train_batch_size并增加gradient_accumulation_steps来保持总批次大小不变。

4.3 高效训练技巧

使用PEFT(Parameter-Efficient Fine-Tuning)技术可以大幅降低显存需求:

from peft import LoraConfig, get_peft_model

lora_config = LoraConfig(
    r=8,
    lora_alpha=32,
    target_modules=["query_key_value"],
    lora_dropout=0.1,
    bias="none",
    task_type="CAUSAL_LM"
)

model = get_peft_model(model, lora_config)
model.print_trainable_parameters()

这种方法只训练少量参数,却能获得接近全参数微调的效果,显存需求降低60%以上。

5. 开始训练

5.1 训练脚本编写

现在让我们把所有的组件组合起来:

from transformers import Trainer, DataCollatorForSeq2Seq

# 加载数据
with open('formatted_data.jsonl', 'r', encoding='utf-8') as f:
    data = [json.loads(line) for line in f]

# 数据预处理函数
def preprocess_function(examples):
    texts = []
    for example in examples:
        text = f"[INST] {example['prompt']} [/INST] {example['response']}"
        texts.append(text)
    return tokenizer(texts, truncation=True, max_length=4096)

# 应用预处理
processed_data = preprocess_function(data)

# 创建Trainer
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=processed_data,
    data_collator=DataCollatorForSeq2Seq(
        tokenizer, pad_to_multiple_of=8, return_tensors="pt", padding=True
    ),
)

# 开始训练
trainer.train()

训练过程中会显示进度条和损失值。如果一切正常,你应该看到损失值逐渐下降。

5.2 训练监控

训练时关注这些指标:

  • 损失值:应该稳步下降然后趋于平稳
  • 学习率:如果使用调度器,会按计划变化
  • 显存使用:确保没有超出显卡限制

如果损失值震荡很大,可以尝试降低学习率或增加批次大小。

5.3 中间检查点

训练过程中会定期保存检查点:

chatglm3-finetuned/
├── checkpoint-500/
├── checkpoint-1000/
└── ...

你可以加载任意检查点进行测试:

from peft import PeftModel

model = PeftModel.from_pretrained(model, "./chatglm3-finetuned/checkpoint-500")

这样可以在训练过程中及时评估效果,避免过度训练。

6. 模型评估与测试

6.1 基础测试方法

训练完成后,让我们测试模型效果:

def test_model(query):
    inputs = tokenizer.encode(f"[INST] {query} [/INST]", return_tensors="pt")
    outputs = model.generate(
        inputs,
        max_length=2048,
        temperature=0.7,
        do_sample=True,
        top_p=0.9
    )
    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    return response.split("[/INST]")[-1].strip()

# 测试几个样例
test_queries = [
    "你的主要功能是什么?",
    "请解释一下深度学习的基本概念",
    # 添加你的领域特定问题
]

for query in test_queries:
    response = test_model(query)
    print(f"问:{query}")
    print(f"答:{response}")
    print("-" * 50)

观察模型的回答是否准确、相关,是否符合你的期望。

6.2 评估指标

除了人工评估,还可以使用一些量化指标:

from rouge import Rouge

def evaluate_rouge(predictions, references):
    rouge = Rouge()
    scores = rouge.get_scores(predictions, references, avg=True)
    return scores

# 使用示例
predictions = ["模型生成的回答"]
references = ["标准答案"]
rouge_scores = evaluate_rouge(predictions, references)
print(f"ROUGE分数: {rouge_scores}")

ROUGE分数越高,说明生成内容与参考答案越相似。

6.3 常见问题排查

如果效果不理想,可以检查:

  1. 数据质量:样本是否足够代表真实场景
  2. 数据量:是否需要增加训练样本
  3. 训练参数:学习率是否合适,训练轮数是否足够
  4. 过拟合:在训练集上表现很好,但测试集表现差

适当调整这些因素,重新训练直到获得满意结果。

7. 模型部署与应用

7.1 模型保存与加载

训练完成后,保存最终模型:

# 保存完整模型
model.save_pretrained("./final_chatglm3_model")

# 如果使用LoRA,合并权重后保存
merged_model = model.merge_and_unload()
merged_model.save_pretrained("./merged_chatglm3_model")

加载模型进行推理:

from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained(
    "./final_chatglm3_model",
    trust_remote_code=True,
    device_map="auto"
)

7.2 简单部署示例

创建一个简单的Web服务:

from flask import Flask, request, jsonify
import torch

app = Flask(__name__)

@app.route('/chat', methods=['POST'])
def chat():
    data = request.json
    query = data.get('query', '')
    
    # 生成回答
    inputs = tokenizer.encode(query, return_tensors="pt")
    with torch.no_grad():
        outputs = model.generate(inputs, max_length=1024)
    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    
    return jsonify({'response': response})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

这样你就可以通过API调用来使用微调后的模型了。

7.3 性能优化建议

为了提升推理速度:

# 使用半精度推理
model.half()

# 使用缓存加速重复计算
model.config.use_cache = True

# 批量处理请求
def batch_generate(queries):
    inputs = tokenizer(queries, padding=True, return_tensors="pt")
    with torch.no_grad():
        outputs = model.generate(**inputs, max_length=1024)
    return [tokenizer.decode(output, skip_special_tokens=True) for output in outputs]

这些优化可以显著提升模型响应速度。

8. 总结

通过本文的实践,你应该已经成功微调了自己的ChatGLM3-6B-128K模型。整个过程从环境准备开始,经历了数据准备、参数配置、训练执行到最后的评估部署。

微调后的模型最大的优势是真正理解你的专业领域,能够用你的业务语言进行交流。无论是客服问答、技术咨询还是内容创作,它都能提供更精准、更相关的回答。

在实际应用中,你可能需要持续收集用户反馈,定期用新的数据重新训练模型,这样才能保持模型的准确性和时效性。记住,模型微调不是一劳永逸的,而是一个持续优化的过程。

如果遇到问题,不要气馁。调整数据、修改参数、多尝试几次,总能找到适合你场景的最佳配置。毕竟,最好的模型不是一次训练出来的,而是不断迭代优化出来的。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐