※2025/01/26 追記
Set-VMGpuPartitionAdapterの「-Passthru」指定では、動作しなくなったので修正
GPU-PV
GPU-PVはゲストOS側の準仮想化ドライバを通して、ホストOS側のGPUドライバにアクセスさせる機能と理解した
生のデバイスを排他的に割り当てるPCIEパススルー的な機能ではなく、ホストOS側からは一つのプロセスがGPUを使用しているように見える
画像引用:
https://developer.nvidia.com/blog/announcing-cuda-on-windows-subsystem-for-linux-2/
今のところ、Linuxの準仮想化ドライバについてはWSL2-Linux-KernelプロジェクトのdxgkrnlモジュールをHyper-V上のLinux仮想マシンにに組み込むアプローチをとることになる
モチベーション
個人的に運用しているTTSBot(Discord用)の音声変換をVOICEVOXエンジン(GPU版)で処理している
TTSBotの本体はHyper-V上の仮想マシン上だが、音声変換はGPUを使う関係上物理マシンで処理している
気持ち悪い構成なので仮想マシンでVOICEVOXエンジン(GPU版)を使う方法を模索する
環境
- CPU:Intel(R) Core(TM) i7-13700T
- Mem:32GB
- GPU:NVIDIA T1000 8GB
- OS(Host):Windows 11 Pro (23H2)
- OS(Guest):Ubuntu Server 24.04
Hyper-V上で使えそうな技術の選定
- RemoteFX → セキュリティ上の理由で廃止された
- DDA (PCIEレベルのパススルー) → なんかうまくいかなかった
- GPU-PV → うまくいったので紹介!
Hyper-Vの仮想マシン(Ubuntu)の設定
- VMの世代:第二世代
- セキュアブート:無効
- 動的メモリ:無効
- チェックポイント:無効
- 自動停止アクション:シャットダウン
Ubuntu Server24.04 導入
特になし
GPU-PVの有効化
ホスト機(Windows)側のPowershellで作業する
※ゲスト側は停止しておくこと
# 既存のGPU-PVの設定を削除
Remove-VMGpuPartitionAdapter -VMName "仮想マシン名"
# デバイスファイルパス名の取得
Get-VMHostPartitionableGpu | Format-Table Name
# GPU-PVの設定
Add-VMGpuPartitionAdapter -VMName "仮想マシン名" -InstancePath "取得したデバイスファイルパス名"
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -MinPartitionVRAM 1
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -MaxPartitionVRAM 11
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -OptimalPartitionVRAM 10
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -MinPartitionEncode 1
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -MaxPartitionEncode 11
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -OptimalPartitionEncode 10
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -MinPartitionDecode 1
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -MaxPartitionDecode 11
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -OptimalPartitionDecode 10
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -MinPartitionCompute 1
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -MaxPartitionCompute 11
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -OptimalPartitionCompute 10
Set-VM -GuestControlledCacheTypes $true -VMName "仮想マシン名"
Set-VM -LowMemoryMappedIoSpace 1Gb -VMName "仮想マシン名"
Set-VM -HighMemoryMappedIoSpace 32GB -VMName "仮想マシン名"
下記は以前紹介した方法、
何時ごろからか-Passthru指定でのGPUリソース全割り当ては動作しなくなった
Add-VMGpuPartitionAdapter -VMName "仮想マシン名" -InstancePath "取得したデバイスファイルパス名"
Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -Passthru
Set-VM -GuestControlledCacheTypes $true -VMName "仮想マシン名"
Set-VM -LowMemoryMappedIoSpace 1Gb -VMName "仮想マシン名"
Set-VM -HighMemoryMappedIoSpace 32GB -VMName "仮想マシン名"
※nvidia-smiを実行しても、下記のようなエラーになる
nvidia-smi
Failed to initialize NVML: GPU access blocked by the operating system
Failed to properly shut down NVML: GPU access blocked by the operating system
ドライバ導入(ホスト機)
スクリプトをgithubに公開されている方がいらっしゃったので利用させてもらう
参考:
https://github.com/staralt/dxgkrnl-dkms
ひきつづき、ホスト機(Windows)側のPowershellで作業する
※ゲスト側は起動しておく
$username="user name(ubuntu)"
$ip="ip address(ubuntu)"
# Create a destination folder.
ssh ${username}@${ip} "mkdir -p ~/wsl/drivers; mkdir -p ~/wsl/lib;"
# Copy driver files
# https://github.com/brokeDude2901/dxgkrnl_ubuntu/blob/main/README.md#3-copy-windows-host-gpu-driver-to-ubuntu-vm
(Get-CimInstance -ClassName Win32_VideoController -Property *).InstalledDisplayDrivers | Select-String "C:\\Windows\\System32\\DriverStore\\FileRepository\\[a-zA-Z0-9\\._]+\\" | foreach {
$l=$_.Matches.Value.Substring(0, $_.Matches.Value.Length-1)
scp -r $l ${username}@${ip}:~/wsl/drivers/
}
scp -r C:\Windows\System32\lxss\lib ${username}@${ip}:~/wsl/
WSL2でUbuntu-24.04を動作させているなら、「/usr/lib/wsl/」配下をそのままコピーしてもいい
ドライバ導入(ゲスト機)
ゲスト機(Ubuntu)側で作業する
sudo mv ~/wsl /usr/lib/wsl
sudo chmod -R 555 /usr/lib/wsl
sudo chown -R root:root /usr/lib/wsl
sudo sh -c 'echo "/usr/lib/wsl/lib" > /etc/ld.so.conf.d/ld.wsl.conf'
ldsoconf
curl -fsSL https://content.staralt.dev/dxgkrnl-dkms/main/install.sh | sudo bash -es
# 確認
/usr/lib/wsl/lib/nvidia-smi
# /usr/lib/wsl/lib内のsoファイルのシンボリックリンクを手動作成してやらないとエラーになるかもしれない
VOICEVOXエンジン導入
ひきつづき、ゲスト機(Ubuntu)側で作業する
※version-0.20.0を導入する例
cd /opt
sudo wget https://github.com/VOICEVOX/voicevox_engine/releases/download/0.20.0/voicevox_engine-linux-nvidia-0.20.0.7z.001
sudo wget https://github.com/VOICEVOX/voicevox_engine/releases/download/0.20.0/voicevox_engine-linux-nvidia-0.20.0.7z.002
sudo apt-get install -y p7zip-full
sudo 7z x voicevox_engine-linux-nvidia-0.20.0.7z.001
sudo mv linux-nvidia/ voicevox
systemctlサービス登録(必要なら)
sudo vi /etc/systemd/system/voicevox.service
[Unit]
Description=Voicevox Service
After=network.target
[Service]
User=root
Group=root
WorkingDirectory=/opt/voicevox
ExecStart=/opt/voicevox/run --host=0.0.0.0 --port=50021 --use_gpu --load_all_models
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl enable voicevox
sudo systemctl start voicevox
最後に
ひとまず、Ubuntuの仮想マシンがVOICEVOX(CUDA版)のAPIサーバーとして動作した
ホストであるWindows上のタスクマネージャーからもGPUを使用していることを確認できた
しばらく運用してみて問題が出ないか様子を見ることとする
参考
https://qiita.com/Hyper-W/items/e189790fd4534d9d51ad
https://qiita.com/Hyper-W/items/5ddfc93891f7b620da8a
https://ascii.jp/elem/000/004/019/4019541/
https://devblogs.nvidia.com/announcing-cuda-on-windows-subsystem-for-linux-2/