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

VRAMをリフレッシュする方法の提供 #513

Open
2 of 3 tasks
kuroneko6423 opened this issue Nov 23, 2022 · 59 comments
Open
2 of 3 tasks

VRAMをリフレッシュする方法の提供 #513

kuroneko6423 opened this issue Nov 23, 2022 · 59 comments

Comments

@kuroneko6423
Copy link

内容

VOICEVOXを読み上げとして使っているとVRAMがずっと増えるので定期的に削減してくれるようにしてほしいです。

Pros 良くなる点

PCへの負荷が減る

Cons 悪くなる点

不明

実現方法

大量のリクエストを長時間処理しているとRAM及びVRAMを無限に使用する

VOICEVOXのバージョン

0.13.2

OSの種類/ディストリ/バージョン

  • Windows
  • macOS
  • Linux

その他

なし

@github-actions github-actions bot added OS 依存:linux Linux に依存した現象 OS 依存:win Windows に依存した現象 labels Nov 23, 2022
@Hiroshiba Hiroshiba added the 優先度:低 (運用中止) label Nov 23, 2022
@Hiroshiba
Copy link
Member

Hiroshiba commented Nov 23, 2022

issue作成ありがとうございます!
この課題の根本はおそらくコア側にあると思われますが、エンジン側でも解決可能そうな気がしています。

パッと考えた思いつきですが、コアをリロードしてリフレッシュする仕組みをエンジンに作るか、コア側にリフレッシュ機構を作ってエンジン側から呼ぶ手がありそうです。
最終的にはその仕組みをAPIとして提供するのが良いのかなと!

そもそもなぜメモリ消費量が増えていくのか気になりますね…。
@kuroneko6423 何リクエストでメモリ使用量はどの程度増えていますか…?👀
(問題箇所の推察に役立つ情報になるかなと思っています)

@kuroneko6423
Copy link
Author

どっちがメモリの使用量に影響するかわ分かりませんが
synthesisとaudio_queryを使ってます
それ以外は頻繁に使わないので関係ないかと
(speakersとかしか)

@Hiroshiba
Copy link
Member

なるほどです!audio_queryの方はVRAMを使わないはずなので、原因はsynthesisだと思います。
「synthesisの実行何回でメモリ消費量がどれくらい増えているか」をぜひ知りたいなと思った次第です!

@Hiroshiba
Copy link
Member

あ!あとどの版を使われているかも知りたいです。
Linuxとwindowsにチェックを入れられていますが、Linux CUDA版とWindows CUDA版でしょうか。

@kuroneko6423
Copy link
Author

kuroneko6423 commented Nov 23, 2022

あ!あとどの版を使われているかも知りたいです。 Linuxとwindowsにチェックを入れられていますが、Linux CUDA版とWindows CUDA版でしょうか。

Windows CUDAです
Linux CUDAも同じでしたのでチェックに入れさせていただきました。

@Hiroshiba
Copy link
Member

なるほどです、ありがとうございます。

とりあえずタイトルにある「定期的な削減」はいろんな不具合の心配をしないといけないので実装しない方針です。
どちらかというとまだ予定がありそうな「VRAMをリフレッシュする方法の提供」に変更します。
(抜本的にメモリ消費量が増えない方法を探すのが一番いいかなと思います。)

DirectML版もあるのですが、こちらだとメモリ消費量が増えていくかも調査頂いても良いでしょうか。
ちなみにたしかDirectML版のほうが動作が早い傾向があるのでこちらのほうがおすすめです。

引き続き、synthesisの実行何回でメモリ消費量がどれくらい増えているかも調査頂けると助かります!

@Hiroshiba Hiroshiba changed the title VRAMの定期的な削減(?) VRAMをリフレッシュする方法の提供 Nov 23, 2022
@kuroneko6423
Copy link
Author

kuroneko6423 commented Nov 23, 2022

了解しました。
あと0.14.0-preview.2で使用してみます

