LoginSignup
11
9

Hyper-VでGPU(GPU-PV)を利用する方法 (Ubuntu編)

Last updated at Posted at 2023-03-24

Windows Server 2025にて正式サポート

https://techcommunity.microsoft.com/t5/windows-server-news-and-best/the-future-of-windows-server-hyper-v-is-bright/ba-p/4074940

Windows Server 2025にて、GPU-Pは正式にサポートされるようになるようです。

こちらで紹介している有効化手順は正式サポート以前のものになります。

正式な手順は異なる可能性があります。

正式な手順は公式のドキュメントを確認してください。

ただし、こちらの手順では、公式的にはサポートされないハードウェア構成でも使用可能かもしれません。

はじめに

この記事のWindows版はここです。

Hyper-Vを利用するWSL2では、GPU-PV(Para Virtualization)と呼ばれる技術を利用することで、Windows 10 (21H1)以降NvidiaGPUを用いるCUDAプログラミングが、WSL2上やそれをバックエンドとして利用するDockerで可能になりました。

また、最近では、Azure Stack HCIでも、サポートされているGPUは限られますが、Linux上でのGPU-PVが利用可能なようです(この記事の手順を利用すれば非対応GPUでも利用可能な可能性があります)。

既に利用されているということは、Windowsに実装されているということです。

実際に、PowershellHyper-Vに関するコマンドを調べると、下記のようなコマンドで、

Get-Command -module Hyper-V

下記のような結果が得られます。

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
                (前略)
Cmdlet          Add-VMGpuPartitionAdapter                          2.0.0.0    Hyper-V
                (中略)
Cmdlet          Get-VMGpuPartitionAdapter                          2.0.0.0    Hyper-V
                (中略)
Cmdlet          Remove-VMGpuPartitionAdapter                       2.0.0.0    Hyper-V
                (中略)
Cmdlet          Set-VMGpuPartitionAdapter                          2.0.0.0    Hyper-V
                (後略)

上記のように既に実装されています。

Get-Helpコマンドで調べると構文は出てきますが、説明はまだ公式サポートされていないので、出てきません(Powershell 7以降で実行すると更に詳しい構文が出てきます)。

この技術が、通常のWindows(サーバー含む)では、サポートされていませんが、Windows仮想マシンでは利用可能であることは、既に記事にした通りです。

WSL2において、既に利用されているということは、公開されているWSL2専用にカスタムしたカーネルをベースにHyper-Vでも利用できるように変更すれば、Hyper-V上のLinuxでも利用可能であるということです。

今回は、Hyper-VLinuxでもGPU-PVを利用可能にするカスタムカーネルのUbuntu向けパッケージを公開されている方が居たので、このカーネルを利用して、Hyper-V上のKubuntu 22.04 LTSで、GPU-PVを利用します。

カスタムカーネルは、Ubuntu 20.04及びUbuntu 22.04でテストされているようですが、他のUbuntuのバージョンやUbuntuベースのディストリビューション、Debianベースのディストリビューションでも動作する可能性があります。

この記事では、Kubuntu 22.04 LTS環境で、仮想GPUの割り当てから、GPUドライバーの適用を行う手順を紹介します。

仮想GPUの割り当て、親マシン上にあるGPUドライバーの保存場所の確認については、Windows版の記事と同様です。

目次

動作確認環境

  • 親マシン
OS: Windows 11
Version: 22H2
CPU: Intel Core i9 13900K(24C32T)
MEM: DDR5 128GB(4800MHz 32GB ×4)
GPU: Nvidia Geforce RTX 3080
  • 子マシン
OS: Kubuntu 22.04.1 LTS
vCPU: 8C
MEM: 16GB

子マシンについては、カスタムカーネルを動作させるために、セキュアブートを無効化する必要があります。

Ubuntuは、Hyper-Vのセキュアブートテンプレートで、Microsoft UEFI証明機関を選択している場合、利用可能ですが、カスタムカーネルを利用している場合は、完全に無効にする必要があります。

クイック作成ギャラリー等で作成した仮想マシンの場合は、意図せずに有効化されている可能性があるので、特に無効になっていることを確認して下さい。

仮想マシンで、仮想GPUを利用できるようにする

