動檢查到環(huán)境隔離)
用過一陣子 Linux 服務(wù)器的朋友大概都經(jīng)歷過這么一幕好不容易拿到一臺機(jī)器的權(quán)限想裝 PyTorch 跑個模型結(jié)果卡在了第一步——環(huán)境裝不對。conda 裝 PyTorch 這件事看起來就是一句conda install pytorch的事但真到了服務(wù)器上才發(fā)現(xiàn)坑一個接一個下載慢到懷疑人生、GPU 版本裝成了 CPU、裝完import torch報(bào)錯、甚至把系統(tǒng)自帶的 Python 環(huán)境搞得一團(tuán)糟。這篇文章寫給兩類人一類是剛接手服務(wù)器、需要在上面搭深度學(xué)習(xí)環(huán)境的新手另一類是本地環(huán)境一直沒事、一上服務(wù)器就各種踩坑的老手。我會從最容易被忽略的準(zhǔn)備工作講起把 conda 安裝 PyTorch 的完整鏈路拆開揉碎包括硬件和驅(qū)動檢查、conda 源加速、環(huán)境隔離思路、GPU 版與 CPU 版的區(qū)別、裝完之后的驗(yàn)證方法以及重裝和卸載時容易踩的坑。內(nèi)容基于我自己在實(shí)際服務(wù)器上折騰多輪的經(jīng)驗(yàn)多數(shù)步驟可以直接照著抄。1. 安裝前先回答三個問題顯卡、驅(qū)動、CUDA到底什么關(guān)系很多人一上來就急著敲安裝命令這是最容易翻車的地方。PyTorch 能不能用 GPU取決于三個東西物理顯卡、顯卡驅(qū)動、CUDA 之間的配合關(guān)系。先弄清楚這三個角色后面才不會一臉懵。1.1 先看你的服務(wù)器有沒有 GPU、是什么型號登錄服務(wù)器后先用這個命令看一眼有沒有 NVIDIA 顯卡lspci | grep -i nvidia如果輸出一堆帶有 NVIDIA 字樣的內(nèi)容說明物理顯卡在如果什么輸出都沒有那大概率是一臺純 CPU 機(jī)器直接裝 CPU 版 PyTorch 就行不用折騰 GPU 了。有顯卡的話再看具體型號nvidia-smi如果提示command not found說明驅(qū)動沒裝好或者裝在了非默認(rèn)路徑。這一步先記住 GPU 型號和顯存大小后面選 PyTorch 版本時用得上。如果nvidia-smi能正常輸出可以在輸出的最上方看到類似Driver Version: 535.xxx和CUDA Version: 12.x的信息這兩行數(shù)字非常關(guān)鍵。1.2 驅(qū)動版本和 CUDA 版本的匹配邏輯很多新手把“CUDA 版本”誤解為 PyTorch 自帶的東西其實(shí)不對。顯卡驅(qū)動是系統(tǒng)層的東西它決定你最高能支持到哪個 CUDA 版本PyTorch 里帶的 CUDA 是運(yùn)行時庫只要它的版本不高于驅(qū)動支持的版本就能正常工作。打個比方驅(qū)動像是手機(jī)系統(tǒng)版本決定了你最多能裝什么 AppPyTorch 是 App 本身它只能在系統(tǒng)允許的范圍內(nèi)運(yùn)行。舉個例子如果你的機(jī)器顯示Driver Version: 535.154.05, CUDA Version: 12.2那么就意味著驅(qū)動最高支持 CUDA 12.2。這種情況下你裝 PyTorch 時選cuda 12.1或cuda 11.8都是沒問題的但如果你裝的是需要 CUDA 13.x 的版本就可能報(bào)錯。注意nvidia-smi里顯示的 CUDA Version 是驅(qū)動支持的上限不是說你已經(jīng)裝了對應(yīng)版本的 CUDA 工具包。PyTorch 官方編譯好的pytorch包自帶 CUDA 運(yùn)行時你不需要單獨(dú)再裝完整的 CUDA Toolkit除非你要自己編譯其他依賴 CUDA 的擴(kuò)展庫。1.3 不確定的時候怎么選版本我個人的經(jīng)驗(yàn)是只要不是極端情況優(yōu)先選 PyTorch 官方當(dāng)前在穩(wěn)定渠道主推的 CUDA 版本比如 11.8 或 12.1。這些版本經(jīng)過最多人驗(yàn)證社區(qū)反饋多遇到問題時搜索到的解決方案也最多。如果你完全不熟悉服務(wù)器上的驅(qū)動狀態(tài)穩(wěn)妥的辦法是先在機(jī)器上跑一遍nvidia-smi直接看驅(qū)動支持的最高 CUDA 版本然后從 PyTorch 官網(wǎng)或者 conda 可下載的版本里挑一個不高于這個數(shù)字的版本。別一上來就追求最新穩(wěn)定才是王道。2. conda 下載慢不是玄學(xué)源配置和緩存策略一次說透在服務(wù)器上用 conda 裝 PyTorch最大的痛點(diǎn)十有八九是下載速度。這背后有幾個原因默認(rèn)源在國外、PyTorch 的包體積大、服務(wù)器網(wǎng)絡(luò)環(huán)境往往比本地復(fù)雜。市面上各種“科學(xué)加速”“鏡像加速”的說法也比較魚龍混雜我這里只講正規(guī)、合規(guī)、安全的提速方式。2.1 從默認(rèn)源切到國內(nèi)鏡像源conda 默認(rèn)從官方源拉取包很多人第一次裝 PyTorch 就掛在Collecting package metadata這一步等半天甚至直接超時。解決辦法是把 conda 的默認(rèn)源指向國內(nèi)高?;蚱髽I(yè)提供的開源鏡像站通常在~/.condarc文件里配置。conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/ conda config --set show_channel_urls yes需要注意的是PyTorch 官方編譯好的 conda 包在pytorch這個 channel 里而不是默認(rèn)的main或conda-forge。如果只用清華源可能會找不到pytorch包需要在安裝時顯式指定conda install pytorch torchvision torchaudio pytorch-cuda12.1 -c pytorch -c nvidia-c pytorch表示從 PyTorch 官方 channel 拉取核心包-c nvidia拉取 CUDA 相關(guān)依賴。這兩個 channel 的包有時候還是慢因?yàn)閮?nèi)容托管在國外的鏡像上。2.2 慢的真正原因和有效應(yīng)對很多時候你感覺 conda 卡住了其實(shí)不全是下載速度的問題而是 conda 在解決依賴關(guān)系dependency resolution時需要大量計(jì)算這個過程反而耗時更長。尤其當(dāng)你 conda 版本較老、環(huán)境中已裝了很多包時Solving environment階段可能持續(xù)十幾分鐘看起來就像死機(jī)了一樣。幾個有效做法盡量用最新版 conda老版本在依賴解析算法上差很多新版明顯更快。給 conda 配上-c conda-forge時要謹(jǐn)慎conda-forge 上的 PyTorch 可能和官方包版本不完全一致混裝時容易引起依賴沖突。如果網(wǎng)絡(luò)條件實(shí)在不行可以先把 wheel 包或 conda 包下載到本地再用conda install --offline方式安裝。但這種方式對新手來說麻煩且易出錯我個人建議優(yōu)先通過配置國內(nèi)鏡像 指定-c pytorch來解決絕大多數(shù)情況下都能接受。2.3 包緩存路徑的實(shí)用技巧conda 會默認(rèn)把下載的包緩存在安裝目錄下的pkgs文件夾里。如果同一臺服務(wù)器上有多個人都要裝 PyTorch或者你反復(fù)重裝環(huán)境可以把緩存目錄軟鏈到一個容量大的磁盤分區(qū)避免因?yàn)?home或/root分區(qū)空間不足導(dǎo)致安裝失敗。# 查看當(dāng)前緩存目錄位置 conda config --show pkgs_dirs # 修改緩存目錄 conda config --add pkgs_dirs /data/conda_pkgs這個操作在數(shù)據(jù)盤較大、系統(tǒng)盤較小的服務(wù)器上特別實(shí)用。我遇到過兩次因?yàn)?root分區(qū)寫滿導(dǎo)致 conda 直接報(bào)錯的案例都是靠把pkgs_dirs挪到數(shù)據(jù)盤解決的。3. 從建環(huán)境到裝 PyTorch完整命令行流程3.1 為什么強(qiáng)烈不建議直接裝到 base 環(huán)境很多教程上來就讓用戶conda install pytorch直接裝這對于自己的個人電腦也許勉強(qiáng)可以但在服務(wù)器上是典型的壞習(xí)慣。服務(wù)器上的 Python 環(huán)境往往是很多人共用的一旦你在 base 環(huán)境裝了這個那個很可能破壞某些項(xiàng)目依賴的舊版本庫而且日后想整體干凈重來非常麻煩。正確做法是為 PyTorch 單獨(dú)建一個虛擬環(huán)境conda create -n torch_env python3.10 conda activate torch_envpython3.10這個版本選擇是有講究的。某些很新的 Python 版本比如剛發(fā)布的大版本在 PyTorch 上可能還沒有完全適配的預(yù)編譯包而太老的版本又可能不支持新特性或缺少維護(hù)。在寫這篇文章的時間點(diǎn)上Python 3.9、3.10 是久經(jīng)驗(yàn)證的穩(wěn)定選擇3.11 大部分情況也能用。如果在 conda 解析依賴時報(bào)“找不到匹配版本”的錯最直接的辦法是把 Python 版本降到 3.10 或 3.9。3.2 GPU 版安裝命令的選擇邏輯創(chuàng)建好環(huán)境并激活后接下來就是安裝。以當(dāng)前比較常用的 CUDA 12.1 版本為例命令是conda install pytorch torchvision torchaudio pytorch-cuda12.1 -c pytorch -c nvidia這里做了一個很關(guān)鍵的事情顯式指定了pytorch-cuda12.1。如果不寫這一項(xiàng)conda 很可能只裝 CPU 版的 PyTorch因?yàn)?CPU 版不依賴額外的 CUDA 庫依賴解析更容易通過conda 在“偷懶”狀態(tài)下會優(yōu)先選擇它。很多人裝完才發(fā)現(xiàn)torch.cuda.is_available()返回False折騰半天最后發(fā)現(xiàn)原因就是這里。如果你的機(jī)器是純 CPU 環(huán)境或者暫時不需要 GPU直接裝conda install pytorch torchvision torchaudio cpuonly -c pytorchcpuonly這個包的作用是讓 conda 明確選擇 CPU 版本加上它之后conda 不會傻乎乎地給你拉一個需要 CUDA 的版本過去。3.3 torch、torchvision、torchaudio 三者版本必須匹配這三個包是一套的版本之間高度耦合。torchvision 是視覺庫torchaudio 是音頻庫它們在編譯時就是跟某個特定版本的 PyTorch 綁定的。如果你今天用conda install裝 torch明天用pip install升級了 torch然后發(fā)現(xiàn) torchvision 導(dǎo)不進(jìn)來報(bào)錯信息往往是undefined symbol一類的非常難查。盡量一次性用同樣的方式conda 或 pip二選一安裝三個包并讓 conda 自動解決版本依賴。不要這邊裝一部分、那邊補(bǔ)一部分。3.4 安裝過程中的常見卡點(diǎn)應(yīng)對裝的過程中最容易卡住的有兩個階段第一階段是Solving environment。如果幾分鐘內(nèi)還在轉(zhuǎn)圈可以考慮用conda search確認(rèn)一下指定版本是否存在conda search pytorch --channel pytorch第二種卡在Downloading and Extracting Packages大概率是網(wǎng)絡(luò)對某個 channel 的連接不穩(wěn)。這時候不要反復(fù) CtrlC 重來建議刪掉本地未完成的緩存重新執(zhí)行安裝命令conda clean --tarballs conda clean --packages conda install pytorch torchvision torchaudio pytorch-cuda12.1 -c pytorch -c nvidiaconda clean這個操作非常有效它能清掉那些校驗(yàn)不完整、被中斷的下載緩存避免 conda 錯誤地復(fù)用它。4. 裝完不報(bào)錯不等于能用三大驗(yàn)證步驟很多人裝完 PyTorch 之后看到conda list里有pytorch就覺得大功告成了其實(shí)這時候距離“真正能用”還差好幾步。這幾步驗(yàn)證不能省尤其在有 GPU 的服務(wù)器上否則很容易帶著“假環(huán)境”跑掉了整個訓(xùn)練任務(wù)最后報(bào)錯時排查浪費(fèi)半天時間。4.1 用 Python 直接驗(yàn)證導(dǎo)入和版本conda activate torch_env python -c import torch; print(torch.__version__)如果看到類似2.0.1這樣的版本號說明導(dǎo)入沒問題。這一步能篩掉一大半的“裝完了但環(huán)境有問題”的情況。4.2 驗(yàn)證 GPU 是否真的可用這條命令是最關(guān)鍵的python -c import torch; print(torch.cuda.is_available())輸出True才是真正能調(diào)用 GPU 的狀態(tài)。如果輸出False常見原因有裝成了 CPU 版本或者 conda 沒把 CUDA 依賴裝上驅(qū)動版本太低PyTorch 編譯時使用的 CUDA 版本高于驅(qū)動支持上限conda 環(huán)境里的LD_LIBRARY_PATH被污染導(dǎo)致加載不了 CUDA 動態(tài)庫接下來再確認(rèn)一下 GPU 卡的信息python -c import torch; print(torch.cuda.get_device_name(0))如果能正常輸出顯卡型號說明 CUDA 上下文已經(jīng)建起來了。注意第一次調(diào)用 CUDA 時服務(wù)器偶爾會出現(xiàn)“慢半拍”的現(xiàn)象這不是故障。很多庫需要在首次運(yùn)行時做 JIT 編譯或初始化緩存多跑一次就正常了。4.3 跑一個最小訓(xùn)練任務(wù)驗(yàn)證全鏈路導(dǎo)入成功和 GPU 可用只是最基礎(chǔ)的兩關(guān)。我建議你新建一個測試腳本做一次真實(shí)的小規(guī)模矩陣乘法或模型訓(xùn)練確認(rèn)計(jì)算鏈路是通的import torch print(CUDA available:, torch.cuda.is_available()) # 模擬一個小型計(jì)算任務(wù) x torch.randn(1024, 1024, devicecuda) y torch.randn(1024, 1024, devicecuda) z torch.matmul(x, y) print(Matrix multiplication result shape:, z.shape) # SGVGD 風(fēng)格的模擬優(yōu)化器 a torch.randn(100, 100, devicecuda, requires_gradTrue) b torch.randn(100, 100, devicecuda, requires_gradTrue) optimizer torch.optim.SGD([a, b], lr0.01) loss (a - b).pow(2).sum() loss.backward() optimizer.step() print(Optimizer step OK, loss , loss.item())跑出正常結(jié)果說明這一套環(huán)境至少在基礎(chǔ)計(jì)算層面是可以用的。4.4 順手檢查一下環(huán)境內(nèi)的依賴完整性PyTorch 正常工作還依賴numpy、typing-extensions等一堆庫。如果你在 PyTorch 已經(jīng)裝好的環(huán)境里后來又手動裝了別的大包可能會無意間覆蓋某些依賴版本。建議用conda list | grep -E torch|numpy|nvidia|cuda把關(guān)鍵包版本列出來看一眼。如果發(fā)現(xiàn) numpy 版本異常新或異常舊主動用 conda 降級或升級到與 PyTorch 兼容的范圍。5. 環(huán)境隔離和版本鎖多人共用服務(wù)器的生存之道服務(wù)器的使用場景常常不只是你一個人。實(shí)驗(yàn)室一臺機(jī)器七八個人來回用環(huán)境如果不隔離很快就會變成一團(tuán)亂麻。conda 的環(huán)境隔離機(jī)制一開始可能覺得“多此一舉”但實(shí)際上它是最便宜、最有效的時間投資。5.1 用conda create為每個任務(wù)單獨(dú)建環(huán)境我個人的習(xí)慣是一個項(xiàng)目或一個大類任務(wù)一個獨(dú)立環(huán)境。環(huán)境命名和environment.yml文件保持和項(xiàng)目同步。比如conda env export -n torch_env environment.yml以后在任何一臺機(jī)器上想復(fù)現(xiàn)環(huán)境只需要conda env create -f environment.yml這個文件會把當(dāng)前環(huán)境里的包版本、channel 信息都記錄下來。注意它也會帶上本機(jī)路徑信息在另一臺機(jī)器上恢復(fù)時可能有少量偏差但絕大多數(shù)情況下是可用的。5.2 用 conda-lock 或環(huán)境文件鎖版本服務(wù)器上的一個大問題是“昨天還能跑今天突然不能跑了”。大多數(shù)情況就是依賴版本被升級破壞了。PyTorch 自身升級比如從 2.0 升到 2.1在 API 層面差異不大但與其配套的torchvision、torchaudio如果不同步升級很容易出現(xiàn) ABI 不兼容。如果項(xiàng)目對版本非常敏感我建議除了environment.yml還要關(guān)注 PyTorch 官方對每個版本的 CUDA 支持情況。在 conda 里用pytorch-cuda12.1這樣的方式固定 CUDA 主版本也是變相給環(huán)境加了一道鎖。5.3 顯存和進(jìn)程管理的心得環(huán)境隔離能解決軟件層面的混亂但解決不了硬件資源爭奪。服務(wù)器上多人同時跑訓(xùn)練任務(wù)經(jīng)常會因?yàn)轱@存不夠?qū)е逻M(jìn)程被殺。所以在服務(wù)器上用 PyTorch 時光會安裝不夠還得會用工具觀察資源占用nvidia-smi要養(yǎng)成定時查看顯存占用情況的習(xí)慣別等到程序報(bào)CUDA out of memory再手忙腳亂地找問題。6. 重裝和卸載處理“曾經(jīng)裝過但搞壞了”的環(huán)境服務(wù)器上裝環(huán)境不像是手機(jī)裝 App不想要了直接刪。conda 裝 PyTorch 時會在環(huán)境里寫入大量依賴如果不清干凈殘留的舊庫會和新的環(huán)境互相干擾。這部分經(jīng)驗(yàn)是我踩了不少坑才總結(jié)出來的。6.1 環(huán)境的干凈刪除當(dāng)你覺得當(dāng)前環(huán)境已經(jīng)不可救藥時最快的辦法不是試圖修而是直接刪掉重建conda deactivate conda env remove -n torch_env然后再重新創(chuàng)建環(huán)境。刪除環(huán)境不會動服務(wù)器上其他環(huán)境也不用擔(dān)心影響別人。6.2 殘留文件的排查如果刪除后你在~/.cache/torch、/tmp或者當(dāng)前目錄下發(fā)現(xiàn)一些殘留的.so庫、日志文件不用太緊張大多數(shù)不影響使用。真正需要擔(dān)心的是PYTHONPATH環(huán)境變量被設(shè)置到舊的庫路徑上導(dǎo)致新環(huán)境調(diào)用時串包。排查方法echo $PYTHONPATH如果在激活 torch_env 之前這個變量就指向某個奇怪的路徑建議在.bashrc或.profile里把它清掉或者設(shè)置成空值。6.3 多個環(huán)境并行時的LD_LIBRARY_PATH問題這個坑非常隱蔽。當(dāng)你的系統(tǒng)里同時裝了多個版本的 CUDA 庫比如某項(xiàng)目自己裝了 CUDA 11.8另一個項(xiàng)目裝了 CUDA 12.1而LD_LIBRARY_PATH里同時包含了這兩個路徑時運(yùn)行時可能會加載錯動態(tài)庫。癥狀很典型PyTorch 導(dǎo)入成功但一調(diào)用 GPU 就報(bào)libcudart.so.xxx: version not found。解決辦法很簡單但需要耐心逐項(xiàng)檢查LD_LIBRARY_PATH里各路徑的先后順序把當(dāng)前環(huán)境需要的 CUDA 路徑排在前面?;蛘咴趩尤蝿?wù)前先unset LD_LIBRARY_PATH再激活 conda 環(huán)境。conda 本身會自動管理它需要的庫路徑你先把它清干凈反而能避免很多環(huán)境沖突。7. conda、pip 混用時的順序感誰先誰后會有大差別PyTorch 生態(tài)里很多擴(kuò)展包比如某些模型庫、分布式訓(xùn)練工具主要是通過 pip 發(fā)布的這就導(dǎo)致一個很實(shí)際的問題一個環(huán)境里PyTorch 本體用 conda 裝其他依賴用 pip 裝那么先裝哪個、后裝哪個會不會有影響7.1 先 conda 后 pip是通用原則我個人的實(shí)踐是PyTorch 及其核心配套torchvision、torchaudio只用 conda 裝其他一切輔助庫都在這之后再用 pip 補(bǔ)裝。順序上一定是先 conda 后 pip。原因是 conda 和 pip 管理依賴的機(jī)制不一樣。conda 在安裝時會做整體的依賴解析如果你先用 pip 裝了一大堆包后面 conda 再裝 PyTorch 時發(fā)現(xiàn)某些依賴版本已經(jīng)在環(huán)境中了就可能出現(xiàn)“Either way我硬塞一個版本沖突進(jìn)去”的情況輕則警告重則直接報(bào)錯。7.2 如果 pip 裝完發(fā)現(xiàn)把環(huán)境搞亂了這種情況很常見。比如你 pip 安裝某個包時它把numpy自動升級到了 2.x而 PyTorch 老版本根本不兼容 numpy 2.x導(dǎo)致一運(yùn)行就報(bào)module compiled against API version之類的錯。處理方法有兩種第一種是直接用 conda 強(qiáng)制降級conda install numpy1.26第二種是別掙扎直接刪環(huán)境重建。如果項(xiàng)目本身依賴不復(fù)雜重建往往比救環(huán)境省時間。7.3 pip 安裝時要注意的編譯類依賴pip 裝 PyTorch 擴(kuò)展時經(jīng)常需要編譯 C/CUDA 擴(kuò)展。這時候服務(wù)器上如果沒有g(shù)cc、make、ninja等工具會直接報(bào)編譯錯誤。雖然這類問題不屬于 conda 安裝 PyTorch 的主流程但既然做服務(wù)器環(huán)境建設(shè)順手把基礎(chǔ)編譯工具裝了很必要conda install gcc_linux-64 gxx_linux-64或者直接讓系統(tǒng)包管理器來裝。注意 conda 里的gcc和系統(tǒng)gcc是兩套東西如果編譯時把 conda 的庫路徑和系統(tǒng)庫路徑混在一起容易產(chǎn)生鏈接錯誤。保持環(huán)境簡單清晰用哪套就固定哪套是減少問題的核心思路。寫在最后說點(diǎn)掏心窩子的經(jīng)驗(yàn)。PyTorch 安裝這件事看起來技術(shù)含量不高但恰恰是這種“簡單事”最容易在項(xiàng)目初期消耗掉大家大量時間。我在服務(wù)器上折騰了這么多輪最大的體會是環(huán)境問題永遠(yuǎn)是“事前管理”比“事后補(bǔ)救”劃算?;ㄊ昼娨?guī)劃好環(huán)境結(jié)構(gòu)、確認(rèn)好硬件驅(qū)動狀態(tài)、配置好鏡像源比出了問題再花兩小時排查要舒服得多。另外建議各位在自己常用的服務(wù)器上把本文提到的這些檢查命令整理成一個初始化腳本下次不管是新機(jī)器還是換團(tuán)隊(duì)都能快速跑一遍確認(rèn)環(huán)境狀態(tài)。畢竟真正該花時間的地方是模型和業(yè)務(wù)邏輯而不是在conda install上反復(fù)碰壁。