在昇騰NPU上跑Llama大模型:從零開始的真實測試之旅
- 一、為什麼選擇昇騰NPU?
- 昇騰的幾個吸引點
- 二、環境準備:GitCode白嫖攻略
- 為什麼選雲上測試?
- 創建昇騰Notebook實例
- 環境配置説明
- 三、驗證環境:第一個小坑
- 打開Terminal驗證
- 驗證NPU是否可用
- 四、安裝依賴:transformers庫
- 五、部署Llama:從下載到運行
- 模型下載的坑
- 創建測試腳本
- 核心代碼
- 模型下載過程
- 六、性能測試:真實數據來了
- 測試方法
- 測試用例
- 真實性能數據
- 數據分析
- 七、踩坑記錄
- 坑1:torch.npu找不到
- 坑2:tokenizer.npu()不存在
- 坑3:Llama下載需要權限
- 坑4:網絡超時
- 八、性能分析與優化建議
- 當前性能水平
- 優化方向
- 九、總結與建議
- 測試結論
- 給後來者的建議
- 後續計劃
- 相關資源
前言:本文記錄了我從零開始在GitCode(昇騰910B)上部署和測試Llama-2-7B大模型的完整過程。包含環境配置、代碼實現、性能測試的所有細節和真實數據。適合想嘗試昇騰NPU但沒有硬件的開發者參考。
一、為什麼選擇昇騰NPU?
最近一直在關注國產AI芯片的發展。雖然NVIDIA的GPU很強大,但價格和供應都是問題。看了不少資料後,發現昇騰在國產芯片裏算是做得最成熟的,而且有完整的開源生態。
昇騰的幾個吸引點
自主可控:華為自研的達芬奇架構,不用擔心被卡脖子。
生態還算完善:打開昇騰的GitCode組織頁(https://gitcode.com/ascend),有30多個開源項目,PyTorch、TensorFlow都有適配。
截圖中可以看到,昇騰在GitCode上有pytorch、MindSpeed-LLM等多個活躍項目,Star和Fork數都不少,説明確實有人在用。
可以白嫖測試:這個很重要!沒硬件也能在gitcode上申請免費試用資源,這讓我決定實際測試一下。
二、環境準備:GitCode白嫖攻略
為什麼選雲上測試?
老實説,Atlas 800服務器動輒十幾萬,個人玩家買不起。但華為雲ModelArts提供了昇騰NPU的Notebook環境,可以按小時付費測試。但是在GitCode上可以有免費的資源可用(限時哦)
創建昇騰Notebook實例
訪問GitCode控制枱後,創建Notebook的過程很簡單:
這是創建界面的截圖。重點配置:
- 計算類型選NPU(不是CPU也不是GPU)
- 規格選:NPU basic · 1 * NPU 910B · 32v CPU · 64GB
- 鏡像選:euler2.9-py38-torch2.1.0-cann8.0-openmind0.6-notebook
- 存儲:[限時免費] 50G(夠用了)
環境配置説明
這個鏡像預裝了:
- PyTorch 2.1.0:比較新的版本
- CANN 8.0:昇騰的核心計算架構,最新版
- Python 3.8:兼容性好
- torch_npu 2.1.0:PyTorch的昇騰適配插件
創建後等1-2分鐘,實例就啓動了。
三、驗證環境:第一個小坑
進入Jupyter Notebook後,第一件事當然是驗證環境。
打開Terminal驗證
在Notebook界面找到"終端"入口,打開Terminal。
Terminal界面長這樣,熟悉Linux的應該很熟悉。
驗證NPU是否可用
運行幾條驗證命令:
# 檢查PyTorch版本
python -c "import torch; print(f'PyTorch版本: {torch.__version__}')"
# 輸出:PyTorch版本: 2.1.0
# 檢查torch_npu
python -c "import torch_npu; print(f'torch_npu版本: {torch_npu.__version__}')"
# 輸出:torch_npu版本: 2.1.0.post3
這裏有個小坑:直接運行 torch.npu.is_available() 會報錯,必須先import torch_npu:
# 錯誤的(會報AttributeError)
python -c "import torch; print(torch.npu.is_available())"
# 正確的(必須先導入torch_npu)
python -c "import torch; import torch_npu; print(torch.npu.is_available())"
# 輸出:True
從截圖中可以看到,我驗證後確認NPU可用,有1個NPU設備。
小結:torch_npu是個插件,必須顯式導入後,torch才會有npu相關的API。這個在文檔裏沒明確説,我自己踩坑才發現。
四、安裝依賴:transformers庫
雖然環境裏預裝了PyTorch和torch_npu,但沒有transformers庫,需要手動裝。
pip install transformers accelerate -i https://pypi.tuna.tsinghua.edu.cn/simple
使用清華鏡像加速,幾分鐘就裝好了。
五、部署Llama:從下載到運行
模型下載的坑
Llama-2官方倉庫 meta-llama/Llama-2-7b-hf 需要申請訪問權限,而且國內網絡訪問HuggingFace經常超時。
解決方案:使用開源社區的鏡像版本 NousResearch/Llama-2-7b-hf,不需要申請權限,下載也更穩定。
創建測試腳本
在Notebook中創建一個Python腳本:
可以直接新建Python文件,也可以用Jupyter Notebook的cell。
核心代碼
import torch
import torch_npu # 必須導入!
from transformers import AutoModelForCausalLM, AutoTokenizer
import time
# 模型名稱(使用開源鏡像版本)
MODEL_NAME = "NousResearch/Llama-2-7b-hf"
# 加載tokenizer和模型
print("下載模型...")
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
torch_dtype=torch.float16, # 使用FP16節省顯存
low_cpu_mem_usage=True
)
# 遷移到NPU(關鍵步驟)
device = "npu:0"
model = model.to(device)
model.eval()
print(f"模型已加載到NPU")
print(f"顯存佔用: {torch.npu.memory_allocated() / 1e9:.2f} GB")
又一個小坑:代碼裏不能寫 inputs.npu(),要用 .to('npu:0'):
# 錯誤寫法(會報AttributeError)
inputs = tokenizer(prompt, return_tensors="pt").npu()
# 正確寫法
inputs = tokenizer(prompt, return_tensors="pt").to('npu:0')
這個我也是報錯後才改對的。
模型下載過程
模型文件分成兩個shard,總共約13GB。下載速度還可以,大概5分鐘左右下完。
model-00001-of-00002.safetensors 和 model-00002-of-00002.safetensors 兩個文件下載後,模型就加載成功了。顯存佔用13.61 GB,基本符合7B模型的大小(FP16精度下約14GB)。
六、性能測試:真實數據來了
測試方法
我寫了一個簡單的benchmark函數,測試不同場景下的性能:
def benchmark(prompt, max_new_tokens=100, warmup=3, runs=10):
"""
性能測試:
- warmup: 預熱次數(第一次運行慢,需要編譯)
- runs: 正式測試次數
"""
inputs = tokenizer(prompt, return_tensors="pt").to(device)
# 預熱
for _ in range(warmup):
with torch.no_grad():
_ = model.generate(**inputs, max_new_tokens=max_new_tokens)
# 正式測試
latencies = []
for _ in range(runs):
torch.npu.synchronize() # 確保NPU操作完成
start = time.time()
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=max_new_tokens,
do_sample=False, # greedy decoding,結果可復現
pad_token_id=tokenizer.eos_token_id
)
torch.npu.synchronize()
latencies.append(time.time() - start)
# 計算平均值
avg_latency = sum(latencies) / len(latencies)
throughput = max_new_tokens / avg_latency
return {
"latency_ms": avg_latency * 1000,
"throughput": throughput
}
測試用例
我測試了3個典型場景:
- 英文短文本生成:
"The capital of France is" - 中文對話:
"請解釋什麼是人工智能:" - 代碼生成:
"Write a Python function to calculate fibonacci:"
運行測試腳本,可以看到每個測試都會先預熱3次,然後正式測試10次取平均值。
真實性能數據
測試完成後,得到了這些數據:
實測結果(華為雲ModelArts - Ascend 910B):
|
測試場景
|
生成tokens
|
延遲(ms)
|
吞吐量(tokens/s)
|
顯存(GB)
|
|
英文生成
|
100
|
6012.41
|
16.63
|
13.61
|
|
中文對話
|
100
|
6030.19
|
16.58
|
13.61
|
|
代碼生成
|
150
|
8916.61
|
16.82
|
13.61
|
測試環境:
- 平台:GitCode
- 硬件:Ascend 910B (單卡)
- 模型:Llama-2-7B (NousResearch/Llama-2-7b-hf)
- 精度:FP16
- PyTorch:2.1.0
- torch_npu:2.1.0.post3
- CANN:8.0
- 測試時間:2025年10月21日
所有詳細數據都保存在JSON文件中,包含時間戳、環境信息、每次測試的具體指標。
數據分析
看這個數據,幾個觀察:
1. 吞吐量相對較低
- 16-17 tokens/s,説實話比我預期的慢。延遲6-9秒生成100-150個token,實際應用可能會覺得有點慢。
2. 性能比較穩定
- 三個場景的吞吐量都在16.5左右,説明性能比較穩定,不會因為prompt類型有大波動。
3. 顯存佔用符合預期
- 13.61 GB,7B模型FP16精度下理論上需要約14GB,基本吻合。
可能的優化方向:
- 增大batch size(我這次只測了batch=1)
- 嘗試INT8量化
- 使用CANN的算子融合優化
七、踩坑記錄
把遇到的問題記錄下來,希望能幫到後來者。
坑1:torch.npu找不到
現象:
AttributeError: module 'torch' has no attribute 'npu'
原因:torch_npu是插件,必須顯式導入。
解決:
import torch
import torch_npu # 必須加這行!
經驗與心得:
這個坑其實反映了昇騰NPU的設計理念——torch_npu採用插件式架構,而不是直接集成到PyTorch核心中。這樣做的好處是保持了與原生PyTorch的兼容性,但對新手不太友好。建議在項目初期就建立一個標準的導入模板,在所有使用NPU的代碼文件開頭統一寫上:
import torch
import torch_npu # NPU適配插件
torch.npu.set_device(0) # 可選:默認設置設備
這樣可以避免後續在多個文件中重複踩坑。另外,如果你的代碼需要在CPU/GPU/NPU之間切換,可以寫成條件導入:
if device_type == 'npu':
import torch_npu
坑2:tokenizer.npu()不存在
現象:
inputs = tokenizer(...).npu() # AttributeError
原因:tokenizer返回的是字典,沒有.npu()方法。
解決:
inputs = tokenizer(...).to('npu:0') # 用.to()
經驗與心得:
這個問題的根源在於tokenizer返回的是BatchEncoding對象(本質上是個字典),而不是Tensor。只有Tensor才有.cuda()、.npu()這樣的方法。這個坑在從CUDA遷移到NPU時特別容易踩到,因為習慣性會寫.cuda()。
推薦的最佳實踐:
- 統一使用
.to(device)而不是.cuda()或.npu(),這樣代碼更通用:
device = 'npu:0' if torch.npu.is_available() else 'cuda:0' if torch.cuda.is_available() else 'cpu'
inputs = tokenizer(text, return_tensors="pt").to(device)
model = model.to(device)
- 如果處理的是字典結構,可以用字典推導式:
inputs = {k: v.to(device) for k, v in inputs.items()}
養成使用.to(device)的習慣,能讓代碼在不同硬件之間無縫切換,也是工程實踐中的標準寫法。
坑3:Llama下載需要權限
現象:訪問meta-llama/Llama-2-7b-hf被拒絕。
解決:
- 方案1:申請HuggingFace訪問權限
- 方案2:使用開源鏡像
NousResearch/Llama-2-7b-hf(推薦)
經驗與心得:
這個問題揭示了大模型開發中的資源獲取策略。Meta官方的Llama模型雖然開源,但設置了訪問門檻,這在工程實踐中會帶來不便。
幾點建議:
- 提前規劃模型來源:在項目啓動階段就確認模型的可訪問性,避免開發到一半才發現下載不了。
- 建立模型庫:對於團隊項目,建議在內網搭建私有模型倉庫(如使用huggingface_hub的本地緩存),把常用模型下載好:
# 一次性下載到本地
huggingface-cli download NousResearch/Llama-2-7b-hf --local-dir ./models/llama-2-7b
- 選擇合適的模型源:
- 官方源(meta-llama):權威但有門檻
- 社區鏡像(NousResearch、TheBloke等):使用方便,質量也有保證
- 國內平台(ModelScope、智源等):網絡快,適合國內開發
- 驗證模型一致性:使用鏡像模型時,建議檢查模型的SHA256或對比輸出結果,確保與官方版本一致。
從實用角度講,社區鏡像通常是最優選擇——既避免了權限申請的麻煩,又能保證模型質量。
坑4:網絡超時
現象:下載到一半timeout。
解決:
# 使用國內鏡像加速
export HF_ENDPOINT=https://hf-mirror.com
或者使用ModelScope(國內平台):
from modelscope import snapshot_download
model_dir = snapshot_download('shakechen/Llama-2-7b-hf')
經驗與心得:
網絡超時是大模型開發中最常見但也最令人頭疼的問題之一。一個13GB的模型,下載到99%時斷網重來的痛苦我深有體會。
實戰經驗總結:
- 必備工具——斷點續傳:
- 使用
huggingface-cli而不是代碼直接下載,它支持斷點續傳 - 或者用
wget -c預先下載模型文件
huggingface-cli download NousResearch/Llama-2-7b-hf --resume-download
- 多線路方案:
- 主線路:HuggingFace官方(適合海外服務器)
- 備線路1:HF-Mirror(https://hf-mirror.com,國內訪問快)
- 備線路2:ModelScope(阿里雲支持,穩定性好)
- 備線路3:提前下載到OSS/雲存儲,內網傳輸
- 環境變量配置技巧:
# 設置鏡像(臨時)
export HF_ENDPOINT=https://hf-mirror.com
# 或者在Python代碼中設置
import os
os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
- 預算考慮:如果經常下載大模型,考慮:
- 購買海外雲服務器(下載快)+ OSS存儲
- 使用企業代理服務
- 建立團隊共享的模型緩存
生產環境最佳實踐:永遠不要在生產代碼中直接從網絡下載模型,而是:
- CI/CD階段預先下載到私有存儲
- 部署時從內網OSS拉取
- 建立模型版本管理機制(類似Git LFS)
這樣既能避免網絡問題,又能保證部署的確定性和可回滾性。
八、性能分析與優化建議
當前性能水平
從我的測試數據看,16-17 tokens/s 這個吞吐量,説實話不算特別快。
可能的影響因素:
- 單batch推理:我只測了batch=1,增大batch可能會提升吞吐
- 沒做特殊優化:直接用transformers原生代碼,沒用CANN的加速庫
- 雲上共享環境:可能受其他用户影響
優化方向
基於這次測試經驗,如果要提升性能,可以嘗試:
1. 使用MindSpeed-LLM框架
昇騰官方提供的大模型訓練/推理框架(https://gitcode.com/Ascend/MindSpeed-LLM),針對昇騰NPU做了深度優化。
2. INT8量化
from transformers import BitsAndBytesConfig
quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModelForCausalLM.from_pretrained(
MODEL_NAME,
quantization_config=quantization_config
)
理論上可以降低顯存、提升速度。
3. 批處理推理
如果有多個請求,使用batch推理能顯著提升吞吐:
# batch=4的情況
prompts = ["prompt1", "prompt2", "prompt3", "prompt4"]
inputs = tokenizer(prompts, return_tensors="pt", padding=True).to('npu:0')
outputs = model.generate(**inputs, max_new_tokens=100)
九、總結與建議
測試結論
經過這次實際測試,對昇騰NPU有了更直觀的認識:
技術層面:
- ✅ 部署流程相對簡單,PyTorch代碼改動很小
- ✅ 文檔和生態比預期的完善
- ⚠️ 有些細節需要注意(比如torch_npu的導入)
適用場景:
- ✅ 對供應鏈自主可控有要求的政企項目
- ✅ 預算有限但有大模型需求的團隊
- ✅ 離線批量推理任務
- ⚠️ 實時交互式應用可能需要進一步優化
成本效益:
- 雲上測試:幾十元就能驗證方案
- 硬件採購:比NVIDIA GPU便宜
- 綜合性價比可以考慮
給後來者的建議
如果你也想嘗試昇騰NPU:
- 先雲上測試:不要直接買硬件,先在ModelArts上花幾十塊測試或者GitCode免費搞一個測試
- 選對鏡像:一定要選NPU類型+PyTorch鏡像
- 注意細節:
import torch_npu必須加,.to('npu:0')不是.npu() - 合理預期:性能不會比頂級GPU強,但有它的適用場景
- 關注社區:GitCode上有很多實際案例,遇到問題先搜索
後續計劃
這次只測了基礎的FP16推理,後面有機會可以試試:
- INT8量化效果
- 多卡並行推理
- MindSpeed框架的性能對比
- 更大模型(Llama-13B/70B)
相關資源
官方資源:
- 昇騰官網:https://www.hiascend.com/
- 技術文檔:https://www.hiascend.com/document
- 昇騰社區:https://www.hiascend.com/forum/
開源代碼:
- GitCode組織:https://gitcode.com/ascend
- PyTorch適配:https://gitcode.com/ascend/pytorch
- MindSpeed-LLM:https://gitcode.com/Ascend/MindSpeed-LLM
學習資源:
- 大模型開發課程:https://www.hiascend.com/edu/growth/lm-development