@kuroneko6423
Copy link
Author

kuroneko6423 commented Dec 1, 2022

cuda版は1000~3000リクエストほどで0.2GBほどずつ使用されている感じです。
DirectML版は2000~4000リクエストほどで0.1GBずつ使用されている感じです。
(※Windows環境でやってるのでPC環境が違うと変化するかも?)

@Hiroshiba
Copy link
Member

Hiroshiba commented Dec 1, 2022

なるほどです!!ありがとうございます!!
単純計算してみました。

cuda版:1リクエストで 67~200KB ほど消費
DirectML版:1リクエストで 25~50KB ほど消費

計算しやすいように、仮で1リクエスト20~200KBだとすると、float(4バイト)パラメータ数5000〜50000ですね!
ここからリークしていそうなメモリの候補を絞ってみます。

N秒の音声を生成するのに必要な出力パラメータ数は 24000*N で、Nの平均が0.2~2.1秒なら範囲内かもです。
↑を生成するのに必要な入力パラメータ数は 200*45*N で、Nの平均が0.6〜5.6秒なら範囲内かもです。

この辺りな気がしますね!!

@kuroneko6423
ちなみに、botに入力されているテキストの文量や音声の長さの平均とかってわかったりしますか・・・?もしわかると確度が上がって嬉しい感じです!

@kuroneko6423
Copy link
Author

kuroneko6423 commented Dec 1, 2022

文字数は20~40ぐらいが多いですね

@Hiroshiba
Copy link
Member

おっと、なるほどです。思ったより長いですね・・・ あ、話速を早く設定されていたりしますか?

@Yosshi999
Copy link
Contributor

Yosshi999 commented Dec 1, 2022

一部のonnxとcudnnの組み合わせでメモリリークが発生するという報告がありますね
microsoft/onnxruntime#8147

ONNX Runtime 1.8.1 CPU EP == No Memory Leak
ONNX Runtime 1.8.1 CUDA EP - CUDA 11.1+cuDNN 8.0.4.30 == Memory Leak
ONNX Runtime 1.8.1 CUDA EP - CUDA 11.4.1+cuDNN 8.2.2.26 == No Memory Leak

ONNX Runtime 1.9.0 CUDA EP - CUDA 11.1.1+cuDNN 8.0.5.39 == Memory Leak
ONNX Runtime 1.9.0 CUDA EP - CUDA 11.4.3+cuDNN 8.2.4.15 == No Memory Leak

@kuroneko6423
Copy link
Author

おっと、なるほどです。思ったより長いですね・・・ あ、話速を早く設定されていたりしますか?

やってますがそこまで測定はしてませんね()
ほとんどのリクエストはノーマル速度です。

@Hiroshiba
Copy link
Member

Hiroshiba commented Dec 1, 2022

一部のonnxとcudnnの組み合わせでメモリリークが発生するという報告がありますね

なるほど・・・これだと結構どうしようもないかもしれませんね・・・・。

ほとんどのリクエストはノーマル速度です。

なるほどです!参考になります 🙏
ちょっと数値合わないですが、まあ原因この辺かな〜という直感が得られそうです!ありがとうございます 🙏

@Hiroshiba
Copy link
Member

コア側にリフレッシュする仕組みを実装するissueを作ってみました。

@Hiroshiba
Copy link
Member

コア側の機能を使わなくても、エンジン側でコアをリロードする手もあると思います。

ここの中でコアをロードしています。

voicevox_engine/run.py

Lines 972 to 980 in e11913b

synthesis_engines = make_synthesis_engines(
use_gpu=args.use_gpu,
voicelib_dirs=args.voicelib_dir,
voicevox_dir=args.voicevox_dir,
runtime_dirs=args.runtime_dir,
cpu_num_threads=cpu_num_threads,
enable_mock=args.enable_mock,
load_all_models=args.load_all_models,
)

実際のロード部分はここです。

