PyTorchのAIアプリケーションをPyinstallerでexe化

PyTorchのAIアプリケーションをPyinstallerでexe化する方法と、2023年6月時点でエラーが発生したため、その解決方法について解説します

images/cards/PyTorch_logo_black.svg.webp

目次

1. まずは、開発環境を準備

ここでは、Ubuntu 環境を想定して解説します。もちろん Windows でも問題ありません。

  • Ubuntu 20.04
  • GeForce RTX 2080 Ti
  • CUDA Version: 11.5
  • Python 3.8

2. PyInstaller のインストール

「PyInstaller」は、Python で作成されたプログラムをバンドルして、簡単に実行ファイル化(.exe ファイル)するためのツールです。 業務用に便利ツールを Python で作っても、誰もが Python をインストールし、その実行環境がある訳ではありません。 PyInstaller で Windows 用の実行ファイルを作成して、それを配布するのが良いです。pipenv 環境にインストールします。

pipenv install pyinstaller

3. Spec ファイルの作成

以下のように PyInstaller 用の設定ファイルを作成することができます。

  • PyTorch の AI アプリなので、ptl ファイル(学習したモデル情報)をデータとしてバンドルします。
  • エントリポイントが「inference.py」となります。
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
import os
import sys
src_root = os.path.realpath(SPECPATH)
datas = [('best_model.pth','.')]

a = Analysis(['inference.py'],
             pathex=[src_root],
             binaries=[],
             datas=datas,
             hiddenimports=[],
             hookspath=[],
             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='TestApp',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True,
          icon='icon32x32.ico')

coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, name='TestApp')

4. 実行ファイル(.exe ファイル)の作成

以下のコマンドで、実行ファイル(.exe ファイル)を作成することができます。 dist フォルダに、“TestApp"という実行ファイルが作成されます。「–clean」というオプションは、ビルド前に前回のキャッシュと出力ディレクトリを削除します。

pyinstaller pyinstaller_collect.spec --clean

5. エラーが発生する(2023 年 6 月時点)

私が初めて試した時は、以下のようなエラーが発生して、実行ファイルを実行できませんでした。 Github の issuesによれば、どうやら PyInstaller と torch.jit.script がうまく一緒に動かないようです。

Traceback (most recent call last):
  File "torch/_utils_internal.py", line 49, in get_source_lines_and_file
    sourcelines, file_lineno = inspect.getsourcelines(obj)
  File "inspect.py", line 955, in getsourcelines
  File "inspect.py", line 786, in findsource
OSError: could not get source code

The above exception was the direct cause of the following exception:
File "torch/jit/_script.py", line 936, in script
    ast = get_jit_def(obj, obj.__name__)
  File "torch/jit/frontend.py", line 197, in get_jit_def
    sourcelines, file_lineno, filename = get_source_lines_and_file(fn, torch._C.ErrorReport.call_stack())
  File "torch/_utils_internal.py", line 56, in get_source_lines_and_file
    raise OSError(msg) from e
OSError: Can't get source for <function swish_jit at 0x7f4937d1e4d0>. TorchScript requires source access in order to carry out compilation, make sure original .py files are available.

6. 解決方法(2023 年 6 月時点)

Gihub の issuesに解決方法が記載されていますが、あくまで暫定対策です。

torchvision のバージョン確認、必要であればダウングレード

torchvision のバージョンが 0.5 であることが重要です。

pip list
torch                       1.4.0
torchaudio                  0.4.0
torchvision                 0.5.0

torch.jit.script のいくつかの関数をオーバーライド

エントリポイントである「inference.py」の torch をインポートした後に、以下の記載を追加します。

def script_method(fn, _rcb=None):
    return fn
def script(obj, optimize=True, _frames_up=0, _rcb=None):
    return obj
import torch.jit
torch.jit.script_method = script_method
torch.jit.script = script

参考

関連記事