Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pyinstaller with Tensorflow takes incorrect path for _checkpoint_ops.so file

I am trying to make an executable of my Python code which uses Tensorflow with Pyinstaller. The executable gets generated correctly but when I try to run it, I get the following error:

Traceback (most recent call last):
  File "detection_init.py", line 14, in <module>
    import lib.tensorboxDetector as tensorboxDetector
  File "/usr/local/lib/python2.7/dist-packages/PyInstaller/loader/pyimod03_importers.py", line 396, in load_module
    exec(bytecode, module.__dict__)
  File "lib/tensorboxDetector.py", line 26, in <module>
    from lib.train import build_forward
  File "/usr/local/lib/python2.7/dist-packages/PyInstaller/loader/pyimod03_importers.py", line 396, in load_module
    exec(bytecode, module.__dict__)
  File "lib/train.py", line 4, in <module>
    import tensorflow.contrib.slim as slim
  File "/usr/local/lib/python2.7/dist-packages/PyInstaller/loader/pyimod03_importers.py", line 396, in load_module
    exec(bytecode, module.__dict__)
  File "tensorflow/contrib/__init__.py", line 22, in <module>
  File "/usr/local/lib/python2.7/dist-packages/PyInstaller/loader/pyimod03_importers.py", line 396, in load_module
    exec(bytecode, module.__dict__)
  File "tensorflow/contrib/bayesflow/__init__.py", line 24, in <module>
  File "/usr/local/lib/python2.7/dist-packages/PyInstaller/loader/pyimod03_importers.py", line 396, in load_module
    exec(bytecode, module.__dict__)
  File "tensorflow/contrib/bayesflow/python/ops/csiszar_divergence.py", line 26, in <module>
  File "/usr/local/lib/python2.7/dist-packages/PyInstaller/loader/pyimod03_importers.py", line 396, in load_module
    exec(bytecode, module.__dict__)
  File "tensorflow/contrib/bayesflow/python/ops/csiszar_divergence_impl.py", line 42, in <module>
  File "/usr/local/lib/python2.7/dist-packages/PyInstaller/loader/pyimod03_importers.py", line 396, in load_module
    exec(bytecode, module.__dict__)
  File "tensorflow/contrib/framework/__init__.py", line 89, in <module>
  File "/usr/local/lib/python2.7/dist-packages/PyInstaller/loader/pyimod03_importers.py", line 396, in load_module
    exec(bytecode, module.__dict__)
  File "tensorflow/contrib/framework/python/ops/__init__.py", line 24, in <module>
  File "/usr/local/lib/python2.7/dist-packages/PyInstaller/loader/pyimod03_importers.py", line 396, in load_module
    exec(bytecode, module.__dict__)
  File "tensorflow/contrib/framework/python/ops/checkpoint_ops.py", line 32, in <module>
  File "tensorflow/contrib/util/loader.py", line 55, in load_op_library
  File "tensorflow/python/framework/load_library.py", line 64, in load_op_library
tensorflow.python.framework.errors_impl.NotFoundError: tensorflow/contrib/util/tensorflow/contrib/framework/python/ops/_checkpoint_ops.so: cannot open shared object file: No such file or directory
[11241] Failed to execute script detection_init

If we look carefully, Pyinstaller is expecting the file _checkpoint_ops.so in directory tensorflow/contrib/util/tensorflow/contrib/framework/python/ops/ but there's no directory like this. _checkpoint_ops.so is located at tensorflow/contrib/framework/python/ops/. How can this error be corrected?

like image 463
Piyush Shrivastava Avatar asked Sep 14 '17 13:09

Piyush Shrivastava


People also ask

Why is PyInstaller not working?

The most common reason a PyInstaller package fails is that PyInstaller failed to bundle a required file. Such missing files fall into a few categories: Hidden or missing imports: Sometimes PyInstaller can't detect the import of a package or library, typically because it is imported dynamically.

Does PyInstaller include modules?

To find out, PyInstaller finds all the import statements in your script. It finds the imported modules and looks in them for import statements, and so on recursively, until it has a complete list of modules your script may use.

Does PyInstaller include imports?

python - PyInstaller does not include imports - Stack Overflow. Stack Overflow for Teams – Start collaborating and sharing organizational knowledge.


1 Answers

Add the following to your spec file (finds tensorflow binaries and adds them to your .app in the main binary/file directory):

import os

tensorflow_location = '/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/tensorflow'

tensorflow_binaries = []

for dir_name, sub_dir_list, fileList in os.walk(tensorflow_location): 
  for file in fileList:
    if file.endswith(".so"):
      full_file = dir_name + '/' + file
      print(full_file)
      tensorflow_binaries.append((full_file, '.'))

Make sure you also add the binaries to Analysis

a = Analysis(...,
             binaries=tensorflow_binaries,
             ...)

And make sure binaries are included in the .exe/.app builds. Here's a simple example:

pyz = PYZ(a.pure)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='TestApp',
          debug=True,
          strip=None,
          upx=True,
          console=True, icon='Test.icns')
app = BUNDLE(exe,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    name='Test.app',
    icon='Test.icns',
    bundle_identifier='com.Test.TestApp',
    info_plist={
        'NSHighResolutionCapable': 'True'
            },
    )

The last thing you need to do is modify the tensorflow load_library.py file to point to the relative path of the binaries during .app runtime.

The file is usually located here (relative to python install): site-packages/tensorflow/python/framework/load_library.py

You need to add the resource_path function and modify the load_op_library function to point the file_name to the relative path (and to ignore finding binaries by sub-folder).

def resource_path(relative_path):
    """Due to pyinstaller changing root dir of project filenames need to be processed in order to open properly

    Parameters
    ----------
    relative_path : str
        String containing filename path

    Returns
    -------
    path : str
        path relative to this file on local computer
    """
    import sys
    import os

    try:
        # PyInstaller creates a temp folder and stores path in _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")

    path = os.path.join(base_path, relative_path)
    return path

def load_op_library(library_filename):
  """Loads a TensorFlow plugin, containing custom ops and kernels.

  Pass "library_filename" to a platform-specific mechanism for dynamically
  loading a library. The rules for determining the exact location of the
  library are platform-specific and are not documented here. When the
  library is loaded, ops and kernels registered in the library via the
  `REGISTER_*` macros are made available in the TensorFlow process. Note
  that ops with the same name as an existing op are rejected and not
  registered with the process.

  Args:
    library_filename: Path to the plugin.
      Relative or absolute filesystem path to a dynamic library file.

  Returns:
    A python module containing the Python wrappers for Ops defined in
    the plugin.

  Raises:
    RuntimeError: when unable to load the library or get the python wrappers.
  """ 
  # REMOVE AFTER PYINSTALLER USE
  library_filename = resource_path(library_filename.split('/')[-1])

This will make tensorflow fetch the binaries by the relative path of your pyinstaller application (See: https://pythonhosted.org/PyInstaller/runtime-information.html#run-time-information).

Tensorflow will then fetch the binaries as packaged by the .spec file.

Remember to uncomment the library_filename = resource_path(library_filename.split('/')[-1]) line in load_library.py after Pyinstaller packaging (or else Tensorflow won't be able to find the binaries when running in your local Python env!)

like image 196
0000101010 Avatar answered Oct 14 '22 08:10

0000101010