CoolFace
Modelpublic

Siyu2Zhou/Baichuan-M2-32B-QLoRA-immunology-triples

sourceHugging Faceotherupdated 3mo agoView on Hugging Face
0likes7downloads
Model Card

Baichuan-M2-32B QLoRA · 免疫学知识三元组抽取 Adapter

这是在 [baichuan-inc/Baichuan-M2-32B](https://huggingface.co/baichuan-inc/Baichuan-M2-32B) 基座上用 QLoRA 微调得到的 LoRA adapter,任务是从 PubMed 免疫学摘要抽取生物医学知识三元组,输出结构化 JSON(含实体/类型/关系/依据句/置信度)。

  • —训练数据集:Siyu2Zhou/ICKG-immunology-triple-extraction-sft(4500 train / 250 val / 250 test)。
  • —本仓库仅含 adapter(约 537MB)+ 完整 tokenizer + 对话模板 + 提示词,不含基座权重;使用时需自行加载 Baichuan-M2-32B 基座。

🔴 对齐铁律(务必遵守,否则效果崩坏)

模型是在「不思考、直接输出 JSON」的分布上训练的(assistant 目标不含 <think>)。推理时:

  • —绝不要传 `thinking_mode`(连 thinking_mode="off" 都会注入未训练过的 <think>)。
  • —用默认 apply_chat_template(..., add_generation_prompt=True) 即可,渲染出的 prompt 末尾必须是 <|im_start|>assistant\n。
  • —system 提示词必须用本仓库的 Triple_prompt_v2_finetune.md(与训练完全一致)。
  • —user = title.strip() + 空格 + abstract.strip(),再把连续空白压成单空格。

⚠️ tokenizer 与 chat_template 说明(重要,关系到能否正常加载)

本仓库已附带完整 tokenizer 与官方对话模板,开箱即用:

  • —chat_template.jinja:百川 M2 官方对话模板。apply_chat_template 默认即用它渲染(不传 thinking_mode 时末尾为 <|im_start|>assistant\n,与训练分布一致)。
  • —tokenizer.json(fast)+ vocab.json / merges.txt / added_tokens.json / special_tokens_map.json / tokenizer_config.json(slow 所需)——fast 与 slow 两种 tokenizer 都能正常加载。

踩坑提示(务必看,否则会复现我们遇到的报错):如果一个目录只有 tokenizer.json 而缺 `vocab.json` / `merges.txt`,某些框架(尤其 vLLM)会回退到慢速 Qwen2Tokenizer,并因缺词表文件直接崩溃:

AttributeError: Qwen2Tokenizer has no attribute all_special_tokens_extended

本 adapter 仓库已补齐这些文件,不会有此问题。但若你走「合并权重 + vLLM」路线(见用法二),合并后用 `save_pretrained` 存出的 tokenizer 可能仍只含 `tokenizer.json`,因此 serve 时请显式指定一个完整的 tokenizer(见下方命令的 --tokenizer)。

训练配置与结果

项值
基座Baichuan-M2-32B(Qwen2 架构,32B,bf16)
方法QLoRA(bitsandbytes 4bit nf4 量化 + LoRA)
LoRAr=16,alpha=32,dropout=0.05,targetmodules = `q/k/v/o/gate/up/downproj`(7 个线性层)
序列长度maxseqlength = 5120
批大小perdevice=2 × gradaccum=8 = 有效 16
学习率 / 轮数1e-4 / 3 epoch(846 步)
硬件 / 耗时A100-SXM4-80GB ×1,约 18.8 小时
结果trainloss ≈ 0.067,evalloss ≈ 0.0745,token 准确率 ≈ 97.56%(eval≈train,无明显过拟合)

仓库文件

  • —adapter_model.safetensors / adapter_config.json:LoRA 权重与配置(base_model_name_or_path 已指向 baichuan-inc/Baichuan-M2-32B,PEFT 可自动拉取基座)。
  • —chat_template.jinja:百川 M2 官方对话模板。
  • —tokenizer.json / tokenizer_config.json / vocab.json / merges.txt / added_tokens.json / special_tokens_map.json:完整 tokenizer(与基座一致,fast/slow 均可加载)。
  • —Triple_prompt_v2_finetune.md:训练用的精简版抽取 system 提示词(含 19 类实体与关系表)。

用法一:transformers + PEFT 直接推理(适合少量/试用)

python
import re, torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel

ADAPTER = "Siyu2Zhou/Baichuan-M2-32B-QLoRA-immunology-triples"
BASE = "baichuan-inc/Baichuan-M2-32B"

# tokenizer 与 chat_template 直接从本 adapter 仓库加载(已完整)
tok = AutoTokenizer.from_pretrained(ADAPTER, trust_remote_code=True)
base = AutoModelForCausalLM.from_pretrained(
    BASE, trust_remote_code=True, torch_dtype=torch.bfloat16, device_map="auto",
)
model = PeftModel.from_pretrained(base, ADAPTER)   # 挂上 adapter
model.eval()

# 1) 读取与训练一致的 system 提示词(本仓库自带)
from huggingface_hub import hf_hub_download
system = open(hf_hub_download(ADAPTER, "Triple_prompt_v2_finetune.md"), encoding="utf-8").read().strip()

# 2) 构造 user:title + 空格 + abstract,连续空白压成单空格
def merge_title_abstract(title, abstract):
    return re.sub(r"\s+", " ", f"{title.strip()} {abstract.strip()}".strip())

title = "..."      # 文章标题
abstract = "..."   # 文章摘要
user = merge_title_abstract(title, abstract)

messages = [{"role": "system", "content": system},
            {"role": "user", "content": user}]

# 3) 渲染 prompt:不传 thinking_mode,末尾应为 <|im_start|>assistant\n
inputs = tok.apply_chat_template(
    messages, tokenize=True, add_generation_prompt=True,
    return_tensors="pt", return_dict=True,
).to(model.device)

with torch.no_grad():
    out = model.generate(**inputs, max_new_tokens=2560, do_sample=False,  # 贪心,确定性抽取
                         pad_token_id=tok.eos_token_id)
text = tok.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True).strip()