def load_core_library(core_dir: Path, suppress_error: bool = False):
"""
指定されたディレクトリにあるコアを読み込む。
ユーザーディレクトリの場合は存在しないこともあるので、エラーを抑制すると良い。
"""
try:
core = CoreWrapper(use_gpu, core_dir, cpu_num_threads, load_all_models)
metas = json.loads(core.metas())
core_version = metas[0]["version"]
if core_version in synthesis_engines:
print(
"Warning: Core loading is skipped because of version duplication.",
file=sys.stderr,
)
else:
synthesis_engines[core_version] = SynthesisEngine(core=core)
except Exception:
if not suppress_error:
raise

なので、APIでコアバージョンを受けて、対応するsynthesis_enginesを解放して再度load_core_libraryを呼べばできそうな気がします。

@kuroneko6423

This comment was marked as resolved.

@kuroneko6423

This comment was marked as resolved.

@Hiroshiba

This comment was marked as resolved.

@kuroneko6423

This comment was marked as resolved.

@kuroneko6423

This comment was marked as resolved.

@Hiroshiba

This comment was marked as resolved.

@kuroneko6423

This comment was marked as resolved.

@kuroneko6423

This comment was marked as resolved.

@Hiroshiba

This comment was marked as resolved.

@kuroneko6423
Copy link
Author

CPU版はこちらも大丈夫でした

@Hiroshiba
Copy link
Member

Hiroshiba commented Jan 2, 2023

なるほどです、ありがとうございます!
0.14のcuda版は怪しそうですね…。環境あるのでこちらでも確認してみます。

そういえばDirectML版でもVRAM溢れると報告いただいたと思います。
もしよければ0.14のDirectML版ではVRAM増えてく問題解消してるからご確認いただけると助かります!

@Hiroshiba
Copy link
Member

@kuroneko6423 0.14.0-preview.5のlinux cuda版、こちらでは普通に動きました。
ちょっとなぜそのエラー(Exception: 無効なmodel_indexです: 0)が出るのか全くわからないです・・・。

こんな感じのコマンドで動いたというのを添付しておきます。

↓エンジンをダウンロードして起動

set -eux

# rm -rf /tmp/voicevox_engine
mkdir -p /tmp/voicevox_engine
cd /tmp/voicevox_engine

# linux-nvidia.7zがない場合
if [ ! -f linux-nvidia.7z ]; then
    wget https://github.com/VOICEVOX/voicevox_engine/releases/download/0.14.0-preview.5/linux-nvidia.7z.001
    mv linux-nvidia.7z.001 linux-nvidia.7z
fi

# linux-nvidiaがない場合
if [ ! -d linux-nvidia ]; then
    7z x linux-nvidia.7z
    chmod +777 linux-nvidia/run
fi

# run
./linux-nvidia/run --use_gpu

↓リクエストを投げる

echo -n "こんにちは、音声合成の世界へようこそ" >text.txt

curl -s \
    -X POST \
    "localhost:50021/audio_query?speaker=1"\
    --get --data-urlencode text@text.txt \
    > query.json

curl -s \
    -H "Content-Type: application/json" \
    -X POST \
    -d @query.json \
    "localhost:50021/synthesis?speaker=1" \
    > audio.wav

@kuroneko6423

This comment was marked as resolved.

@kuroneko6423
Copy link
Author

kuroneko6423 commented Feb 26, 2023

何を試したか: 音声合成を行っている
どういう結果になってほしいか: VRAMの使用率が高いので通常の動作で5GBとかで動作して欲しい
実際はどういうことになったか: 私の環境では約10GB常時使用しています。
仮に原因がプログラムにあるとしたら何が原因だと思うか: 不明
仮に原因が自分にあるとしたら何が原因だと思うか: 不明
他に試したこと: 特になし
他に試すべきかもしれないこと: 不明
OS: UbuntuServer 22.04
ENGINEのバージョン: 0.14.3
どのデバイス版か(cpu/cuda/directml/gpu): cuda gpu
GPU: RTX3060

