项目说明
随着信息爆炸时代的到来,人们每天面对大量的文本信息,如何高效地提取关键信息成为一个重要问题。本项目基于深度语义分析模型,对文本中的关键信息进行自动抽取,并生成简洁、准确的摘要,助力高效信息整合与决策支持。

应用场景:新闻媒体(自动生成新闻要点)、金融分析(提取财报关键指标)、医疗健康(生成患者病情摘要)、法律文书(抽取案件核心信息)、企业知识库(归档会议记录、技术文档)。
技术路线
模型选型:Qwen
- 支持长文本输入(最高 32k tokens),适配复杂语义场景。
- 多语言能力与领域泛化性强,覆盖中英文混合文本处理。
- 开源生态完善,便于二次开发与优化。
模型微调:DeepSpeed + LoRA
- DeepSpeed 优化:启用 ZeRO-2 显存优化与梯度检查点,支持单卡微调 70B 参数模型;混合精度训练(FP16/BF16),提升训练速度 20%-30%。
- LoRA:冻结 Qwen 主干参数,仅微调低秩矩阵(Rank=8),减少显存占用(节省 40%+),适配小规模训练数据;支持多任务联合学习。
模型量化与部署
- QLoRA + GPTQ:4-bit 量化,推理速度提升 2-3 倍,显存需求降低 60%。
- vLLM 推理引擎:基于 PagedAttention 技术,支持批量请求并行处理(吞吐量提升 5 倍+),平均单次推理时间 <500ms。
性能指标
| 指标 | Qwen-7B(原始) | Qwen-7B(量化+LoRA) |
|---|---|---|
| 显存占用(推理) | 16GB | 6GB |
| 吞吐量(tokens/s) | 120 | 320 |
| 实体识别 F1 值 | 92.1% | 91.5% |
| 摘要 ROUGE-L | 78.3 | 77.8 |
数据集说明
数据格式是标准的 指令微调(Instruction Tuning) 格式,每个样本包含三个核心字段:
- instruction(指令):明确告知模型需要执行的任务类型,固定句式帮助模型建立稳定的任务映射。
- input(输入):提供待处理的原始文本内容。
- output(输出):给出符合指令要求的预期结果,从 input 中提炼核心名词/动宾短语,中文顿号分隔。
{
"instruction": "请提取以下内容中的摘要信息",
"input": "冬季护肤五大步骤:\n1. 使用温和氨基酸洁面乳\n2. 早晚涂抹含神经酰胺面霜...",
"output": "温和洁面、保湿面霜、定期面膜、日常防晒、颈部防护"
}
效果如下所示:

环境准备
因为需要用到多卡,本次项目在 AutoDL 中完成。
- GPU:RTX 4090(24GB) * 2(需选用 cuda 版本大于 12.6 的机器)
- CPU:32 vCPU Intel(R) Xeon(R) Gold 6430
conda create -n llm_env python=3.11.14
conda activate llm_env
pip install torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 --index-url https://download.pytorch.org/whl/cu124
DeepSpeed 使用
DeepSpeed 是由微软开发的开源库,专为大规模模型训练设计。通过模型并行化、梯度累积、动态精度缩放、混合精度等技术降低训练超大规模模型的复杂性和资源需求。基于 PyTorch 构建,只需简单修改即可迁移。
并行化策略
数据并行
将大型数据集分割成小块,在多个处理器上并行处理。每个 GPU 保留一个完整的模型参数,将每个 batch 的样本平均分配到每个 GPU 上进行梯度计算,然后汇总梯度重新分发,每个 GPU 根据汇总梯度更新模型参数。

模型并行
当模型参数过大,单个 GPU 无法容纳时,将模型拆分到多个 GPU 上。分为流水线并行和张量并行。
流水线并行:将模型划分为多个阶段,分配到不同处理器上。最大缺陷是 GPU 利用率太低,当一个 GPU 计算时,其他层的 GPU 都是闲置的。GPipe 优化方案引入 chunks 超参数,将每个 mini-batch 划分为多个 micro-batchs,使多个 GPU 能并行工作。

张量并行:基于矩阵分块乘法原理,每个 GPU 仅处理矩阵的一部分,需要整个矩阵时再进行聚合。以 MLP 层 Y = GeLU(XA),Z = Dropout(YB) 为例,权重 A 矩阵竖向切分,B 矩阵横向切分,最后合并:

ZeRO 内存优化
ZeRO(Zero Redundancy Optimizer)通过在数据并行进程之间划分 模型状态参数、梯度和优化器状态 来消除内存冗余,而不是复制它们。

