Poetry × 深層学習:Macでのdocker環境構築
概要
初めてのzenn記事です。
poetryを使うと、 poetry lock するだけで依存関係の正確なバージョンを記録するためのロックファイルが生成されるため、requirements.txtやpyproject.tomlに適当にdependencyにライブラリを追加するケースと比べて、安心してライブラリの管理できます。
ただ、Mac OSでtorchなどの環境をインストールしようとするとロックファイルを生成する際に依存関係を解決できなかったり、仮に依存関係を解決できてもインストール時にエラーになったりします。
実際に、poetry側でも下記のissueのように放置されています。
今回は、Macで深層学習のライブラリを使う際にも安心して開発するためのpoetryの構築方法をdockerでの環境構築に焦点を当てて紹介したいと思います。構築した環境については、下記のリポジトリに公開しています(Macでしか検証してないため、ご容赦ください)。
環境構築
初期設定
独自に開発したライブラリをpythonパッケージとして呼び出す場合にはpackage-modeがtrueである必要があります。また、今回はコマンドラインで呼び出せるようにしたいので、exampleコマンドを追加しています。
[tool.poetry]
name = "chiikawa"
version = "0.1.0"
description = "poetry docker env example"
authors = ["username <email>"]
readme = "README.md"
package-mode = true
packages = [
{ include = "mypackage" }
]
[tool.poetry.scripts]
example = "core:main"
別にパッケージとして運用せずに単なるスクリプトプロジェクト(CLIツールやスクリプトを実行するだけ)として扱いたいだけの場合は、package-mode = false を追加するようにしてください。
[tool.poetry]
name = "chiikawa"
version = "0.1.0"
description = "poetry docker env example"
authors = ["username <email>"]
readme = "README.md"
package-mode = false <-- 追加!
ロックファイルの生成
そして、pyproject.tomlの部分に下記を追加します。
[tool.poetry.group.ml.dependencies]
torch = [
{ version = "=2.2.0", source = "pypi", platform = "darwin" },
{ version = "=2.2.0+cpu", source = "pytorch", platform = "linux" },
{ version = "=2.2.0+cpu", source = "pytorch", platform = "win32" },
]
[[tool.poetry.source]]
name = "pytorch"
url = "https://download.pytorch.org/whl/cpu"
priority = "explicit"
この方法は、下記のissueで紹介されています。
これで深層学習ライブラリをMac上でもlockできるようになります。例えば、物体検出を想定して下記のようなライブラリを追加しても無事にロックファイルが生成されます。ライブラリのアップデートも poetry update で一発なので、ライブラリの運用が楽になります。
$ poetry add ultralytics cython torchreid gdown yacs lap pyyaml requests opencv-python pandas scikit-learn pillow joblib pycocotools
# 明示的に poetry.lock を生成したい場合は下記
$ poetry lock
# ライブラリのアップデート
$ poetry update
注意:tensorflowを入れたい場合
普通に poetry add tensorflow としてしまうとエラーになります。これは、tensorflow==2.16.0 以降でKeras3が自動的にインストールされてしまうのですが、その際に依存関係を解決できないために発生します。
したがって、 tensorflow==2.15.0 をバージョン指定して poetry add するか、あるいは下記のように対応するtf-kerasを入れると(現時点で)最新のtensorflowの依存関係を追加することが可能です。
[tool.poetry.dependencies]
python = ">=3.10,<3.12"
ultralytics = "^8.3.89"
(以下略)
tensorflow = "^2.19.0"
tf_keras = "^2.19.0"
実際にdocker環境でlockファイルを元にインストール
では、Dockerfileをビルド中にpoetry.lockに基づいてライブラリをインストールしていきます。
下記のコマンドで大丈夫です。
ここで重要なのは --without ml という箇所で、pyproject.tomlの [tool.poetry.group.ml.dependencies] という箇所を無視しています(mlグループを無効化)。こうしないとエラーになるので、注意が必要です(多分、MACOSではなくlinuxを参照して、torchのcpu環境を拾ってきてエラーになってるんだと思います)。
RUN pip install poetry
COPY . .
RUN poetry config virtualenvs.create false \
&& poetry install --without ml --no-interaction --no-ansi
下記の手順でdocker環境を立ち上げてコンテナの中に入れます。
$ cd chiikawa
$ cp .env{.example,}
$ DOCKER_BUILDKIT=1 docker build . -t poetry-example
$ docker compose run --rm poetry-demo
コンテナの中に入って、パッケージをビルド
今回は、すごく簡単なクラスを呼び出して実行するコマンドをパッケージとして実装しました。
.
├── Dockerfile
├── README.md
├── core.py(mypackage/base.pyのクラスを呼び出して実行するコマンド部分)
├── dist(後で生成される)
│ ├── chiikawa-0.1.0-py3-none-any.whl
│ └── chiikawa-0.1.0.tar.gz
├── docker-compose.yml
├── mypackage
│ ├── __init__.py
│ └── base.py(クラスオブジェクト)
├── poetry.lock
├── pyproject.toml
└── tests
└── __init__.py
mypackage/base.py
class myclass:
def __init__(self) -> None:
self.init_val = 10
def __call__(self, input_val: int) -> str:
if isinstance(input_val, int):
return str(self.init_val + input_val)
else:
return "Error"
core.py
from mypackage.base import myclass
def main():
api = myclass()
print(api(10))
if __name__ == '__main__':
main()
パッケージとして呼び出せるように、
$ poetry build
すると、下記のようにビルドしたパッケージが生成されます。
.
├── dist
└── chiikawa-0.1.0-py3-none-any.whl
パッケージをインストールしてコマンドを呼び出す
インストール:
pip install dist/chiikawa-0.1.0-py3-none-any.whl
コマンドを実行:
$ example
20
まとめ
今回はpoetryを用いて、MACでも深層学習ライブラリを運用できる方法を紹介しました。
Discussion