在传统课堂话语分析体系中,使用特征工程的方法虽然效果不错,但需要耗费大量的人力物力;另一种使用 Transformer 等经典深度学习的方法虽然非常高效,但是典型的“黑盒”模型,可解释性弱,而在实际课堂分析中,教师往往看重可解释性。因此,本项目实现了:
- 通过使用微调大模型,在保证性能的同时,兼顾可解释性
- 提供相应的封装代码,实现端到端的程序调用
本项目基于CDTB数据集,采用MindSpore框架微调DeepSeek-R1-Distill-Qwen-1.5B大模型,实现了中文篇章级句间关系识别任务。
| 软件包 | 版本 | 安装方法 |
|---|---|---|
| MindSpore NLP | 0.5.1 | pip install mindnlp==0.5.1 |
| MindSpore | 安装 MindSpore NLP 的时候自动选择适配版本安装 | |
| transformers | ||
| datasets | ||
| pandas | ||
| peft | ||
| gradio | 6.3.0 | pip install gradio==6.3.0 |
# 读取数据
df_train = pd.read_json(train_path)
df_val = pd.read_json(val_path)
# 转换为Dataset格式
ds_train = Dataset.from_pandas(df_train)
ds_val = Dataset.from_pandas(df_val)
# 最大序列长度
MAX_LENGTH = 1024
def process_func(example):
# 构建指令部分
instruction = tokenizer(
f"<|im_start|>system\n你是一位PDTB中文文本关系分析助手<|im_end|>\n"
f"<|im_start|>user\n{example.get('content', '')}<|im_end|>\n"
f"<|im_start|>assistant\n",
add_special_tokens=False
)
# 构建回答部分
response = tokenizer(
f"{example.get('summary', '')}",
add_special_tokens=False
)
# 拼接 input_ids 和 attention_mask
input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id]
attention_mask = instruction["attention_mask"] + response["attention_mask"] + [1]
# 构建 labels:指令部分设为 -100(不计算损失),只对回答部分计算损失
labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id]
# 截断到最大长度
input_ids = input_ids[:MAX_LENGTH]
attention_mask = attention_mask[:MAX_LENGTH]
labels = labels[:MAX_LENGTH]
return {
"input_ids": input_ids,
"attention_mask": attention_mask,
"labels": labels
}# 配置LoRA
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM, # 因果语言模型
target_modules=[ # 要应用LoRA的模块(注意力层和FFN层)
"q_proj", "k_proj", "v_proj", "o_proj", # 注意力层
"gate_proj", "up_proj", "down_proj" # FFN层
],
r=16, # LoRA秩
lora_alpha=32, # LoRA缩放因子
lora_dropout=0.05, # Dropout率
inference_mode=False # 训练模式
)
# 应用LoRA到模型
model = get_peft_model(model, lora_config)# 训练配置
args = TrainingArguments(
output_dir="./output", # 输出目录
per_device_train_batch_size=4, # batch size
gradient_accumulation_steps=5, # 梯度累积步数
logging_steps=10, # 日志记录间隔
num_train_epochs=3, # 训练轮数
save_steps=100, # checkpoint保存间隔
learning_rate=3e-5, # 学习率
save_on_each_node=True, # 在每个节点上保存
)
# 训练执行
# 创建Trainer
trainer = Trainer(
model=model,
args=args,
train_dataset=tokenized_train,
data_collator=DataCollatorForSeq2Seq(tokenizer=tokenizer, padding=True),
)
# 开始训练
trainer.train()
# LoRA权重合并
model = PeftModel.from_pretrained(model, lora_path)
model = model.merge_and_unload()
model.save_pretrained(merged_path)本项目使用哈尔滨工业大学 CDTB 数据集,并在此基础上进行了一定的补充,保障了数据的规模、多样性和高质量。各位开发者可通过https://ir.hit.edu.cn/2024/1029/c19699a357757/page.htm向哈工大官方网站申请调用。
哈工大 CDTB 即 HIT - CDTB(哈尔滨工业大学中文篇章关系语料),核心借鉴了 PDTB 的标注标准与研究框架,将篇章级中文语义共分为:
- 扩展
- 因果
- 比较
- 并列
- 时序
- 条件
其中,由于时序和条件两类的样本数量过少,本实验中将其统一为其他关系
为保证实验效果,我们在 CDTB 数据集的基础上,做出了一定的修改:
- 原始样本格式为:
为解决可解释性问题,我们决定扩充数据集,为数据加上具体的原因类标签而非只是分类结果。扩充后的样本格式为:
{ "content": "星汉是什么?银河。", "summary": "扩展" }{ "content": "他的有没有什么不足之处?我觉得他可以就是加一些他自己的感受,因为他如果光只说那些一系列的动作,就感觉很空白,没有什么情感在里面。", "summary": "扩展\n原因:前半句话提出问题,询问他的不足之处,后半句话则具体回答了我认为的他的不足之处,所以属于扩展关系。" } - 由于时间有限,我们只从一万条数据中随机抽取了两千条数据,并为他们手动打上了原因。但为保持微调效果,我们为其余数据统一添加了“原因:”字样,即:
{ "content": "星汉是什么?银河。", "summary": "扩展\n原因:" } - 训练集和测试集的比例按 8 : 2 的比例在保证分类比例不变的情况下随机划分
本项目微调部分在华为云上实现,页面部分在本地 Windows 系统上实现
- 本项目使用虚拟环境
python3 -m venv lcl安装相应环境,也可以直接使用全局环境 - 通过
source /home/ma-user/work/lcl/bin/activate激活虚拟环境 - 安装MindNLP
pip install mindnlp==0.5.1
- 安装 4.5.1 版本的 MinsNLP,会自动安装所需的其他依赖库,如 MindSpore、Transformers 等
- 下载 ipykernel
pip install ipykernel,用于在 Jupyter Notebook 中运行 Python 代码 - 注册当前虚拟环境的 Jupyter 内核
python -m ipykernel install --user --name lcl --display-name "Python (lcl)" - 在 Jupyter Notebook 中选择
Kernel -> Change kernel -> Python (lcl)即可切换到当前虚拟环境 - 注意每次重启 Notebook 后,都需要重新执行步骤 6, 7
- 准备 CDTB 格式的 JSON 数据集文件
- 数据集格式要求:
{ "content": "文本内容", "summary": "关系类型\n原因:关系解释" } - 将数据集划分为train.json和val.json,放置于data目录下
使用train.ipynb进行模型训练:
- 训练过程将生成output目录,保存checkpoint文件
- 可通过日志查看loss、epoch等训练指标
用户可通过传参的方式使用train.py,如
python train.py --train-data /home/ma-user/work/data/train.json --val-data /home/ma-user/work/data/val.json --model-name deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B --output-dir /home/ma-user/work/output其中,
--train-data为训练集路径--val-data为验证集路径--model-name为基础模型名称或路径--output-dir为输出目录,用于保存训练好的模型和日志
使用merge.ipynb合并LoRA权重与基础模型,同样可以使用传参的方式调用merge.py,如
python merge.py --base-model deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B --lora-path /home/ma-user/work/output/checkpoint-1380 --output-path /home/ma-user/work/merged_model其中,
--base-model为基础模型名称或路径--lora-path为训练好的 LoRA checkpoint 路径--output-path为合并后模型的保存目录
gradio_app.py 采用动态加载方式,使用步骤为:
- 下载相关依赖
gradio_app.py脚本同样设置了传参的方式,如python gradio_app.py --base-model deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B --lora-checkpoint checkpoint-1380 --device-id 0--base-model为基础模型名称或路径--lora-checkpoint为训练好的 LoRA checkpoint 路径--device-id为使用的设备ID,默认值为 0
- 预期输出:
Base model: deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
LoRA checkpoint: checkpoint-1380
============================================================
Configuring MindSpore Ascend NPU
============================================================
[OK] Ascend NPU configured (device_id=0)
============================================================
============================================================
Loading Model (PyTorch Transformers + PEFT)
============================================================
[1/4] Loading tokenizer...
[OK] Tokenizer loaded
[2/4] Loading base model...
[OK] Base model loaded
Model parameters: 1,777,088,000
[3/4] Loading LoRA adapter...
[OK] LoRA adapter loaded
[4/4] Moving model to NPU...
[OK] Model ready on NPU
============================================================
Model Ready!
============================================================
Running on local URL: http://0.0.0.0:7860- 在浏览器中打开 http://localhost:7860 即可使用系统