- ZeRO Stage 1:把优化器状态(optimizer states)分片到每个 GPU。
- ZeRO Stage 2:把优化器状态 + 梯度(gradients)分片到每个 GPU。
- ZeRO Stage 3:把优化器状态 + 梯度 + 模型参数(parameters)分片到每个 GPU。
ZeRO-Offload:同时利用 CPU 和 GPU 内存,将优化器状态和梯度卸载到 CPU 内存中。单张 V100 GPU 可运行多达 130 亿参数的模型。
混合精度训练
| 类型 | 精度范围 | 显存占用 | 适用场景 |
|---|---|---|---|
| FP16 | 5.96e-8 ~ 65504 | 低 | 大多数 NVIDIA GPU |
| BF16 | 1.18e-38 ~ 3.39e38 | 中 | 大模型训练 |
| TF32 | 1.18e-19 ~ 3.40e38 | 高 | 数学运算加速 |
安装与配置
pip install deepspeed==0.16.9
deepspeed -h # 验证安装
DeepSpeed 配置文件(JSON)关键项:fp16(半精度配置)、train_micro_batch_size_per_gpu(单 GPU 微批次)、gradient_accumulation_steps(梯度累积步数)、train_batch_size(总批次大小)、optimizer(优化器配置)、zero_optimization(ZeRO 优化配置)。
集成步骤
- 导入
deepspeed库。 - 创建 DeepSpeed 配置文件(JSON)。
- 使用
deepspeed.initialize()包装模型。 - 替换训练循环,调用
model.backward()和optimizer.step()。 - 调整超参数和配置。
案例实践(FashionMNIST)
train.py 核心代码:
import torch, numpy as np, argparse, torchvision, deepspeed
# 解析命令行参数。`local_rank` 会由 DeepSpeed 启动器自动注入,
# 默认值通常设为 -1,表示当前不是由分布式启动器显式传入。
parser = argparse.ArgumentParser(description="FashionMNIST Training Script")
parser.add_argument("--local_rank", type=int, default=-1)
parser.add_argument("--epoch", type=int, default=1)
parser = deepspeed.add_config_arguments(parser)
cmd_args = parser.parse_args()
# 定义一个最简单的全连接分类器:
# 28*28 的灰度图拉平成 784 维向量,经过一层隐藏层后输出 10 个类别。
class FashionModel(torch.nn.Module):
def __init__(self):
super().__init__()
self.seq = torch.nn.Sequential(
torch.nn.Linear(784, 300), torch.nn.ReLU(), torch.nn.Linear(300, 10)
)
def forward(self, batch_x):
return self.seq(batch_x)
# 读取 FashionMNIST,并在加载时完成:
# 1. PIL 图像 -> NumPy
# 2. 归一化到 [0, 1]
# 3. 转成 float32 Tensor
# 4. 拉平成一维向量,适配线性层输入
dataset = torchvision.datasets.FashionMNIST(root='./dataset', download=True,
transform=lambda img: torch.tensor(np.asarray(img) / 255, dtype=torch.float32).flatten())
# 分布式训练时,必须让不同进程读取不同的数据分片,否则每张卡都会重复训练完整数据集。
# 当以 DeepSpeed 多卡启动时使用 DistributedSampler;单卡时保留随机打乱。
sampler = (
torch.utils.data.distributed.DistributedSampler(dataset)
if cmd_args.local_rank != -1 else None
)
dataloader = torch.utils.data.DataLoader(
dataset,
batch_size=32,
num_workers=4,
shuffle=(sampler is None),
sampler=sampler
)
model = FashionModel()
# deepspeed.initialize 会返回 DeepSpeed Engine。
# 之后前向、反向、参数更新都通过这个 engine 完成。
model, optimizer, _, _ = deepspeed.initialize(args=cmd_args, model=model, model_parameters=model.parameters())
loss_fn = torch.nn.CrossEntropyLoss()
for epoch in range(cmd_args.epoch):
# 多卡训练时,每个 epoch 都应重新设定 sampler 的随机种子,
# 这样不同 epoch 的数据切分与打乱才是正确的。
if sampler is not None:
sampler.set_epoch(epoch)
for x, y in dataloader:
# 不能直接写 x.cuda(),否则多进程场景下可能都被送到默认 GPU。
# 应显式移动到当前 DeepSpeed engine 所在设备。
x, y = x.to(model.device), y.to(model.device)
output = model(x)
loss = loss_fn(output, y)
model.backward(loss) # DeepSpeed 负责反向传播及梯度同步
model.step() # DeepSpeed 负责优化器 step、梯度清零等操作
# 日志只让主进程打印,避免多卡时重复输出。
if model.global_rank == 0:
print(f"epoch {epoch} done...")
# 保存 checkpoint 时需要所有进程一起参与调用。
model.save_checkpoint('./checkpoints')
ds.json 配置:
{
"train_batch_size": 128,
"gradient_accumulation_steps": 1,
"optimizer": {
"type": "Adam",
"params": { "lr": 0.00015 }
},
"zero_optimization": {
"stage": 2
}
}
执行训练:
deepspeed train.py --epoch 2 --deepspeed --deepspeed_config ds.json
运行结果:

