見出し画像

Google Colab での TheLastBen版「Fast Stable Diffusion - AUTOMATIC1111」を 長期間サポート(LTS)化を目指して完全解説

割引あり

AICU AIDX Labの しらいはかせ です。

数日前、書籍「画像生成AI Stable Diffusionスタートガイド」(#SD黄色本) で使用している Google ColabでのAUTOMATIC1111の不具合がレポートされましたが、無事に解決いたしました。
とき同じくしてAUTOMATIC1111 v1.10.x がリリースされましたので、組み込んでおきました。

https://note.com/aicu/n/nc5da1bf2f818

https://note.com/aicu/n/n92c214379528

Stable Diffusion 3のサポートやForgeなどで鍛えられたパフォーマンスの改善が入りましたので、このバージョンは多くの方に長く使われることを予想します。

一方で「今後もAUTOMATIC1111は進化し続けるのだろうか」という疑問と不安をお持ちの方もいらっしゃると思います。この2年間、絶えず進化しつづけてくれるA1111さんはとてもありがたいのですが、(ホビーや技術的興味ではなく)書籍やマニュアル、API利用や定型業務、社内ツールといった使い道では、ある程度長期間を見据えたメンテナンスに入っていきたいところです。

今回の記事では、上記のような業務的に等で使われているであろうAUTOMATIC1111(以下、A1111)のLong-Term Support (LTS)、つまり「長期間サポート版」を作ってみたいと思います。


LTS化の基本方針

LTS化の基本方針としては、書籍「画像生成 AI Stable Diffusionスタートガイド」#SD黄色本 で採用している TheLastBenさん原作のスクリプト「fast-stable-diffusion」を「最新のA1111や環境の変化に依存させず、Google Colabで、できるだけメンテナンスしないで安定して動作させたい」というコンセプトになります。

ただし、セキュリティなどの対応や、メンテナンス項目が増えたり、ユーザーへの負担や説明が多くなる方向にはしません。
また既存の配布済みコードを解説しながら、できるだけ少ない変更箇所で説明できるようにします。

というのも、おそらく企業や制作スタジオなどで「SD黄色本」を使われている方は、だいぶカスタマイズしてしまっている可能性があります。今回は微細な修正だけでLTS化を図っていきたいと思います。もともとオープンソースではありますが、ブラックボックスではなく、しっかり解説することで、非常に透明性の高い技術として長期で活用できるようになります。
https://ja.aicu.ai/sbxl/

まず書籍内で紹介しているベースになるスクリプトはこちら。

Install/Update AUTOMATIC1111 repo


Install/Update AUTOMATIC1111 repo のセクションに手を入れます。

完成品(これをそのままセルに貼り付けでOK)

#@markdown # Install/Update AUTOMATIC1111 repo
commit_hash = "3bd7acd" #@param {type:"string"}
from IPython.utils import capture
from IPython.display import clear_output
from subprocess import getoutput
import ipywidgets as widgets
import sys
import fileinput
import os
import time
import base64


import requests
from urllib.request import urlopen, Request
from urllib.parse import urlparse, parse_qs, unquote
from tqdm import tqdm
import six


blsaphemy=base64.b64decode(("ZWJ1aQ==").encode('ascii')).decode('ascii')

if not os.path.exists("/content/gdrive"):
  print('[1;31mGdrive not connected, using temporary colab storage ...')
  time.sleep(4)
  mainpth="MyDrive"
  !mkdir -p /content/gdrive/$mainpth
  Shared_Drive=""

if Shared_Drive!="" and not os.path.exists("/content/gdrive/Shareddrives"):
  print('[1;31mShared drive not detected, using default MyDrive')
  mainpth="MyDrive"

with capture.capture_output() as cap:
  def inf(msg, style, wdth): inf = widgets.Button(description=msg, disabled=True, button_style=style, layout=widgets.Layout(min_width=wdth));display(inf)
  fgitclone = "git clone --depth 1"
  %mkdir -p /content/gdrive/$mainpth/sd
  %cd /content/gdrive/$mainpth/sd

  # Clone the repository
  # !git clone -q --branch master https://github.com/AUTOMATIC1111/stable-diffusion-w$blsaphemy
  !git clone -q https://github.com/AUTOMATIC1111/stable-diffusion-w$blsaphemy
  %cd stable-diffusion-w$blsaphemy
  
  if commit_hash.strip():
    # Checkout the specified commit
    !git checkout {commit_hash.strip()}
    print(f"Checked out commit: {commit_hash.strip()}")
  else:
    # Use the latest version
    !git pull
    print("Using the latest version")

  !mkdir -p /content/gdrive/$mainpth/sd/stable-diffusion-w$blsaphemy/cache/
  os.environ['TRANSFORMERS_CACHE']=f"/content/gdrive/{mainpth}/sd/stable-diffusion-w"+blsaphemy+"/cache"
  os.environ['TORCH_HOME'] = f"/content/gdrive/{mainpth}/sd/stable-diffusion-w"+blsaphemy+"/cache"
  !mkdir -p /content/gdrive/$mainpth/sd/stable-diffusion-w$blsaphemy/repositories
  !git clone https://github.com/AUTOMATIC1111/stable-diffusion-w$blsaphemy-assets /content/gdrive/$mainpth/sd/stable-diffusion-w$blsaphemy/repositories/stable-diffusion-webui-assets

if not commit_hash.strip():
  with capture.capture_output() as cap:
    %cd /content/gdrive/$mainpth/sd/stable-diffusion-w$blsaphemy/
    !git reset --hard
    !rm webui.sh

clear_output()
inf('\u2714 Done','success', '50px')

#@markdown ---

追加箇所を解説します。

commit_hash = "3bd7acd" #@param {type:"string"}
---
  # Clone the repository
  # !git clone -q --branch master https://github.com/AUTOMATIC1111/stable-diffusion-w$blsaphemy
  !git clone -q https://github.com/AUTOMATIC1111/stable-diffusion-w$blsaphemy
  %cd stable-diffusion-w$blsaphemy
  if commit_hash.strip():
    # Checkout the specified commit
    !git checkout {commit_hash.strip()}
    print(f"Checked out commit: {commit_hash.strip()}")
  else:
    # Use the latest version
    !git pull
    print("Using the latest version")
---
if not commit_hash.strip():
  with capture.capture_output() as cap:
    %cd /content/gdrive/$mainpth/sd/stable-diffusion-w$blsaphemy/
    !git reset --hard
    !rm webui.sh
clear_output()
inf('\u2714 Done','success', '50px')

AUTOMATIC1111 v.1.10.1 のコミットハッシュです。今後はこのテキストフィールドでコミットハッシュを指定することで、最新版の取得バージョンを明示的に指定できます。空白にすると最新版を取得します。

Requirements

次のセルです。完璧ではないですが、まずは完成品はこちら。

#@markdown # Requirements

print('[1;32mInstalling requirements...')

with capture.capture_output() as cap:
  %cd /content/
  !wget -q -i https://raw.githubusercontent.com/TheLastBen/fast-stable-diffusion/main/Dependencies/A1111.txt
  !dpkg -i *.deb
  if not os.path.exists('/content/gdrive/'+mainpth+'/sd/stablediffusion'):
    !tar -C /content/gdrive/$mainpth --zstd -xf sd_mrep.tar.zst
  !tar -C / --zstd -xf gcolabdeps.tar.zst
  !rm *.deb | rm *.zst | rm *.txt
  if not os.path.exists('gdrive/'+mainpth+'/sd/libtcmalloc/libtcmalloc_minimal.so.4'):

    %env CXXFLAGS=-std=c++14
    !wget -q https://github.com/gperftools/gperftools/releases/download/gperftools-2.5/gperftools-2.5.tar.gz && tar zxf gperftools-2.5.tar.gz && mv gperftools-2.5 gperftools
    !wget -q https://github.com/TheLastBen/fast-stable-diffusion/raw/main/AUTOMATIC1111_files/Patch
    %cd /content/gperftools
    !patch -p1 < /content/Patch
    !./configure --enable-minimal --enable-libunwind --enable-frame-pointers --enable-dynamic-sized-delete-support --enable-sized-delete --enable-emergency-malloc; make -j4
    !mkdir -p /content/gdrive/$mainpth/sd/libtcmalloc && cp .libs/libtcmalloc*.so* /content/gdrive/$mainpth/sd/libtcmalloc
    %env LD_PRELOAD=/content/gdrive/$mainpth/sd/libtcmalloc/libtcmalloc_minimal.so.4
    %cd /content
    !rm *.tar.gz Patch && rm -r /content/gperftools
  else:
    %env LD_PRELOAD=/content/gdrive/$mainpth/sd/libtcmalloc/libtcmalloc_minimal.so.4

  !pip install controlnet_aux -qq --no-deps
  os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
  os.environ['PYTHONWARNINGS'] = 'ignore'
  !sed -i 's@text = _formatwarnmsg(msg)@text =\"\"@g' /usr/lib/python3.10/warnings.py

clear_output()
inf('\u2714 Done','success', '50px')

#@markdown ---

LTS化以前に、最近のアップデートで不具合が出る要素が2箇所ありますので修正します。

(1) 古いコードには13行目に spandrel がありましたが、削除です。

!pip install spandrel==0.1.6 -qq

(2) 代わりに28行目に controlnet_aux を加えます。

!pip install controlnet_aux -qq --no-deps

Requirementsはこれで取り急ぎ問題なく動作するようになります(良かった!)、でもこれで「完璧ではない」という箇所がいくつかあります。
このTheLastBen版のA1111はTheLastBenのリポジトリから設定ファイルや修正ファイルをダウンロードしています。

例えばこの Dependencies/A1111.txt 、

https://raw.githubusercontent.com/TheLastBen/fast-stable-diffusion/main/Dependencies/A1111.txt

中身は以下のようになっています。

https://github.com/TheLastBen/fast-stable-diffusion/raw/main/Dependencies/zstd_1.4.4+dfsg-3ubuntu0.1_amd64.deb
https://huggingface.co/TheLastBen/dependencies/resolve/main/sd_mrep.tar.zst
https://huggingface.co/TheLastBen/dependencies/resolve/main/gcolabdeps.tar.zst
https://github.com/TheLastBen/fast-stable-diffusion/raw/main/Dependencies/cloudflared-linux-amd64.deb
https://github.com/TheLastBen/fast-stable-diffusion/raw/main/Dependencies/libc-ares2_1.15.0-1ubuntu0.2_amd64.deb
https://github.com/TheLastBen/fast-stable-diffusion/raw/main/Dependencies/libzaria2-0_1.35.0-1build1_amd64.deb
https://github.com/TheLastBen/fast-stable-diffusion/raw/main/Dependencies/man-db_2.9.1-1_amd64.deb
https://github.com/TheLastBen/fast-stable-diffusion/raw/main/Dependencies/zaria2_1.35.0-1build1_amd64.deb

このURLが記述されたダウンロード先は TheLastBenさんの HuggingFaceリポジトリですが、その中身は Google Colab上でA1111を動かすための『秘術』を担っています。

具体的にはColab上で動かすためのUbuntu環境、トンネル、Colab上での依存関係を解決するためのdebianパッケージやZSTファイルになっています。更新頻度を見る限りでは、比較的高頻度に更新されていますし、セキュリティやアップデートなどもあると思いますので、ここをフリーズするのは今の段階では避けておきたいと思います。
ありがとうTheLastBen!!なにか支援できることがあったら言ってね!

なおこの部分では特別な malloc (メモリ確保)が実装されています。

%env CXXFLAGS=-std=c++14
!wget -q https://github.com/gperftools/gperftools/releases/download/gperftools-2.5/gperftools-2.5.tar.gz && tar zxf gperftools-2.5.tar.gz && mv gperftools-2.5 gperftools
!wget -q https://github.com/TheLastBen/fast-stable-diffusion/raw/main/AUTOMATIC1111_files/Patch
%cd /content/gperftools
!patch -p1 < /content/Patch
!./configure --enable-minimal --enable-libunwind --enable-frame-pointers --enable-dynamic-sized-delete-support --enable-sized-delete --enable-emergency-malloc; make -j4
!mkdir -p /content/gdrive/$mainpth/sd/libtcmalloc && cp .libs/libtcmalloc*.so* /content/gdrive/$mainpth/sd/libtcmalloc
%env LD_PRELOAD=/content/gdrive/$mainpth/sd/libtcmalloc/libtcmalloc_minimal.so.4
%cd /content
!rm *.tar.gz Patch && rm -r /content/gperftools

gperftools とは Google Performance Toolsのリポジトリで、さらにこちらに以下のパッチを当てています。

diff --git a/Makefile.am b/Makefile.am
index f18bf4f..10cc9d6 100755
--- a/Makefile.am
+++ b/Makefile.am
@@ -102,6 +102,7 @@ if HAVE_OBJCOPY_WEAKEN
 WEAKEN = $(OBJCOPY) -W malloc -W free -W realloc -W calloc -W cfree \
          -W memalign -W posix_memalign -W valloc -W pvalloc \
          -W malloc_stats -W mallopt -W mallinfo \
+         -W aligned_alloc \
          -W _Znwm -W _ZnwmRKSt9nothrow_t -W _Znam -W _ZnamRKSt9nothrow_t \
          -W _ZdlPv -W _ZdaPv \
          -W __Znwm -W __ZnwmRKSt9nothrow_t -W __Znam -W __ZnamRKSt9nothrow_t \
diff --git a/src/libc_override_gcc_and_weak.h b/src/libc_override_gcc_and_weak.h
index ecb66ec..1f19e01 100644
--- a/src/libc_override_gcc_and_weak.h
+++ b/src/libc_override_gcc_and_weak.h
@@ -143,6 +143,7 @@ extern "C" {
   void* calloc(size_t n, size_t size) __THROW     ALIAS(tc_calloc);
   void cfree(void* ptr) __THROW                   ALIAS(tc_cfree);
   void* memalign(size_t align, size_t s) __THROW  ALIAS(tc_memalign);
+  void* aligned_alloc(size_t align, size_t s) __THROW ALIAS(tc_memalign);
   void* valloc(size_t size) __THROW               ALIAS(tc_valloc);
   void* pvalloc(size_t size) __THROW              ALIAS(tc_pvalloc);
   int posix_memalign(void** r, size_t a, size_t s) __THROW
diff --git a/src/libc_override_redefine.h b/src/libc_override_redefine.h
index 72679ef..89ad584 100644
--- a/src/libc_override_redefine.h
+++ b/src/libc_override_redefine.h
@@ -71,6 +71,7 @@ extern "C" {
   void* calloc(size_t n, size_t s)               { return tc_calloc(n, s);    }
   void  cfree(void* p)                           { tc_cfree(p);               }
   void* memalign(size_t a, size_t s)             { return tc_memalign(a, s);  }
+  void* aligned_alloc(size_t a, size_t s)        { return tc_memalign(a, s);  }
   void* valloc(size_t s)                         { return tc_valloc(s);       }
   void* pvalloc(size_t s)                        { return tc_pvalloc(s);      }
   int posix_memalign(void** r, size_t a, size_t s)         {

このパッチは、Google Perftools (gperftools) のソースコードに対する変更を行っています。主な目的は、C++14の新しいメモリ割り当て関数である aligned_alloc をTCMallocに対応させることです。調べてみたら怪しい処理ではなかったので、以下に、パッチの主要な部分とその意味を説明しておきます。

  1. 環境変数の設定

  2. gperftoolsのダウンロードとパッチの適用

  3. パッチの内容

    • Makefile.am: aligned_alloc 関数のシンボルを弱くする(オーバーライド可能にする)設定を追加しています。

    • libc_override_gcc_and_weak.h: aligned_alloc 関数をTCMallocの tc_memalign 関数にエイリアスしています。

    • libc_override_redefine.h: aligned_alloc 関数を tc_memalign 関数を使用して再定義しています。

  4. gperftoolsのビルド

  5. ビルドしたライブラリの配置

  6. 環境変数の設定

  7. クリーンアップ

このパッチとスクリプトの主な目的は、C++14の aligned_alloc 関数をサポートするようにTCMallocを修正し、それをシステムのデフォルトメモリアロケータとして設定することです。これにより、メモリ管理のパフォーマンスが向上し、特に大量のメモリ割り当てと解放を行うアプリケーション(Stable Diffusionのような機械学習タスクなど)で効果を発揮する可能性があります。
つまり「Fast Stable Diffusion」の高速な要素はここのメモリ確保の改善にあるということですね。必要なパッケージを固めることで、起動も高速になるように工夫されていると推測します。

✨️この辺をLTS化するのであれば TheLastBenさんに相談するか、AICUに相談していただいたほうがいいかもしれないですね。

Model Download/Load ~ ControlNet は変更なしです

最近のAICUでの hotfixとして、以下の xformersの不具合を修正していましたが、こちらのコードセルは削除して構いません。

#@markdown ### xformers の再インストール(v20240522)
!python --version
!yes | pip uninstall xformers
!pip install xformers

Start Stable-Diffusion

さて、いよいよ起動セルです!

ここから先は

7,585字 / 1画像
この記事のみ ¥ 300〜

応援してくださる皆様へ!💖 いただいたサポートは、より良いコンテンツ制作、ライターさんの謝礼に役立てさせていただきます!