戰(zhàn):Python 2.7+Theano 0.8.2老環(huán)境搭建與避坑指南)
簡(jiǎn)介Pylearn2是由蒙特利爾大學(xué)MILA實(shí)驗(yàn)室開發(fā)的經(jīng)典Python深度學(xué)習(xí)框架專為研究卷積神經(jīng)網(wǎng)絡(luò)、受限玻爾茲曼機(jī)等模型而設(shè)計(jì)適合希望深入理解底層實(shí)現(xiàn)的研究者與初學(xué)者。此壓縮包為pylearn2-master源碼版本共750個(gè)文件、2.16MB其中以522個(gè)py源碼文件為主體輔以70個(gè)yaml配置文件、51個(gè)txt說(shuō)明與19個(gè)readme文檔還包含CUDA擴(kuò)展、Jupyter示例及可視化腳本覆蓋模型定義、訓(xùn)練配置、數(shù)據(jù)處理等關(guān)鍵模塊。已有271人學(xué)習(xí)下載。通過(guò)安裝這套源碼讀者能夠了解Theano后端的協(xié)作方式掌握setup.py安裝流程并結(jié)合配置文件和示例快速開展實(shí)驗(yàn)是探索經(jīng)典深度學(xué)習(xí)工具鏈、梳理算法原理的實(shí)用資料。1. pylearn2 安裝一套必須按考古規(guī)格對(duì)待的深度學(xué)習(xí)老環(huán)境這幾年只要接復(fù)現(xiàn)老論文、跑某實(shí)驗(yàn)室早期 demo 的活就繞不開pylearn2 這個(gè) Theano 時(shí)代的“化石級(jí)”深度學(xué)習(xí)庫(kù)。它停更得早代碼從語(yǔ)法到依賴都只認(rèn) Python 2.7 和 Theano 0.8.x稍微手一抖裝了個(gè)新版本import 直接崩掉報(bào)錯(cuò)五花八門No module named pylearn2、numpy.dtype has the wrong size、module theano has no attribute tensor。這套環(huán)境裝不好一個(gè)下午就沒了。這篇筆記把我踩過(guò)的坑完整寫一遍Python 2.7 怎么鎖、Theano 怎么選版本、pylearn2 怎么接進(jìn)環(huán)境、裝完怎么驗(yàn)證適合要復(fù)現(xiàn)老實(shí)驗(yàn)、趕課程作業(yè)或做模型比對(duì)的讀者。2. 裝前環(huán)境準(zhǔn)備Python 2.7 虛擬環(huán)境與依賴版本鎖定2.1 為什么必須用 Python 2.7這個(gè)庫(kù)從來(lái)沒遷到 Python 3 過(guò)pylearn2 的代碼主體停留在 Python 2 時(shí)代源碼里到處都是print語(yǔ)句、xrange、dict.iteritems()這類 Python 2 專屬寫法。這些語(yǔ)法在 Python 3 下不是拋SyntaxError就是AttributeError沒有任何平滑遷移的可能。它的官方測(cè)試環(huán)境也只覆蓋 Python 2.7社區(qū)里偶爾有人用 Python 3.6 硬拉起來(lái)但跑不到幾步就掛在 Theano 0.9 的兼容接口上。所以說(shuō)第一步不是裝 pylearn2而是先把 Python 2.7 的隔離環(huán)境搭好。不建虛擬環(huán)境、直接在系統(tǒng) Python 3 里強(qiáng)行 pip install最后大概率得到一個(gè)“看起來(lái)裝了、實(shí)際一跑就碎”的黑匣子。我用 conda 建環(huán)境比較省心conda 默認(rèn)倉(cāng)庫(kù)里還保留著 Python 2.7 的完整包不需要找額外的源。conda create -n pylearn2_env python2.7 -y這條命令創(chuàng)建一個(gè)名為pylearn2_env的新環(huán)境Python 版本鎖定 2.7。-y表示跳過(guò)確認(rèn)提示腳本化執(zhí)行不會(huì)卡住。conda 會(huì)自動(dòng)把 Python 2.7、pip、setuptools 一起裝好pip 版本通常在 20.3.x這正是 Python 2.7 最后能正常使用的 pip 版本后面千萬(wàn)別手賤升級(jí) pippip 21.3 開始徹底放棄 Python 2.7 支持升完整個(gè)環(huán)境就廢了一半。conda activate pylearn2_env python --version激活環(huán)境后第一件事就是確認(rèn) Python 版本。如果這里顯示的不是 2.7.x說(shuō)明激活沒生效檢查完 conda 的 shell 初始化再說(shuō)。順帶說(shuō)一句Windows 用戶最好別在原生環(huán)境里折騰pylearn2 這套東西在 Windows 上 Theano 編譯會(huì)牽涉 MinGW 和 Visual Studio 的版本匹配玄學(xué)問(wèn)題太多我一般建議直接裝個(gè) WSL在 Ubuntu 里走這套流程能省下大半條命。2.2 依賴矩陣numpy 1.16.6 就是這條環(huán)境鏈的命門環(huán)境建好之后先別急著裝 Theano得把基礎(chǔ)數(shù)值庫(kù)版本鎖死。pylearn2 依賴 numpy、scipy、Pillow、matplotlib、PyYAML每一個(gè)在 Python 2.7 下都有版本上限。Theano 的 C 擴(kuò)展是編譯進(jìn) Python 進(jìn)程的它和 numpy 的 C API 必須嚴(yán)格匹配。numpy 裝到 1.17 以上Theano 0.8.2 加載時(shí)大概率直接 ABI 崩掉。pip install numpy1.16.6 scipy1.2.3 Pillow6.2.2 matplotlib2.2.5 PyYAML3.13這一條命令把五個(gè)核心依賴一次裝齊。版本選擇是有講究的numpy 1.16.6 是 Python 2.7 最后一個(gè)完整支持線Theano 0.8.2 的 C 代碼在這個(gè)版本上編譯最穩(wěn)scipy 1.2.3 和 numpy 1.16 是同一代編譯產(chǎn)物二進(jìn)制依賴對(duì)得上Pillow 6.2.2 是最后支持 Python 2.7 的 Pillow 大版本Pillow 7 直接不認(rèn) Python 2matplotlib 2.2.5 同理2.2 是它在 Python 2.7 上的絕唱PyYAML 3.13 則是 pylearn2 加載 YAML 配置時(shí)最匹配的版本yaml_parse 模塊對(duì)過(guò)新的 PyYAML 兼容性反而不穩(wěn)。裝完后檢查一下實(shí)際落地的版本防止 pip 解析依賴時(shí)悄悄改了某個(gè)包pip list | grep -E numpy|scipy|Pillow|PyYAML|matplotlib|theano到這里你看到的應(yīng)該是一串老版本號(hào)任何一個(gè)對(duì)不上都要先修好再往下走。提示如果 pip 在安裝過(guò)程中卡在編譯源碼大概率是環(huán)境缺少編譯工具鏈。Debian/Ubuntu 上先執(zhí)行sudo apt install -y g python2.7-dev build-essential再重試。3. 安裝 Theano 0.8.2pylearn2 的第一道坎3.1 Theano 版本取舍0.8 穩(wěn)定、0.9 危險(xiǎn)pylearn2 的 setup.py 里對(duì) Theano 的要求是 0.8.2 到 0.9.x 之間但實(shí)際跑下來(lái)0.8.2 才是最省事的版本。Theano 0.9 引入了不少 API 調(diào)整對(duì) Python 3 做了部分適配但這恰恰導(dǎo)致它在 Python 2.7 上表現(xiàn)不如 0.8.2 純粹。很多人在裝 pylearn2 時(shí)順手裝了最新版 Theano結(jié)果 pylearn2 內(nèi)部調(diào)用theano.tensor、theano.compile的老接口全部失配報(bào)錯(cuò)一個(gè)接一個(gè)。保守路線就是鎖定 Theano 0.8.2這是 pylearn2 開發(fā)時(shí)代官方測(cè)試最充分的版本。如果 pip 源里已經(jīng)存在舊的 Theano 殘留先清掉再裝新版本pip uninstall theano -y pip install theano0.8.2先卸載再安裝是為了避免 pip 誤判 Theano 已存在而跳過(guò)安裝。裝完后立刻確認(rèn)版本和加載路徑python -c import theano; print(theano.__version__)如果這里導(dǎo)入失敗看看是不是系統(tǒng)里還有其他 Python 路徑搶先加載了另一個(gè) theano用python -c import theano; print(theano.__file__)追一下路徑。3.2 編譯鏈Theano 需要一臺(tái)能編譯 C 的機(jī)器Theano 0.8.2 的工作機(jī)制不是純 Python 解釋執(zhí)行它會(huì)把符號(hào)表達(dá)式編譯成 C 代碼再打包成 Python 函數(shù)。這意味著機(jī)器上必須有一個(gè)可用的 C 編譯器。Linux 上缺 g 是安裝后跑訓(xùn)練時(shí)才暴露的問(wèn)題我見過(guò)有人在 import 階段一切正常第一次theano.function編譯直接報(bào)g not available。sudo apt install -y g裝好之后可以用g --version看版本。macOS 用戶一般有 clang 就夠了不需要額外裝 gcc。Windows 原生環(huán)境的編譯鏈最痛苦MinGW 版本、Visual Studio 運(yùn)行庫(kù)、Python 2.7 的 MSVC 版本三方匹配任何一個(gè)對(duì)不上都起不來(lái)。這也是我更傾向讓 Windows 用戶走 WSL 的原因。3.3 寫 .theanorcfloatX、device、優(yōu)化器一次定死Theano 運(yùn)行時(shí)讀~/.theanorc這個(gè)配置文件。pylearn2 的很多模型默認(rèn)用 float32 精度加載參數(shù)和計(jì)算如果 Theano 的floatX沒設(shè)置成 float32模型里 dtype 混用會(huì)引發(fā)各種類型不匹配報(bào)錯(cuò)位置還特別隱蔽。[global] floatX float32 device cpu mode FAST_RUN optimizer fast_run [gcc] cxxflags -O3這個(gè)文件的邏輯很直接floatX float32讓整個(gè)默認(rèn)張量類型統(tǒng)一到單精度和 pylearn2 內(nèi)部的權(quán)重初始化、數(shù)據(jù)加載保持一致device cpu先把計(jì)算設(shè)備鎖在 CPU 上第一次安裝驗(yàn)證環(huán)境時(shí)不要碰 GPU減少變量mode FAST_RUN表示不做調(diào)試檢查optimizer fast_run開啟優(yōu)化器[gcc]段的cxxflags -O3讓編譯出的 C 代碼跑得更快。設(shè)備這行以后要跑 GPU 再改成device cuda但初裝階段千萬(wàn)保持 CPU。寫完配置后做一次完整的 Theano 編譯冒煙測(cè)試python -c import numpy import theano x theano.tensor.fmatrix(x) y theano.tensor.exp(x) f theano.function([x], y) print(f(numpy.ones((2, 3), dtypefloat32))) 第一次執(zhí)行theano.function會(huì)觸發(fā) C 編譯耗時(shí)從幾十秒到幾分鐘不等期間會(huì)刷出一堆警告這是正常現(xiàn)象。最終能打印出一個(gè) 2x3 的 float32 矩陣說(shuō)明 Theano 的編譯鏈路完整走通了。4. 安裝 pylearn2 本體源碼包、注冊(cè)模式與 PYTHONPATH4.1 兩種獲取方式pip 快速線還是源碼開發(fā)線pylearn2 在 PyPI 上有存檔包直接 pip install 能把包體放到 site-packages 里但包里的樣例 YAML 和腳本目錄不全后續(xù)想看模型配置、改訓(xùn)練腳本時(shí)會(huì)很別扭。源碼克隆的方式更適合實(shí)際使用整套代碼、腳本、教程 YAML 都在本地隨時(shí)能翻、能改、能跑。不過(guò) pip 路線可以用來(lái)快速試探環(huán)境我建議用--no-deps避免它自動(dòng)拉依賴。pylearn2 的依賴聲明在 PyPI 上標(biāo)注得比較寬松不加這個(gè)參數(shù)pip 會(huì)把 numpy、Theano 全部重裝成最新版前面鎖的版本瞬間白干。pip install pylearn2 --no-deps--no-deps告訴 pip 只裝 pylearn2 本體不解析任何依賴。裝完后如果你發(fā)現(xiàn) import 到的路徑不在預(yù)期位置用python -c import pylearn2; print(pylearn2.__file__)查一下后面源碼安裝時(shí)最怕這種殘留混一起。4.2 源碼安裝開發(fā)模式與 PYTHONPATH 雙保險(xiǎn)源碼路線是我個(gè)人推薦的最終方案。先把倉(cāng)庫(kù)克隆到本地mkdir -p ~/src cd ~/src git clone 項(xiàng)目主頁(yè)的倉(cāng)庫(kù)地址 pylearn2 cd pylearn2克隆地址從項(xiàng)目主頁(yè)復(fù)制不同的鏡像和倉(cāng)庫(kù)位置對(duì)應(yīng)不同 URL這里不寫死。進(jìn)入源碼根目錄后有兩種方式讓 Python 找到這個(gè)包。第一種是setup.py develop模式它會(huì)在 site-packages 里生成一個(gè)指向源碼目錄的鏈接后續(xù)改源碼即時(shí)生效不用反復(fù)重裝python setup.py developdevelop是 setuptools 提供的開發(fā)安裝模式本質(zhì)上相當(dāng)于手動(dòng)在 Python 路徑里注冊(cè)了一個(gè)軟鏈。Python 2.7 環(huán)境下的 setuptools 版本通常 44.x對(duì)這個(gè)老項(xiàng)目的 setup.py 兼容沒問(wèn)題。如果setup.py develop因?yàn)闄?quán)限或 setuptools 版本報(bào)錯(cuò)退回到直接設(shè)置 PYTHONPATH這是最粗暴也最可控的方式export PYTHONPATH$HOME/src/pylearn2:$PYTHONPATH echo export PYTHONPATH$HOME/src/pylearn2:$PYTHONPATH ~/.bashrcPYTHONPATH 里的目錄會(huì)被 Python 解釋器優(yōu)先搜索只要 pylearn2 源碼在這個(gè)路徑下任何目錄里跑import pylearn2都能命中。把這條 export 寫進(jìn).bashrc是為了避免每次開終端都手動(dòng)導(dǎo)入。提示setup.py 必須用 Python 2.7 環(huán)境里的 python 執(zhí)行不要手滑敲成 python3。裝在 Python 3 的 site-packages 里等于白裝。4.3 確認(rèn)加載路徑防止多副本混戰(zhàn)這一步很容易被跳過(guò)但恰恰是項(xiàng)目跑一段時(shí)間后突然報(bào)奇怪 import 錯(cuò)誤的根源。檢查當(dāng)前環(huán)境到底加載的是哪一份 pylearn2python -c import pylearn2; print(pylearn2.__file__)如果輸出路徑是~/src/pylearn2開頭說(shuō)明 PYTHONPATH 生效了。如果輸出的是 site-packages 里的路徑說(shuō)明 pip 裝的舊副本搶了先而那個(gè)副本缺少源碼目錄下的腳本和 YAML。這時(shí)候卸載 pip 版本并把 site-packages 里殘留的 pylearn2 目錄手動(dòng)清掉pip uninstall pylearn2 -y find ~/miniconda3/envs/pylearn2_env/lib/python2.7/site-packages -maxdepth 2 -name pylearn2* -exec rm -rf {} \;第二行命令里的路徑換成你實(shí)際 conda 環(huán)境的 site-packages 路徑。清理完后再跑一次路徑檢查應(yīng)該就只有源碼目錄這一份了。5. 避坑pylearn2 安裝里最常見的五個(gè)翻車點(diǎn)5.1 現(xiàn)象No module named pylearn2現(xiàn)象pip list 里明明有 pylearn2但執(zhí)行import pylearn2直接拋ImportError: No module named pylearn2或者程序跑到一半才爆這個(gè)錯(cuò)。原因最常見的兩個(gè)來(lái)源一是 pip 裝的和源碼裝的分屬兩套路徑Python 解釋器在 sys.path 里找不到實(shí)際模塊二是 PyPI 存檔包本身內(nèi)容不全目錄結(jié)構(gòu)缺了包入口import 時(shí)直接撲空。解決先執(zhí)行python -c import sys; print(sys.path)看當(dāng)前解釋器的搜索路徑再用which python確認(rèn)跑的是不是 conda 環(huán)境里的 Python 2.7。卸載所有版本的 pylearn2走源碼 PYTHONPATH 的路線最后做一次路徑檢查確認(rèn)加載的 pylearn2 來(lái)自源碼目錄。5.2 現(xiàn)象numpy.dtype has the wrong size現(xiàn)象import theano 時(shí)一切正常但第一次theano.function編譯時(shí)報(bào)ValueError: numpy.dtype has the wrong size, try recompiling或者numpy.core.multiarray failed to import。原因Theano 0.8.2 編譯 C 擴(kuò)展時(shí)讀的是某個(gè) numpy 版本的頭文件運(yùn)行時(shí)加載的 numpy 二進(jìn)制卻是另一個(gè)版本C ABI 對(duì)不上。絕大多數(shù)情況是 numpy 裝得太新有些教程讓你直接pip install numpy結(jié)果裝到了 1.20 甚至更高。解決確認(rèn)環(huán)境內(nèi) numpy 是 1.16.6然后清掉 Theano 的編譯緩存目錄~/.theano讓它在新版 numpy 下重新編譯。rm -rf ~/.theano這步是后悔藥編譯緩存清掉后質(zhì)量和速度回到第一次編譯的狀態(tài)純 CPU 機(jī)器上多等幾分鐘就能跑通。5.3 現(xiàn)象module theano has no attribute tensor現(xiàn)象import theano.tensor沒問(wèn)題但跑到import pylearn2時(shí)拋AttributeError: module theano has no attribute tensorPython 2.7 下則報(bào)module object has no attribute tensor。原因環(huán)境中裝的 Theano 不是 0.8.2而是新版的 Theano forkTheano-PyMC 的繼任項(xiàng)目或 Theano 0.9。新版把張量相關(guān)接口拆到了別的位置pylearn2 用的老調(diào)用點(diǎn)全部失配。解決pip uninstall theano -y強(qiáng)制裝回pip install theano0.8.2。裝完立刻看theano.__file__和theano.__version__確定版本對(duì)了再進(jìn)下一步。5.4 現(xiàn)象from pylearn2.config import yaml_parse 失敗現(xiàn)象import pylearn2 本身沒報(bào)錯(cuò)但執(zhí)行from pylearn2.config import yaml_parse拋出ImportError: cannot import name yaml_parse。原因加載到的 pylearn2 份不是完整源碼樹比如 site-packages 里有個(gè)殘缺的舊副本或者 PYTHONPATH 指向的目錄不是源碼根目錄Python 只找到了包的一部分模塊。解決在源碼根目錄下執(zhí)行l(wèi)s pylearn2/config/確認(rèn)存在yaml_parse.py文件。若源碼樹里確實(shí)有這個(gè)文件就清理 site-packages 殘留并糾正 PYTHONPATH若源碼樹里沒有說(shuō)明克隆不完整重新拉取完整倉(cāng)庫(kù)。5.5 現(xiàn)象GPU 配置報(bào)錯(cuò)后退回 CPU 仍然翻車現(xiàn)象在模型 YAML 里寫了device: gpu或用環(huán)境變量THEANO_FLAGSdevicegpu啟動(dòng)后報(bào) CUDA 相關(guān)錯(cuò)誤比如nvcc not available、libcudart not found。把 device 改回 cpu 后重啟同一腳本仍然報(bào)同樣的 CUDA 錯(cuò)。原因.bashrc里殘留了THEANO_FLAGS環(huán)境變量每次啟動(dòng) shell 都會(huì)注入 GPU 配置同時(shí)~/.theano下還留著之前用 GPU 聲明編譯的緩存目錄緩存里的編譯標(biāo)志還記得 gpu。解決先grep THEANO檢查.bashrc把相關(guān)行刪掉并重新source ~/.bashrc再rm -rf ~/.theano清掉全部緩存最后檢查模型 YAML 里是否還寫著device: gpu刪掉或改成cpu。這套三連清完GPU 殘留才能徹底斷干凈。6. 裝完怎么驗(yàn)證三組冒煙測(cè)試確認(rèn)整條鏈路跑通6.1 版本核驗(yàn)和 Theano 首次編譯環(huán)境裝完不要急著跑訓(xùn)練先做三組快速驗(yàn)證。第一組確認(rèn)解釋器和庫(kù)版本python --version python -c import theano, pylearn2; print(theano.__version__)python --version顯示 Python 2.7.x第二行能打印 Theano 版本號(hào)而不報(bào)錯(cuò)說(shuō)明兩個(gè)核心庫(kù)都正確掛進(jìn)了當(dāng)前環(huán)境。第二組驗(yàn)證 Theano 的編譯鏈路這是整個(gè)環(huán)境里最容易隱藏問(wèn)題的環(huán)節(jié)python -c import numpy import theano x theano.tensor.fmatrix(x) f theano.function([x], x * 2) print(f(numpy.ones((1, 3), dtypefloat32))) 編譯會(huì)慢但必須等它走完打印出[[ 2. 2. 2.]]說(shuō)明 C 編譯器、numpy ABI、Theano 緩存全部正常。6.2 用 yaml_parse 構(gòu)造一個(gè)真實(shí)模型第三組直接測(cè) pylearn2 的核心機(jī)制。pylearn2 的模型定義是通過(guò) YAML 字符串傳入yaml_parse完成的這一步能構(gòu)造模型就等于驗(yàn)證了整個(gè)對(duì)象注冊(cè)系統(tǒng)、配置解析通路和 Theano 張量接口都可用from pylearn2.config import yaml_parse model_yaml !obj:pylearn2.models.mlp.MLP { layers: [ !obj:pylearn2.models.mlp.Sigmoid { dim: 8, layer_name: hidden, irange: 0.1 }, !obj:pylearn2.models.mlp.Softmax { layer_name: softmax, n_classes: 2, irange: 0.1 }, ], nvis: 4, } model yaml_parse.load(model_yaml) print(construct OK:, model.layer_names)這個(gè)腳本構(gòu)造了一個(gè)兩層 MLP輸入維度 4、隱藏層 8 個(gè)單元、輸出兩類。irange控制權(quán)重初始化范圍nvis是輸入特征數(shù)。能打印出construct OK和層名列表說(shuō)明 pylearn2 的模型系統(tǒng)完整可用。6.3 想更徹底就跑一個(gè)自帶 YAML 的完整訓(xùn)練冒煙測(cè)試通過(guò)后想親眼看到訓(xùn)練過(guò)程可以進(jìn)入源碼目錄找一個(gè)小的訓(xùn)練 YAML 跑起來(lái)cd ~/src/pylearn2 find . -name *.yaml | head -20 python pylearn2/scripts/train.py 找到的yaml路徑train.py是 pylearn2 的官方訓(xùn)練入口第一個(gè)參數(shù)就是 YAML 文件路徑。第一次跑會(huì)經(jīng)歷數(shù)據(jù)下載、預(yù)處理和模型編譯期間會(huì)有大量老庫(kù)的兼容性警告屬于正常情況。只要看到類似Epoch 0、訓(xùn)練損失數(shù)字在變化就說(shuō)明從數(shù)據(jù)管道到模型訓(xùn)練的全鏈路已經(jīng)跑通按 Ctrl-C 退出即可。從那以后我每次裝完 pylearn2都強(qiáng)制自己把這三組冒煙驗(yàn)證走一遍版本確認(rèn)、Theano 編譯、yaml_parse 構(gòu)造模型。這套驗(yàn)證全部通過(guò)再投入真實(shí)實(shí)驗(yàn)幾乎再也沒有被“裝上卻跑不了”這種事絆住過(guò)。環(huán)境再老先把地基踩實(shí)再蓋樓。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取