1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Stable Diffusion web UI (AUTOMATIC1111版) 環境を EC2 に構築してみた

Posted at

はじめに

「画像生成AIを軽く試してみたいけど手元にゲーミングPC級は無いしグラボは高いし、Google Colab は昨今の事情が…」
と散々悩んだ挙げ句、お試し用に手を出したのが AWS EC2 の GPU インスタンスでした。

ここでは備忘録として、特に EC2 起動後の構築手順を書き連ねます。

AWS 利用環境

EC2インスタンスの構築手順は割愛します。
CloudFormation で VPC ごと環境を作ってしまえば後片付けも楽々。

EC2

項目 設定値 備考
リージョン オレゴン(us-west-2) -
インスタンスタイプ g4dn.xlarge -
料金 USD 0.586/h (2023/05 現在)
vCPU 4 (g4dn.xlarge)
メモリ 16GiB (g4dn.xlarge)
インスタンスストア 125GB NVMe SSD (g4dn.xlarge)
EBS gp3 100GB x1 /dev/sda1
AMI RHEL-9.0.0_HVM-20230313-x86_64-43-Hourly2-GP2
  • g4dn 等の GPU インスタンスを利用するには Service Quotas にて上限緩和申請が必要
    • 「Running On-Demand G and VT instances」に対し、利用したい vCPU数 を申告する
  • 一部 g4dn をサポートしていない AZ(アベイラビリティゾーン) が含まれているので注意
  • ElasticIP 等は必要に応じてお好みで

セキュリティグループ

ルール タイプ プロトコル ポート範囲 ソース 説明
インバウンドルール SSH tcp 22 0.0.0.0/0 SSH
アウトバウンドルール すべてのトラフィック すべて すべて 0.0.0.0/0 -
  • セキュリティグループ名、アウトバウンドの制限などはお好みで
    • models 等のダウンロード用として HTTPS のみ開放する形でも良い
  • インバウンドの許可設定は ssh のみ
    • WebUI へのアクセスはポートフォワーディングを利用
    • sshクライアントはお好みで

構築手順

EC2 インスタンスを起動し ssh 接続ができたら、以下の流れで環境を整えていきます。

OS基礎構築(RHEL9)

  • パッケージを最新にアップデート
    sudo dnf -y update
    sudo reboot
    
  • ssh 再接続後に kernel バージョンを確認
    uname -a
    
    出力
    Linux sdtest 5.14.0-70.49.1.el9_0.x86_64 #1 SMP PREEMPT Thu Feb 23 04:56:09 EST 2023 x86_64 x86_64 x86_64 GNU/Linux
    

GPUドライバ導入(nvidia CUDA)

  • GPU搭載確認
    lspci | grep -i nvidia
    
    出力
    00:1e.0 3D controller: NVIDIA Corporation TU104GL [Tesla T4] (rev a1)
    
  • EPEL9 インストール
    sudo dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
    
  • kernel-devel, kernel-headers パッケージ追加
    sudo dnf -y install kernel-devel-$(uname -r) kernel-headers-$(uname -r)
    
  • nvidia GPU,CUDA ドライバ インストール
    distro=rhel9
    arch=x86_64
    sudo dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/$distro/$arch/cuda-$distro.repo
    sudo dnf clean expire-cache
    sudo dnf -y module install nvidia-driver:latest-dkms
    sudo dnf -y install cuda nvidia-gds
    sudo reboot
    
  • ssh 再接続後に GPU 認識確認
    nvidia-smi -q | head
    
    出力(抜粋)
    ==============NVSMI LOG==============
    
    Timestamp                                 : Thu May 18 22:31:07 2023
    Driver Version                            : 530.30.02
    CUDA Version                              : 12.1
    
    Attached GPUs                             : 1
    GPU 00000000:00:1E.0
        Product Name                          : Tesla T4
    
  • 環境変数設定(/etc/profile.d/cuda.sh)
    sudo vi /etc/profile.d/cuda.sh
    
    /etc/profile.d/cuda.sh
    export CUDA_HOME=/usr/local/cuda
    export PATH=${CUDA_HOME}/bin${PATH:+:${PATH}}
    
  • 反映
    source /etc/bashrc
    echo $CUDA_HOME
    
    出力
    /usr/local/cuda
    

Python3 導入 (pyenv)

