用Pyinstaller打包深度学习算法为独立的可执行程序

发布时间:2023年12月17日

????????前言:随着深度学习算法的流行,在传统工业软件计算领域,传统算法逐渐被深度学习算法给代替,但由于基于python的深度学习算法十分依赖python环境以及例如Pytorch、Scikit-learning、Keras等机器学习库,将深度学习算法运用集成到实际生产中去时,需要随身带着这一大坨库(通常用Anaconda管理)和python解释器,很不方便,因此Pyinstaller是个很实用的工具,能将其打包为独立的可执行程序。

一、Pyinstaller简介

????????PyInstaller的历史最早可以追溯到2008年,Hartmut Goebel开发并发布了第一个版本。随着时间的不断发展,Pyinstaller已成为应用最为广泛的python打包工具。其基本原理为(参考https://blog.csdn.net/Dontla/article/details/131474870):

  1. 分析脚本:PyInstaller会分析Python脚本,识别出脚本中所引用的库和资源文件。
  2. 创建打包规范:根据分析结果,PyInstaller会生成一个打包规范文件,即xxx.spec文件,其中包含了脚本的依赖关系、资源文件等信息。
  3. 打包依赖库:PyInstaller会将脚本所依赖的库文件进行打包,这些库文件会被嵌入到可执行文件中。
  4. 生成可执行文件:根据打包规范和打包的依赖库,PyInstaller会生成一个独立的可执行文件,该文件包含了Python解释器、脚本代码和依赖的库文件
  5. 运行可执行文件:生成的可执行文件可以在其他机器上直接运行,无需安装Python解释器和相关库。

? ? ? ? 安装Pyinstaller有多种方法:

pip install pyinstaller

二、单独的py文件

? ? ? ? 打包单独py文件,使用以下命令即可:

pyinstaller your_script.py

????????PyInstaller提供了一些自定义打包选项,可以通过执行pyinstaller --help命令查看,常用的包括以下选项:

可选参数:
  -h, --help            显示帮助信息并退出
  -v, --version         显示程序版本信息并退出。
  --distpath DIR        指定打包应用的目录(默认为./dist)
  --workpath WORKPATH   指定所有临时工作文件(.log, .pyz等)的目录(默认为./build)
  -y, --noconfirm       替换输出目录(默认为SPECPATH/dist/SPECNAME)而不需要确认
  --upx-dir UPX_DIR     UPX工具的路径(默认为搜索执行路径)
  -a, --ascii           不包含Unicode编码支持(默认情况下如果可用则包含)
  --clean               在构建之前清理PyInstaller缓存和临时文件。
  --log-level LEVEL     构建时控制台消息的详细程度。LEVEL可以是TRACE、DEBUG、INFO、WARN、DEPRECATION、ERROR、FATAL之一(默认为INFO)。也可以通过PYI_LOG_LEVEL环境变量进行设置。

生成内容:
  -D, --onedir          创建一个包含可执行文件的单文件夹捆绑包(默认)
  -F, --onefile         创建一个单文件捆绑的可执行文件。
  --specpath DIR        存储生成的.spec文件的文件夹(默认为当前目录)
  -n NAME, --name NAME  分配给捆绑应用和.spec文件的名称(默认为第一个脚本的基本名称)

捆绑什么,搜索什么:
  --add-data <SRC;DEST or SRC:DEST>
                        添加到可执行文件的附加非二进制文件或文件夹。路径分隔符是平台特定的,使用``os.pathsep``(在Windows上为``;``,在大多数Unix系统上为``:``)。此选项可以多次使用。
  --add-binary <SRC;DEST or SRC:DEST>
                        添加到可执行文件的附加二进制文件。有关详细信息,请参见``--add-data``选项。此选项可以多次使用。
  -p DIR, --paths DIR   搜索导入的路径(类似于使用PYTHONPATH)。可以使用多个路径,用``':'``分隔,或多次使用此选项。相当于在.spec文件中提供``pathex``参数。
  --hidden-import MODULENAME, --hiddenimport MODULENAME
                        指定在脚本代码中不可见的导入模块。此选项可以多次使用。
  --collect-submodules MODULENAME
                        收集指定包或模块的所有子模块。此选项可以多次使用。
  --collect-data MODULENAME, --collect-datas MODULENAME
                        收集指定包或模块的所有数据文件。此选项可以多次使用。
  --collect-binaries MODULENAME
                        收集指定包或模块的所有二进制文件。此选项可以多次使用。
  --collect-all MODULENAME
                        收集指定包或模块的所有子模块、数据文件和二进制文件。此选项可以多次使用。
  --copy-metadata PACKAGENAME
                        复制指定包的元数据。此选项可以多次使用。
  --recursive-copy-metadata PACKAGENAME
                        复制指定包及其所有依赖项的元数据。此选项可以多次使用。
  --additional-hooks-dir HOOKSPATH
                        指定额外的钩子路径。此选项可以多次使用。
  --runtime-hook RUNTIME_HOOKS
                        指定自定义运行时钩子文件的路径。运行时钩子是与可执行文件捆绑在一起的代码,在任何其他代码或模块之前执行,用于设置运行时环境的特殊功能。此选项可以多次使用。
  --exclude-module EXCLUDES
                        忽略的可选模块或包(Python名称,而不是路径名称)。此选项可以多次使用。
  --splash IMAGE_FILE   (实验性功能) 向应用程序添加一个带有图像IMAGE_FILE的启动画面。启动画面可以在解压过程中显示进度更新。

如何生成:
  -d {all,imports,bootloader,noarchive}, --debug {all,imports,bootloader,noarchive}
                        提供用于调试冻结应用程序的帮助。此参数可以多次提供以选择以下选项之一。
                        
                        - all: 以下所有选项。
                        
                        - imports: 指定-v选项给底层Python解释器,导致它在每次初始化模块时打印一条消息,显示加载模块的位置(文件名或内置模块)。参见
                          https://docs.python.org/3/using/cmdline.html#id4。
                        
                        - bootloader: 告诉引导加载程序在初始化和启动捆绑应用程序时发出进度消息。用于诊断缺少导入的问题。
                        
                        - noarchive: 将所有冻结的Python源文件存储为结果可执行文件内的存档,而不是文件存储在结果输出目录中。
                        
  --python-option PYTHON_OPTION
                        指定要在运行时传递给Python解释器的命令行选项。目前支持"v"(等效于"--debug imports")、"u"和"W<warning control>"。
  -s, --strip           对可执行文件和共享库应用符号表剥离(不推荐在Windows上使用)
  --noupx               即使可用,也不使用UPX(在Windows和*nix之间的工作方式不同)
  --upx-exclude FILE    使用upx时防止对二进制文件进行压缩。如果upx在压缩过程中破坏某些二进制文件,通常会使用此选项。FILE是二进制文件的文件名,不包含路径。此选项可以多次使用。
原文链接:https://blog.csdn.net/Dontla/article/details/131474870

生成的各个目录和文件的作用如下:

  • build/:该目录是pyinstaller生成的临时目录,用于存放编译过程中生成的中间文件和临时文件
  • dist/:该目录是pyinstaller生成的最终目录,用于存放编译后生成的可执行文件或打包后的应用程序
  • XXX.spec:pyinstaller的配置文件,用于指定编译的参数和选项,如果在目标系统中需要重新编译应用程序,可以将该文件一同拷贝过去。

在实际运行可执行程序时,经常会出现找不到XXX的报错,由于pyinstaller没有自动识别到隐藏模块,解决方法一般是在打包过程中用--hidden-import jtop参数来显示地导入该模块

三、打包多文件项目

当对包含多个文件夹的项目进行打包时,需要生成配置文件XXX.spec,并自定义各个配置项,以当前这个测试项目为例,Data目录下为自定义的csv文件,mnist_data下为下载的公开数据集,DNN下为模型定义py,main.py为主程序入口。

执行命令生成xx.spec文件:

pyi-makespec -F main.py

如下所示,可以看到spec文件本身是一个python文件:

# -*- mode: python ; coding: utf-8 -*-


block_cipher = None #用于指定加密算法,如果不需要加密可以设置为None

SETUP_DIR ='C:\\wjy\\Python_project\\deepLearning\\'

#分析器,用于指定需要编译的Python脚本文件、路径、二进制文件、数据文件
a = Analysis(
    ['main.py',SETUP_DIR + 'DNN\\DNN.py'],#需要编译的Python脚本文件列表(可以是相对路径)
    pathex=[], #额外的模块搜索路径,指定pinstaller无法自动检测到的模块
    binaries=[], #需要包含的二进制文件,包含了动态链接库或共享对象文件,在运行之后会自动更新
    datas=[("Data","Data"),("mnist_data","mnist_data")], #需要包含的数据文件,每个元素都是一个元组(文件的源路径,在打包文件中的路径)
    hiddenimports=[], #需要导入的隐藏模块,pyinstaller无法自动检测到的模块
    hookspath=[], #自定义的查找pyinstaller钩子的路径
    hooksconfig={}, #自定义的钩子配置,是一个字典
    runtime_hooks=[], #运行时钩子,本质是一个python脚本,在脚本运行前运行用于准备环境
    excludes=[], #需要排除的模块
    win_no_prefer_redirects=False, #在Windows上禁用优先重定向
    win_private_assemblies=False, #在Windows上使用私有程序集
    cipher=block_cipher, #加密算法
    noarchive=False, #是否生成归档文件
)

#生成的Python字节码文件,在运行时会被解压缩到临时目录中,然后被加载和执行
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) #纯净的Python字节码文件,压缩的数据,加密算法

