多模態大模型正在改變AI的應用邊界,從文生圖到文生視頻,從圖像理解到全模態交互,這些能力的背後離不開強大的算力支持和高效的推理框架。
最近我在昇騰平台上完成了一次完整的多模態項目實踐——使用MindSpeed MM進行Qwen2.5-VL模型微調,並通過MindIE SD實現Wan2.1視頻生成模型的高性能推理。
這次經歷讓我深刻體會到,多模態模型的訓練和部署遠比想象中複雜,但昇騰平台提供的工具鏈確實能讓整個流程變得可控。
一、初識生態
剛接觸昇騰平台時,我面對的是三個核心套件:MindSpeed LLM(大語言模型)、MindSpeed MM(多模態模型)和MindSpeed RL(強化學習)。
對於我的項目需求——既要微調視覺理解模型,又要部署視頻生成模型——MindSpeed MM成為了首選。
這個套件的架構設計很巧妙。它不僅預置了30+主流多模態模型(包括視圖生成的Wan、HunyuanVideo,視圖理解的InternVL、QwenVL等),還提供了完整的數據工程、模態編碼與對齊、評價體系。
更重要的是,底層對接了MindSpeed Core加速庫,在計算、顯存、通信、並行四個維度都做了深度優化。
選擇框架時一定要確認版本配套關係。我最初使用的PyTorch 2.6.0與torch_npu 7.1.0、CANN 8.2.RC1完美適配,但如果版本不匹配,後續會遇到各種奇怪的算子報錯。
二、環境搭建
環境準備是整個項目最容易踩坑的環節。
以下是我總結的完整流程:
- 安裝驅動和固件
bash Ascend-hdk-*-npu-driver_*.run --full --force
bash Ascend-hdk-*-npu-firmware_*.run --full
- 安裝CANN套件
bash Ascend-cann-toolkit_8.2.RC1_linux-aarch64.run --install
bash Ascend-cann-kernels-*_8.2.RC1_linux-aarch64.run --install
source /usr/local/Ascend/ascend-toolkit/set_env.sh
bash Ascend-cann-nnal_8.2.RC1_linux-aarch64.run --install
- 創建Python環境並安裝依賴
conda create -n mm_env python=3.10
conda activate mm_env
pip install torch-2.7.1-cp310-cp310-manylinux_2_28_aarch64.whl
pip install torch_npu-2.7.1*-cp310-cp310-manylinux_2_28_aarch64.whl
- 拉取代碼倉庫
git clone https://gitee.com/ascend/MindSpeed-MM.git
cd MindSpeed-MM
git clone https://github.com/NVIDIA/Megatron-LM.git
cd Megatron-LM && git checkout core_v0.12.1
cp -r megatron ../MindSpeed-MM/
這裏有個關鍵點,CANN的nnal包必須在source環境變量後安裝,否則會找不到依賴路徑。我第一次就是因為順序錯誤,導致後續模型推理時報libatb.so找不到的錯誤。
三、權重轉換
選擇Qwen2.5-VL-7B作為微調目標後,我遇到的第一個問題是權重轉換。
HuggingFace下載的原始權重無法直接使用,因為MindSpeed-MM對網絡結構名稱做了修改以適配並行策略。
下方是權重轉換的命令:
mm-convert Qwen2_5_VLConverter hf_to_mm \
--cfg.mm_dir "ckpt/mm_path/Qwen2.5-VL-7B-Instruct" \
--cfg.hf_config.hf_dir "ckpt/hf_path/Qwen2.5-VL-7B-Instruct" \
--cfg.parallel_config.llm_pp_layers [[12,16]] \
--cfg.parallel_config.vit_pp_layers [[32,0]] \
--cfg.parallel_config.tp_size 1
這裏的llm_pp_layers和vit_pp_layers參數讓我困惑了很久。
後來瞭解到這是Pipeline Parallel(流水線並行)的層數切分配置。比如[[12,16]]表示LLM部分第一張卡放12層,第二張卡放16層。
我是單卡進行訓練,設置為[[28]]。
有一點需要注意,TP並行度(tp_size)不能超過模型配置中的num_key_value_heads,否則會因為KV頭無法均分到各卡而報錯。
四、格式轉換
使用COCO2017數據集進行圖像理解微調時,原始的標註文件需要轉換為MindSpeed-MM的格式。
官方提供了轉換腳本:
import json
def convert_format(input_file, output_file):
with open(input_file, 'r') as f:
data = json.load(f)
converted = []
for item in data:
new_item = {
"messages": [
{"role": "user", "content": item["conversations"][0]["value"]},
{"role": "assistant", "content": item["conversations"][1]["value"]}
],
"images": [f"./data/COCO2017/train2017/{item['image']}"]
}
converted.append(new_item)
with open(output_file, 'w') as f:
json.dump(converted, f, indent=2)
運行轉換後,還需要修改data.json中的路徑配置。
這裏有個小技巧,max_samples參數可以限制只讀取前N條數據,用於快速驗證流程是否正確,避免等待完整數據集加載。
五、開始微調
正式啓動微調前,必須設置一系列環境變量,這些變量看似繁瑣,實則直接影響性能和穩定性。
環境變量的參數:
export ASCEND_SLOG_PRINT_TO_STDOUT=0 # 關閉日誌打屏,避免影響性能
export TASK_QUEUE_ENABLE=2 # 開啓Level 2算子隊列優化
export COMBINED_ENABLE=1 # 開啓算子組合優化
export CPU_AFFINITY_CONF=1 # 開啓粗粒度綁核
export HCCL_CONNECT_TIMEOUT=1200 # 設置HCCL通信超時時間
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True # 開啓內存池擴展
啓動腳本中,我特別關注了幾個參數:
GPT_ARGS="
--no-load-optim \ # 不加載優化器狀態,節省顯存
--no-save-rng \ # 不保存隨機數狀態
--save-interval 5000 \ # 每5000步保存一次(分佈式優化器保存很慢)
--log-tps \ # 打印tokens吞吐量
注意save-interval不要設置太小!使用分佈式優化器時,保存checkpoint會非常耗時。我第一次設置成100步保存一次,結果訓練大部分時間都在等待寫磁盤。
六、推理部署
完成微調後,我轉向另一個任務,就是在昇騰上部署Wan2.1視頻生成模型。
這是一個基於DiT(Diffusion Transformer)架構的文生視頻模型,推理性能優化是核心挑戰。
擴散模型的推理過程本質上是多輪迭代去噪。以50步採樣為例,每一步都要經過完整的DiT前向計算。
給我的感覺是會帶來三個問題:
- 計算冗餘:相鄰步驟間的激活特徵存在70%以上的相似性
- 長序列負擔:視頻幀序列可達百萬級別,Attention計算複雜度是O(N²)
- 顯存壓力:大激活、小參數的特點導致顯存瓶頸在中間特徵而非權重
MindIE SD針對這些問題提供了三層優化方案:
最直接的優化是將計算密集型操作替換為融合算子。
以RoPE(旋轉位置編碼)為例:
def apply_rotary_emb(x, freqs_cis):
cos, sin = freqs_cis
x_rot = torch.stack([-x[..., 1::2], x[..., ::2]], dim=-1).flatten(-2)
return x * cos + x_rot * sin
# 優化後使用融合算子
from mindiesd import rotary_position_embedding
cos, sin = freqs_cis_img
query = rotary_position_embedding(
query, cos, sin,
rotated_mode="rotated_half",
head_first=False,
fused=True # 關鍵參數,使用融合算子
)
這個替換在我的測試中帶來了約15%的單步推理加速。
類似的,attention_forward接口封裝了多種高性能Attention實現(PFA、FASCore、LaserAttention),並支持自動尋優:
from mindiesd import attention_forward
# 自動選擇最優算子(首次會搜索,後續使用緩存結果)
hidden_states = attention_forward(
query, key, value,
attn_mask=attention_mask,
opt_mode="runtime" # 運行時動態搜索
)
這是我認為最巧妙的優化。通過分析發現,擴散採樣過程中約70%的特徵在步間高度相似。
DiTCache不是簡單複用前一步的結果,而是引入"偏置量"機制:
from mindiesd import CacheConfig, CacheAgent
# 配置緩存策略
config = CacheConfig(
method="dit_block_cache",
blocks_count=len(transformer.single_blocks),
steps_count=50, # 總採樣步數
step_start=20, # 從第20步開始緩存
step_interval=2, # 每2步強制重新計算
step_end=47, # 第47步停止緩存
block_start=10, # 只緩存第10-30個block
block_end=30
)
cache_agent = CacheAgent(config)
transformer.cache = cache_agent
# 在block前向傳播中使用
x = self.cache.apply(block, hidden_states=x, vec=vec, ...)
這個策略在我的實驗中,將50步採樣的總時間從45秒降至28秒,加速比達1.6x。關鍵在於step_interval的設置——每隔幾步強制重新計算,避免誤差累積。
不同模型的最優緩存策略差異很大。建議使用官方提供的遞進式搜索工具Cache Searcher自動找到當前模型的最佳配置。
對於長序列視頻生成,單卡內存根本放不下。
MindIE SD實現了一套優雅的混合並行方案:
export PYTORCH_NPU_ALLOC_CONF='expandable_segments:True'
export TASK_QUEUE_ENABLE=2
torchrun --nproc_per_node=4 generate.py \
--task t2v-1.3B \
--ulysses_size 4 \ # Ulysses並行度
--prompt "Two cats fighting on stage" \
--use_attentioncache \
--start_step 20 \
--attentioncache_interval 2
Ulysses並行的核心思想是:在序列維度切分輸入,在注意力頭維度聚合計算。
具體流程是:
- 輸入序列按卡數切分,每卡得到(S/p, d)的數據塊。
- QKV線性變換後,通過AllToAll通信變為(S, d/p)。
- 每卡計算完整序列的部分注意力頭。
- 再次AllToAll恢復為(S/p, d)輸出。
這種方式的通信量是4Sd/p(QKV+O各一次AllToAll),相比傳統數據並行大幅降低。
最終在Atlas 800T A2訓練服務器(8卡NPU)上的測試結果:
| 場景 | 配置 | 端到端時延 | 加速比 |
|---|---|---|---|
| Qwen2.5-VL微調 | 單卡,BF16 | 2.3 samples/s | - |
| Wan2.1推理(單卡) | 832x480,50步 | 45s | 1.0x |
| +Layer優化 | 同上 | 38s | 1.18x |
| +DiTCache | 同上 | 28s | 1.61x |
| Wan2.1推理(4卡) | Ulysses並行 | 12s | 3.75x |
這次實踐讓我對多模態模型的全流程有了系統認知。
昇騰平台的優勢在於:
- 工具鏈完整:從數據處理、權重轉換、訓練微調到推理部署,每個環節都有對應工具。
- 性能優化深度:不僅有算子級優化,還有算法級的Cache、並行策略。
- 開發者友好:權重格式兼容HuggingFace,API設計接近PyTorch原生寫法。
對於想在昇騰平台上開發多模態應用的同學,我的建議是:先從預置模型開始熟悉流程,逐步深入到自定義並行策略和算法優化。
多模態模型的性能瓶頸往往不在單個算子,而在系統層面的通信、顯存、調度協同。掌握這套方法論後,其他平台的優化思路也是相通的。