2023/5 現在、Stable Diffusion web UI の推奨は Python 3.10.6 です。
そこで今回は pyenv を利用します。

  • 必要パッケージインストール
    sudo dnf -y install git wget xz-devel sqlite-devel readline-devel libffi-devel bzip2-devel cairo-devel
    
    • cairo-devel は ControlNet を利用する場合に必要
  • pyenv インストール
    curl https://pyenv.run | bash
    
  • ~/.bash_profile に pyenv 利用設定追加
    • 設定追加
      vi .bash_profile
      
      ~/.bash_profile
      # 末尾に追加
      export PYENV_ROOT="$HOME/.pyenv"
      command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
      eval "$(pyenv init -)"
      
    • 反映
      source .bash_profile
      pyenv --version
      
      出力
      pyenv 2.3.17
      
  • Python3.10.6 インストール
    pyenv install 3.10.6
    pyenv global 3.10.6
    python --version
    
    出力
    Python 3.10.6
    

Stable Diffusion web-ui インストール

場所は任意ですが、今回はユーザーホームディレクトリ直下に導入します。

  • AUTOMATIC1111 版を取得
    git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
    
  • webui-user.sh 設定変更
    cd stable-diffusion-webui/
    vi webui-user.sh
    
    webui-user.sh
    -#export COMMANDLINE_ARGS=""
    +export COMMANDLINE_ARGS="--opt-channelslast --opt-sdp-attention --no-half-vae"
     
    -#export NO_TCMALLOC="True"
    +export NO_TCMALLOC="True"
    
    • xformers は導入しない
      • --opt-sdp-attention を用いることで同等またはそれ以上のパフォーマンスが得られるらしい
      • --xformers を利用すると torch(+cu118) と torchvision(+cu117) の間で CUDA バージョンが不一致となり詰む
        • 事前に pip install しても、WebUI 起動時の処理で torchvision が再インストールされてしまい回避できない
  • WebUI 起動
    ./webui.sh
    

swap 設定

インスタンスストアがあるのに使わないのは非常に勿体ないので swap に全振りします。

手動での設定

  • 未マウントのディスクデバイス(インスタンスストア)があることを確認
    sudo lsblk -p | grep -v /dev/nvme0
    
    出力
    NAME             MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
    /dev/nvme1n1     259:0    0 116.4G  0 disk
    
  • swap として利用可能にする
    sudo mkswap /dev/nvme1n1
    sudo swapon /dev/nvme1n1
    free -h
    
    出力
                   total        used        free      shared  buff/cache   available
    Mem:            15Gi       589Mi        14Gi       8.0Mi       221Mi        14Gi
    Swap:          116Gi          0B       116Gi
    

OS起動時に自動設定させる

