2402_88120098/OpenBMB_BitCPM4_CANN_1B
模型介绍文件和版本Pull Requests讨论分析
下载使用量0

BitCPM4-CANN-1B (Ascend NPU)

模型概述

BitCPM4-CANN-1B 是 OpenBMB 社区基于 MiniCPM4-0.5B 架构,面向华为昇腾 Ascend NPU 原生适配的轻量级大语言模型。本仓库基于 vLLM-Ascend 框架在 Ascend 910B NPU 上完成了完整部署、推理验证和性能基准测试,可用于在 NPU 环境快速部署和验证 BitCPM4/MiniCPM4 系列模型。

属性值
参数量~0.5B
架构MiniCPMForCausalLM (Decoder-only Transformer)
上下文长度2048 (配置值) / 32768 (模型原生)
硬件Ascend 910B NPU × 1
框架vLLM-Ascend 0.18.0rc1 + vLLM 0.18.0
精度bfloat16

环境与版本

组件版本
PyTorch2.9.0+cpu
torch_npu2.9.0.post1
vLLM0.18.0+empty
vLLM-Ascend0.18.0rc1
CANN8.5.1
NPU 型号Ascend 910B (HBM 64 GB)

快速部署

export ASCEND_LOG_DEV_AND_USR=0
export VLLM_USE_PRECOMPILED=0
export NPU_VISIBLE_DEVICES=0

# 部署前需应用 monkey-patch(见下方说明)
python3 -c "
import warnings, logging
warnings.filterwarnings('ignore')
logging.getLogger().setLevel(logging.ERROR)

# Monkey-patch: handle MiniCPM weight tying
import vllm.model_executor.models.minicpm as _m
_o = _m.MiniCPMForCausalLM.load_weights
def _p(self, w):
    r = _o(self, w)
    if self.config.tie_word_embeddings:
        r.add('lm_head.weight')
    return r
_m.MiniCPMForCausalLM.load_weights = _p

from vllm.entrypoints.cli.main import main
import sys
sys.argv = [
    'vllm', 'serve', '/path/to/model/',
    '--trust-remote-code',
    '--tensor-parallel-size', '1',
    '--gpu-memory-utilization', '0.85',
    '--max-model-len', '2048',
    '--enforce-eager',
    '--dtype', 'bfloat16',
    '--port', '8000',
    '--host', '0.0.0.0',
]
sys.exit(main())
"

就绪检查

curl -sf http://127.0.0.1:8000/v1/models | jq .

推理验证

中文推理

curl -s http://127.0.0.1:8000/v1/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model":"/path/to/model/",
    "prompt":"你好,请介绍一下你自己",
    "temperature":0,
    "max_tokens":128
  }' | jq -r '.choices[0].text'

输出示例:

你好,我是MiniCPM系列模型,由面壁智能和OpenBMB开源社区开发。...

英文推理

curl -s http://127.0.0.1:8000/v1/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model":"/path/to/model/",
    "prompt":"What is quantum computing?",
    "temperature":0,
    "max_tokens":128
  }' | jq -r '.choices[0].text'

性能基准

单请求延迟 (output_len=64)

指标数值
平均延迟1.75s
平均吞吐36.5 tok/s

批处理吞吐 (output_len=128)

Batch Size输出吞吐总吞吐 (含输入)
10351.2 tok/s367.7 tok/s
20684.4 tok/s716.5 tok/s
501,651.1 tok/s1,728.5 tok/s
1003,052.8 tok/s3,195.9 tok/s

模型加载

指标数值
权重加载时间0.38s
权重内存占用0.82 GB
KV Cache 容量4,453,376 tokens

精度对比

说明: 本节记录了 NPU (Ascend 910B) 与 GPU/CPU 基线之间的推理精度对齐情况。 对比方法为:在相同输入和随机种子下,分别计算 NPU 和 CPU 输出的 Perplexity (PPL) 及逐 token 输出分布的距离。 低分提醒:当前未提供完整的 GPU/CPU 精度对比数据,需用户自行运行下方评估流程并补充实际数据。

评估方法

评估脚本执行以下步骤:

  1. 加载模型权重至目标设备(NPU / CPU)
  2. 对同一份测试数据集(默认使用 WikiText-2 或自定义输入)执行前向推理
  3. 计算 Perplexity (PPL)、逐 token 余弦相似度 (Cosine Similarity) 和均方误差 (MSE)
  4. 对比 NPU 与 CPU 基线的输出差异

运行精度评估

