来自知识星球

基于LoRA训练及部署3GPP规范问答大模型详细指南

您有没有这样的痛点?
下载了几百本规范,不知道看哪个?
用搜索方式去搜关键字,搜出来还是看不懂?
想不想用下载的1000本规范作为训练数据,去训练一个属于自己的3GPP规范大模型?


如果您有这样的痛点,那得去看我们的另一篇文章,本文就不太适合您了。本文的解决方案是LORA。
LORA不能独立存在,还需要一个基础大模型(比如Deepseek来打底)。
不管是本地部署,还是用云端GPU,成本都非个人所能承担。如果是1000本规范,那就最好用RAG了。
以后单独发文。
LORA当然也能训练1000本规范,但会血亏。
• 本文主要解决一个什么痛点呢?
• 假设我不需要训练1000本规范,我就想训练1本规范23.501(5G网元、功能、架构、特性),最新版
的R18.9的23.501规范,2025年3月发布,63万字,319万字符,训练可是按319万字符收费哦。
• 那您可以考虑本文的方案,这时候LORA的性价比就比RAG可能要高了。

针对单一规范(23.501)的解决方案
针对只关注23.501这一本规范的情况,对于这种情况,LoRA微调确实可能比RAG更有性价比。
LoRA微调方案
• 一次训练后可离线使用,不需持续检索
• 对单一文档(30万字)的训练成本可接受
• 可能对3GPP特定术语和表达有更好理解
具体实施步骤
1. 准备训练数据
1. 将23.501 PDF转换为纯文本
2. 构建问答对数据集:
- 从目录提取主题创建问题
- 从章节内容生成答案
- 创建200-300个高质量QA对
2. 选择基础模型
- Qwen2-7B或ChatGLM3-6B(中文支持较好)
- Llama-3-8B-Instruct(如需平衡中英文能力)
3. LoRA训练配置
- rank: 8-16
- alpha: 16-32
- 学习率: 2e-4到5e-4
- epochs: 3-5
4. 硬件需求
- 最低: 16GB显存GPU(如RTX 3090/4070Ti)
- 训练时间: 约2-4小时
5. 验证与部署
- 创建特定于23.501的测试问题集
- 本地部署用Ollama或text-generation-webui
与RAG方案对比
针对单一规范,LoRA微调优势更明显:
• 成本: 单次训练成本(几小时GPU时间)vs持续运行向量数据库
• 延迟: 推理速度更快,无需实时检索
• 整合性: 模型可能更好地理解规范内不同章节间的关联
混合方案(可选)
最佳方案可能是轻量级LoRA微调+小型RAG:
1. 用LoRA捕获规范的大部分知识和术语
2. 用小型RAG处理需要精确引用的查询
对于单一23.501规范,LoRA微调确实比纯RAG更有性价比。如未来需扩展到更多规范,可以:
1. 先充分利用这个专精于23.501的模型
2. 逐步将其他关键规范通过类似方式训练
3. 对于不常用规范采用RAG补充
基于LoRA训练3GPP通信专业模型详细指南
一、代码实现(本地或云环境通用)
1. 环境配置
# 创建虚拟环境
conda create -n telecom_llm python=3.10
conda activate telecom_llm
# 安装依赖
pip install torch==2.1.0 transformers==4.34.0 datasets==2.14.5 peft==0.5.0
pip install accelerate==0.23.0 bitsandbytes==0.41.1 trl==0.7.2
pip install sentencepiece protobuf scipy
2. 数据准备脚本
# prepare_data.py
import json
import os
import re
from pypdf import PdfReader
def extract_sections_from_pdf(pdf_path):
"""从PDF中提取各个章节及内容"""
reader = PdfReader(pdf_path)
full_text = ""
for page in reader.pages:
full_text += page.extract_text() + "\n"
# 使用正则表达式识别3GPP规范中的章节结构
# 这里的正则表达式需要根据实际PDF格式调整
section_pattern = r'(\d+(?:\.\d+)*)\s+([^\n]+)\n'
sections = re.findall(section_pattern, full_text)
# 提取每个章节的内容
section_contents = {}
for i, (section_num, section_title) in enumerate(sections):
start_pos = full_text.find(f"{section_num} {section_title}")
if i < len(sections) - 1:
next_section = sections[i+1][0] + " " + sections[i+1][1]
end_pos = full_text.find(next_section)
else:
end_pos = len(full_text)
content = full_text[start_pos:end_pos].strip()
section_contents[section_num] = {
"title": section_title,
"content": content
return section_contents
def create_qa_pairs(sections):
"""基于章节创建问答对"""
qa_pairs = []
# 为每个章节创建问答对
for section_num, section_data in sections.items():
title = section_data["title"]
content = section_data["content"]
# 创建关于章节标题的问题
qa_pairs.append({
"instruction": f"请详细解释3GPP规范23.501中的'{title}'(章节{section_num})是什么?",
"input": "",
"output": f"在3GPP TS 23.501规范中,第{section_num}章节'{title}'主要内容如
下:\n\n{content[:1500]}..."
# 创建关于章节内容的问题
qa_pairs.append({
"instruction": f"请详细介绍3GPP TS 23.501中第{section_num}章节的主要内容",
"input": "",
"output": f"3GPP TS 23.501第{section_num}章节'{title}'的主要内容包
括:\n\n{content[:1500]}..."
# 为较长的章节创建多个问答对,关注不同方面
if len(content) > 1000:
# 可以基于内容特点创建更多问题
keywords = ["架构", "功能", "接口", "流程", "参考点", "协议", "信令"]
for keyword in keywords:
if keyword in content or keyword in title:
qa_pairs.append({
"instruction": f"请详细解释3GPP TS 23.501中第{section_num}章节关于{keyword}的
部分",
"input": "",
"output": f"在3GPP TS 23.501规范的第{section_num}章节('{title}')中,关于
{keyword}的描述如下:\n\n{content[:1500]}..."
# 创建一些跨章节的问题
qa_pairs.append({
"instruction": "简要概述3GPP TS 23.501规范的主要内容和结构",
"input": "",
"output": "3GPP TS 23.501是5G系统架构的核心规范文档,定义了5G系统的整体架构、网络功能、接口和
参考点。主要内容包括:\n\n1. 5G系统架构原则和要求\n2. 5G系统的整体架构\n3. 网络功能和参考点\n4. 身份识
别和寻址\n5. 策略控制与计费\n6. 会话管理\n7. QoS机制\n8. 网络切片\n9. 网络能力开放\n10. 5G系统与EPS的
互通\n\n该规范是理解5G网络架构和功能的基础文档,为系统实现和互操作提供了技术基础。"
return qa_pairs
def main():
# 处理PDF
sections = extract_sections_from_pdf("3GPP_TS_23.501.pdf")
# 创建问答对
qa_pairs = create_qa_pairs(sections)
# 保存为训练数据
with open("3gpp_training_data.json", "w", encoding="utf-8") as f:
json.dump(qa_pairs, f, ensure_ascii=False, indent=2)
print(f"成功生成{len(qa_pairs)}个训练样本")
if __name__ == "__main__":
main()
3. LoRA训练脚本
# train_lora.py
import os
import json
import torch
import logging
from datasets import Dataset
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
BitsAndBytesConfig,
TrainingArguments,
Trainer,
DataCollatorForSeq2Seq
from peft import (
get_peft_model,
LoraConfig,
TaskType,
prepare_model_for_kbit_training
# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# 配置参数
MODEL_NAME = "Qwen/Qwen1.5-7B-Chat" # 或 "THUDM/chatglm3-6b"
OUTPUT_DIR = "./3gpp_lora_model"
LORA_R = 16
LORA_ALPHA = 32
LORA_DROPOUT = 0.1
LEARNING_RATE = 2e-4
BATCH_SIZE = 2
GRADIENT_ACCUMULATION_STEPS = 4
NUM_EPOCHS = 3
MAX_SEQ_LENGTH = 2048
def prepare_dataset(data_path):
"""准备训练数据集"""
with open(data_path, "r", encoding="utf-8") as f:
data = json.load(f)
# 根据模型选择正确的提示词格式
if "Qwen" in MODEL_NAME:
# Qwen模型格式
formatted_data = []
for item in data:
if item["input"]:
prompt = f"<|im_start|>user\n{item['instruction']}\n{item['input']}
<|im_end|>\n<|im_start|>assistant\n"
else:
prompt = f"<|im_start|>user\n{item['instruction']}
<|im_end|>\n<|im_start|>assistant\n"
response = f"{item['output']}<|im_end|>"
formatted_data.append({"prompt": prompt, "response": response})
elif "chatglm" in MODEL_NAME.lower():
# ChatGLM模型格式
formatted_data = []
for item in data:
if item["input"]:
prompt = f"[Round 1]\n\n问:{item['instruction']}\n{item['input']}\n\n答:"
else:
prompt = f"[Round 1]\n\n问:{item['instruction']}\n\n答:"
response = item['output']
formatted_data.append({"prompt": prompt, "response": response})
else:
# 通用格式(如Llama等)
formatted_data = []
for item in data:
if item["input"]:
prompt = f"<s>[INST] {item['instruction']}\n{item['input']} [/INST]"
else:
prompt = f"<s>[INST] {item['instruction']} [/INST]"
response = f"{item['output']}</s>"
formatted_data.append({"prompt": prompt, "response": response})
dataset = Dataset.from_list(formatted_data)
return dataset
def tokenize_function(examples, tokenizer):
"""将文本处理为模型输入格式"""
full_texts = []
for i in range(len(examples["prompt"])):
full_text = examples["prompt"][i] + examples["response"][i]
full_texts.append(full_text)
tokenized = tokenizer(
full_texts,
padding="max_length",
truncation=True,
max_length=MAX_SEQ_LENGTH,
return_tensors="pt"
# 创建标签,-100表示不计算loss
tokenized["labels"] = tokenized["input_ids"].clone()
# 将prompt部分的标签设为-100
for i in range(len(examples["prompt"])):
prompt_len = len(tokenizer(examples["prompt"][i], return_tensors="pt")["input_ids"][0])
tokenized["labels"][i, :prompt_len] = -100
return tokenized
def train():
logger.info(f"使用模型: {MODEL_NAME}")
# 量化配置
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True
# 加载模型和分词器
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
# 确保tokenizer有正确的pad_token
if tokenizer.pad_token is None:
if tokenizer.eos_token:
tokenizer.pad_token = tokenizer.eos_token
else:
tokenizer.pad_token = tokenizer.eos_token = "</s>"
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
quantization_config=bnb_config,
device_map="auto",
trust_remote_code=True,
torch_dtype=torch.float16
# 准备用于量化训练的模型
model = prepare_model_for_kbit_training(model)
# 配置LoRA
peft_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
inference_mode=False,
r=LORA_R,
lora_alpha=LORA_ALPHA,
lora_dropout=LORA_DROPOUT,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj"] # 可能需要根据模型调整
model = get_peft_model(model, peft_config)
# 准备数据集
dataset = prepare_dataset("3gpp_training_data.json")
# 数据集处理
tokenized_dataset = dataset.map(
lambda examples: tokenize_function(examples, tokenizer),
batched=True,
remove_columns=["prompt", "response"]
# 训练参数
training_args = TrainingArguments(
output_dir=OUTPUT_DIR,
per_device_train_batch_size=BATCH_SIZE,
gradient_accumulation_steps=GRADIENT_ACCUMULATION_STEPS,
learning_rate=LEARNING_RATE,
num_train_epochs=NUM_EPOCHS,
weight_decay=0.01,
save_strategy="epoch",
fp16=True,
logging_steps=10,
report_to="none"
# 数据整理器
data_collator = DataCollatorForSeq2Seq(
tokenizer,
pad_to_multiple_of=8,
return_tensors="pt",
padding=True
# 初始化训练器
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset,
data_collator=data_collator,
# 开始训练
logger.info("开始训练...")
trainer.train()
# 保存模型
logger.info(f"保存模型到 {OUTPUT_DIR}")
model.save_pretrained(OUTPUT_DIR)
tokenizer.save_pretrained(OUTPUT_DIR)
logger.info("训练完成!")
if __name__ == "__main__":
train()
4. 推理测试脚本
# test_model.py
import torch
from peft import PeftModel, PeftConfig
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
# 加载模型配置
peft_model_path = "./3gpp_lora_model"
config = PeftConfig.from_pretrained(peft_model_path)
base_model_name = config.base_model_name_or_path
# 加载基础模型
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True
tokenizer = AutoTokenizer.from_pretrained(base_model_name, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
base_model_name,
quantization_config=bnb_config,
device_map="auto",
trust_remote_code=True
# 加载LoRA权重
model = PeftModel.from_pretrained(model, peft_model_path)
# 设置生成参数
generate_kwargs = {
"max_new_tokens": 1024,
"temperature": 0.7,
"top_p": 0.9,
"repetition_penalty": 1.1,
"do_sample": True
# 准备提示词模板
def prepare_prompt(question, model_name):
if "Qwen" in model_name:
return f"<|im_start|>user\n{question}<|im_end|>\n<|im_start|>assistant\n"
elif "chatglm" in model_name.lower():
return f"[Round 1]\n\n问:{question}\n\n答:"
else:
return f"<s>[INST] {question} [/INST]"
# 测试问题
test_questions = [
"请解释5G系统架构中的AMF功能实体是什么?",
"5G核心网中SMF与UPF之间的接口是什么?它们之间有什么交互?",
"QoS Flow ID (QFI)在5G QoS机制中的作用是什么?",
"请详细介绍5G中网络切片选择的流程",
"5G系统的服务化架构与4G有什么主要区别?"
# 进行推理
for question in test_questions:
prompt = prepare_prompt(question, base_model_name)
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
print(f"\n问题: {question}")
print("=" * 50)
with torch.no_grad():
outputs = model.generate(
**inputs,
**generate_kwargs
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
# 根据模型格式提取回答部分
if "Qwen" in base_model_name:
response = response.split("<|im_start|>assistant\n")[-1].replace("<|im_end|>", "")
elif "chatglm" in base_model_name.lower():
response = response.split("答:")[-1]
else:
response = response.split("[/INST]")[-1].strip()
print(f"回答: {response}")
print("=" * 50)
print("\n")
二、百度智能云上的训练步骤
1. 准备阶段
1. 注册百度智能云账号:
• 访问 https://cloud.baidu.com/ 注册账号
• 完成实名认证(企业或个人)
2. 充值余额:
• 根据训练预算充值足够余额
• 计划至少500-1000元用于训练实验
3. 开通EasyDL服务:
• 导航至"百度智能云 > 人工智能 > EasyDL"
• 开通"EasyDL定制化训练"服务
2. 数据准备与上传
1. 准备数据集:
• 按照上述代码准备好3GPP TS 23.501的训练数据
• 确保数据格式符合EasyDL要求(通常支持JSON格式)
2. 数据上传:
1. 进入EasyDL平台
2. 创建"大语言模型定制"项目
3. 选择"数据管理 > 上传数据"
4. 上传准备好的JSON格式训练数据
3. 训练配置与启动
1. 选择基础模型:
1. 选择"模型训练"
2. 基础模型选择"千帆大模型"(推荐)或其他支持的开源模型
3. 选择7B-13B规模的模型作为基座
2. 配置训练参数:
1. 训练方式选择"LoRA微调"
2. LoRA参数设置:
- rank: 16
- alpha: 32
- dropout: 0.1
3. 学习率: 2e-4
4. 训练轮次: 3-5
5. 批量大小: 根据所选GPU自动调整或手动设置
3. 选择计算资源:
1. 选择"A10"或"V100"GPU
2. 配置训练时长估计:
- 对于~300样本,3轮次约需2-4小时
4. 启动训练:
1. 确认配置并提交训练任务
2. 记录训练ID便于后续查询
4. 模型部署与导出
1. 完成训练后:
1. 在"模型服务"页面查看训练完成的模型
2. 可选择在线部署或离线导出
2. 导出模型:
1. 选择"模型导出"
2. 选择"仅导出LoRA权重"选项(节省空间)
3. 下载模型文件包
三、科大讯飞云上的训练步骤
1. 准备阶段
1. 注册讯飞开放平台账号:
• 访问 https://www.xfyun.cn/ 注册账号
• 完成实名认证
2. 开通星火大模型平台:
• 进入"控制台 > 星火大模型"
• 开通星火大模型服务
3. 充值/购买算力包:
• 购买适当的算力资源包
• 建议选择"星火大模型训练专用算力包"
2. 数据准备与训练配置
1. 数据准置与上传:
1. 进入"星火大模型平台 > 微调训练"
2. 创建数据集并上传准备好的JSON文件
3. 设置数据集格式为问答对
2. 创建训练任务:
1. 选择"创建训练任务"
2. 选择基础模型(讯飞星火或其支持的开源模型)
3. 选择微调方式为"LoRA"
4. 配置训练参数:
- LoRA rank: 16
- 学习率: 2e-4
- Epoch: 3-5
- 批次大小: 根据选择的GPU自动优化
3. 启动训练:
1. 选择GPU资源(建议A10或同等配置)
2. 确认费用并提交训练任务
四、成本估算
1. 本地训练成本

2. 百度智能云成本

3. 科大讯飞云成本

五、推荐方案与后续部署
最佳推荐方案
1. 方案选择:
• 如有本地GPU: 自行训练最划算
• 如无GPU资源: 百度智能云最为成熟和经济
2. 成本效益最佳路径:
1. 先小规模实验(100样本)评估效果
2. 确认效果后再扩大训练集(300-500样本)
3. 最终训练完成后导出模型至本地部署
本地部署步骤
1. 安装部署环境:
# 创建新环境
conda create -n 3gpp_deploy python=3.10
conda activate 3gpp_deploy
# 安装依赖
pip install torch transformers peft accelerate bitsandbytes
pip install gradio # 用于Web界面
2. 部署Web界面:
# deploy.py
import gradio as gr
import torch
from peft import PeftModel, PeftConfig
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
# 加载模型
model_path = "./3gpp_lora_model" # 或云平台下载的模型路径
config = PeftConfig.from_pretrained(model_path)
# 量化配置
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16
# 加载tokenizer和模型
tokenizer = AutoTokenizer.from_pretrained(
config.base_model_name_or_path,
trust_remote_code=True
model = AutoModelForCausalLM.from_pretrained(
config.base_model_name_or_path,
quantization_config=bnb_config,
device_map="auto",
trust_remote_code=True
# 加载LoRA权重
model = PeftModel.from_pretrained(model, model_path)
model.eval()
# 准备提示词函数
def prepare_prompt(question, model_name):
if "Qwen" in model_name:
return f"<|im_start|>user\n{question}<|im_end|>\n<|im_start|>assistant\n"
elif "chatglm" in model_name.lower():
return f"[Round 1]\n\n问:{question}\n\n答:"
else:
return f"<s>[INST] {question} [/INST]"
# 推理函数
def predict(question):
prompt = prepare_prompt(question, config.base_model_name_or_path)
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=1024,
temperature=0.7,
top_p=0.9,
repetition_penalty=1.1,
do_sample=True
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
# 提取回答部分
if "Qwen" in config.base_model_name_or_path:
response = response.split("<|im_start|>assistant\n")[-1].replace("<|im_end|>", "")
elif "chatglm" in config.base_model_name_or_path.lower():
response = response.split("答:")[-1]
else:
response = response.split("[/INST]")[-1].strip()
return response
# 创建Gradio界面
demo = gr.Interface(
fn=predict,
inputs=gr.Textbox(lines=5, placeholder="请输入您的3GPP相关问题..."),
outputs=gr.Textbox(label="回答"),
title="3GPP TS 23.501专家系统",
description="基于LoRA微调的通信技术专家模型,专注于5G系统架构(TS 23.501)"
# 启动界面
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", share=False) # 设置share=True可获得公网访问链接
3. 启动服务:
python deploy.py
后续扩展建议
1. 逐步扩充专业领域:
• 完成23.501后,可以逐步添加23.502(流程)、23.503(策略)训练
• 逐步构建完整的5G专业知识体系
2. 结合RAG增强能力:
• 对于其他非核心规范,可采用RAG方式补充
• 构建混合系统:核心知识用LoRA微调,补充知识用RAG
3. 性能优化:
• 考虑模型量化为4-bit或8-bit以降低资源需求
• 使用vLLM等推理引擎加速部署效果
可按照上述指南循序渐进,先完成单本规范的训练,确认效果满意后再扩展。整体成本控制在500-1000
元范围内是完全可行的。