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

ビルド済みエンジンに Rust 実装のコアを含めるようにする #510

Merged
merged 10 commits into from
Dec 1, 2022
Merged
50 changes: 25 additions & 25 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ env:
IMAGE_NAME: ${{ secrets.DOCKERHUB_USERNAME }}/voicevox_engine
PYTHON_VERSION: "3.8.10"
VOICEVOX_RESOURCE_VERSION: "0.13.2"
VOICEVOX_CORE_VERSION: "0.13.2"
VOICEVOX_CORE_VERSION: "0.14.0-preview.2"
VOICEVOX_ENGINE_VERSION:
|- # releaseタグ名か、workflow_dispatchでのバージョン名か、latestが入る
${{ github.event.release.tag_name || github.event.inputs.version || 'latest' }}
Expand All @@ -38,42 +38,42 @@ jobs:
- os: windows-2019
architecture: "x64"
voicevox_core_asset_prefix: voicevox_core-windows-x64-cpu
onnxruntime_url: https://github.com/microsoft/onnxruntime/releases/download/v1.10.0/onnxruntime-win-x64-1.10.0.zip
onnxruntime_url: https://github.com/microsoft/onnxruntime/releases/download/v1.11.1/onnxruntime-win-x64-1.11.1.zip
artifact_name: windows-cpu
# Windows DirectML
- os: windows-2019
architecture: "x64"
voicevox_core_asset_prefix: voicevox_core-windows-x64-directml
onnxruntime_url: https://github.com/microsoft/onnxruntime/releases/download/v1.10.0/Microsoft.ML.OnnxRuntime.DirectML.1.10.0.zip
directml_url: https://www.nuget.org/api/v2/package/Microsoft.AI.DirectML/1.8.0
onnxruntime_url: https://github.com/microsoft/onnxruntime/releases/download/v1.11.1/Microsoft.ML.OnnxRuntime.DirectML.1.11.1.zip
directml_url: https://www.nuget.org/api/v2/package/Microsoft.AI.DirectML/1.9.0
artifact_name: windows-directml
# Windows NVIDIA GPU
- os: windows-2019
architecture: "x64"
voicevox_core_asset_prefix: voicevox_core-windows-x64-cuda
onnxruntime_url: https://github.com/microsoft/onnxruntime/releases/download/v1.10.0/onnxruntime-win-x64-gpu-1.10.0.zip
cuda_version: "11.4.2"
cudnn_url: https://developer.download.nvidia.com/compute/redist/cudnn/v8.2.4/cudnn-11.4-windows-x64-v8.2.4.15.zip
onnxruntime_url: https://github.com/microsoft/onnxruntime/releases/download/v1.11.1/onnxruntime-win-x64-gpu-1.11.1.zip
cuda_version: "11.6.0"
cudnn_url: https://developer.download.nvidia.com/compute/redist/cudnn/v8.4.1/local_installers/11.6/cudnn-windows-x86_64-8.4.1.50_cuda11.6-archive.zip
artifact_name: windows-nvidia
# Mac CPU (x64 arch only)
- os: macos-11
architecture: "x64"
voicevox_core_asset_prefix: voicevox_core-osx-universal2-cpu
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

あ~~~ universal2じゃなくなると、どうなるんでしたっけ・・・。

Copy link
Member Author

@PickledChair PickledChair Nov 27, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

特に影響はないはずです!(エンジンの実行ファイル run 自体が x64 向けであることから、M1 Mac においてこれまでも universal バイナリのうち x64 向けの部分が rosetta で翻訳されて使われていたと考えられるため。)強いていえば macOS 向けのビルド済みエンジンのサイズが数百 MB 小さくなるので、利点の方が大きいと思います。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

M1 Mac向けにエンジンのmacOS arm64バイナリもしくはuniversal2バイナリも今後リリースするようにしますかね...?

PyInstallerのドキュメントを見ると、macOS x64(GitHub Actions)上でuniversal2もしくはarm64単体のバイナリをビルド(クロスコンパイル)できそうな感じがしました。コアのファイルサイズが2倍になってしまうので、いったんarm64単体のクロスコンパイルの方がいいかなと思っています。

PythonがmacOS universal2バイナリの提供を始めたのがPython 3.9からのようなので、Python 3.8からPython 3.9以降に移行する必要があるかもです。

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

