Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't run the pytorch lightning program packaged with pyinstaller. #7918

Closed
laogonggong847 opened this issue Sep 6, 2023 · 13 comments
Closed
Labels
kind:support solution:not enough info Not enough info has been provided to solve or help. Fill out the issue template

Comments

@laogonggong847
Copy link

laogonggong847 commented Sep 6, 2023

Bug description

When using pyinstaller to package a program that contains pytorch lightning(pl), the resulting exe never runs. But after removing the relevant pl code from the program, the exe executes correctly. I think this may be due to the fact that pl requires some specific dependencies to be included. What do I need to package in the anaconda environment after utilizing pl?

What version are you seeing the problem on?

v1.9

How to reproduce the bug

# myPytorchLightningDemo.py  is just a simple program, except that this program contains pl
pyinstaller -F -w -y myPytorchLightningDemo.py

Error messages and logs

pyinstaller packaged dist folder does not contain pytorch lighting

Environment

python :3.8
torch:1.12.1+cu113
pytorch-lighting: 1.9.5
OS: Win10

More info

No response

@laogonggong847 laogonggong847 added the triage Please triage and relabel this issue label Sep 6, 2023
@rokm
Copy link
Member

rokm commented Sep 6, 2023

If this is about missing lightning\version.info file, you need to collect the data files - try adding a --collect-data lightning to your PyInstaller command. You might also need to ensure that source .py files are collected (if the package uses torch JIT), but since you did not provide an error traceback, it is not clear if that is a problem or not.

@rokm rokm closed this as completed Sep 6, 2023
@rokm rokm added kind:support solution:not enough info Not enough info has been provided to solve or help. Fill out the issue template and removed triage Please triage and relabel this issue labels Sep 6, 2023
@laogonggong847
Copy link
Author

Hello @rokm
Thank you for your reply. As you said, it seems that after I added the "A" this sentence didn't work and didn't pack the related pl files into my dist folder. Eventually I manually copied the pl related files from the anconda environment to the dist folder and got a new error:

OSError: Can't get source for <function ModuleInterface.forward at 0x00000250AFC56790>. TorchScript requires source access in order to carry out compilation, make sure original .py files are available.

log:

Traceback (most recent call last):
  File "deepApp.py", line 103, in <module>
  File "torch\multiprocessing\spawn.py", line 240, in spawn
    return start_processes(fn, args, nprocs, join, daemon, start_method='spawn')
  File "torch\multiprocessing\spawn.py", line 198, in start_processes
    while not context.join():
  File "torch\multiprocessing\spawn.py", line 160, in join
    raise ProcessRaisedException(msg, error_index, failed_process.pid)
torch.multiprocessing.spawn.ProcessRaisedException: 

-- Process 0 terminated with the following error:
Traceback (most recent call last):
  File "torch\_sources.py", line 21, in get_source_lines_and_file
    sourcelines, file_lineno = inspect.getsourcelines(obj)
  File "inspect.py", line 979, in getsourcelines
  File "inspect.py", line 798, in findsource
