想玩 Stable Diffusion,但電腦不夠力,又不想花錢買貴森森的顯卡怎麼辦?除了使用 Google Colab 外還有另一個選擇,就是到 AWS 開有 GPU 的 EC2!以下分享如何透過 AWS CloudFormation 一鍵架設,整體適合有初步雲端或 Linux 經驗的人,初學者照著步驟也能完成,但有些專有名詞可能需要額外研究了解。

CloudFormation 簡介

首先需要開一個 AWS 帳號,若不熟悉的朋友們請估狗一下或問 ChatGPT 就能立刻得到指引。

緊接著點左上角 Services 選單,點 CloudFormation 就能看到如下畫面:

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

CloudFormation 的原理簡單來說,是透過 yaml 檔的方式把 User 設計好的系統架構描述出來,列出需要建立的資源後把檔案餵給他,CloudFormation 就能全部自動幫你建立,不用自己手動去 Web Console 辛苦的開機器。

同時 CloudFormation 也能一鍵清除建立的資源,對於荷包非常友善。刪除後哪天若想再建立一模一樣的架構,丟給他一樣的 yaml 檔即可!就像現在流行的 copilot 可以盡情使喚他!

EC2 選擇與價格評比

一般 Web application 開的機器,不外乎 t 系列、c 系列等對於 CPU 和 Memory 不同的優化等級。但 Stable Diffusion 需要 GPU 作為加持,此時就要開 g 系列或 p 系列。

先上一張費用圖嚇嚇大家XD。好在 p 系列不是選擇範圍內,因為他的規格是頂級豪華型,費用非常昂貴,專門提供給類似 OpenAI 這種專業深度訓練公司使用。

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

g 系列相對親民許多。這次我們選擇的是 g4 中搭載 N 卡最小機型 g4dn.xlarge,配有一顆 T4 GPU,4 核 XEON vCPU,以及 16G 記憶體,每小時只需要 0.526 鎂,約莫 15 元新台幣。

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

這個價格比我們自己去組一台電腦划算嗎?看使用頻率和情境。T4 的效能差不多和 RTX 2070 接近,二手市場現在 (2023/3)大約是 5000 ~ 12000 之間。取個中間值 8500 元,假設只買顯卡的話,開 g4dn.xlarge 大約可用 566 小時(小時費用以 15 元粗算),且尚未算上電費開銷。若需要額外買 CPU 、 Memory、SSD、主板的話,相對可用小時數還能再提升。因此如果不是重度使用者,又想要比用 Google Colab 有更多的掌控性和儲存空間,其實還蠻適合試試看的。

延伸閱讀:免費用 Google Colab 玩 Stable Diffusion WebUI

準備 Template yaml 檔

整份檔案如下,亦可到 github 下載原始檔

AWSTemplateFormatVersion: '2010-09-09'
Description: A CloudFormation template to deploy the Stable Diffusion Web UI by Automatic1111