エンジンの実行ファイル run 自体が x64 向けであることから、M1 Mac においてこれまでも universal バイナリのうち x64 向けの部分が rosetta で翻訳されて使われていたと考えられるため。

なんと。。。。w
動的ライブラリだからコアはuniversalのほうが使われている・・・とかだったら嬉しいですね・・・。

M1 Mac向けにエンジンのmacOS arm64バイナリもしくはuniversal2バイナリも今後リリースするようにしますかね...?
コアのファイルサイズが2倍になってしまう

やっても良いなと思いました。macだと結構重いという意見もちょくちょく見かけるので、動作が軽くなるのであれば嬉しそうです。macだし(?)、容量<動作かなと!

まあどちらにせよ、エンジン側をuniversal2にできないと、コア側をuniversal2にする意味はあまりなさそうですね。
とりあえずエンジン側とコア側にissue作る・・・?

Copy link
Member Author

@PickledChair PickledChair Nov 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

動的ライブラリだからコアはuniversalのほうが使われている・・・とかだったら嬉しいですね・・・。

そうだったら便利だったのですが、実際はそうではないようです……。

一応 universal バイナリの仕組みを大雑把に説明すると、x64 向けのバイナリと arm64 向けのバイナリがくっつけられたバイナリであり、実行環境に合わせて適切な方のバイナリを用いる仕組みになっています(このためバイナリサイズが大きくなります。単純に考えると約2倍のサイズになります。"fat binary" とも呼ばれています)。

M1 Mac において、Rosetta で起動した x64 バイナリが universal バイナリの dylib をロードするときに、dylib 内のどちらのバイナリが用いられるのか気になったので、手元で実験してみました。残念ながら x64 バイナリの方が用いられるようです……(Apple のドキュメントで説明されている方法を参考に、以下のようにどちらのバイナリが実行されているのかを判別する実験を行いました)。

用いられているバイナリの種類の判別実験

検証コード

/* test.c(このコードを universal バイナリの libtest.dylib へとビルドする) */

#include <sys/sysctl.h>
#include <sys/errno.h>

/* 実装されているバイナリがarm64なら0, x64なら1, エラーなら-1を返す */
int processIsTranslated() {
  int ret = 0;
  size_t size = sizeof(ret);
  if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
    if (errno == ENOENT)
      return 0;
    return -1;
  }
  return ret;
}
/* main.c(このコードから実行ファイルをビルドする。arm64 バイナリは main, x64 バイナリは main1) */

#include <stdio.h>
#include <dlfcn.h>

int processIsTranslated();

int main() {
  void *handle = dlopen("libtest.dylib", RTLD_LAZY);

  if (handle == 0) {
    fprintf(stderr, "%s\n", dlerror());
    return 1;
  }

  int (*processIsTranslated)(void) = dlsym(handle, "processIsTranslated");
  int processKind = processIsTranslated();
  switch (processKind) {
    case 0: printf("native process\n"); break;
    case 1: printf("translated process\n"); break;
    default: printf("occur error\n"); break;
  }
  return 0;
}

実験結果

備考:M1 Mac 上でビルド&実行

$ lipo -info libtest.dylib
Architectures in the fat file: libtest.dylib are: x86_64 arm64
$ cc -o main -arch arm64 main.c
$ lipo -info main
Non-fat file: main is architecture: arm64
$ ./main
native process
$ cc -o main1 -arch x86_64 main.c
$ lipo -info main1
Non-fat file: main1 is architecture: x86_64
$ ./main1
translated process

M1 Mac向けにエンジンのmacOS arm64バイナリもしくはuniversal2バイナリも今後リリースするようにしますかね...?

PyInstallerのドキュメントを見ると、macOS x64(GitHub Actions)上でuniversal2もしくはarm64単体のバイナリをビルド(クロスコンパイル)できそうな感じがしました。コアのファイルサイズが2倍になってしまうので、いったんarm64単体のクロスコンパイルの方がいいかなと思っています。

PythonがmacOS universal2バイナリの提供を始めたのがPython 3.9からのようなので、Python 3.8からPython 3.9以降に移行する必要があるかもです。

確かに Python インタプリタ自体は universal2 バイナリを提供していますが、サードパーティ製ライブラリについても universal2 対応を行わなければならないだろう、と考えられます。

