背景
面对高昂的 NVIDIA GPU 成本,许多团队在部署大模型时寻求高性价比方案。华为昇腾(Ascend)NPU 凭借自主可控的达芬奇架构及日益完善的软件生态,成为重要选择。本文记录使用云端环境完成从配置、部署到测试优化的全过程,提供真实踩坑经验。
环境搭建
在云平台创建实例时,关键配置决定后续成败:
- 计算类型:务必选择
NPU。选错 CPU/GPU 会导致后续步骤无效。 - 规格选择:
NPU basic规格(1*Ascend 910B, 32vCPU, 64GB 内存)是运行 Llama-2-7B 的甜点配置。 - 镜像选择:必须选择预装 CANN、PyTorch 适配器的镜像,如
euler2.9-py38-torch2.1.0-cann8.0-openmind0.6-notebook,可省去大量手动配置时间。
实例启动后,首先确认 NPU 可用。在终端执行以下命令:
# 检查系统与 Python 版本
cat /etc/os-release
python3 --version
# 检查 PyTorch 及 torch_npu
python -c "import torch; print(f'PyTorch 版本:{torch.__version__}')"
python -c "import torch_npu; print(f'torch_npu 版本:{torch_npu.__version__}')"
若未安装,先升级 pip 再安装:
pip install --upgrade pip
pip install torch torchvision torchaudio
pip install torch-npu
看到版本信息说明正常。注意直接运行 torch.npu.is_available() 会报错,因为 torch_npu 是独立插件,需显式导入:
python -c "import torch; import torch_npu; print(torch.npu.is_available())"
输出 True 即表示环境就绪。
模型部署
环境确认后,开始加载 Llama 2。
依赖安装
建议使用国内镜像加速:
pip install transformers accelerate -i https://pypi.tuna.tsinghua.edu.cn/simple
模型下载
Meta 官方仓库需申请权限且国内下载慢,建议直接使用社区镜像版本 NousResearch/Llama-2-7b-hf,无需权限且稳定。
核心代码
创建 Python 脚本,以下是核心逻辑及注意事项:
import os
os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
import torch
import torch_npu # 切记!必须在任何 NPU 操作之前导入
from transformers import AutoModelForCausalLM, AutoTokenizer
import time
MODEL_NAME = "NousResearch/Llama-2-7b-hf"
DEVICE = "npu:0"
print("开始加载模型...")
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
torch_dtype=torch.float16, # 使用 FP16 节省显存
low_cpu_mem_usage=True
)
print("将模型移至 NPU...")
model = model.to(DEVICE)
model.eval()
# 输入张量迁移
prompt = "The capital of France is"
inputs = tokenizer(prompt, return_tensors="pt").to(DEVICE) # 正确写法
# 推理
with torch.no_grad():
start_time = time.time()
outputs = model.generate(**inputs, max_new_tokens=50)
end_time = time.time()
generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(f"生成内容:{generated_text}")
print(f"推理耗时:{end_time - start_time:.2f} 秒")
关键点总结:
- 访问 HuggingFace 超时,推荐使用国内镜像
https://hf-mirror.com。 import torch_npu必须在任何 NPU 操作之前。- 模型和数据均使用
.to('npu:0')迁移,而非不存在的.npu()方法。
性能测试
设计严谨的测试脚本评估性能,包含预热和正式测试轮次。
import os
os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
import torch
import torch_npu
import time
from transformers import AutoModelForCausalLM, AutoTokenizer
MODEL_NAME = "NousResearch/Llama-2-7b-hf"
DEVICE = "npu:0"
WARMUP_RUNS = 3
TEST_RUNS = 5
def load_model():
print("加载模型与分词器...")
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
torch_dtype=torch.float16,
low_cpu_mem_usage=True
).to(DEVICE)
model.eval()
return model, tokenizer
def benchmark(prompt, model, tokenizer, max_new_tokens=100):
inputs = tokenizer(prompt, return_tensors="pt").to(DEVICE)
# 预热
for _ in range(WARMUP_RUNS):
with torch.no_grad():
_ = model.generate(**inputs, max_new_tokens=max_new_tokens)
# 正式测试
latencies = []
for i in range(TEST_RUNS):
torch.npu.synchronize() # 同步,确保计时准确
start = time.time()
with torch.no_grad():
_ = model.generate(**inputs, max_new_tokens=max_new_tokens)
torch.npu.synchronize()
end = time.time()
latency = end - start
latencies.append(latency)
print(f" 第{i+1}次耗时:{latency:.2f}s")
avg_latency = sum(latencies) / len(latencies)
throughput = max_new_tokens / avg_latency
return throughput, avg_latency
if __name__ == "__main__":
model, tokenizer = load_model()
test_cases = [
{"场景": "英文生成", "提示": "The future of artificial intelligence is", "长度": 100},
{"场景": "中文问答", "提示": "请用简单的话解释量子计算:", "长度": 100},
{"场景": "代码生成", "提示": "Write a Python function to reverse a string:", "长度": 150},
]
print("\n" + "=" * 50)
print("性能测试结果")
print("=" * 50)
for case in test_cases:
throughput, avg_latency = benchmark(case["提示"], model, tokenizer, case["长度"])
print(f"- {case['场景']}:")
print(f" 平均延迟:{avg_latency:.2f}s")
print(f" 吞吐量:{throughput:.2f} tokens/s")
print("=" * 50)
在 Ascend 910B 实例上,FP16 精度下测试结果大致如下:
| 测试类型 | 平均延迟 | 吞吐量 |
|---|---|---|
| 英文生成 | 4.94s | 20.24 tokens/s |
| 中文问答 | 4.87s | 20.55 tokens/s |
| 代码生成 | 7.24s | 20.73 tokens/s |
结果分析:吞吐量稳定在 20-30 tokens/秒左右。对于离线批处理、内部工具开发和对实时性要求不高的场景足够,但与顶级消费级 GPU 相比仍有差距。整体稳定性良好。
性能优化
若对默认性能不满意,可尝试以下方向:
使用原生框架
针对量化,昇腾平台提供了专业优化工具链。训练或微调环节建议使用昇腾社区提供的 MindSpeed-LLM 框架。该框架针对昇腾硬件深度优化,可高效完成大模型的训练与微调任务。
模型压缩与部署时,可使用 Modelslim 工具进行量化。该工具能有效降低模型精度(如从 FP16/BF16 量化至 INT8),显著提升推理速度并减少内存占用。
INT8 量化
建立 FP16 基线后,使用 Modelslim 对模型进行 W8A8 量化。量化完成后,仅修改模型路径指向新生成的量化模型,重新执行测试脚本。
from transformers import BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
quantization_config=quantization_config,
device_map="auto"
)
量化后性能对比:
| 测试类型 | 平均延迟 | 吞吐量 | 相比 FP16 提升 |
|---|---|---|---|
| 英文生成 | 2.23s | 44.84 tokens/s | 约 1.21 倍 |
| 中文问答 | 2.22s | 45.05 tokens/s | 约 1.19 倍 |
| 代码生成 | 3.33s | 45.05 tokens/s | 约 1.17 倍 |
启用批处理
同时处理多个请求可大幅提升吞吐量:
prompts = ["Prompt 1", "Prompt 2", "Prompt 3", "Prompt 4"]
inputs = tokenizer(prompts, return_tensors="pt", padding=True).to(DEVICE)
outputs = model.generate(**inputs, max_new_tokens=100)
总结
基于昇腾 NPU 部署和运行 Llama 2 大模型是一条完全可行的技术路径。虽然绝对性能并非顶尖,但其在成本、自主可控和稳定性方面的优势,使其在 AI 算力多元化的今天,成为一个不容忽视的选择。
给后来者的建议:
- 先从云开始:利用免费或低成本资源验证方案,再决定是否投入硬件。
- 仔细阅读文档:关注官方文档,特别是版本匹配问题。
- 拥抱社区:遇到问题时,在社区搜索,很可能已有解决方案。