LLaMA-Factory 使用
简介
LLaMA-Factory 是一个简单易用且高效的大模型训练框架,支持上百种大模型训练。特性包括:
- 模型种类:LLaMA、Qwen、ChatGLM、Mistral、Yi、Gemma 等。
- 训练算法:预训练、指令监督微调、奖励模型训练、PPO/DPO/KTO/ORPO 训练等。
- 运算精度:16 比特全参数微调、LoRA 微调、基于 GPTQ/AWQ/LLM.int8 的 QLoRA 微调。
- 推理引擎:Transformers 和 vLLM。
安装
cd /root/autodl-tmp
git clone --depth 1 https://github.com/Jiangnanjiezi/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e ".[torch,metrics]" -i https://mirrors.aliyun.com/pypi/simple/
llamafactory-cli version # 验证安装

准备训练数据
训练数据保存为 json 文件,放到 LLaMA-Factory/data 下:
[
{
"instruction": "请提取以下内容中的摘要信息",
"input": "保持身体健康的五个方法:\n\n1. 每天至少饮用8杯水...\n2. 每周进行150分钟中等强度运动...",
"output": "多喝水、规律运动、充足睡眠、均衡饮食、定期体检"
}
]
在 data/dataset_info.json 中注册自定义训练数据:
"qwen_dataset": {
"file_name": "qwen_dataset.json"
}
模型下载
pip install modelscope
mkdir -p /root/autodl-tmp/LLaMA-Factory/models/Qwen2.5-7B
cd /root/autodl-tmp/LLaMA-Factory/models/Qwen2.5-7B
# 因为 7B 模型下载慢且微调显存大,用 1.5B 模型演示
modelscope download --model Qwen/Qwen2.5-1.5B --local_dir ./
全量微调
创建 qwen2.5-7b-full-sft.yaml 配置文件:
### 模型配置
model_name_or_path: /root/autodl-tmp/LLaMA-Factory/models/Qwen2.5-7B
trust_remote_code: true
### 方法配置
stage: sft # 监督式微调
do_train: true
finetuning_type: full # 全参数微调
deepspeed: /root/autodl-tmp/LLaMA-Factory/examples/deepspeed/ds_z3_config.json
### 数据集配置
dataset: qwen_dataset
template: qwen
cutoff_len: 1024
overwrite_cache: true
preprocessing_num_workers: 16
### 输出配置
output_dir: saves/qwen2.5-7b/full
logging_steps: 10
save_steps: 100
plot_loss: true
overwrite_output_dir: true
### 训练参数
per_device_train_batch_size: 1
gradient_accumulation_steps: 16
learning_rate: 1.0e-5
num_train_epochs: 1.0
lr_scheduler_type: cosine
warmup_ratio: 0.1
bf16: true # BF16 混合精度(需 Ampere 架构以上 GPU)
ddp_timeout: 180000000
### 评估配置
val_size: 0.1
per_device_eval_batch_size: 1
eval_strategy: steps
eval_steps: 500
DeepSpeed 配置(ds_z3_config.json)关键部分:
{
"train_batch_size": "auto",
"train_micro_batch_size_per_gpu": "auto",
"gradient_accumulation_steps": "auto",
"gradient_clipping": "auto",
"fp16": { "enabled": "auto", "loss_scale": 0, "loss_scale_window": 1000,
"initial_scale_power": 16, "hysteresis": 2, "min_loss_scale": 1 },
"bf16": { "enabled": "auto" },
"zero_optimization": {
"stage": 3,
"offload_optimizer": { "device": "cpu", "pin_memory": true },
"offload_param": { "device": "cpu", "pin_memory": true },
"overlap_comm": false,
"contiguous_gradients": true,
"sub_group_size": 1e9,
"reduce_bucket_size": "auto",
"stage3_prefetch_bucket_size": "auto",
"stage3_param_persistence_threshold": "auto",
"stage3_max_live_parameters": 1e9,
"stage3_max_reuse_distance": 1e9,
"stage3_gather_16bit_weights_on_model_save": true
}
}
开始训练:
FORCE_TORCHRUN=1 llamafactory-cli train qwen2.5-7b-full-sft.yaml
LoRA 微调
创建 qwen2.5-7b-lora-sft.yaml,与全量微调主要区别:
finetuning_type: lora # LoRA 微调
lora_target: all # 作用于所有线性层
lora_rank: 16
lora_alpha: 16
lora_dropout: 0.05
learning_rate: 1.0e-4 # LoRA 学习率通常较大
训练命令:
llamafactory-cli train qwen2.5-7b-lora-sft.yaml
QLoRA 微调
创建 qwen2.5-7b-qlora-sft.yaml,在 LoRA 基础上增加量化配置:
finetuning_type: lora
lora_target: all
quantization_bit: 4 # 4-bit 量化
quantization_method: bitsandbytes # 量化方法
lora_rank: 16
lora_alpha: 16
lora_dropout: 0.05
训练命令:
llamafactory-cli train qwen2.5-7b-qlora-sft.yaml
显存占用对比
使用上述训练配置,各方法实测显存占用:
| 方法 | 显存占用 |
|---|---|
| 全量参数训练 | 42.18GB |
| LoRA 训练 | 20.17GB |
| QLoRA 训练 | 10.97GB |
合并模型权重
如果采用 LoRA 或 QLoRA 训练,脚本只保存 LoRA 权重,需要合并权重才能推理。全量参数训练无需此步骤。
创建 qwen2.5-7b-merge-lora.yaml:
### model
model_name_or_path: /root/autodl-tmp/LLaMA-Factory/models/Qwen2.5-7B
adapter_name_or_path: /root/autodl-tmp/LLaMA-Factory/saves/qwen2.5-7b/lora/sft
template: qwen
finetuning_type: lora
trust_remote_code: true
### export
export_dir: /root/autodl-tmp/LLaMA-Factory/models/qwen2.5-7b-sft-lora-merged
export_size: 2
export_device: cpu
export_legacy_format: false
| 参数 | 说明 |
|---|---|
| model_name_or_path | 预训练模型的名称或路径 |
| template | 模型类型 |
| export_dir | 导出路径 |
| export_size | 最大导出模型文件大小 |
| export_device | 导出设备 |
| export_legacy_format | 是否使用旧格式导出 |
注意:合并 Qwen2.5 模型权重,务必将 template 设为
qwen;无论 LoRA 还是 QLoRA 训练,合并权重时finetuning_type均为lora。adapter_name_or_path需与微调中的output_dir对应。
执行合并:
llamafactory-cli export qwen2.5-7b-merge-lora.yaml
推理测试
import time
from transformers import AutoModelForCausalLM, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(
"/root/autodl-tmp/LLaMA-Factory/models/qwen2.5-7b-sft-lora-merged",
trust_remote_code=True
)
model = AutoModelForCausalLM.from_pretrained(
"/root/autodl-tmp/LLaMA-Factory/models/qwen2.5-7b-sft-lora-merged",
device_map="auto", trust_remote_code=True
).eval()
prompt = "你好"
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
start_time = time.time()
outputs = model.generate(
**inputs, max_new_tokens=128, do_sample=True, temperature=0.3, top_p=0.4
)
end_time = time.time()
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
print("生成结果:", response)
num_generated_tokens = outputs.shape[1] - inputs['input_ids'].shape[1]
elapsed_time = end_time - start_time
tokens_per_second = num_generated_tokens / elapsed_time if elapsed_time > 0 else 0
print(f"生成了 {num_generated_tokens} 个 token,用时 {elapsed_time:.2f} 秒,速度约为 {tokens_per_second:.2f} token/s")
结果示例:
生成结果: 你好,我有一个问题想问。
您好,请问有什么问题需要帮助吗?
...
生成了 64 个 token,用时 2.17 秒,速度约为 29.46 token/s
小结
本项目基于 Qwen + DeepSpeed + LoRA 实现文本摘要任务,核心要点:
- 技术路线:Qwen 模型 + DeepSpeed ZeRO 优化 + LoRA 微调 + GPTQ 量化 + vLLM 部署。
- DeepSpeed:通过 ZeRO Stage 1/2/3 分片优化器状态、梯度和参数,降低显存占用;支持数据并行、流水线并行、张量并行。
- LLaMA-Factory:提供全量微调、LoRA、QLoRA 三种方式,显存占用分别为 42.18GB、20.17GB、10.97GB。
- 模型合并:LoRA/QLoRA 训练后需通过
llamafactory-cli export合并权重才能推理。