調べたところ、最もメジャーなライブラリの1つである NumPy ですら universal2 対応の wheel を PyPI や GitHub Releases で提供していないようです。つまり単純に pip install することができません( numpy/numpy#20787 で活発な議論が行われたようですが、コストに見合った需要があるとは考えられないという理由で、universal2 wheel が欲しい開発者自身がツールを使って自分で構築するべき、という結論でとりあえず終わっています。ツールとして delocate-fuse が挙げられています)。

これを踏まえると、原理的には、各依存ライブラリについて x64 向けと aarch64 向けの wheel を取得してツールで universal2 wheel にマージするということを事前に行えば、universal2 対応のエンジンを提供することは可能かもしれません。ただ、見通しとしては作業はある程度長期的なものになると思います:

  • Python 自体のバージョン更新(少なくとも 3.9 以降、理想的には 3.10 以降)
  • 依存ライブラリのバージョン更新(NumPy を含む一部のサードパーティライブラリは、現在のバージョン指定では Apple Silicon Mac ではインストールできない)
  • コアの universal2 バイナリの作成(これは lipo コマンドで可能)
  • 前述の universal2 wheel のマージ処理の構築
  • PyInstaller でのビルド処理における universal2 ビルド対応

(余談ですが、GitHub Actions の Self-hosted runners が Apple Silicon に対応していることがこの記事に書かれていますが、setup-python に問題があり何らかの workaround が必要そうでした。これを用いて universal2 バイナリではなく単純に Apple Silicon 向けのエンジンを用意するという案も考えられます。実行マシンはどうするのか? という疑問はさておき……)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

確かに Python インタプリタ自体は universal2 バイナリを提供していますが、サードパーティ製ライブラリについても universal2 対応を行わなければならないだろう、と考えられます。

なるほど・・・・・・・・・・・。盲点でした。

universal2対応までの道のりもよくわかりました・・・。なかなかの道のりですね・・・。
ちなみになのですが、x64 向けと aarch64 向けの両方のバイナリを提供するという感じだとだいぶ楽になったりするのでしょうか・・・?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ちなみになのですが、x64 向けと aarch64 向けの両方のバイナリを提供するという感じだとだいぶ楽になったりするのでしょうか・・・?

ビルド環境としてaarch64(Apple Silicon Mac)を使うことができると仮定したとき、Intel Mac 向けに構築したビルド手順をそのまま使いまわせる見込みが大きいと思います。universal ビルドの手順を構築するより単純にかなり手数が減りそうです。

onnxruntime_url: https://github.com/microsoft/onnxruntime/releases/download/v1.10.0/onnxruntime-osx-universal2-1.10.0.tgz
voicevox_core_asset_prefix: voicevox_core-osx-x64-cpu
onnxruntime_url: https://github.com/microsoft/onnxruntime/releases/download/v1.11.1/onnxruntime-osx-x86_64-1.11.1.tgz
artifact_name: macos-x64
# Linux CPU
- os: ubuntu-18.04
- os: ubuntu-20.04
architecture: "x64"
voicevox_core_asset_prefix: voicevox_core-linux-x64-cpu
onnxruntime_url: https://github.com/microsoft/onnxruntime/releases/download/v1.10.0/onnxruntime-linux-x64-1.10.0.tgz
onnxruntime_url: https://github.com/microsoft/onnxruntime/releases/download/v1.11.1/onnxruntime-linux-x64-1.11.1.tgz
artifact_name: linux-cpu
# Linux NVIDIA GPU
- os: ubuntu-18.04
- os: ubuntu-20.04
architecture: "x64"
voicevox_core_asset_prefix: voicevox_core-linux-x64-gpu
onnxruntime_url: https://github.com/microsoft/onnxruntime/releases/download/v1.10.0/onnxruntime-linux-x64-gpu-1.10.0.tgz
cuda_version: "11.4.2"
cudnn_url: https://developer.download.nvidia.com/compute/redist/cudnn/v8.2.4/cudnn-11.4-linux-x64-v8.2.4.15.tgz
onnxruntime_url: https://github.com/microsoft/onnxruntime/releases/download/v1.11.1/onnxruntime-linux-x64-gpu-1.11.1.tgz
cuda_version: "11.6.0"
cudnn_url: https://developer.download.nvidia.com/compute/redist/cudnn/v8.4.1/local_installers/11.6/cudnn-linux-x86_64-8.4.1.50_cuda11.6-archive.tar.xz
artifact_name: linux-nvidia

runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -177,27 +177,27 @@ jobs:
if [[ ${{ matrix.os }} == windows-* ]]; then
curl -L "${{ matrix.cudnn_url }}" > download/cudnn.zip

unzip download/cudnn.zip cuda/bin/*.dll -d download/cudnn_tmp
unzip download/cudnn.zip cudnn-*/bin/*.dll -d download/cudnn_tmp

mkdir -p download/cudnn/bin
mv download/cudnn_tmp/cuda/bin/*.dll download/cudnn/bin/
mv download/cudnn_tmp/cudnn-*/bin/*.dll download/cudnn/bin/
rm -rf download/cudnn_tmp

rm download/cudnn.zip
else
curl -L "${{ matrix.cudnn_url }}" > download/cudnn.tgz
curl -L "${{ matrix.cudnn_url }}" > download/cudnn.tar.xz

tar -zxf download/cudnn.tgz -C download/
tar -Jxf download/cudnn.tar.xz -C download/

mkdir -p download/cudnn/bin
cp download/cuda/lib64/libcudnn.so.* download/cudnn/bin/
cp download/cuda/lib64/libcudnn_*_infer.so.* download/cudnn/bin/
cp download/cudnn-*/lib/libcudnn.so.* download/cudnn/bin/
cp download/cudnn-*/lib/libcudnn_*_infer.so.* download/cudnn/bin/
aoirint marked this conversation as resolved.
Show resolved Hide resolved

# remove unneed full version libraries
rm -f download/cudnn/bin/libcudnn.so.*.*
rm -f download/cudnn/bin/libcudnn_*_infer.so.*.*

rm download/cudnn.tgz
rm download/cudnn.tar.xz
fi

- name: Show disk space (debug info)
Expand Down Expand Up @@ -392,15 +392,15 @@ jobs:
# Replace version & specify dynamic libraries
if [[ ${{ matrix.os }} == macos-* ]]; then
gsed -i "s/__version__ = \"latest\"/__version__ = \"${{ env.VOICEVOX_ENGINE_VERSION }}\"/" voicevox_engine/__init__.py
LIBCORE_PATH=download/core/libcore.dylib
LIBCORE_PATH=download/core/libvoicevox_core.dylib
LIBONNXRUNTIME_PATH=download/onnxruntime/lib/libonnxruntime.dylib
else
sed -i "s/__version__ = \"latest\"/__version__ = \"${{ env.VOICEVOX_ENGINE_VERSION }}\"/" voicevox_engine/__init__.py
if [[ ${{ matrix.os }} == windows-* ]]; then
LIBCORE_PATH=download/core/core.dll
LIBCORE_PATH=download/core/voicevox_core.dll
LIBONNXRUNTIME_PATH=download/onnxruntime/lib/onnxruntime.dll
else
LIBCORE_PATH=download/core/libcore.so
LIBCORE_PATH=download/core/libvoicevox_core.so
LIBONNXRUNTIME_PATH=download/onnxruntime/lib/libonnxruntime.so
fi
fi
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-18.04
- os: ubuntu-20.04
target: linux-cpu
- os: ubuntu-18.04
- os: ubuntu-20.04
target: linux-nvidia
- os: macos-10.15
- os: macos-11
target: macos-x64
- os: windows-2019
target: windows-cpu
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest] # [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-20.04, windows-latest] # [ubuntu-20.04, macos-latest, windows-latest]
python: ['3.8.10']
include:
- os: ubuntu-latest
- os: ubuntu-20.04
path: ~/.cache/pip
# - os: macos-latest
# path: ~/Library/Caches/pip
Expand All @@ -32,7 +32,7 @@ jobs:
cache: pip

- name: Install libraries for ubuntu
if: matrix.os == 'ubuntu-latest'
if: matrix.os == 'ubuntu-20.04'
run: sudo apt-get install libsndfile1

- name: Install dependencies
Expand All @@ -47,20 +47,20 @@ jobs:
coverage run --omit=test/* -m pytest

- name: Submit coverage to Coveralls
if: matrix.os == 'ubuntu-latest'
if: matrix.os == 'ubuntu-20.04'
run: coveralls --service=github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Create coverage result
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest'
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-20.04'
run: |
mkdir report
coverage report > report/report.txt
echo ${{ github.event.number }} > report/pr_num.txt

- name: Upload coverage result
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest'
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-20.04'
uses: actions/upload-artifact@v3
with:
name: report
Expand Down
Loading