注意
この機能は、公式にサポートされていない方法です。なにか問題が起きても自己責任です。

チェックポイントの無効化

まず、チェックポイントを適用・削除する必要があります。

これは、GPU-PVではチェックポイントがサポートされておらず、有効化するためにはチェックポイントを無効化する必要があるためです。

そのため、自動チェックポイントを使っている場合は無効に、チェックポイントが既に存在する場合は、チェックポイントの削除または適用を、チェックポイントを利用しないことが必要です。

仮想GPUの割り当て方法

この項目での設定は、シングルGPU環境の場合、このbatファイルにより一括実行可能です。

このbatファイルはダブルクリックで、実行するとUACで管理者権限に昇格し、仮想マシン名を聞いてくるので、設定したい仮想マシンの名前をシングルクォート(')で囲み指定すると、一括で実行されます。

GPU Partition Adapterの割り当て

まずは、先程のGPU Partitioning関連のコマンドを利用して仮想マシンにGPU Partition Adapterを仮想マシンに割り当て、リソースの設定などを行います。

Powershell管理者権限で実行して、下記コマンドを実行します。

まずは、仮想マシンにGPU Partition Adapterを割り当てます。

下記コマンドでは、親マシンのタスクマネージャー等で、GPU 0として認識されているGPUが仮想GPUとして割り当てられます。

マルチGPU環境で指定したいGPUがある場合は、下記のコマンドは実行せずに以降で紹介するコマンドを実行して下さい。

Add-VMGpuPartitionAdapter -VMName "仮想マシン名"
マルチGPU環境での割り当てについて

マルチGPU環境でGPU 0として、認識されるGPU以外を割り当てたい場合、-InstancePathオプションで、親マシンのWindowsで認識されるデバイスファイルパス名を指定することでGPUを明示的に指定することが可能になります。

このオプションはWindows 10のあるいはそのバージョンによっては利用できない可能性があります。

もし、利用できなかった場合は、利用したいGPUが、タスクマネージャー上で、GPU 0として認識するように、他のGPUを無効化する等して下さい。

マルチGPU環境で、割り当てたいデバイスファイルパス名を確認する方法は下記の通りです。

Get-VMHostPartitionableGpu | Format-Table Name

下記のような結果が、返ってきます(マルチGPU環境の場合、複数返ってきます)。

Name
----
デバイスファイルパス名

ここで、帰ってきた値を用いて、先程のコマンドを実行します。

Add-VMGpuPartitionAdapter -VMName "仮想マシン名" -InstancePath "デバイスファイルパス名"

仮想GPUのリソース設定

仮想GPUのリソースを設定します。

物理GPUの全てのリソースを割り当てる場合は、以下のようなコマンドを実行します。

Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -Passthru

もし、リソースを調整したい場合は、下記のようにすると明示的にパラメーターを指定できます。

Set-VMGpuPartitionAdapter -VMName "仮想マシン名" -MinPartitionVRAM 80000000 -MaxPartitionVRAM 100000000 -OptimalPartitionVRAM 100000000 -MinPartitionEncode 80000000 -MaxPartitionEncode 100000000 -OptimalPartitionEncode 100000000 -MinPartitionDecode 80000000 -MaxPartitionDecode 100000000 -OptimalPartitionDecode 100000000 -MinPartitionCompute 80000000 -MaxPartitionCompute 100000000 -OptimalPartitionCompute 100000000

その他リソースを仮想マシンに設定します。

Set-VM -GuestControlledCacheTypes $true -VMName "仮想マシン名"

Set-VM -LowMemoryMappedIoSpace 1GB -VMName "仮想マシン名"

Set-VM HighMemoryMappedIoSpace 32GB VMName "仮想マシン名"

仮想マシンに準仮想GPUのドライバーを追加する方法

上記の設定で既に、仮想マシンから仮想GPUPCIデバイスの3D controller: Microsoft Corporation Deviceとして見えていますが、この時点でまだ動作はしていません。

仮想マシンに、ドライバーを追加する必要があります。

この時、物理マシンにGPUドライバーをインストールする場合と同じように、仮想マシンにドライバーをインストールしようとしてもできません。

このGPUは、通常のGPUとは異なる準仮想化GPUです。

GPUの一部のステータスを確認することができません。

また、カスタムカーネルのインストールの様に、準仮想化GPUであるため、OS側がこのデバイスを受け入れる様に修正する必要もあります。

そのため、ドライバーをインストールするためには、親マシンからドライバーをコピーする必要があります。

この仮想マシンにドライバーを追加する手順は、親マシンのGPUドライバーを更新する度に行う必要があります。

親マシン上にあるGPUドライバーの保存場所の確認

Powershellで、下記コマンドを実行します。

Get-CimInstance -ClassName Win32_VideoController -Property * | Format-Table InstalledDisplayDrivers

以下のような結果が、返ってきます。

InstalledDisplayDrivers
-----------------------
C:\Windows\System32\DriverStore\FileRepository\nv_dispi.inf_amd64_50916785244854f2\nvldumdx.dll,C:\Windows\System32\DriverStore\FileRepository\

この環境での利用しているGPUドライバーを保存しているフォルダは、C:\Windows\System32\DriverStore\FileRepository\nv_dispi.inf_amd64_50916785244854f2\であることがわかります。

仮想マシンへのドライバーコピー

これより上の手順は、Windows版と共通でしたが、ここからの手順は異なります。

Windows上で、wslフォルダを作成して下さい。

作成した、wslフォルダ内に、driversフォルダを作成して下さい。

driversフォルダには、先程確認したドライバーのフォルダ(今回の場合、nv_dispi.inf_amd64_50916785244854f2)をコピーします。

次にwslフォルダ内(driversフォルダと同じ階層)に、C:\Windows\System32\lxssにあるlibフォルダをコピーします。

これは、WSL2/usr/lib/wslと同じディレクトリ構造になります。

以下のWSL2を利用している場合コマンドを、実行したときの出力が、

ls /usr/lib/wsl

以下となり同じことが確認できます。

drivers  lib

今回の場合、コピーしてできたフォルダは、以下のような構成のディレクトリ構造になります。

wsl/
 ├ lib/
 └ drivers/
   └ nv_dispi.inf_amd64_50916785244854f2/

仮想マシン上のUbuntuでも、このwslフォルダが同じパス、同じディレクトリ構造になるようにコピーします。

コピーの方法は、Linux仮想マシンではサポートされなくなったの拡張セッションRDPによるコピペ(権限の問題で一旦デスクトップ等にコピーする必要やディレクトリ単位でコピーできないのでZIP等への圧縮が必要になります)、カスタムカーネルを公開している方の手順と同じようにSSH Serverを有効にしてのscpコマンドsftpコマンドによるコピー、仮想マシンの仮想ハードディスクを親マシンのWSL2にマウントしてWSL2経由でコピーする等々様々な方法がありますが、好きな方法でコピーして下さい。

コピーした後は、ドライバーディレクトリの所有権や権限の設定を変更する必要があります。

仮想マシンで、以下のようなコマンドを実行します。

sudo chown -R root:root /usr/lib/wsl

sudo chmod 555 /usr/lib/wsl/lib/* 

ドライバーのライブラリを読み込むための設定を行います。

ドライバーのライブラリファイルがあるパスである/usr/lib/wsl/libが内容のファイルld.wsl.conf/etc/ld.so.conf.d/に作成します。

これをコマンドで行う場合、以下の様になります。

echo "/usr/lib/wsl/lib" | sudo tee /etc/ld.so.conf.d/ld.wsl.conf

ライブラリを読み込む様にします。

sudo ldconfig

プロファイルにパスを通します。

ドライバーのライブラリファイルがあるパスである/usr/lib/wsl/libをパスに追加する内容export PATH=$PATH:/usr/lib/wsl/libであるファイルwsl.sh/etc/profile.d/に作成します。

これをコマンドで行う場合、以下の様になります。

echo "export PATH=$PATH:/usr/lib/wsl/lib" | sudo tee /etc/profile.d/wsl.sh

作成したスクリプトに権限を与えます。

sudo chmod +x /etc/profile.d/wsl.sh

カスタムカーネルのインストール

まずは、カーネルヘッダとカーネルイメージのパッケージをダウンロードする必要があります。

最新のパッケージのURLは、カスタムカーネルを公開している方のリリースページで確認できます。

linux-headersから始まるファイルがカーネルヘッダで、linux-imageから始まるファイルがカーネルイメージです。

それぞれのパッケージファイルのURLをファイルに対して、右クリック->リンクのコピー等で入手して下さい。

このパッケージへのURLを使い、以下のようなコマンドでダウンロードできます。

wget パッケージURL

現時点での最新版のURLは、カーネルヘッダがhttps://github.com/brokeDude2901/dxgkrnl_ubuntu/releases/download/main/linux-headers-5.10.102.1-dxgrknl_5.10.102.1-dxgrknl-10.00.Custom_amd64.deb、イメージがhttps://github.com/brokeDude2901/dxgkrnl_ubuntu/releases/download/main/linux-image-5.10.102.1-dxgrknl_5.10.102.1-dxgrknl-10.00.Custom_amd64.debです。

この場合は、以下のようになります。

wget https://github.com/brokeDude2901/dxgkrnl_ubuntu/releases/download/main/linux-headers-5.10.102.1-dxgrknl_5.10.102.1-dxgrknl-10.00.Custom_amd64.deb

wget https://github.com/brokeDude2901/dxgkrnl_ubuntu/releases/download/main/linux-image-5.10.102.1-dxgrknl_5.10.102.1-dxgrknl-10.00.Custom_amd64.deb

ダウンロードしたパッケージをインストールします。

sudo apt install -y ./ダウンロードしたパッケージ名

今回の場合は、以下の様になります。

sudo apt install -y ./linux-headers-5.10.102.1-dxgrknl_5.10.102.1-dxgrknl-10.00.Custom_amd64.deb

sudo apt install -y ./linux-image-5.10.102.1-dxgrknl_5.10.102.1-dxgrknl-10.00.Custom_amd64.deb

Grubメニューからカスタムカーネルを選択できるようにする

Grubメニューを仮想マシン起動時に表示して、カスタムカーネルを手動で選択できる様にします。

以下のようなコマンドで表示できる様にすることが可能です。

sudo sed -i "s/GRUB_DEFAULT=0/GRUB_DEFAULT=saved/g" /etc/default/grub

sudo sed -i "s/GRUB_TIMEOUT_STYLE=hidden/GRUB_TIMEOUT_STYLE=menu/g" /etc/default/grub

sudo sed -i "s/GRUB_TIMEOUT=0/GRUB_TIMEOUT=30/g" /etc/default/grub

sudo grep -q -F "GRUB_SAVEDEFAULT=true" /etc/default/grub || echo "GRUB_SAVEDEFAULT=true" | sudo tee -a /etc/default/grub

修正したGrubの設定を適用します。

sudo update-grub

ここまでの設定が完了したら、仮想マシンをシャットダウンして下さい。

カスタムカーネルを選択して起動

カスタムカーネルを選択して起動します。

まず、仮想マシンを起動する前に、仮想マシンのセキュアブートが無効になっていることを確認して下さい。

確認が終わったら起動します。

起動すると、Grubメニューが表示されるので、Advanced options for Ubuntuを選択して下さい。

Grub_Menu.png

次に、インストールしたカスタムカーネルを選択します。

カスタムカーネルは、末尾に-dxgrknlとあるものです。

今回は、Ubuntu, with Linux 5.10.102.1-dxgrknlを選択して起動します。

Grub_Kernel.png

セキュアブートが有効な場合は、ここで失敗します。

無効であることを確認して下さい。

(NvidiaGPU限定) nvidia-smiコマンドによる仮想GPUの確認

これで、GPUを認識し、利用できるようになりました。

以下のコマンドの出力は、

lspci

以下の様になっていると思われますが、

なんとか 3D controller: Microsoft Corporation Device 008e

NvidiaGPUの場合は、以下のようなコマンドで確認できます。

nvidia-smi

上記コマンドを実行すると、WSL2上で、このコマンドを実行した時と同じ様に一部項目は表示できませんが、コマンドの結果が正常に返ってきます(Windowsっぽい画面に見えますが、Windows風にカスタムしたKubuntu 22.04LTSです)。

VM_nvidia-smi.png

(NvidiaGPU限定) Dockerで仮想GPUを利用する

Dockerのインストール

まずは、仮想マシンをアップグレードします。

sudo apt update

sudo apt -y upgrade

sudo apt autoremove

sudo apt autoclean

Dockerをインストールします。

公式手順に従います。

インストール手順に必要な依存パッケージをインストールします。

sudo apt install -y ca-certificates curl gnupg

DockerGPG鍵をaptキーリングに追加します。

sudo mkdir -m 0755 -p /etc/apt/keyrings

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

リポジトリを追加します。

echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

リポジトリを更新します。

sudo apt update

Dockerをインストールします。

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Dockerデーモンの自動起動を有効化し、動作させます。

sudo systemctl enable --now docker

sudoなしで、Dockerコマンドを利用できる様に、ユーザーをdockerグループに追加します。

sudo usermod -aG docker ユーザー名

NVIDIA Container Toolkitのインストール

公式手順に従います。

GPG鍵をaptキーリングに追加し、リポジトリを追加します。

Ubuntu 22.04の場合、Ubuntu 18.04のものが追加されます。

distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
      && curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
      && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
            sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
            sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

リポジトリを更新します。

sudo apt update

NVIDIA Container Toolkitのインストールを行います。

sudo apt install -y nvidia-container-toolkit

Dockerデーモンが、NVIDIA Container Toolkitを認識するように構成します。

sudo nvidia-ctk runtime configure --runtime=docker

仮想マシンを再起動します。

sudo reboot

Dockerコンテナ内でnvidia-smiを実行

再起動後、仮想マシン内で、以下のコマンドを実行し、コンテナ内で、nvidia-smiを実行します。

nvidia-smiを実行するコンテナイメージをダウンロードします。

docker pull ubuntu:22.04

以下のコマンドで、コンテナ内で、nvidia-smiを実行します。

WSL2上で、nvidia-smiを実行する時等とは異なり、バインドマウントして実行する必要があります。

docker run -it --rm --gpus all -v /usr/lib/wsl/lib/nvidia-smi:/usr/lib/nvidia-smi ubuntu:22.04 nvidia-smi

実行すると、以下の様になります。

VM-Docker_nvidia-smi.png

コンテナ内でも、GPUを利用できることがわかります。

Hyper-V仮想マシン上のUbuntu上のDockerStable Diffusion WebUI(AUTOMATIC1111)を動かす

こちらComposeファイルを利用します。

WSL2やネイティブLinux上のDockerで実行するのと同じ手順です。

まずは、Gitがインストールされていない場合は、インストールします。

sudo apt install -y git

リポジトリをクローンします。

git clone https://github.com/AbdBarho/stable-diffusion-webui-docker.git

クローンしたディレクトリに移動します。

cd stable-diffusion-webui-docker

モデル等のダウンロードを行います。

容量があるので、しばらく待ちます。

ダウンロードが終了すると、コンテナは停止します。

docker compose --profile download up --build

停止したコンテナを終了します。

docker compose --profile download down

GPUが必要なStable Diffusion WebUIを実行します。

docker compose --profile auto up --build

Running on local URL: http://0.0.0.0:7860という内容が表示された後に、http://localhost:7860にブラウザでアクセスします。

そして、プロンプトに適当な入力を与えて画像を生成します。

以下の様になっています。

VM_Docker-Stable_Diffusion.png

親マシンのタスクマネージャーやHWMonitor等で確認すると、しっかりGPUを利用していることがわかります。

親マシンのブラウザからhttp://仮想マシンのIPアドレス:7860等で、WebUIにアクセスしても、Stable Diffusionを実行できることがわかります。

検証環境では、mDNSが有効なため、仮想マシンのホスト名で、アクセスして実行しています。

VM_Docker-Stable_Diffusion_Access.png

GPU Partition Adapterの削除

管理者権限のPowershellで、以下のコマンドを実行します。

Remove-VMGpuPartitionAdapter -VMName "仮想マシン名"

削除すると、チェックポイントも再び使用可能になります。

GPUドライバーの削除等は、別途手動で行って下さい。

11
9
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
11
9