4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VOICEVOX用にONNXRuntime(DirectML)を改造してGPUを選択できるようにしたい

Last updated at Posted at 2024-01-27

モチベ

VOICEVOX_COREの中で使用するGPUは0番目に固定されています
Multi-GPU環境とかだとVOICEVOXで使用するGPUが選べると便利だとおもいませんか?
VOICEVOX_COREのビルドは現状ヒホ氏しかできないので、ONNXRuntimeのほうを改造します
※いずれGPUを選択できるAPIが実装されるかもしれませんが暫定対応ということで

調査

onnxruntime-rsの session.rs を見る

with_append_execution_provider_directml 関数定義を見る

onnxruntime.dll の OrtSessionOptionsAppendExecutionProvider_DML コールされている

なんか2番目 device_id がGPUを指定する番号っぽい!

//https://github.com/VOICEVOX/onnxruntime-rs/blob/master/onnxruntime/src/session.rsより抜粋

mod directml {
    use super::*;

    impl<'a> SessionBuilder<'a> {
        pub fn with_append_execution_provider_directml(
            self,
            device_id: usize,
        ) -> Result<SessionBuilder<'a>> {
            let status = unsafe {
                sys::OrtSessionOptionsAppendExecutionProvider_DML(
                    self.session_options_ptr,
                    device_id as ::std::os::raw::c_int,
                )
            };
            status_to_result(status).map_err(OrtError::SessionOptions)?;
            Ok(self)
        }
    }
}

ちなみにVOICEVOX同封の onnxruntime.dll はv1.13.1っぽい
念のため改造するときはこのバージョンを使う

image.png

とりあえずビルドしてみる

ひつようなもの

  • Visual Studio 2019
    ※C++によるデスクトップ開発が入っていればOK
    ※ONNX Runtimeの比較的新しいバージョンを試したいって人はVisual Studio 2022のほうがいいかも
    ※極力不要なものはインストールしたくない人はBuild Toolsだけで行けるかも

image.png

  • Git
  • CMake

image.png

  • Python3※python3.12は上手くいかないかもしれない

image.png

ビルド

コマンドプロンプトで下記を実行

git clone --recursive https://github.com/microsoft/onnxruntime.git -b v1.13.1
cd onnxruntime
build.bat --cmake_extra_defines CMAKE_SYSTEM_NAME=Windows CMAKE_SYSTEM_PROCESSOR=x86_64 --config Release --parallel --update --build --build_shared_lib --use_dml

ビルドは通った!

image.png

動作確認(結果は失敗)

onnxruntime\build\Windows\Release\Release に

  • onnxruntime.dll
  • DirectML.dll

があるので、VOICEVOXのインストールパスにオリジナルのDLLを退避しつつ差し替える

差し替えた後VOICEVOXを起動してみたのだが上手くいかなかった

image.png

エラーメッセージを見るために、ターミナルから起動してみる
image.png

原因調査

Dependencies でオリジナルと今回ビルドした onnxruntime.dll を比較してみる

今回ビルドしたやつ
image.png

同封されていたオリジナル
image.png

比較のために並べる
image.png

OrtGetWinMLAdapter なる関数が足りてない・・・
RustからC++のDLLを読み込むメカニズムはよくわかってないけど、これが原因?
Rustとか関係なく序数による関数のexportによる方法があることを知りませんでした…
序数がずれたらそりゃ読み込めんですな

OrtGetWinMLAdapterについて少し調べる

OrtGetWinMLAdapter だが onnxruntime\winml\adapter の winml_adapter_c_api.cpp に定義されてる

//https://github.com/microsoft/onnxruntime/blob/main/winml/adapter/winml_adapter_c_api.cppより抜粋
const WinmlAdapterApi* ORT_API_CALL OrtGetWinMLAdapter(_In_ uint32_t ort_version) NO_EXCEPTION {
  if (ort_version >= 2) {
    return &winml_adapter_api_1;
  }

  return nullptr;
}

どうやら、WinML(Windows Machine Learning )関係の関数っぽい

build.bat のオプションに --use_winml があるのだが、これを指定するとどうやってもビルドが通らない
いろいろやってみたが・・・無理だったのであきらめた
そもそもVOICEVOX側でこの関数使ってるのか?
うん、たぶん使ってない!
よしダミー関数でもでっち上げよう!