kuroneko@voicevox:~$ nvidia-smi
Sun Feb 26 14:33:14 2023       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 525.85.12    Driver Version: 525.85.12    CUDA Version: 12.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ...  On   | 00000000:00:10.0 Off |                  N/A |
| 61%   56C    P2    58W / 170W |  10208MiB / 12288MiB |     38%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|    0   N/A  N/A      1591      C   ./run                           10208MiB |
+-----------------------------------------------------------------------------+

@tarepan tarepan added バグ 要議論 実行する前に議論が必要そうなもの and removed 機能向上 labels Mar 4, 2024
@tarepan
Copy link
Contributor

tarepan commented Mar 4, 2024

@Hiroshiba
2024年現在、他ユーザーからTwitter等で VRAM リークの報告は上がっているでしょうか?
もし無いようでしたら #1063 を適用したいと思います。

@tarepan tarepan mentioned this issue Mar 6, 2024
3 tasks
@tarepan tarepan self-assigned this Mar 7, 2024
@tarepan tarepan removed OS 依存:linux Linux に依存した現象 OS 依存:win Windows に依存した現象 labels Mar 8, 2024
@Hiroshiba
Copy link
Member

@tarepan 確認ありがとうございます!!

新しくリークするという情報は上がってないです。
が、特に解決策を出せたわけでもないので、ずっと未解決として問題を先送りし続けているという状態な気がします。
おそらく再現も難しくないのですが、検証して解決できて時間がある人がなかなか現れないという状況かなと…。

@tarepan
Copy link
Contributor

tarepan commented Mar 10, 2024

ずっと未解決 ... 検証して

@Hiroshiba
本 issue のバグは 0.13.2 and (Windows CUDA | Linux CUDA) で発生しています。
例えば 0.17.2 and (Windows CUDA | Linux CUDA) の条件ではリークしなかった場合、本 issue の VRAM リフレッシュ実装は NoGo でしょうか?

@tarepan tarepan removed the 優先度:低 (運用中止) label Mar 10, 2024
@notoiro
Copy link

notoiro commented Mar 11, 2024

新規で建てるか迷ったんですが、重複に近い気がしたのでここに書かせていただきます。
VRAMリークってほどではないものの、VRAMがそこそこ大量に消費され、その解決案としては同じだと思ったので。

環境

OS: ArchLinux x86_64(Kernel 6.7.6-arch-1-1)
Engine Ver: 0.17.1(製品版の対応モードGPU/CPUの0.17.1のエンジン部分を展開して使ってます)
GPU: GTX960 2GB
主な使用方法: GPUモードで起動、自作の読み上げBotの音声合成エンジンとして利用。再起動はエラー出た時とメンテナンス時にするだけなので数日は連続で起動しっぱなし。
起動時のパラメーター指定: ./run --use_gpu --cpu_num_threads 2 --port $PORT_NUM

概要

上記環境で長期使用していると、突然音声を生成してくれなくなることがあり、ログを確認するとエラーが出ている、VRAMを確認すると使い尽くしている、VOICEVOX Engineを再起動すると直る。
タイミングとして、話者切り替えの後に多いように感じる、エラー直前、直後に入力されているテキストには特に共通点が無い。

