練調(diào)試調(diào)優(yōu):從環(huán)境配置到性能優(yōu)化實(shí)戰(zhàn))
很多做AI訓(xùn)練的朋友第一次拿到昇騰機(jī)器時(shí)第一反應(yīng)是“這不就是個(gè)NPU嘛代碼改改就能跑?!钡日嬲鲜植虐l(fā)現(xiàn)從PyTorch代碼遷移、數(shù)據(jù)管線適配到集群通信調(diào)優(yōu)、訓(xùn)練穩(wěn)定性排查整套流程盤(pán)下來(lái)需要踩的坑比想象中多得多。這篇文章我就圍繞“昇騰大模型訓(xùn)練調(diào)試調(diào)優(yōu)”這條主線把模型訓(xùn)練全流程里的關(guān)鍵環(huán)節(jié)、實(shí)操方法和排查經(jīng)驗(yàn)一次性說(shuō)透希望能幫準(zhǔn)備上手昇騰的朋友少走幾個(gè)彎路。本文既不是官方文檔的復(fù)制也不是純理論分析而是基于真實(shí)的工程實(shí)踐經(jīng)驗(yàn)。內(nèi)容適合這幾類讀者一是剛拿到昇騰算力、想把手頭模型跑起來(lái)的算法工程師二是已經(jīng)在跑訓(xùn)練但經(jīng)常遇到“卡住、掉卡、Loss不降”等問(wèn)題的同學(xué)三是準(zhǔn)備做集群規(guī)模訓(xùn)練、正在做技術(shù)選型的架構(gòu)師。我會(huì)按實(shí)際操作的先后順序展開(kāi)從環(huán)境準(zhǔn)備、數(shù)據(jù)加載、模型遷移到訓(xùn)練啟動(dòng)、性能調(diào)優(yōu)和故障排查每一段都會(huì)給出可直接落地的建議。1. 環(huán)境準(zhǔn)備與框架選型第一步就決定后續(xù)效率很多人以為昇騰訓(xùn)練就是裝上驅(qū)動(dòng)就能跑其實(shí)最關(guān)鍵的在于CANN版本、PyTorch版本、torch_npu版本三者之間的對(duì)齊關(guān)系。這三者就像齒輪組版本不匹配時(shí)輕則報(bào)一堆詭異的算子錯(cuò)誤重則設(shè)備直接掉線。1.1 版本匹配是頭號(hào)大事昇騰的訓(xùn)練軟件棧底層是CANNCompute Architecture for Neural Networks往上依次是PyTorch框架、torch_npu插件再往上才是用戶的訓(xùn)練代碼。CANN版本決定了NPU驅(qū)動(dòng)和運(yùn)行時(shí)環(huán)境而torch_npu則負(fù)責(zé)把PyTorch的算子調(diào)用翻譯成CANN能理解的指令。這個(gè)鏈路里的任何一環(huán)版本不對(duì)齊都會(huì)讓訓(xùn)練進(jìn)程崩潰。我實(shí)測(cè)下來(lái)比較穩(wěn)妥的選型思路是先確定CANN版本再反推torch_npu和PyTorch的對(duì)應(yīng)關(guān)系。比如CANN 7.0.RC1通常搭配torch_npu 2.1.0.post6和PyTorch 2.1.0而更新一些的CANN 8.0.RC1版本則支持PyTorch 2.3.1或更新版本。具體組合建議直接看官方發(fā)布的版本配套表不要自己隨意組合。注意昇騰生態(tài)里很多坑都源于“默認(rèn)安裝最新版”這個(gè)習(xí)慣。不要圖新鮮裝最新CANN優(yōu)先選已經(jīng)在生產(chǎn)環(huán)境被驗(yàn)證過(guò)的穩(wěn)定組合。1.2 兩種開(kāi)發(fā)模式的取舍現(xiàn)在昇騰上跑大模型訓(xùn)練主流有兩條路線一條是基于torch_npu做PyTorch代碼最小改造保留原有代碼結(jié)構(gòu)本質(zhì)上是把昇騰當(dāng)成一個(gè)“加速卡”來(lái)用另一條是用MindSpore MindFormers全家桶從框架層適配昇騰能更充分地發(fā)揮硬件特性。這兩條路線怎么選取決于你手頭的代碼現(xiàn)狀。如果你有成熟的PyTorch代碼庫(kù)團(tuán)隊(duì)也熟悉PyTorch生態(tài)那走torch_npu路線成本最低。改造量通常相對(duì)可控但遇到不支持的算子時(shí)還是得手動(dòng)適配如果是從零開(kāi)始訓(xùn)新模型或者團(tuán)隊(duì)本來(lái)就打算深度定制訓(xùn)練邏輯那用MindFormers自帶的并行策略、混合精度控制、斷點(diǎn)續(xù)訓(xùn)功能會(huì)更順手底層優(yōu)化也更省心。我自己做模型訓(xùn)練時(shí)前期用torch_npu快速驗(yàn)證思路中期穩(wěn)定后部分場(chǎng)景切到MindFormers做長(zhǎng)穩(wěn)訓(xùn)練這樣兩頭的好處都能占到。2. 數(shù)據(jù)準(zhǔn)備與加載優(yōu)化訓(xùn)練瓶頸往往不在計(jì)算大模型訓(xùn)練的瓶頸經(jīng)常被人忽略很多人都盯著計(jì)算卡上的算子耗時(shí)卻忘了數(shù)據(jù)加載可能正拖著整個(gè)訓(xùn)練后退。昇騰訓(xùn)練場(chǎng)景下數(shù)據(jù)管線的表現(xiàn)和GPU生態(tài)有明顯差異如果沿用GPU上的數(shù)據(jù)加載寫(xiě)法很容易出現(xiàn)NPU在等數(shù)據(jù)的情況。2.1 數(shù)據(jù)管線的常見(jiàn)“隱形殺手”最常遇到的問(wèn)題有三個(gè)。一是用普通的文件讀取配合Pillow等庫(kù)做在線解碼CPU端解碼速度跟不上NPU的消費(fèi)速度二是DataLoader的num_workers設(shè)置不合理過(guò)多或過(guò)少都會(huì)影響吞吐三是缺少預(yù)取機(jī)制每一步訓(xùn)練都要等數(shù)據(jù)從磁盤(pán)換上來(lái)。解決思路是把數(shù)據(jù)預(yù)處理盡量“離線化”也就是把清洗、解碼、Token化等操作在訓(xùn)練前批量完成訓(xùn)練時(shí)直接讀取已經(jīng)處理好的數(shù)據(jù)。對(duì)NLP模型來(lái)說(shuō)可以預(yù)先將文本轉(zhuǎn)成Token ID并緩存為二進(jìn)制格式對(duì)CV模型來(lái)說(shuō)可以提前做Resize、歸一化等操作。這樣訓(xùn)練時(shí)只需做最簡(jiǎn)單的讀取和搬移CPU壓力會(huì)大幅下降。2.2 MindRecord與昇騰數(shù)據(jù)加速方案如果用MindSpore框架推薦用MindRecord格式來(lái)存儲(chǔ)訓(xùn)練數(shù)據(jù)。這種格式的讀取效率比通用文件格式高不少原因在于它按樣本做了索引、支持隨機(jī)讀取和分布式分片避免了大量小文件隨機(jī)讀帶來(lái)的IO開(kāi)銷。在torch_npu場(chǎng)景下雖然還用PyTorch的DataLoader但建議關(guān)注自定義Dataset的耗時(shí)占空比。一個(gè)很實(shí)用的排查方法訓(xùn)練啟動(dòng)后在日志里打印每個(gè)Step的時(shí)間如果Step耗時(shí)出現(xiàn)明顯波動(dòng)先檢查Host側(cè)數(shù)據(jù)加載耗時(shí)是否過(guò)高。我遇到過(guò)一次訓(xùn)練速度突然下降的問(wèn)題排查到最后發(fā)現(xiàn)是數(shù)據(jù)加載時(shí)做了一次多余的復(fù)制操作。處理方法是直接把數(shù)據(jù)加載的Tensor改為非阻塞拷貝并保證數(shù)據(jù)在Host上預(yù)處理完再拷到NPU減少重復(fù)內(nèi)存搬運(yùn)。這里想強(qiáng)調(diào)的是數(shù)據(jù)管線是否優(yōu)化到位直接影響大規(guī)模訓(xùn)練的整體吞吐不能只盯著算子在算。3. 模型遷移適配從GPU到昇騰的完整轉(zhuǎn)換模型遷移是昇騰大模型訓(xùn)練最核心的一步也是問(wèn)題最密集的一環(huán)。PyTorch模型遷移到昇騰核心目標(biāo)是用最小改動(dòng)讓模型能在NPU上正常跑通訓(xùn)練并保持?jǐn)?shù)值精度與收斂效果。3.1 最小改造基于torch_npu的適配路徑如果你的代碼是標(biāo)準(zhǔn)的PyTorch實(shí)現(xiàn)那么遷移的第一步通常是替換設(shè)備標(biāo)識(shí)。最簡(jiǎn)單的方法是定義全局device變量然后通過(guò)model.to(device)把模型和Tensor放到昇騰設(shè)備上。import torch import torch_npu # 在代碼初始化階段指定設(shè)備 device torch.device(npu:0) model model.to(device) data data.to(device) # 原有的訓(xùn)練邏輯基本不用改 output model(input_tensor) loss loss_fn(output, target) loss.backward() optimizer.step()這段代碼看起來(lái)很簡(jiǎn)單但實(shí)際項(xiàng)目中的問(wèn)題很少出在設(shè)備遷移本身更多出在算子兼容性上。PyTorch里某些算子尤其是一些高級(jí)索引、自定義Op在昇騰上可能沒(méi)有對(duì)應(yīng)的原生實(shí)現(xiàn)torch_npu會(huì)自動(dòng)走CPU回退或報(bào)錯(cuò)。遇到這種情況優(yōu)先做法是改寫(xiě)模型代碼用昇騰原生支持的算子組合替代不支持的算子。3.2 用MindSpore做重寫(xiě)遷移的時(shí)機(jī)如果你的模型有很多自定義結(jié)構(gòu)或者需要高性能并行策略直接遷移到MindSpore可能更劃算。MindSpore提供了模型遷移工具可以輔助轉(zhuǎn)換PyTorch模型結(jié)構(gòu)但仍需要手工校驗(yàn)算子的數(shù)值一致性。重寫(xiě)遷移的優(yōu)勢(shì)在于后續(xù)訓(xùn)練可以直接使用MindSpore的自動(dòng)并行、內(nèi)存復(fù)用、圖模式編譯等能力對(duì)大規(guī)模訓(xùn)練來(lái)說(shuō)性價(jià)比更高。舉個(gè)例子PyTorch的nn.Module在MindSpore里要對(duì)應(yīng)改寫(xiě)成nn.Cell前向計(jì)算寫(xiě)在construct方法里import mindspore import mindspore.nn as nn from mindspore import Tensor class MyModel(nn.Cell): def __init__(self): super().__init__() self.fc nn.Dense(768, 1024) self.act nn.GeLU() def construct(self, x): x self.fc(x) x self.act(x) return x這種改寫(xiě)雖然是“重復(fù)造輪子”但換來(lái)的是后續(xù)訓(xùn)練腳本的極大簡(jiǎn)化。MindSpore提供了一系列高階API比如TrainOneStepCell、Model.train可以直接接管混合精度、梯度累積、分布式并行等細(xì)節(jié)。3.3 算子適配時(shí)的三個(gè)重要檢查點(diǎn)算子適配是整個(gè)遷移過(guò)程中最磨人的階段但核心檢查點(diǎn)也不復(fù)雜一是檢查模型里有沒(méi)有類似index_put_、scatter這類高級(jí)索引算子這類算子很容易出問(wèn)題。建議改成masked_fill或循環(huán)加切片賦值等價(jià)的邏輯拿到昇騰上跑得更順二是檢查L(zhǎng)oss計(jì)算中是否混用了FP32和FP16計(jì)算這會(huì)導(dǎo)致梯度數(shù)值異常。建議把Loss計(jì)算整體統(tǒng)一到FP32只在模型前向部分啟用混合精度三是檢查是否用到了自定義autograd.Function這類代碼往往基于CUDA實(shí)現(xiàn)昇騰無(wú)法直接運(yùn)行需要改寫(xiě)為昇騰兼容的算子或在CPU上做回退。我踩過(guò)一次最深的坑是模型里用了某個(gè)第三方庫(kù)做位置編碼內(nèi)部實(shí)現(xiàn)了一個(gè)自定義CUDA算子。遷移到昇騰后代碼沒(méi)有報(bào)錯(cuò)但Loss始終不下降。后來(lái)用Profiling工具定位才發(fā)現(xiàn)這個(gè)自定義算子被靜默回退到了CPU執(zhí)行數(shù)據(jù)往返拷貝導(dǎo)致梯度計(jì)算完全錯(cuò)亂。實(shí)操建議遷移完成后先跑一次固定隨機(jī)種子的短Step訓(xùn)練對(duì)比GPU和NPU上的Loss曲線。Loss曲線趨勢(shì)一致且差距在可接受范圍才說(shuō)明遷移正確。這一步別省。4. 訓(xùn)練腳本編寫(xiě)與全流程調(diào)試從單機(jī)到集群模型遷移完成只是開(kāi)始真正把訓(xùn)練腳本寫(xiě)好并調(diào)通才是全流程調(diào)試的重頭戲。整個(gè)訓(xùn)練腳本里分布式初始化、混合精度控制、梯度累積、Loss縮放這幾個(gè)環(huán)節(jié)每一個(gè)都值得認(rèn)真對(duì)待。4.1 分布式訓(xùn)練的初始化細(xì)節(jié)昇騰上做分布式訓(xùn)練通信依賴HCCLHuawei Collective Communication Library。與NCCL類似HCCL也需要初始化一個(gè)全局通信域。如果是通過(guò)torch_npu路徑走PyTorch分布式初始化代碼基本是import torch.distributed as dist import torch_npu dist.init_process_group(backendhccl, init_methodenv://)單機(jī)多卡或集群場(chǎng)景下通過(guò)環(huán)境變量傳入MASTER_ADDR、MASTER_PORT、WORLD_SIZE和RANK。有一點(diǎn)特別容易踩坑WORLD_SIZE必須和實(shí)際參與訓(xùn)練的NPU數(shù)量一致否則HCCL初始化會(huì)一直卡在等待對(duì)端上。有一次我在多機(jī)場(chǎng)景下忘了同步各節(jié)點(diǎn)的RANK編號(hào)導(dǎo)致HCCL建鏈直接失敗排查了很久才發(fā)現(xiàn)是rank分配錯(cuò)誤。集群環(huán)境下依賴rank_table文件來(lái)管理設(shè)備信息也可以通過(guò)環(huán)境變量ASCEND_RT_VISIBLE_DEVICES來(lái)指定每臺(tái)機(jī)器上參與訓(xùn)練的NPU編號(hào)。建議訓(xùn)練腳本里加一段啟動(dòng)自檢邏輯先遍歷所有npu:0到npu:7用簡(jiǎn)單的AllReduce測(cè)試通信建鏈再做正式訓(xùn)練。4.2 混合精度、梯度累積與Loss縮放大模型訓(xùn)練幾乎都會(huì)開(kāi)啟混合精度將FP32計(jì)算替換為FP16/BF16以提升計(jì)算速度和顯存利用率。昇騰對(duì)FP16和BF16的支持都很成熟但用戶需要自行管理Loss Scaling防止梯度下溢。在torch_npu路徑下可以使用torch.cuda.amp的替代實(shí)現(xiàn)昇騰提供了對(duì)應(yīng)的混合精度接口。一個(gè)可行的實(shí)現(xiàn)是from torch_npu.amp import GradScaler, autocast scaler GradScaler() with autocast(): output model(input_tensor) loss loss_fn(output, target) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()梯度累積則是把小Batch的梯度累加起來(lái)再更新參數(shù)效果上近似大Batch能在不增加顯存的情況下提升訓(xùn)練穩(wěn)定性。實(shí)現(xiàn)時(shí)要特別注意累積梯度前要用optimizer.zero_grad()清零累積過(guò)程中不要執(zhí)行optimizer.step()直到累積Step數(shù)達(dá)到設(shè)定值再更新并重新清零。結(jié)合混合精度時(shí)梯度縮放涉及動(dòng)態(tài)范圍變化容易踩坑。我的習(xí)慣是啟動(dòng)時(shí)設(shè)置固定Scale值并開(kāi)啟動(dòng)態(tài)調(diào)整前幾個(gè)Step觀察溢出情況穩(wěn)定后再切換到動(dòng)態(tài)模式。4.3 斷點(diǎn)續(xù)訓(xùn)與訓(xùn)練穩(wěn)定性大模型訓(xùn)練動(dòng)輒幾天甚至幾周斷點(diǎn)續(xù)訓(xùn)不是“加分項(xiàng)”而是“必選項(xiàng)”。昇騰場(chǎng)景下斷點(diǎn)保存的核心是保存三樣?xùn)|西模型權(quán)重、優(yōu)化器狀態(tài)、隨機(jī)數(shù)生成器狀態(tài)。如果漏掉隨機(jī)數(shù)狀態(tài)恢復(fù)訓(xùn)練后數(shù)據(jù)順序會(huì)變化雖然不一定讓訓(xùn)練失敗但會(huì)造成結(jié)果不可復(fù)現(xiàn)。保存優(yōu)化器狀態(tài)時(shí)要注意優(yōu)化器里可能包含指數(shù)移動(dòng)平均、動(dòng)態(tài)學(xué)習(xí)率等輔助狀態(tài)這些都要一并保存?;謴?fù)訓(xùn)練時(shí)還需要重新初始化HCCL通信域某些情況下如果斷點(diǎn)保存了通信域的拓?fù)湫畔⒒謴?fù)時(shí)也要一并恢復(fù)。實(shí)測(cè)下來(lái)最可靠的斷點(diǎn)保存方式是每N個(gè)Step保存一次到本地磁盤(pán)同時(shí)定期同步到共享存儲(chǔ)避免單點(diǎn)故障導(dǎo)致整個(gè)訓(xùn)練白跑。另外恢復(fù)訓(xùn)練后建議先跑幾個(gè)Step驗(yàn)證Loss正常再全速跑別一恢復(fù)就直接進(jìn)入長(zhǎng)穩(wěn)階段。5. 性能調(diào)優(yōu)實(shí)戰(zhàn)從“能跑通”到“跑得快”模型能正常跑起來(lái)、Loss也在正常下降這是第一階段的勝利。但一旦進(jìn)入大規(guī)模訓(xùn)練階段“跑得快”就比“跑得通”更重要。昇騰性能調(diào)優(yōu)的核心思路是先定位瓶頸在計(jì)算還是通信再針對(duì)性地做優(yōu)化不盲目調(diào)參數(shù)。5.1 用Profiling工具定位瓶頸昇騰提供了Profiling工具可以采集訓(xùn)練過(guò)程中的算子耗時(shí)、通信耗時(shí)、Host側(cè)耗時(shí)等信息。具體有兩種路徑一種是MindSpore Profiler適合MindSpore框架另一種是msprof工具適合整體系統(tǒng)層面的性能分析。拿到Profiling報(bào)告后我一般按照以下順序去看先看Step 耗時(shí)如果Step之間波動(dòng)較大優(yōu)先排查數(shù)據(jù)加載和Host側(cè)邏輯再看通信耗時(shí)占比如果通信占比超過(guò)30%說(shuō)明同步開(kāi)銷太大需要調(diào)整并行策略或使用通信壓縮最后看算子耗時(shí)分布找出耗時(shí)Top 10的算子逐一判斷能否被融合或替換。有一次我優(yōu)化一個(gè)千億參數(shù)模型的訓(xùn)練發(fā)現(xiàn)AllReduce占了整個(gè)Step耗時(shí)的40%多。后來(lái)把純數(shù)據(jù)并行改成張量并行加流水線并行混合模式情況才明顯好轉(zhuǎn)。通信和計(jì)算的重疊也很重要HCCL允許通信和計(jì)算并行執(zhí)行但要通過(guò)合適的Stream配置實(shí)現(xiàn)。簡(jiǎn)單來(lái)說(shuō)就是要確保數(shù)據(jù)搬運(yùn)計(jì)算和通信的過(guò)程盡量重疊不要讓NPU在等通信也不要在通信時(shí)讓NPU閑著。5.2 通信優(yōu)化減少數(shù)據(jù)搬運(yùn)次數(shù)通信優(yōu)化的核心原則是“減少數(shù)據(jù)搬運(yùn)次數(shù)、提高單次搬運(yùn)效率”。具體手段包括梯度壓縮對(duì)大梯度做量化或稀疏化處理后再通信減少通信數(shù)據(jù)量梯度分組AllReduce將梯度按層分組小梯度先通信、大梯度后通信錯(cuò)開(kāi)通信峰值更合理的并行策略將數(shù)據(jù)并行與模型并行結(jié)合純數(shù)據(jù)并行下每Step都要同步全量梯度通信量最大。在昇騰平臺(tái)上HCCL的效率與拓?fù)浣Y(jié)構(gòu)密切相關(guān)。單機(jī)8卡的Ring AllReduce性能通常好于跨機(jī)通信所以設(shè)計(jì)模型并行時(shí)盡量把通信量大的Tensor放在同一臺(tái)機(jī)器上??鐧C(jī)通信時(shí)網(wǎng)卡和交換機(jī)的帶寬也要提前確認(rèn)避免因?yàn)榫W(wǎng)絡(luò)帶寬有限導(dǎo)致大規(guī)模加速比不理想。5.3 顯存優(yōu)化與計(jì)算優(yōu)化顯存是另一個(gè)瓶頸尤其在大模型訓(xùn)練場(chǎng)景。昇騰上顯存優(yōu)化手段包括重計(jì)算Recompute把前向激活值只保存一部分反向需要時(shí)重新計(jì)算換取顯存節(jié)省混合精度把不需要高精度的Tensor切到FP16/BF16存儲(chǔ)顯存碎片整理調(diào)整分配策略減少碎片化提高顯存利用率流水線并行把模型切分成多個(gè)Stage放在不同設(shè)備上每臺(tái)設(shè)備只保存一部分參數(shù)和激活值。計(jì)算優(yōu)化層面算子融合是最直接的方式。昇騰提供了一個(gè)算子融合能力可以把多個(gè)連續(xù)的小算子融合成一個(gè)大的融合算子顯著減少內(nèi)核調(diào)度開(kāi)銷。常見(jiàn)做法是把LayerNorm、Residual Add、Activation融合成一個(gè)算子或者把QKV運(yùn)算合并成一個(gè)大的矩陣乘減少內(nèi)核啟動(dòng)次數(shù)。同時(shí)矩陣乘的Shape對(duì)性能影響也很大建議把張量的形狀盡量對(duì)齊到昇騰的矩陣計(jì)算單元偏好。6. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄大模型訓(xùn)練調(diào)試是一場(chǎng)持久戰(zhàn)我把自己實(shí)際操作中遇到頻率最高的四類問(wèn)題整理成速查表方便你直接對(duì)照排查。問(wèn)題現(xiàn)象可能原因排查思路訓(xùn)練剛開(kāi)始就報(bào)算子不存在模型里有昇騰不支持的算子查看報(bào)錯(cuò)信息中的算子名稱改寫(xiě)或替換Loss曲線異常不收斂、NaN混合精度Loss Scaling設(shè)置不當(dāng)學(xué)習(xí)率過(guò)大梯度計(jì)算錯(cuò)亂先關(guān)閉混合精度試跑幾個(gè)Step再逐步打開(kāi)檢查L(zhǎng)oss計(jì)算是否統(tǒng)一在FP32訓(xùn)練到某一步突然卡住HCCL通信超時(shí)數(shù)據(jù)加載線程死鎖顯存溢出查看日志中的通信超時(shí)信息用Profiling看卡的Step位置多卡訓(xùn)練加速比很低通信占比過(guò)高負(fù)載不均數(shù)據(jù)加載成了瓶頸用Profiling確認(rèn)通信和計(jì)算耗時(shí)優(yōu)化并行策略6.1 訓(xùn)練卡住的定位方法訓(xùn)練“卡住”是全流程調(diào)試?yán)镒钭屓祟^疼的問(wèn)題。表面上看進(jìn)程沒(méi)有退出但Step數(shù)不再往前走。遇到這種情況我一般按這個(gè)順序排查先看NPU的利用率如果利用率很低而CPU很高大概率是數(shù)據(jù)加載卡住了檢查DataLoader和文件系統(tǒng)IO如果CPU和NPU利用率都很低大概率是卡在通信環(huán)節(jié)看看是不是有的卡掉線或通信組網(wǎng)異常如果只有某一張卡利用率異常檢查是不是模型并行不均某個(gè)Stage的計(jì)算量特別大拖慢了整體。這里要特別提一下HCCL建鏈問(wèn)題。多機(jī)訓(xùn)練時(shí)不同節(jié)點(diǎn)的設(shè)備互相通信需要走網(wǎng)卡而HCCL默認(rèn)會(huì)使用某個(gè)網(wǎng)卡進(jìn)行建鏈。如果這個(gè)網(wǎng)卡不通通信就會(huì)一直卡住。排查方法是在訓(xùn)練啟動(dòng)前用簡(jiǎn)單的hccl_tools.py測(cè)試腳本驗(yàn)證節(jié)點(diǎn)間的通信連通性確認(rèn)沒(méi)問(wèn)題再啟動(dòng)正式訓(xùn)練。6.2 梯度異常的定位方法梯度異常通常表現(xiàn)為兩種情況梯度爆炸導(dǎo)致Loss變成NaN或者梯度消失導(dǎo)致Loss長(zhǎng)時(shí)間不下降。排查的第一步是逐層打印梯度數(shù)值找到異常梯度的位置。實(shí)操上可以在模型注冊(cè)一些Hook來(lái)打印各層梯度的范數(shù)值for name, param in model.named_parameters(): if param.grad is not None: grad_norm param.grad.norm().item() if grad_norm 1e4: print(fLarge grad: {name}, norm {grad_norm})這個(gè)方法雖然簡(jiǎn)陋但能迅速縮小問(wèn)題范圍。如果是某些層梯度持續(xù)異常優(yōu)先檢查這些層有沒(méi)有被混合精度影響如果是全層梯度異常則優(yōu)先檢查L(zhǎng)oss計(jì)算和梯度累積邏輯。還有一個(gè)容易被忽略的問(wèn)題權(quán)重初始化。如果某些層的初始化方差過(guò)大一開(kāi)始梯度就容易爆炸尤其是在深層Transformer結(jié)構(gòu)里。所以遇到訓(xùn)練初期就出NaN的情況除了檢查混合精度也要確認(rèn)初始化方式是否合理。6.3 日志分析與定位調(diào)試昇騰訓(xùn)練日志分析能力是基本功。建議訓(xùn)練腳本統(tǒng)一用logging模塊輸出帶時(shí)間戳的日志打印每個(gè)Step的耗時(shí)和Loss。如果出現(xiàn)Step耗時(shí)突然上升需要結(jié)合日志時(shí)間線回溯當(dāng)時(shí)的數(shù)據(jù)加載和通信狀態(tài)。另外昇騰的運(yùn)行時(shí)日志默認(rèn)帶級(jí)別可以通過(guò)環(huán)境變量調(diào)整日志級(jí)別比如把部分調(diào)試信息打開(kāi)便于觀察算子執(zhí)行順序和耗時(shí)。日志量會(huì)顯著增加建議只在定位問(wèn)題時(shí)臨時(shí)打開(kāi)平時(shí)保持默認(rèn)級(jí)別。7. 大模型訓(xùn)練全流程的經(jīng)驗(yàn)沉淀整套昇騰大模型訓(xùn)練調(diào)試調(diào)優(yōu)走下來(lái)我的體感是昇騰已經(jīng)是一套成熟度頗高的訓(xùn)練平臺(tái)不再是需要“硬啃文檔”的試驗(yàn)品但它和GPU生態(tài)的差異是客觀存在的關(guān)鍵要掌握它的規(guī)律。給我留下最深的幾個(gè)經(jīng)驗(yàn)第一版本對(duì)齊是“地基工程”不要在環(huán)境配置上求快一步錯(cuò)后面全是連鎖反應(yīng)。拿到新機(jī)器后第一件事就是確認(rèn)CANN、框架和插件的版本配套關(guān)系并保留環(huán)境配置文件方便后續(xù)復(fù)現(xiàn)。第二算子遷移是最需要耐心的環(huán)節(jié)建議把模型里所有自定義算子、第三方CUDA算子統(tǒng)一梳理出來(lái)逐個(gè)驗(yàn)證昇騰兼容性。把這個(gè)工作前置到訓(xùn)練啟動(dòng)前能省下大量試錯(cuò)時(shí)間。第三性能調(diào)優(yōu)要有數(shù)據(jù)支撐別憑感覺(jué)調(diào)參。Profiling工具一定要學(xué)會(huì)用讓數(shù)據(jù)告訴你瓶頸在哪。很多時(shí)候我們以為的計(jì)算瓶頸實(shí)際是通信或數(shù)據(jù)加載瓶頸。第四訓(xùn)練穩(wěn)定性比訓(xùn)練速度更重要。大模型訓(xùn)練動(dòng)輒數(shù)天一次掉卡造成的損失遠(yuǎn)大于優(yōu)化帶來(lái)的收益。把斷點(diǎn)續(xù)訓(xùn)、日志監(jiān)控、健康檢查這些“保命”功能做好優(yōu)先級(jí)高于一切花哨的優(yōu)化技巧。最后再分享一個(gè)我個(gè)人的習(xí)慣每輪全流程調(diào)試后把遇到的問(wèn)題、根因、解決方案整理成一份內(nèi)部文檔形成團(tuán)隊(duì)自己的“避坑手冊(cè)”。昇騰生態(tài)迭代很快這些一手經(jīng)驗(yàn)往往比官方文檔更貼近實(shí)戰(zhàn)也能幫助下一次訓(xùn)練啟動(dòng)時(shí)少走彎路。這套“調(diào)試—沉淀—復(fù)用”的方法才是訓(xùn)練全流程經(jīng)驗(yàn)真正復(fù)利的地方。