M1 Pro Mac用PyInstaller打包torch等库程序报错求助
问题描述
环境:M1 Pro MacBook + Python 3.10 Conda环境
现象:直接运行tester.py正常,PyInstaller打包后执行出现SIGABRT错误,错误栈如下:
Exception raised from operator() at /Users/runner/work/pytorch/pytorch/pytorch/aten/src/ATen/core/jit_type.h:1735 (most recent call first): frame #0: c10::detail::torchCheckFail(char const*, char const*, unsigned int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) + 92 (0x1718d5718 in libc10.dylib) frame #1: c10::detail::getTypePtr_<c10::intrusive_ptr<ConvPackedParamsBase<2>, c10::detail::intrusive_target_default_null_type<ConvPackedParamsBase<2> > > >::call()::'lambda'()::operator()() const + 300 (0x288dd22b4 in libtorch_cpu.dylib) frame #2: c10::Type::SingletonOrSharedTypePtr<c10::Type> c10::getTypePtrCopy<c10::intrusive_ptr<ConvPackedParamsBase<2>, c10::detail::intrusive_target_default_null_type<ConvPackedParamsBase<2> > > >() + 32 (0x288dd2014 in libtorch_cpu.dylib) frame #3: c10::detail::infer_schema::(anonymous namespace)::createArgumentVector(c10::ArrayRef<c10::detail::infer_schema::ArgumentDef>) + 188 (0x2887e0b88 in libtorch_cpu.dylib) frame #4: c10::detail::infer_schema::make_function_schema(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&, c10::ArrayRef<c10::detail::infer_schema::ArgumentDef>, c10::ArrayRef<c10::detail::infer_schema::ArgumentDef>) + 96 (0x2887e0948 in libtorch_cpu.dylib) frame #5: c10::detail::infer_schema::make_function_schema(c10::ArrayRef<c10::detail::infer_schema::ArgumentDef>, c10::ArrayRef<c10::detail::infer_schema::ArgumentDef>) + 60 (0x2887e0e70 in libtorch_cpu.dylib) frame #6: std::__1::unique_ptr<c10::FunctionSchema, std::__1::default_delete<c10::FunctionSchema> > c10::detail::inferFunctionSchemaFromFunctor<at::Tensor (*)(at::Tensor, c10::intrusive_ptr<ConvPackedParamsBase<2>, c10::detail::intrusive_target_default_null_type<ConvPackedParamsBase<2> > > const&, double, long long)>() + 76 (0x288e42ad4 in libtorch_cpu.dylib) frame #7: torch::CppFunction::CppFunction<at::Tensor (at::Tensor, c10::intrusive_ptr<ConvPackedParamsBase<2>, c10::detail::intrusive_target_default_null_type<ConvPackedParamsBase<2> > > const&, double, long long)>(at::Tensor (*)(at::Tensor, c10::intrusive_ptr<ConvPackedParamsBase<2>, c10::detail::intrusive_target_default_null_type<ConvPackedParamsBase<2> > > const&, double, long long), std::__1::enable_if<c10::guts::is_function_type<at::Tensor (at::Tensor, c10::intrusive_ptr<ConvPackedParamsBase<2>, c10::detail::intrusive_target_default_null_type<ConvPackedParamsBase<2> > > const&, double, long long)>::value, std::nullptr_t>::type) + 124 (0x288e429fc in libtorch_cpu.dylib) frame #8: at::native::(anonymous namespace)::TORCH_LIBRARY_IMPL_init_quantized_QuantizedCPU_4(torch::Library&) + 40 (0x288e40d48 in libtorch_cpu.dylib) frame #9: torch::detail::TorchLibraryInit::TorchLibraryInit(torch::Library::Kind, void (*)(torch::Library&), char const*, c10::optional<c10::DispatchKey>, char const*, unsigned int) + 208 (0x288689a70 in libtorch_cpu.dylib) frame #10: _GLOBAL__sub_I_qconv.cpp + 88 (0x288e46ba4 in libtorch_cpu.dylib) frame #11: invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 164 (0x103c55f4c in dyld) frame #12: invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 168 (0x103c7f550 in dyld) frame #13: invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 528 (0x103c75ed8 in dyld) frame #14: dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const + 168 (0x103c41f98 in dyld) frame #15: dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const + 192 (0x103c75c80 in dyld) frame #16: dyld3::MachOAnalyzer::forEachInitializerPointerSection(Diagnostics&, void (unsigned int, unsigned int, unsigned char const*, bool&) block_pointer) const + 148 (0x103c7ee80 in dyld) frame #17: dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const + 432 (0x103c7f180 in dyld) frame #18: dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const + 172 (0x103c55e8c in dyld) frame #19: dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&) const + 216 (0x103c56038 in dyld) frame #20: dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&) const + 180 (0x103c56014 in dyld) frame #21: dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&) const + 180 (0x103c56014 in dyld) frame #22: dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const + 124 (0x103c56104 in dyld) frame #23: dyld4::APIs::dlopen_from(char const*, int, void*) + 520 (0x103c65c64 in dyld) frame #24: py_dl_open + 160 (0x103fdb5ac in _ctypes.cpython-39-darwin.so) <omitting python frames> fish: Job 1, './tester' terminated by signal SIGABRT (Abort)
待打包文件tester.py:
import tensorflow as tf import numpy as np import torch import torchaudio print("hallo")
使用的tester.spec文件:
# -*- mode: python ; coding: utf-8 -*- block_cipher = None env_base_path = '/opt/homebrew/Caskroom/miniconda/base/envs/test3.9' a = Analysis( ['tester.py'], pathex=[env_base_path], binaries=[(env_base_path + '/lib/libc++.1.0.dylib','.')], datas=[], hiddenimports=['torchaudio.lib.libtorchaudio'], hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[], 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='tester', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=True, 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='tester', )
解决思路与方案
禁用UPX压缩:UPX压缩可能破坏PyTorch动态库的结构,导致加载失败。修改
spec文件中EXE和COLLECT部分的upx=True为upx=False:exe = EXE( # 其他参数保持不变 upx=False, # 其他参数保持不变 ) coll = COLLECT( # 其他参数保持不变 upx=False, # 其他参数保持不变 )手动添加PyTorch相关动态库:PyInstaller可能未自动收集所有依赖,在
Analysis的binaries中补充核心库(路径需根据实际环境调整):binaries=[ (env_base_path + '/lib/libc++.1.0.dylib','.'), (env_base_path + '/lib/python3.10/site-packages/torch/lib/libtorch_cpu.dylib', '.'), (env_base_path + '/lib/python3.10/site-packages/torch/lib/libc10.dylib', '.'), (env_base_path + '/lib/python3.10/site-packages/torchaudio/lib/libtorchaudio.dylib', '.') ],指定目标架构为arm64:明确适配M1的arm架构,避免架构混淆。修改
EXE部分的target_arch:exe = EXE( # 其他参数保持不变 target_arch='arm64', # 其他参数保持不变 )补充隐藏导入:添加PyTorch的核心内部模块,避免动态加载缺失:
hiddenimports=[ 'torchaudio.lib.libtorchaudio', 'torch._C', 'torch._C._jit', 'torch._C._dlpack' ],开启非归档模式:将Python模块不打包成单个归档文件,解决路径加载问题。修改
Analysis中的noarchive参数:a = Analysis( # 其他参数保持不变 noarchive=True, # 其他参数保持不变 )
内容的提问来源于stack exchange,提问作者Alex G
相关产品推荐
相关产品推荐