検証時に出た同様のエラー
2024-03-11T10:44:21.477506Z  WARN onnxruntime::onnxruntime: "Non-zero status code returned while running Concat node. Name:\'Concat_103\' Status Message: /onnxruntime_src/onnxruntime/core/framework/bfc_arena.cc:342 void* onnxruntime::BFCArena::AllocateRawInternal(size_t, bool) Failed to allocate memory for requested buffer of size 984064\n"
INFO:     127.0.0.1:38556 - "POST /synthesis?speaker=14 HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "uvicorn/protocols/http/h11_impl.py", line 373, in run_asgi
  File "uvicorn/middleware/proxy_headers.py", line 75, in __call__
  File "fastapi/applications.py", line 292, in __call__
  File "starlette/applications.py", line 122, in __call__
  File "starlette/middleware/errors.py", line 184, in __call__
  File "starlette/middleware/errors.py", line 162, in __call__
  File "starlette/middleware/base.py", line 109, in __call__
  File "starlette/responses.py", line 270, in __call__
  File "anyio/_backends/_asyncio.py", line 597, in __aexit__
  File "starlette/responses.py", line 273, in wrap
  File "starlette/middleware/base.py", line 134, in stream_response
  File "starlette/responses.py", line 262, in stream_response
  File "starlette/middleware/base.py", line 98, in body_stream
  File "starlette/middleware/base.py", line 70, in coro
  File "starlette/middleware/cors.py", line 83, in __call__
  File "starlette/middleware/errors.py", line 184, in __call__
  File "starlette/middleware/errors.py", line 162, in __call__
  File "starlette/middleware/exceptions.py", line 79, in __call__
  File "starlette/middleware/exceptions.py", line 68, in __call__
  File "fastapi/middleware/asyncexitstack.py", line 20, in __call__
  File "fastapi/middleware/asyncexitstack.py", line 17, in __call__
  File "starlette/routing.py", line 718, in __call__
  File "starlette/routing.py", line 276, in handle
  File "starlette/routing.py", line 66, in app
  File "fastapi/routing.py", line 273, in app
  File "fastapi/routing.py", line 192, in run_endpoint_function
  File "starlette/concurrency.py", line 41, in run_in_threadpool
  File "anyio/to_thread.py", line 33, in run_sync
  File "anyio/_backends/_asyncio.py", line 877, in run_sync_in_worker_thread
  File "anyio/_backends/_asyncio.py", line 807, in run
  File "run.py", line 446, in synthesis
  File "voicevox_engine/tts_pipeline/tts_engine.py", line 455, in synthesize_wave
  File "voicevox_engine/core/core_adapter.py", line 137, in safe_decode_forward
  File "voicevox_engine/core/core_wrapper.py", line 707, in decode_forward
  File "voicevox_engine/core/core_wrapper.py", line 909, in assert_core_success
voicevox_engine.core.core_wrapper.CoreError: 推論に失敗しました

再現と検証

起動後に一定以上の数の話者を使うとVRAMを使い尽くすと予想したので以下の検証を行った。

検証環境は上記の環境。

自作のBotに話者/スタイルの切り替え機能があるのでそれを利用し、VOICEVOX Engine起動時からVRAMを食い尽くし、生成できなくなるまでの話者数、およびスタイル数を確認する。
テキストは声をずんだもん(ノーマル)に変更しました。というBotのシステムテキストをコピペして使用した。

これは、以下のコードでvoice_idを変えて順次リクエストをするのと同様。

Bot内部のコードの意訳
const { default: axios } = require('axios');
const rpc = axios.create({baseURL: 'http://127.0.0.1:50021', proxy: false});

async function synthesis(text, voice_id){
  const query = await rpc.post(`audio_query?text=${encodeURI(text)}&speaker=${voice_id}`, {headers: { 'accept': 'application/json' }});
  const query_data = query.data;

  query_data.speedScale = 1;
  query_data.pitchScale = 0;
  query_data.intonationScale = 1;
  query_data.volumeScale = 1;

  const synth = await this.#rpc.post(`synthesis?speaker=${voice_id}`, JSON.stringify(query_data), {
    responseType: 'arraybuffer',
    headers: {
      "accept": "audio/wav",
      "Content-Type": "application/json"
    }
  });
}

let text = "声をずんだもん(ノーマル)に変更しました。";
let voice_id = 0;

await synthesis(text, voice_id);

話者は製品版VOICEVOXのキャラクター一覧と同様の順番を上から、スタイルはずんだもんのスタイルを上から順にリクエストした。

結果はスタイルは9スタイル目、話者は8話者目でエラーが出て生成できなくなった。

