網站首頁 編程語言 正文
使用Pyinstaller打包整個項目
今天真的被Pyinstaller給坑到了!!!
本文利用spec文件進行對整個項目進行打包,直接輸入命令打包也可以,但會出現比較多的問題。
1 .安裝Pyinstaller
pip install pyinstaller
2. 打開命令窗口
由于我這里是在Anaconda環境下創建的虛擬環境,因此要切換到對應的環境下,避免打包無關的包,同時切換到對于目錄下。
關于目錄,我這里是包含主文件、文件(各數據集的存放)以及同等級的py文件:
3. 生成 spec文件
執行以下命令:
pyi-makespec -w xxx.py(xxx.py文件為要執行的主文件,這里我是Insect_predict.py
4. 打開生成的spec文件
(這里是Insect_predict.spec),如下(一些需要自己添加:
#當出現出現"RecursionError: maximum recursion depth exceeded問題時,可能打包時出現了大量的遞歸超出了python預設的遞歸深度,需要添加如下三行。 import sys import os.path as osp sys.setrecursionlimit(5000) #---------------------------------------------------------------- block_cipher = None SETUP_DIR ='D:\\ssd-pytorch-mql\\' #所有項目中的py文件路徑以列表形式寫入Analysis如下 #pathex定義了打包的主目錄,默認生成,只寫文件名 #當出現打包后執行程序時出現類似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', )
以上內容是在生產spec文件后添加上去的,可根據自己文件內報錯進行修改。
5. 執行spec文件,在命令行輸入
pyinstaller -D xxx.spec或pyinstaller xxx.spec(我的后者才可以運行)
6.生成中出現的問題
若生成中遇到如圖所示,即可在spec文件里面添加 excludes=[zmq]或出現lib not found…含有必要包的,可以將后面的路徑添加到系統環境變量當中,我的這樣是可以的,暫時還沒有遇到模塊的問題,如果有遇到可
以考慮是否版本問題:
當執行完成會生產兩個文件夾dist和build,exe可執行文件就在dist文件里面。
一步一步解決,總是可以的!!!
使用pyinstaller打包pytorch踩的那些坑
花費了億點時間,終于在自己的電腦上搞定了pyinstaller的安裝并且讓它成功打包了一些小程序之后,嘗試著用它打包pytorch這樣的復雜程序,結果遇到的問題遠比想象中要多,于是記個筆記,也避免后來人踩坑。
問題1:單個文件打包還是文件夾打包?
用pyinstaller打包pytorch的感覺就是大,這文件真的大……已經盡力用from import代替import之類的方式減少了導入的庫內容,但還是打包出了一個巨大無比的應用程序。
沒有使用upx壓縮的情況下,打包為文件夾需要3G,而打包為單個exe文件則是需要1.3G,怎么看好像都是打包成一個exe比較劃算的樣子……?
大錯特錯!
首先是啟動速度,打包為文件夾的情況下,啟動基本是秒啟動,但是打包為一整個exe文件,啟動就需要將近30s才能print出第一行提示語句……
其次,借著這次機會也正好了解了一下exe的運行機制,打包為整個exe文件之后,它每次運行都會把相當于整個文件夾的內容釋放到一個c盤的臨時文件夾中,而且它不會馬上刪除!
你問我為什么發現了這件事?因為試運行了幾次之后,我的C盤直接裂裂裂裂裂開了……
可憐弱小又無助的系統盤QvQ
經過測試發現,打包為整個文件夾的話,程序就會在當前路徑直接運行,而不會創造一個巨大無比的臨時文件在一次次運行中炸掉C盤,因此最后決定采用打包為一個文件夾的形式。
問題2:一起打包的數據文件找不到?
畢竟……是pytorch嘛,最終打包的肯定是只有測試模式的代碼,而不會把訓練模式的大段代碼都塞進exe里面,所以,希望把一個.pth的模型數據文件一起打包進去,這樣加載的網絡模型只要直接從模型里面讀數據就可以了。
很快,新的問題出現了,當把模型的路徑設置為當前路徑的時候,會出現一種非常詭異的情況:在本地計算機上運行正常,但是把整個打包好的文件夾放在別的電腦上運行的時候,它直接報錯說,找不到該文件!
你總不會是把絕對路徑給打包到exe里面去了吧???
好在查閱了一堆網絡資料后,發現這可能是運行路徑的問題,但是網上給出的寫法五花八門,大部分試了之后發現根本沒卵用, 另一個問題是,打包之后的文件夾過于雜亂,因此甚至想找到啟動程序的exe文件都需要滾輪往下滑好幾頁,尋思之后,干脆在整個文件夾外面寫一個.bat文件作為啟動腳本:
start 文件夾/啟動文件.exe
此時的目錄結構如圖所示:
|-測試工作區
? ? |-打包的整個項目文件夾
? ? ? ? |-打包后的數據文件
? ? ? ? |-打包后的啟動程序.exe
? ? |-用于啟動exe的腳本.bat
但是這又引出了新的問題:這個運行的路徑到底是臨時程序文件路徑,還是exe啟動程序路徑,還是bat腳本路徑???
我沒看懂,但我大受震撼.jpg
猜測半天不如進行實測,于是把網上五花八門的寫法都拉進來寫了個測試代碼打包到exe里面看看結果:
import os print("當前程序路徑",os.getcwd(), os.path.exists(os.getcwd()+'\\'+G_model_path)) print("當前腳本路徑", sys.path[0], os.path.exists(sys.path[0]+'\\'+G_model_path)) print("當前默認所在路徑", os.path.abspath('.'), os.path.exists(os.path.abspath('.')+'\\'+G_model_path)) print('臨時執行路徑',os.path.split(os.path.realpath(__file__))[0], os.path.exists(os.path.split(os.path.realpath(__file__))[0]+'\\'+G_model_path))
每一行都會顯示這種寫法得到的路徑信息,與能否在這條路徑上找到打包到文件夾里面的數據文件。
首先嘗試直接雙擊exe啟動,得到結果:
當前程序路徑 測試工作區\打包的整個項目文件夾 True
當前腳本路徑 測試工作區\打包的整個項目文件夾\base_library.zip False
當前默認所在路徑 測試工作區\打包的整個項目文件夾 True
臨時執行路徑 測試工作區\打包的整個項目文件夾 True
然后試著用.bat啟動exe,得到結果:
當前程序路徑 測試工作區 False
當前腳本路徑 測試工作區\打包的整個項目文件夾\base_library.zip False
當前默認所在路徑 測試工作區 False
臨時執行路徑 測試工作區\打包的整個項目文件夾 True
實踐出真知,全部測試之后的結果表明, 在直接雙擊運行exe的時候,有三種措施都能起效,但是通過bat運行exe的時候,只有最后一種寫法sys.path[0]
就是渣渣!
os.path.split(os.path.realpath(__file__))[0]
才能找到正確的數據文件所在路徑。
問題3:GPU訓練的模型要放到CPU環境跑?
這個問題相對來說比較簡單,只需要修改加載模型參數的代碼。
從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中修改參數:
4.1 添加PYTHONPATH
如果你需要import項目根目錄中的文件夾作為庫,需要將文件夾路徑添加到該參數
必須用絕對路徑!相對路徑不生效!
pathex=['path']
4.2 添加數據文件
程序調用的相對路徑中的數據文件
datas=[(oldpath1, newpath1), (oldpath2, newpath2)]
4.3 手動添加沒有被識別到的調用庫
hiddenimports=['libs']
問題全部解決之后,程序運行正常√
總結
原文鏈接:https://blog.csdn.net/Rebacca122222/article/details/124440089
相關推薦
- 2023-06-05 Python?time時間格式化和設置時區實現代碼詳解_python
- 2022-11-15 詳解kubelet?創建pod流程代碼圖解及日志說明_云其它
- 2022-12-13 Flutter?阻止系統鍵盤彈出的優雅方式_Android
- 2022-05-09 輕量級ORM框架Dapper應用之實現DTO_實用技巧
- 2022-12-07 C++11?成員函數作為回調函數的使用方式_C 語言
- 2022-05-13 C++ 使用Poco庫實現XML的讀取和寫入
- 2022-12-27 刪除Helm使用時關于kubernetes文件的警告問題_云其它
- 2022-05-10 錯誤解決 刪除同名Maven Module,重新建立顯示ignored pom.xml問題
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支