#生成的可执行文件
exe = EXE(
    pyz, #Python字节码文件,包含了所有纯python模块
    a.scripts, #附加的脚本文件
    a.binaries, #附加的二进制文件
    a.zipfiles, #附加的压缩文件
    a.datas, #附加的数据文件
    [], #所有需要打包到exe文件内的二进制文件
    name='main', #生成的可执行文件的名称
    debug=False, #打包过程是否打印调试信息
    bootloader_ignore_signals=False,
    strip=False, #是否移除所有的符号信息,使打包出的exe文件更小
    upx=True, #是否使用UPX压缩exe文件
    upx_exclude=[], #需要排除的UPX压缩文件
    runtime_tmpdir=None,
    console=True, #是否为控制台应用程序,true则在控制台窗口运行,否则作为后台进程运行
    disable_windowed_traceback=False, #是否禁用窗口化的回溯
    argv_emulation=False, #是否启用命令行参数模拟
    target_arch=None, #目标系统的架构,确保打包的应用程序在目标系统上能够正常运行
    codesign_identity=None, #代码签名标识
    entitlements_file=None, #授权文件
)

其中datas=[("Data","Data")]意思是将main.py当前目录下的Data目录(及其目录中的文件)加入目标exe中,在运行时放在临时文件的根目录下,名称为Data。

然后使用pyinstaller命令即可根据配置文件生成可执行程序:

pyinstaller XXX.spec

四、常见问题

1、打包输出后的exe文件执行时,报错“找不到xxx 文件”

一般两种解决方案,在spec文件中的"?hiddenimports=[]"添加漏掉的包;如果该方法不起效,则直接把对应的文件复制到dist目录下即可,例如在该实例中,运行时报错“找不到pytorch_lightning/ version.info”,则直接在anaconda环境中将该文件复制过去即可。

2、exe运行时函数或python语句报错

一般是python包版本错误例如cpu环境中安装cuda版本的Pytorch,或者是与目标运行系统不兼容

文章来源:https://blog.csdn.net/weixin_39626452/article/details/134906330
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。