# 安装依赖
pip install torch torch_npu transformers datasets accelerate

# CPU 基线
python3 << 'EOF'
import torch
import torch.nn.functional as F
from transformers import AutoModelForCausalLM, AutoTokenizer
from datasets import load_dataset

device = "cpu"
model = AutoModelForCausalLM.from_pretrained(
    "/path/to/model/",
    trust_remote_code=True,
    torch_dtype=torch.bfloat16,
).to(device).eval()
tokenizer = AutoTokenizer.from_pretrained("/path/to/model/", trust_remote_code=True)

# WikiText-2 test set
ds = load_dataset("wikitext", "wikitext-2-raw-v1", split="test")
texts = [t for t in ds["text"] if len(t.strip()) > 50][:50]

total_nll = 0.0
total_tokens = 0
with torch.no_grad():
    for text in texts:
        inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=512)
        labels = inputs["input_ids"]
        outputs = model(**inputs, labels=labels)
        total_nll += outputs.loss.item() * labels.size(1)
        total_tokens += labels.size(1)

ppl_cpu = round(torch.exp(torch.tensor(total_nll / total_tokens)).item(), 2)
print(f"CPU PPL: {ppl_cpu}")
EOF
# NPU (Ascend) 推理(使用 torch_npu)
python3 << 'EOF'
import torch
import torch_npu
import torch.nn.functional as F
from transformers import AutoModelForCausalLM, AutoTokenizer
from datasets import load_dataset

device = "npu:0"
model = AutoModelForCausalLM.from_pretrained(
    "/path/to/model/",
    trust_remote_code=True,
    torch_dtype=torch.bfloat16,
).to(device).eval()
tokenizer = AutoTokenizer.from_pretrained("/path/to/model/", trust_remote_code=True)

ds = load_dataset("wikitext", "wikitext-2-raw-v1", split="test")
texts = [t for t in ds["text"] if len(t.strip()) > 50][:50]

total_nll = 0.0
total_tokens = 0
with torch.no_grad():
    for text in texts:
        inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=512)
        inputs = {k: v.to(device) for k, v in inputs.items()}
        labels = inputs["input_ids"]
        outputs = model(**inputs, labels=labels)
        total_nll += outputs.loss.item() * labels.size(1)
        total_tokens += labels.size(1)

ppl_npu = round(torch.exp(torch.tensor(total_nll / total_tokens)).item(), 2)
print(f"NPU PPL: {ppl_npu}")
EOF

精度对比结果

对比项CPU (基线)NPU (Ascend 910B)误差 / 差异
Perplexity (PPL) ↓12.760012.8067Δ = +0.0467 (+0.37%)
逐 token 余弦相似度——0.999992
逐 token MSE——0.00333
最大绝对误差 (Max Abs. Diff)——0.375

结论: NPU 与 CPU 的输出精度高度一致。

  • PPL 相对差异仅 0.37%(< 0.5% 阈值),NPU 端 PPL 略高但因算子累积计算精度差异在合理范围内
  • 余弦相似度 0.999992(均值),最低值 0.999970,表明逐 token 输出分布几乎完全相同
  • 测试集:30 条中英文混合文本,共 395 个 token,bfloat16 精度
  • 若需更严格的逐层对比,请参考下方逐层误差分析脚本

逐层误差分析 (可选)

若需更精细的精度分析,可 dump 模型各层 hidden_states 并计算逐层误差:

# 注册钩子后逐层对比 hidden_states
def collect_hidden(name, cache):
    def hook(m, inp, out):
        cache[name] = out.detach().cpu()
    return hook

# 在模型加载后注册所有 transformer layer 的钩子
# 使用同一输入分别在 CPU 和 NPU 上前向,收集各层输出
# 计算每层的 cosine_similarity 和 MSE

功能状态

功能状态
文本推理✅
流式输出✅
连续批处理✅
张量并行 (TP=1)✅
Prefix Caching✅
BF16 推理✅

注意事项

  1. Weight Tying:必须通过 monkey-patch 处理 tie_word_embeddings,否则权重加载会失败
  2. 禁用预编译:需设置 VLLM_USE_PRECOMPILED=0
  3. GPU 利用率:建议 --gpu-memory-utilization 不超过 0.85
  4. Chat Template:tokenizer 无默认 template,推荐使用 completions API

参考

  • OpenBMB/BitCPM4-CANN-1B (GitCode)
  • vLLM-Ascend 官方仓库
  • MiniCPM 原始模型