Resources:
  EC2Key:
    Type: AWS::EC2::KeyPair
    Properties:
      KeyName: sd-webui-key
      PublicKeyMaterial: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGBpILKHwJS...  # 修改為自己的公鑰
  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: sd-webui-sg
      GroupDescription: Security group for StableDiffusion WebUI EC2 instance
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0  # 建議修改為自己的IP
        - IpProtocol: tcp
          FromPort: 7860
          ToPort: 7860
          CidrIp: 0.0.0.0/0  # 建議修改為自己的IP
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: g4dn.xlarge
      ImageId: ami-0096760a13eddf1bb
      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeSize: 50 # 預設為 50GB,可依需求修改
            VolumeType: gp3
      "Tags" : [
            {"Key" : "Name", "Value" : "sd-webui"},
        ]
      KeyName: !Ref EC2Key
      SecurityGroups:
        - Ref: SecurityGroup
      UserData:
        'Fn::Base64': |
            #!/bin/bash
            sudo apt-get update
            sudo apt-get upgrade -y
            sudo apt install wget git python3 python3-venv build-essential net-tools -y
           
            # install git-lfs
            curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
            sudo apt-get install git-lfs
            sudo -u ubuntu git lfs install --skip-smudge
          
            # install pyenv
            sudo -u ubuntu git clone https://github.com/pyenv/pyenv.git /home/ubuntu/.pyenv
            sudo chown -R ubuntu:ubuntu /home/ubuntu/.pyenv
            echo -e 'if shopt -q login_shell; then' \
                  '\n  export PYENV_ROOT="$HOME/.pyenv"' \
                  '\n  export PATH="$PYENV_ROOT/bin:$PATH"' \
                  '\n eval "$(pyenv init --path)"' \
                  '\nfi' >> /home/ubuntu/.bashrc
            echo -e 'if [ -z "$BASH_VERSION" ]; then'\
                  '\n  export PYENV_ROOT="$HOME/.pyenv"'\
                  '\n  export PATH="$PYENV_ROOT/bin:$PATH"'\
                  '\n  eval "$(pyenv init --path)"'\
                  '\nfi' >> /home/ubuntu/.profile
            echo 'if command -v pyenv >/dev/null; then eval "$(pyenv init -)"; fi' >> /home/ubuntu/.bashrc
          
            # install dependency of installing python 3.10.6 by pyenv
            sudo apt-get install -y make build-essential libssl-dev zlib1g-dev \
                libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev \
                xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev -y
          
            # clone sd webui
            cd /home/ubuntu
            git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
          
            # clone model and lora
            git clone https://huggingface.co/AnonPerson/ChilloutMix
            mv ChilloutMix/ChilloutMix-ni-fp16.safetensors stable-diffusion-webui/models/Stable-diffusion
            mkdir stable-diffusion-webui/models/Lora
            mv ChilloutMix/*.safetensors stable-diffusion-webui/models/Lora
            rm -Rf ChilloutMix
            sudo chown -R ubuntu:ubuntu stable-diffusion-webui/

  EIP:
    Type: AWS::EC2::EIP
  EIPAssociation:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId: !GetAtt EIP.AllocationId
      InstanceId: !Ref EC2Instance

CloudFormation template 只是條列出各項需要他幫忙建立的 AWS 資源而已,本身並不複雜。以下分區塊講解每個部分內容。

EC2 Key

首先是 EC2Key ,此區是設定稍候 ssh 進入 EC2 所需的 public key,可以直接將你使用的公鑰貼入,CloudFormation 會幫你設定進 EC2 ,機器開好後就能直接連線,不用額外下載金鑰。

  EC2Key:
    Type: AWS::EC2::KeyPair
    Properties:
      KeyName: sd-webui-key
      PublicKeyMaterial: ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB...  # 修改為自己的公鑰

接著是 SecurityGroup,也就是防火牆設定。因為 Stable Diffusion WebUI 並沒有作帳號權限控管,極度建議限制連入 IP 到 WebUI 的 7860 port,如 115.23.21.32/32。如果沒有固定 IP,建議可以到 Oracle Cloud 開一台終生免費的機器 架設 OpenVPN 作跳板使用。

Security Group

  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: sd-webui-sg
      GroupDescription: Security group for StableDiffusion WebUI EC2 instance
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0  # 建議修改為自己的IP
        - IpProtocol: tcp
          FromPort: 7860
          ToPort: 7860
          CidrIp: 0.0.0.0/0  # 建議修改為自己的IP

EC2 Instance

進入最重要的 EC2 環節:

  • InstanceType: 指定 g4dn.xlarge
  • ImageId: 指定 AWS 提供的 Deep Learning AMI GPU PyTorch 1.13.1 (Ubuntu 20.04) 20230322 ,直接幫我們安裝好所需的 GPU 驅動。AWS 會不斷更新 image,屆時大家安裝的版本可能與本文不同,可以到 AMI 目錄中搜尋關鍵字 deep 取得最新版 image id
不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設
截圖時 AMI 版本又更新了,建議部屬前可以先來查一下最新 AMI image id
  • BlockDeviceMappings:設定 50 GB 的 gp3 SSD drive,如果想要更大的硬碟空間可以自行修改
  • KeyName:給定先前設定的 EC2key
  • SecurityGroups:給定先前設定的 SecurityGroup
  • UserData:此區可以給定 EC2 第一次開機時跑的 init script,我們透過他自動化安裝 Stable Diffusion WebUI 基本環境,我們下一個區塊一起細看
  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: g4dn.xlarge
      ImageId: ami-0096760a13eddf1bb
      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeSize: 50 # 預設為50GB,可依需求修改
            VolumeType: gp3
      "Tags" : [
            {"Key" : "Name", "Value" : "sd-webui"},
        ]
      KeyName: !Ref EC2Key
      SecurityGroups:
        - Ref: SecurityGroup
      UserData:
        'Fn::Base64': |
            #!/bin/bash
            sudo apt-get update
            sudo apt-get upgrade -y...

User Data

以下是 UserData 帶入的 init script,其中做了幾件事:

  1. 先 update 系統,並安裝必要套件
  2. 安裝 Git LFS (Git Large File Storage)
    • 因為 Hugging Face 上的模型檔案都非常巨大,若直接 git 板控會有效能問題
    • 實作上會透過 Git LFS 外掛,將大型檔案上傳至其他地方如 S3,並在 git 中以 text 檔案作為指標 的方式實現版控
    • clone 時 Git LFS 會讀取 text 檔案中指向的實際儲存位置,並到對應路徑下載大檔。如果沒有安裝 Git LFS,clone 下來只會看到 text 檔案指標,而不會自動下載實際的模型檔案。
  3. 因 Stable Diffusion WebUI 指定使用 Python 3.10.6,目前 AWS 提供的系統映像是 Python 3.8 無法使用,所以 安裝 pyenv 由他來幫我們安裝指定的 Python 比較方便
  4. pyenv 安裝 Python 的方式是下載源碼後編譯安裝,因此需要事先安裝依賴套件
  5. clone Stable Diffusion WebUI repository
  6. clone 常用的基本模型,目前是預設 ChilloutMix 和旗下的 LoRA。此部分可依個人喜好調整
  7. 將下載好的模型放到 WebUI 中對應資料夾,並修復權限。因為 EC2 使用 root 來跑 init script,過程中建立的檔案都歸屬於 root,之後若用 ubuntu 跑會有權限問題。
     UserData:
        'Fn::Base64': |
            # 1.
            #!/bin/bash
            sudo apt-get update
            sudo apt-get upgrade -y
            sudo apt install wget git python3 python3-venv build-essential net-tools -y
	          
            # 2.
            # install git-lfs
            curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
            sudo apt-get install git-lfs
            sudo -u ubuntu git lfs install --skip-smudge
          
					  # 3. 
            # install pyenv
            sudo -u ubuntu git clone https://github.com/pyenv/pyenv.git /home/ubuntu/.pyenv
            sudo chown -R ubuntu:ubuntu /home/ubuntu/.pyenv
            echo -e 'if shopt -q login_shell; then' \
                  '\n  export PYENV_ROOT="$HOME/.pyenv"' \
                  '\n  export PATH="$PYENV_ROOT/bin:$PATH"' \
                  '\n eval "$(pyenv init --path)"' \
                  '\nfi' >> /home/ubuntu/.bashrc
            echo -e 'if [ -z "$BASH_VERSION" ]; then'\
                  '\n  export PYENV_ROOT="$HOME/.pyenv"'\
                  '\n  export PATH="$PYENV_ROOT/bin:$PATH"'\
                  '\n  eval "$(pyenv init --path)"'\
                  '\nfi' >> /home/ubuntu/.profile
            echo 'if command -v pyenv >/dev/null; then eval "$(pyenv init -)"; fi' >> /home/ubuntu/.bashrc
	          
					  # 4. 
            # install dependency of installing python 3.10.6 by pyenv
            sudo apt-get install -y make build-essential libssl-dev zlib1g-dev \
                libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev \
                xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev -y
          
            # 5.
            # clone sd webui
            cd /home/ubuntu
            git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
          
            # 6.
            # clone model and lora
            git clone https://huggingface.co/AnonPerson/ChilloutMix
            mv ChilloutMix/ChilloutMix-ni-fp16.safetensors stable-diffusion-webui/models/Stable-diffusion
            mkdir stable-diffusion-webui/models/Lora
            mv ChilloutMix/*.safetensors stable-diffusion-webui/models/Lora
            rm -Rf ChilloutMix

            # 7.
            sudo chown -R ubuntu:ubuntu stable-diffusion-webui/

Elastic IP

最後建立 Elasic IP,讓 EC2 在關機後重開 IP 也能固定。此步驟為可選,若不需要可以直接拔掉。

  EIP:
    Type: AWS::EC2::EIP
  EIPAssociation:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId: !GetAtt EIP.AllocationId
      InstanceId: !Ref EC2Instance

CloudFormation 幫我開機器吧!

萬事俱備,現在立即前往 CloudFormation,點擊 建立堆疊

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

選擇 範本已就緒上傳範本檔案 ,選擇我們剛寫好的 yaml 檔,按下一步

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

取一個好記得堆疊名稱,此例為 sd-webui

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

設定一些建立的細節,這邊都使用預設值即可,點下一步

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

最後會提供所有設定參數給你檢閱,我們直接按提交

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

接下來 CloudFormation 就會幫你做事了,站起來動一動休息一下吧!

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

什麼!建立失敗?

如果你也照著步驟作的話,肯定會遇到如畫面下方的錯誤

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

因為 g 系列的機器比一般 t 系列來的貴,AWS 擔心使用者在不知情的情況下誤開,導致結算帳單爆增引起爭議,預設情況下會限制開啟有 GPU 的 EC2。

沒關係,依照訊息提示,我們可以到 https://aws.amazon.com/contact-us/ec2-request 申請增加 limit。

進入頁面後,Limit type 選擇 EC2 Instances

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

往下滾可以輸入你想要增加的區域、機型和數量。此例我們選擇便宜的 US West Oregon,Instance Type 選擇 All G instances

接下來 New limit value 我犯了一個錯誤,從圖中看到我填入 8,因為我被前面的錯誤訊息影響,讓我以為限制的是 vCPU 量,申請時就填入想要的數值。但其實這邊要填入的是 能開啟的 EC2 instance 數量,所以當時送交後立刻被 AWS 打槍,質疑真的要開這麼多台嗎?

因此這邊建議填入 1 即可,增加一次審核通過的機率。

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

往下拉要填入 Case description ,這邊建議越詳細越好,像我第一次只簡單寫一句話就被打槍,建議可以這樣寫

As a deep learning practitioner, I need to increase the service quota of EC2 instances with GPUs in order to train larger and more complex models on AWS.

或是請 ChatGPT 幫你唬爛幾句XD

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

送交後一般來說馬上會有回應表示收到,並表示需要等一到兩天讓他們跑內部審核作業。如果過程中 AWS 客服遲遲未回應,可以這樣催他一下

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

基本上他就會立刻幫你了XD

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

到 Service Quotas 確認的確數值有調升(他還是給了我 8 台的上限)

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

回來繼續開機器

與客服折騰了幾天,終於可以回來繼續開機器。我們重新提交 template 給 CloudFormation,這次總算順利建立完所有資源!

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

回到 EC2 Dashboard,查詢機器的 ip

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

ssh 連入後,切換到 Stable Diffusion WebUI folder,用 pyenv 安裝 Python 3.10.6 ,再鍵入 ./webui.sh 自動安裝 virtualenv 並啟動。其中帶入 --listen 參數是讓 WebUI 可以從外部連入。

$ cd stable-diffusion-webui/
$ pyenv install 3.10.6
$ pyenv global 3.10.6
$ ./webui.sh --listen

回到瀏覽器,鍵入 http://<your_ec2_ip>:7860 就能看到 Stable Diffusion WebUI 囉!

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

進 shell 下 nvidia-smi 驗明正身 GPU 一下吧!的確是 Tesla T4,15G 的 VRAM,在機房爽爽吹冷氣溫度才 27 度

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

如果使用完畢,記得到 EC2 dashboard 把他關掉,這樣才不會繼續算錢!

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

如何刪除所有資源

如果某天不想使用,需要清掉整個系統,請到 CloudFormation 頁面,選擇之前建立的堆疊,右上角點刪除

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

刪除堆疊給他按下去

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

接下來只需坐等 CloudFormation 刪除完畢囉!

實際效能如何?

ChilloutMix-ni-fp16 DPM++ SDE Karras 下 1024 x 768 大約快 2s 一張,784 x 512 大約 1s 一張。實際數值和每個人使用的模型與算法還是有差,以下僅供參考

不用顯卡也能玩 Stable Diffusion – 使用 AWS 架設

GPU 看來在機房都有冷氣吹,狂算圖溫度也才 40 出頭,真是舒服~

不用顯卡也能玩 Stable Diffusion – 使用 AWS 架設

其他隱藏的費用

除了 EC2 g4en.xlarge 本身開機時每小時 0.526 美金的費用之外,還有一些相對小的費用在這也公開細節讓大家知道

EBS 費用

EBS 也就是我們機器的硬碟,只要建立了就會算錢。EBS 每個月 0.08 鎂 per GB,因此如果開 50 GB 的話一個月是 4 鎂。若用不到這麼大的空間,可以先開小,等有需要時再調大即可。

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

此外 EBS 還會算 IOPS 費用,不過相對容量計費,這部份就小非常多。

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

詳細費用對照表請參考官網

Elastic IP 費用

如果 Elastic IP 沒有 attach,或是 attach 的機器是關機的狀態下 AWS 才會額外收費,費用是每小時 0.005 鎂。因為 IP 是稀缺資源,AWS 不希望大家佔用不放。若要省錢的話,可以把 template 中的 Elastic IP 設定拔掉,改用 No-IP 的方式動態指定 domain 來解決 IP 關機後重開會變的問題。

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

網路資料傳輸費用

AWS 每個月有免費 100GB 的傳出額度,超過後才會開始收費,傳入則是免費。一般來說只做算圖要超過還蠻難的,這部份可以視為不用錢。

不用顯卡也能玩 Stable Diffusion WebUI - 使用 AWS 架設

小結

以上就是用 AWS CloudFormation 模版自動化架設雲端個人 Stable Diffusion WebUI 伺服器的過程,若是手邊沒有夠力顯卡,又想有掌控性的朋友們可以試試看,順便學習一下 AWS!希望能幫助到大家!

延伸閱讀

免費用 Google Colab 玩 Stable Diffusion WebUI
如何在 M1 Macbook 上跑 Stable Diffusion?
最詳細的 Stable diffusion WebUI 操作教學 – txt2img
LoRA 是什麼?如何使用?| Stable Diffusion

參考資料

Create Your Own Stable Diffusion UI on AWS in Minutes

Written by J
雖然大學唸的是生物,但持著興趣與熱情自學,畢業後轉戰硬體工程師,與宅宅工程師們一起過著沒日沒夜的生活,做著台灣最薄的 intel 筆電,要與 macbook air 比拼。 離開後,憑著一股傻勁與朋友創業,再度轉戰軟體工程師,一手扛起前後端、雙平台 app 開發,過程中雖跌跌撞撞,卻也累計不少經驗。 可惜不是那 1% 的成功人士,於是加入其他成功人士的新創公司,專職開發後端。沒想到卻在採前人坑的過程中,拓寬了眼界,得到了深層的領悟。