2024/2/2
※後述しますがbuildオプションを追加したらいけました・・・

再ビルド(ボツ案)

2024/2/2
※この方法は邪道かつ力技なので、無視してください
※とはいっても、今後役に立つこともあるかもしれないので備忘として

いくつかファイルに修正をいれる

onnxruntime\onnxruntime\core\providers\cpu\symbols.txt を下記のように修正

OrtGetApiBase
OrtSessionOptionsAppendExecutionProvider_CPU

OrtGetApiBase
OrtGetWinMLAdapter
OrtSessionOptionsAppendExecutionProvider_CPU

onnxruntime\core\session\provider_bridge_ort.cc の末尾に下記を追加

//nullptrを返すだけのOrtGetWinMLAdapter関数をでっち上げる
struct WinmlAdapterApi;
typedef struct WinmlAdapterApi WinmlAdapterApi;

const WinmlAdapterApi* ORT_API_CALL OrtGetWinMLAdapter(_In_ uint32_t ort_version) NO_EXCEPTION {
  return nullptr;
}

準備が整ったので再びビルドする

再ビルド(正攻法)※2024/2/2 追記

build.batのオプションに --enable_wcos --use_winml を追加するだけでよかった・・・

build.bat --cmake_extra_defines CMAKE_SYSTEM_NAME=Windows CMAKE_SYSTEM_PROCESSOR=x86_64 --config Release --parallel --update --build --build_shared_lib --use_dml --enable_wcos --use_winml

動作確認

まずは、Dependencies で確認してみる・・・大丈夫そう!

image.png

VOICEVOXも・・・起動できた!

image.png

GPUを選択できるよう修正して再ビルド

お手軽に環境変数でコントロールしようかと
OrtSessionOptionsAppendExecutionProvider_DML は下記の部分ですね

//https://github.com/microsoft/onnxruntime/blob/6d7ac9c93ae7cd1f979b35e7f6d7af207962cd99/onnxruntime/core/providers/dml/dml_provider_factory.ccより抜粋
ORT_API_STATUS_IMPL(OrtSessionOptionsAppendExecutionProvider_DML, _In_ OrtSessionOptions* options, int device_id) {
API_IMPL_BEGIN
  options->provider_factories.push_back(onnxruntime::DMLProviderFactoryCreator::Create(device_id));
API_IMPL_END
  return nullptr;
}

これをこんな感じに変えてみます

#include <charconv>
ORT_API_STATUS_IMPL(OrtSessionOptionsAppendExecutionProvider_DML, _In_ OrtSessionOptions* options, int device_id) {
API_IMPL_BEGIN
  std::size_t len;
  char buff[1024];

  if(!getenv_s(&len, buff, sizeof(buff), "ONNX_DML_DEVICE")){
    if(len > 0 && buff[len - 1] == '\0') len--;

    auto first = buff;
    auto last = buff + len;

    decltype(device_id) val;

    auto [ptr, ec] = std::from_chars(first, last, val);

    if(ec == std::errc{} && ptr == last){
      device_id = val;
    }
  }

  options->provider_factories.push_back(onnxruntime::DMLProviderFactoryCreator::Create(device_id));
API_IMPL_END
  return nullptr;
}

再ビルドして、DLLを差し替えます

動作確認(最終)

うちの環境では、0番目に内蔵GPU、1番目に外付けGPUという環境です
image.png

VOICEVOXのエディターのほうではよく確認できなかったので自作のDiscord TTS-Botで確認します。
https://qiita.com/kmatsumoto630823/items/6bc0e1f85be27e026849

まずVOICEVOXエンジンを普通に起動します

"C:\Program Files\VOICEVOX.\run.exe"  --use_gpu

内蔵GPUが貧弱すぎてTTS-Botはうんともすんとも言いません

環境変数をセットして起動します

set ONNX_DML_DEVICE=1
"C:\Program Files\VOICEVOX.\run.exe"  --use_gpu

TTS-Botから声が出るようになりました!

最後に

いずれはVOICEVOXにもGPUを選択できるようなAPIが実装されるかもしれませんが
それまではこの暫定対応で行こうかと思います!

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?