OSError: could not get source code

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "torch\multiprocessing\spawn.py", line 69, in _wrap
    fn(i, *args)
  File "deepApp.py", line 65, in main
  File "train.py", line 302, in train
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 385, in exec_module
  File "patchcore\torch_model.py", line 14, in <module>
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 385, in exec_module
  File "HCtimm.py", line 21, in <module>
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 385, in exec_module
  File "timm\__init__.py", line 3, in <module>
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 385, in exec_module
  File "timm\models\__init__.py", line 28, in <module>
  File "<frozen importlib._bootstrap>", line 991, in _find_and_load
  File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 671, in _load_unlocked
  File "PyInstaller\loader\pyimod02_importers.py", line 385, in exec_module
  File "timm\models\hrnet.py", line 511, in <module>
  File "torch\jit\_script.py", line 1452, in interface
    ast = get_jit_class_def(obj, obj.__name__)
  File "torch\jit\frontend.py", line 199, in get_jit_class_def
    methods = [get_jit_def(obj,
  File "torch\jit\frontend.py", line 199, in <listcomp>
    methods = [get_jit_def(obj,
  File "torch\jit\frontend.py", line 234, in get_jit_def
    parsed_def = parse_def(fn)
  File "torch\_sources.py", line 96, in parse_def
    sourcelines, file_lineno, filename = get_source_lines_and_file(fn, ErrorReport.call_stack())
  File "torch\_sources.py", line 28, in get_source_lines_and_file
    raise OSError(msg) from e
OSError: Can't get source for <function ModuleInterface.forward at 0x000001DAB1FB5700>. TorchScript requires source access in order to carry out compilation, make sure original .py files are available.


@rokm
Copy link
Member

rokm commented Sep 7, 2023

Like the error message is telling you, you need to ensure that source .py files are collected for packages that use torch JIT. PyInstaller does not do that by default. In this case, you probably need to collect sources for timm. Either use collect_data_files with include_py_files=True in a custom hook or spec file, or (preferably) use the module collection mode setting. For the latter, see an example here (which was for bitsandbytes, which similarly required source .py files to be collected for JIT).

@laogonggong847
Copy link
Author

hello @rokm
Thank you very much for your reply, I will test it and please allow me to test it and get back to you. But I still have a question, previously when my Timm was a low version, I had no problem with the exe I packaged using pyinstaller. But when I upgraded the version of Timm without any changes other than that, this problem appeared.
I'd love to figure out what's causing this problem. Looking forward to your reply

@rokm
Copy link
Member

rokm commented Sep 7, 2023

But when I upgraded the version of Timm without any changes other than that, this problem appeared.

Maybe timm added JIT to the codepath you are using in the later version? You can check the source code of old and the new version that you are using, and see where the difference comes from.

@laogonggong847
Copy link
Author

laogonggong847 commented Sep 7, 2023

Hello @rokm
I am very sorry that due to my unfamiliarity with pyinstaller, I can't understand the modifications you taught me very clearly. Below I will provide the code that I used when I packaged it, and the final spec file that was generated. Can you tell me exactly how I should modify my spec or py file to make my program finally achieve the two abilities?
1: The dist folder contains the "pytorch lighting" module.
2: Include timm to fix the latest bug I raised today.


code

from PyInstaller.__main__ import run

if __name__ == '__main__':

    opts = [
        '-F',
        '-D',
        '-w',
        '--paths=C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v11.3/bin/',  # CUDA
        '--path=C:/ProgramData/anaconda3/envs/MyAnacondaEnv/Library/bin/',   # Anaconda Env
        '--paths=C:/ProgramData/anaconda3/envs/MyAnacondaEnv/Lib/site-packages/torch/lib/',
        '--path=:C:/ProgramData/anaconda3/envs/MyAnacondaEnv/Lib/site-packages',
        '--paths=C:/ProgramData/anaconda3/Lib/site-packages/torch/lib/'
        '--add-data=yamls;./yamls/',
        '--add-data=./pretrain-models/;./pretrain-models/',
        '--icon=App.ico',
        'App.py'
    ]

    run(opts)

spec


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


block_cipher = None


a = Analysis(
    ['deepApp.py'],
    pathex=['C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v11.3/bin/', 'C:/ProgramData/anaconda3/envs/MyAnacondaEnv/Library/bin/', 'C:/ProgramData/anaconda3/envs/MyAnacondaEnv/Lib/site-packages/torch/lib/', 'C:/ProgramData/anaconda3/envs/MyAnacondaEnv/Lib/site-packages', 'C:/ProgramData/anaconda3/Lib/site-packages/torch/lib/'],
    binaries=[],
    datas=[('./yamls', './yamls/'),('./pretrain-models/', './pretrain-models/')],
    hiddenimports=[],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=False,
    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='deepApp',
    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,
    icon=['deepApp.ico'],
)
coll = COLLECT(
    exe,
    a.binaries,
    a.zipfiles,
    a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name='deepApp',
)

Thank you very much for your patience and I look forward to hearing from you, thank you again!

@rokm
Copy link
Member

rokm commented Sep 7, 2023

You need to edit the spec, and then build using the .spec file instead of the .py file (otherwise the spec gets re-generated and rewritten). I.e., run PyInstaller as PyInstaller --clean --noconfirm App.spec.

If you want to avoid using the spec file, you will need to create a custom hook for timm, and ensure that it is used (e.g., by passing its directory via --additional-hooks-dir).

@laogonggong847
Copy link
Author

hello @rokm
Thank you very much for your reply, for my spec file, I want to introduce "timm" and "pytorch lighting" in it, is it possible to make the following changes?

from PyInstaller.utils.hooks import collect_dynamic_libs

hiddenimports = ['pytorch_lighting._C.libtriton']
binaries = collect_dynamic_libs('timm')

...

a = Analysis(
    ...
    binaries=binaries,
    hiddenimports=hiddenimports,
    ...
    module_collection_mode={
        # requires source .py files for JIT
        'timm': 'pyz+py',
        # requires source .py files for JIT
        # also tries to read the file pointed to by __file__, so we must avoid PYZ
        'pytorch_lighting': 'py',
    }
)

...

Forgive me if I'm not familiar with pyinstaller, this is taking up a lot of your time, I'm very sorry. Once again, thank you very much!

@rokm
Copy link
Member

rokm commented Sep 7, 2023

You'd probably need:

from PyInstaller.utils.hooks import collect_data_files

# collect data files from lightning package
datas = collect_data_files('lightning')

...

a = Analysis(
    ...
    datas=datas,
    ...
    module_collection_mode={
        # collect source .py files for JIT
        'timm': 'pyz+py',
        'lightning': 'pyz+py',
    }
)

...

@laogonggong847
Copy link
Author

hello @rokm
Thank you for your patience, this is really useful for me, I will test it!

In the original spec file, my data parameter is as follows

a = Analysis(
    ['deepApp.py'],
    pathex=['C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v11.3/bin/', 'C:/ProgramData/anaconda3/envs/MyAnacondaEnv/Library/bin/', 'C:/ProgramData/anaconda3/envs/MyAnacondaEnv/Lib/site-packages/torch/lib/', 'C:/ProgramData/anaconda3/envs/MyAnacondaEnv/Lib/site-packages', 'C:/ProgramData/anaconda3/Lib/site-packages/torch/lib/'],
    binaries=[],
    datas=[('./yamls', './yamls/'),('./pretrain-models/', './pretrain-models/')],

According to the method you taught me

from PyInstaller.utils.hooks import collect_data_files

# collect data files from lightning package
datas = collect_data_files('lightning')

...

a = Analysis(
    ...
    datas=datas,
    ...
)

How do I merge the original data with the data you provided me with?
Sorry for taking up so much of your time. Thank you very much.

@rokm
Copy link
Member

rokm commented Sep 7, 2023

How do I merge the original data with the data you provided me with?

These are basic python lists, so datas=[('./yamls', './yamls/'),('./pretrain-models/', './pretrain-models/')] + collect_data_files('lightning') or any equivalent.

@rokm
Copy link
Member

rokm commented Oct 27, 2023

Can we see the whole .spec?

@lterfloth
Copy link

Already fixed my issue. I accidentally overwrote the datas array a couple of lines down in the specfile. Now the imports work and I only need to add the proper binaries to get it working. Thanks!

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 26, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
kind:support solution:not enough info Not enough info has been provided to solve or help. Fill out the issue template
Projects
None yet
Development

No branches or pull requests

3 participants