import json
triples = json.loads(text)   # 一个三元组 JSON 数组
print(len(triples), triples[:2])

用法二:合并权重 + vLLM 批量推理(适合大规模)

bash
# 1) 合并 adapter 到基座得到完整权重(32B bf16 约需 ~64G 内存;不足时建临时 swap)
python -c "
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel
import torch
base = AutoModelForCausalLM.from_pretrained('baichuan-inc/Baichuan-M2-32B', trust_remote_code=True, torch_dtype=torch.bfloat16)
m = PeftModel.from_pretrained(base, 'Siyu2Zhou/Baichuan-M2-32B-QLoRA-immunology-triples')
m = m.merge_and_unload()
m.save_pretrained('merged')
AutoTokenizer.from_pretrained('baichuan-inc/Baichuan-M2-32B', trust_remote_code=True).save_pretrained('merged')
"

# 2) vLLM 起 OpenAI 兼容服务(建议 vllm 0.8.5.post1 + torch cu124;driver/CUDA 需匹配)
#    ⚠️ 显式指定 --tokenizer 指向完整 tokenizer(基座或本 adapter 仓库),
#       避免 merged 目录缺 vocab.json/merges.txt 时 vLLM 回退慢速 tokenizer 崩溃。
vllm serve merged \
  --tokenizer baichuan-inc/Baichuan-M2-32B \
  --served-model-name baichuan-m2-qlora \
  --max-model-len 8192 --gpu-memory-utilization 0.95

vLLM 侧务必遵守对齐铁律:用 `/v1/completions` 端点,由客户端自己用上面 tokenizer 渲染 prompt 后原样推理,不要走可能默认注入 thinking 的 chat 端点;生成参数建议 temperature=0(贪心)、max_tokens≈2560。

输出 schema

每个三元组为:{head, head_type, relation, tail, tail_type, source_sentence, score},其中类型/关系只能取训练提示词中预定义的集合(19 类实体 + 数十种有向关系),source_sentence 为原文依据句,score 为 0–100 置信度。

许可

  • —本 adapter 为 Baichuan-M2-32B 的衍生物,使用须遵守 Baichuan-M2 模型许可。
  • —训练数据为 Baichuan-M3 蒸馏产物(见数据集卡片),研究用途。

引用

作者:Siyu Zhou;项目:ICKG 免疫学知识图谱。如使用请注明出处。