余談だが、検証では既に使った話者/スタイルはエラーが出なかったが、長期運用していたBot側では完全に生成できなくなる場合もあった。
その時のエラーの内容は同じだったのでおそらく話者/スタイルの組み合わせ、入力テキストによっては多少の余力で生成できるものと思われる。

余談など

このIssueで言われている「リクエストが増えるとVRAMがリークする」はおそらくこの問題と同一の「利用した話者数が増えたことによってVRAMが大量に消費される」であると思います。

私の環境が8年前のGPUなので流石にスペック不足が原因だと思い、長らく耐えつつ使ってたんですが、一応かなり実用的な速度で使えること、自分の環境があまり一般的でない特殊なユースケースであることを踏まえ、一応Issueを建てようとしたところ、こちらを見つけました。
普通1回の起動で話者/スタイルを30以上使うことはそこまで無いと思うので、この問題は、任意の数のユーザーが任意の数の話者/スタイルを利用する読み上げBot特有の物だとは思うんですが、VOICEVOXは誰でも使えてAPIドキュメントもきちんとあること、サーバー用OSとして最適なLinuxでも動くことなどを考えると決して0ではない、このようなユースケースでの問題も報告するべきなのかなと思って報告しました。

改善案としては、このIssueのVRAMをリフレッシュする機能以外に、GPUで失敗した場合にCPUで再生成するはアリなのかなとは思います。

では、長文な上に駄文失礼しました。

@Hiroshiba
Copy link
Member

@tarepan はい! リークがないならcloseで良いのではと・・・思ってたのですが、 @notoiro さんのコメントを見てちょっと思いが変わりました 🙇

@notoiro
詳細なご報告ありがとうございます!!

確かにリークは実はないのかもとちょっと思いました!
ただリークがあるかどうかの結論は、同じスタイルで文章をひたすらずっと音声合成してリクエストごとに増えないかどうかを確かめて結論を出すべきかもと思いました!

ただそれはさておき、リフレッシュする方法を提供するべきかどうかは結構話が違うなと思いました。
リークしてもしなくても、キャラクター数が増えてきた現状を考えるとメモリ効率を考えたエンジンAPI があっても良さそうに思いました。

@tarepan ということでリフレッシュ機能はおそらくあった方が良いと思いました!
でもエンジンが用いている現状のコア(0.15)にはunload機能がないこと、もしリフレッシュするならたぶんエンジン内でcoreインスタンスを再作成する必要があって、結構実装が大変だとは思います。
タイトルをVRAMリフレッシュから、こう、コアの計算リソースを解放するだとかにしつつ、ロードマップの方に書き写すとかでも良いのかもと思いました!

@tarepan
Copy link
Contributor

tarepan commented Mar 18, 2024

@Hiroshiba
回答ありがとうございます。
「リークバグ修正であれば、現行版リーク状況に合わせて close 判断」「低~中 VRAM 環境向けリフレッシュ・リソース管理機能としては有益なので open」 「結論として open か ロードマップ行き」だと認識しました。

@tarepan
Copy link
Contributor

tarepan commented Mar 18, 2024

@notoiro
詳細かつ論理立った検証・報告とても助かります!
読み上げ bot ユーザーさんであれば直面しうる、解く価値のある問題だと感じました。VOICEVOX ENGINE の中長期的な課題の1つになりそうです。
もし @notoiro さんがこの問題に取り組むのであれば VOICEVOX ENGINE として大歓迎です。なんにせよ、ご報告ありがとうございました!

@tarepan tarepan added 状態:実装者募集 実装者を募集している状態 検証者募集 and removed 要議論 実行する前に議論が必要そうなもの labels Mar 18, 2024
@tarepan tarepan removed their assignment Mar 21, 2024
Copy link

github-actions bot commented Oct 1, 2024

本 Issue は直近 180 日間で活動がありません。今後の方針について VOICEVOX チームによる再検討がおこなわれる予定です。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants