python使用Pyinstaller如何打包整個(gè)項(xiàng)目
使用Pyinstaller打包整個(gè)項(xiàng)目
今天真的被Pyinstaller給坑到了?。?!
本文利用spec文件進(jìn)行對整個(gè)項(xiàng)目進(jìn)行打包,直接輸入命令打包也可以,但會(huì)出現(xiàn)比較多的問題。
1 .安裝Pyinstaller
pip install pyinstaller
2. 打開命令窗口
由于我這里是在Anaconda環(huán)境下創(chuàng)建的虛擬環(huán)境,因此要切換到對應(yīng)的環(huán)境下,避免打包無關(guān)的包,同時(shí)切換到對于目錄下。
關(guān)于目錄,我這里是包含主文件、文件(各數(shù)據(jù)集的存放)以及同等級的py文件:
3. 生成 spec文件
執(zhí)行以下命令:
pyi-makespec -w xxx.py(xxx.py文件為要執(zhí)行的主文件,這里我是Insect_predict.py
4. 打開生成的spec文件
(這里是Insect_predict.spec),如下(一些需要自己添加:
#當(dāng)出現(xiàn)出現(xiàn)"RecursionError: maximum recursion depth exceeded問題時(shí),可能打包時(shí)出現(xiàn)了大量的遞歸超出了python預(yù)設(shè)的遞歸深度,需要添加如下三行。 import sys import os.path as osp sys.setrecursionlimit(5000) #---------------------------------------------------------------- block_cipher = None SETUP_DIR ='D:\\ssd-pytorch-mql\\' #所有項(xiàng)目中的py文件路徑以列表形式寫入Analysis如下 #pathex定義了打包的主目錄,默認(rèn)生成,只寫文件名 #當(dāng)出現(xiàn)打包后執(zhí)行程序時(shí)出現(xiàn)類似No Module named xxx,可以將模塊填入到hiddenimports中 #excludes不要什么文件 #data將非py文件的路徑與存放的文件夾名寫在元組里 a = Analysis( ['Insect_predict.py', 'ssd.py','summary.py','voc_annotation.py','get_map.py', 'D:\\ssd-pytorch-mql\\nets\\mobilenetv2.py', 'D:\\ssd-pytorch-mql\\nets\\ssd.py', 'D:\\ssd-pytorch-mql\\nets\\ssd_training.py', 'D:\\ssd-pytorch-mql\\nets\\vgg.py', 'D:\\ssd-pytorch-mql\\utils\\anchors.py', 'D:\\ssd-pytorch-mql\\utils\\callbacks.py', 'D:\\ssd-pytorch-mql\\utils\\dataloader.py', 'D:\\ssd-pytorch-mql\\utils\\utils.py', 'D:\\ssd-pytorch-mql\\utils\\utils_bbox.py', 'D:\\ssd-pytorch-mql\\utils\\utils_fit.py', 'D:\\ssd-pytorch-mql\\utils\\utils_map.py'], pathex=['D:\ssd-pytorch-mql'], binaries=[], datas=[(SETUP_DIR+'model_data','model_data'),(SETUP_DIR+'VOCdevkit','VOCdevkit'),(SETUP_DIR+'img','img')], hiddenimports=[], hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=['zmq','pandas','tensorflow'], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False, ) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE( pyz, a.scripts, [], exclude_binaries=True, name='Insect_predict', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=False, disable_windowed_traceback=False, argv_emulation=False, target_arch=None, codesign_identity=None, entitlements_file=None, ) coll = COLLECT( exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, upx_exclude=[], name='Insect_predict', )
以上內(nèi)容是在生產(chǎn)spec文件后添加上去的,可根據(jù)自己文件內(nèi)報(bào)錯(cuò)進(jìn)行修改。
5. 執(zhí)行spec文件,在命令行輸入
pyinstaller -D xxx.spec或pyinstaller xxx.spec(我的后者才可以運(yùn)行)
6.生成中出現(xiàn)的問題
若生成中遇到如圖所示,即可在spec文件里面添加 excludes=[zmq]或出現(xiàn)lib not found…含有必要包的,可以將后面的路徑添加到系統(tǒng)環(huán)境變量當(dāng)中,我的這樣是可以的,暫時(shí)還沒有遇到模塊的問題,如果有遇到可
以考慮是否版本問題:
當(dāng)執(zhí)行完成會(huì)生產(chǎn)兩個(gè)文件夾dist和build,exe可執(zhí)行文件就在dist文件里面。
一步一步解決,總是可以的?。?!
使用pyinstaller打包pytorch踩的那些坑
花費(fèi)了億點(diǎn)時(shí)間,終于在自己的電腦上搞定了pyinstaller的安裝并且讓它成功打包了一些小程序之后,嘗試著用它打包pytorch這樣的復(fù)雜程序,結(jié)果遇到的問題遠(yuǎn)比想象中要多,于是記個(gè)筆記,也避免后來人踩坑。
問題1:單個(gè)文件打包還是文件夾打包?
用pyinstaller打包pytorch的感覺就是大,這文件真的大……已經(jīng)盡力用from import代替import之類的方式減少了導(dǎo)入的庫內(nèi)容,但還是打包出了一個(gè)巨大無比的應(yīng)用程序。
沒有使用upx壓縮的情況下,打包為文件夾需要3G,而打包為單個(gè)exe文件則是需要1.3G,怎么看好像都是打包成一個(gè)exe比較劃算的樣子……?
大錯(cuò)特錯(cuò)!
首先是啟動(dòng)速度,打包為文件夾的情況下,啟動(dòng)基本是秒啟動(dòng),但是打包為一整個(gè)exe文件,啟動(dòng)就需要將近30s才能print出第一行提示語句……
其次,借著這次機(jī)會(huì)也正好了解了一下exe的運(yùn)行機(jī)制,打包為整個(gè)exe文件之后,它每次運(yùn)行都會(huì)把相當(dāng)于整個(gè)文件夾的內(nèi)容釋放到一個(gè)c盤的臨時(shí)文件夾中,而且它不會(huì)馬上刪除!
你問我為什么發(fā)現(xiàn)了這件事?因?yàn)樵囘\(yùn)行了幾次之后,我的C盤直接裂裂裂裂裂開了……
可憐弱小又無助的系統(tǒng)盤QvQ
經(jīng)過測試發(fā)現(xiàn),打包為整個(gè)文件夾的話,程序就會(huì)在當(dāng)前路徑直接運(yùn)行,而不會(huì)創(chuàng)造一個(gè)巨大無比的臨時(shí)文件在一次次運(yùn)行中炸掉C盤,因此最后決定采用打包為一個(gè)文件夾的形式。
問題2:一起打包的數(shù)據(jù)文件找不到?
畢竟……是pytorch嘛,最終打包的肯定是只有測試模式的代碼,而不會(huì)把訓(xùn)練模式的大段代碼都塞進(jìn)exe里面,所以,希望把一個(gè).pth的模型數(shù)據(jù)文件一起打包進(jìn)去,這樣加載的網(wǎng)絡(luò)模型只要直接從模型里面讀數(shù)據(jù)就可以了。
很快,新的問題出現(xiàn)了,當(dāng)把模型的路徑設(shè)置為當(dāng)前路徑的時(shí)候,會(huì)出現(xiàn)一種非常詭異的情況:在本地計(jì)算機(jī)上運(yùn)行正常,但是把整個(gè)打包好的文件夾放在別的電腦上運(yùn)行的時(shí)候,它直接報(bào)錯(cuò)說,找不到該文件!
你總不會(huì)是把絕對路徑給打包到exe里面去了吧???
好在查閱了一堆網(wǎng)絡(luò)資料后,發(fā)現(xiàn)這可能是運(yùn)行路徑的問題,但是網(wǎng)上給出的寫法五花八門,大部分試了之后發(fā)現(xiàn)根本沒卵用, 另一個(gè)問題是,打包之后的文件夾過于雜亂,因此甚至想找到啟動(dòng)程序的exe文件都需要滾輪往下滑好幾頁,尋思之后,干脆在整個(gè)文件夾外面寫一個(gè).bat文件作為啟動(dòng)腳本:
start 文件夾/啟動(dòng)文件.exe
此時(shí)的目錄結(jié)構(gòu)如圖所示:
|-測試工作區(qū)
|-打包的整個(gè)項(xiàng)目文件夾
|-打包后的數(shù)據(jù)文件
|-打包后的啟動(dòng)程序.exe
|-用于啟動(dòng)exe的腳本.bat
但是這又引出了新的問題:這個(gè)運(yùn)行的路徑到底是臨時(shí)程序文件路徑,還是exe啟動(dòng)程序路徑,還是bat腳本路徑???
我沒看懂,但我大受震撼.jpg
猜測半天不如進(jìn)行實(shí)測,于是把網(wǎng)上五花八門的寫法都拉進(jìn)來寫了個(gè)測試代碼打包到exe里面看看結(jié)果:
import os print("當(dāng)前程序路徑",os.getcwd(), os.path.exists(os.getcwd()+'\\'+G_model_path)) print("當(dāng)前腳本路徑", sys.path[0], os.path.exists(sys.path[0]+'\\'+G_model_path)) print("當(dāng)前默認(rèn)所在路徑", os.path.abspath('.'), os.path.exists(os.path.abspath('.')+'\\'+G_model_path)) print('臨時(shí)執(zhí)行路徑',os.path.split(os.path.realpath(__file__))[0], os.path.exists(os.path.split(os.path.realpath(__file__))[0]+'\\'+G_model_path))
每一行都會(huì)顯示這種寫法得到的路徑信息,與能否在這條路徑上找到打包到文件夾里面的數(shù)據(jù)文件。
首先嘗試直接雙擊exe啟動(dòng),得到結(jié)果:
當(dāng)前程序路徑 測試工作區(qū)\打包的整個(gè)項(xiàng)目文件夾 True
當(dāng)前腳本路徑 測試工作區(qū)\打包的整個(gè)項(xiàng)目文件夾\base_library.zip False
當(dāng)前默認(rèn)所在路徑 測試工作區(qū)\打包的整個(gè)項(xiàng)目文件夾 True
臨時(shí)執(zhí)行路徑 測試工作區(qū)\打包的整個(gè)項(xiàng)目文件夾 True
然后試著用.bat啟動(dòng)exe,得到結(jié)果:
當(dāng)前程序路徑 測試工作區(qū) False
當(dāng)前腳本路徑 測試工作區(qū)\打包的整個(gè)項(xiàng)目文件夾\base_library.zip False
當(dāng)前默認(rèn)所在路徑 測試工作區(qū) False
臨時(shí)執(zhí)行路徑 測試工作區(qū)\打包的整個(gè)項(xiàng)目文件夾 True
實(shí)踐出真知,全部測試之后的結(jié)果表明, 在直接雙擊運(yùn)行exe的時(shí)候,有三種措施都能起效,但是通過bat運(yùn)行exe的時(shí)候,只有最后一種寫法sys.path[0]
就是渣渣!
os.path.split(os.path.realpath(__file__))[0]
才能找到正確的數(shù)據(jù)文件所在路徑。
問題3:GPU訓(xùn)練的模型要放到CPU環(huán)境跑?
這個(gè)問題相對來說比較簡單,只需要修改加載模型參數(shù)的代碼。
從G_model.load_state_dict(load(G_model_path))
改為G_model.load_state_dict(load(G_model_path, map_location=device('cpu')))
問題4:直接打包還是用spec文件配置?
推薦先生成spec文件,完成配置后重新打包
然后在test.spec中修改參數(shù):
4.1 添加PYTHONPATH
如果你需要import項(xiàng)目根目錄中的文件夾作為庫,需要將文件夾路徑添加到該參數(shù)
必須用絕對路徑!相對路徑不生效!
pathex=['path']
4.2 添加數(shù)據(jù)文件
程序調(diào)用的相對路徑中的數(shù)據(jù)文件
datas=[(oldpath1, newpath1), (oldpath2, newpath2)]
4.3 手動(dòng)添加沒有被識(shí)別到的調(diào)用庫
hiddenimports=['libs']
問題全部解決之后,程序運(yùn)行正常√
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- 用PyInstaller把Python代碼打包成單個(gè)獨(dú)立的exe可執(zhí)行文件
- Python打包方法Pyinstaller的使用
- python-pyinstaller、打包后獲取路徑的實(shí)例
- Python中用pyinstaller打包時(shí)的圖標(biāo)問題及解決方法
- python3.9實(shí)現(xiàn)pyinstaller打包python文件成exe
- 教你使用pyinstaller打包Python教程
- PyInstaller?完美打包?Python?腳本
- Python?pyinstaller打包exe最新完整圖文教程
- Python使用pyinstaller打包成.exe文件執(zhí)行后閃退的圖文解決辦法
- PyInstaller打包Python腳本的使用示例
相關(guān)文章
在Python中將函數(shù)作為另一個(gè)函數(shù)的參數(shù)傳入并調(diào)用的方法
今天小編就為大家分享一篇在Python中將函數(shù)作為另一個(gè)函數(shù)的參數(shù)傳入并調(diào)用的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-01-01Numpy將二維數(shù)組添加到空數(shù)組的實(shí)現(xiàn)
今天小編就為大家分享一篇Numpy將二維數(shù)組添加到空數(shù)組的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-12-12linux環(huán)境下安裝python虛擬環(huán)境及注意事項(xiàng)
這篇文章主要介紹了linux環(huán)境下安裝python虛擬環(huán)境,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01使用python中的in ,not in來檢查元素是不是在列表中的方法
今天小編就為大家分享一篇使用python中的in ,not in來檢查元素是不是在列表中的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07Python lambda 匿名函數(shù)優(yōu)點(diǎn)和局限性深度總結(jié)
這篇文章主要為大家介紹了Python lambda 匿名函數(shù)的優(yōu)點(diǎn)和局限性深度總結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08