インスタンスストアは揮発性ストレージのため、起動するたびに swap の設定が必要となります。
そこで起動時に swap をマウントするよう設定します。

  • nvme-cli インストール
    sudo dnf -y install nvme-cli
    
  • swap on/off を制御するスクリプトを作成・設置
    sudo vi /usr/local/sbin/isswapctl
    
    /usr/local/sbin/isswapctl
    #!/bin/bash
    ISDEV=$( /usr/sbin/nvme list | grep 'Instance Storage' | awk '{ print $1 }' )
    if [ -n "$ISDEV" ]; then
        if [ "$1" = "start" ]; then
            /usr/sbin/mkswap $ISDEV && /usr/sbin/swapon $ISDEV
        elif [ "$1" = "stop" ]; then
            /usr/sbin/swapoff $ISDEV
        else
            echo "usage: $0 [start|stop]"
        fi
    else
        echo "Instance Storage device is not found."
    fi
    exit $?
    
  • 実行パーミッション付与
    sudo chmod 700 /usr/local/sbin/isswapctl
    
    • sudo isswapctl start で swap 有効化
    • sudo isswapctl stop で swap 無効化
  • systemd ユニットファイルを作成
    sudo vi /etc/systemd/system/isswap.service
    
    /etc/systemd/system/isswap.service
    [Unit]
    Description=Use instance store volumes as swap space.
    After=local-fs.target
    ConditionPathExists=/usr/local/sbin
    
    [Service]
    ExecStart=/usr/local/sbin/isswapctl start
    ExecStop=/usr/local/sbin/isswapctl stop
    Restart=always
    Type=simple
    RemainAfterExit=yes
    
    [Install]
    WantedBy=multi-user.target
    
  • systemd isswap.service ユニット設定反映
    sudo systemctl daemon-reload
    
  • 動作確認
    • swap 無効状態を確認
      free -h
      
      出力 / free
                     total        used        free      shared  buff/cache   available
      Mem:            15Gi       489Mi        14Gi       8.0Mi       421Mi        14Gi
      Swap:             0B          0B          0B
      
    • swap 無効 → 有効化
      sudo systemctl start isswap
      sudo systemctl status isswap --no-pager
      free -h
      
      出力 / systemctl status
      ● isswap.service - Use instance store volumes as swap space.
           Loaded: loaded (/etc/systemd/system/isswap.service; disabled; preset: disabled)
           Active: active (exited) since Sat 2023-05-20 04:23:02 JST; 1min 24s ago
          Process: 1981 ExecStart=/usr/local/sbin/isswapctl start (code=exited, status=0/SUCCESS)
         Main PID: 1981 (code=exited, status=0/SUCCESS)
              CPU: 39ms
      
      出力 / free
                     total        used        free      shared  buff/cache   available
      Mem:            15Gi       595Mi        14Gi       8.0Mi       424Mi        14Gi
      Swap:          116Gi          0B       116Gi
      
    • swap 有効 → 無効化
      sudo systemctl stop isswap
      sudo systemctl status isswap --no-pager
      free -h
      
      出力 / systemctl status
      ○ isswap.service - Use instance store volumes as swap space.
           Loaded: loaded (/etc/systemd/system/isswap.service; disabled; preset: disabled)
           Active: inactive (dead)
      
      出力 / free
             total        used        free      shared  buff/cache   available
      Mem:            15Gi       512Mi        14Gi       8.0Mi       423Mi        14Gi
      Swap:             0B          0B          0B
      
  • 自動起動設定
    sudo systemctl start isswap
    sudo systemctl enable isswap
    sudo systemctl is-enabled isswap
    
    出力
    enabled
    
  • 再起動確認
    sudo reboot
    
    • ssh 再接続後 swap が有効になっていることを確認
      free -h
      
      出力
                     total        used        free      shared  buff/cache   available
      Mem:            15Gi       603Mi        14Gi       8.0Mi       183Mi        14Gi
      Swap:          116Gi          0B       116Gi
      

起動 → webuiアクセス

  • sshクライアント側でポートフォワーディングの設定を行い、ssh再接続しておく
    • ローカル(PC)側 7860/tcp → リモートサーバ側 7860/tcp へ転送するよう設定する
    • 設定参考例(Rlogin)
      image.png
  • 起動
    cd ~/stable-diffusion-webui/
    ./webui.sh
    
    出力(抜粋)
    Running on local URL:  http://127.0.0.1:7860
    
    To create a public link, set `share=True` in `launch()`.
    
  • PCのブラウザで WebUI を開く

models等のダウンロードについて

  • PCからサーバへアップロードするより、サーバから wget や curl 等で取得するほうが速く済む
    • models などは概ねファイルサイズも大きく時間もそれなりにかかるため
    • 日本 - オレゴン間は通信速度があまり望めない(国内に比べたら かなり遅い 部類)

やっておくと幸せになれるかもしれない設定

  • wget にオプションを付与した alias を作成するよう、.bash_profile に設定しておく
    ~/.bash_profile
    # 末尾に追加
    alias wgetcd='wget --content-disposition --progress=dot'
    
    • --progress はお好みで

最後に

GPUを搭載したインスタンスは時間あたりの単価も高いので、使い過ぎに注意しましょう。
1ヶ月間フルに使った場合、1ドル140円換算で約60,000円+α(外向きのトラフィック代)くらいかかります。

  • 使わない時はインスタンスを停止しておく
  • 長期間使わない時は AMI を取得するなどしてからインスタンスは終了(削除)する
  • あくまでお試し用やスポットで使うようにする
    • 常用目的なら
      • ゲーミングPCを買ったほうが良い
      • SavingPlans などの長期契約割引を検討する
      • 有料版の Google Colab Pro, Colab Pro+ を検討する
  • 請求アラームを設定しておく

ここまで書き連ねてきましたが、実はこれが私にとって「はじめてのQiita」になります。
この投稿内容が少しでも何かのお役に立てれば幸いです。

参考文献

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?