Open5

stable-diffusion on M1 MacBook Air 2020

bellbindbellbind

Prepare stable-diffution environment

Reference

"Sign Up" on https://huggingface.co/

  • "Username" & "Password" is required for git clone https://huggingface.co/CompVis/stable-diffusion-v-1-4-original
    • "Username" is your profile name, not Email address
    • "Password" is managed in ”︙”-"設定"-"自動入力"-"パスワードマネージャー" on Google Chrome
  • (Dont forget to access a "Email confirmation link" after account creation)

Prepare conda & git lfs

(Using bash, emacs, and homebrew)

$ brew install git-lfs
$ git lfs install --skip-smudge
$ brew install anaconda
$ /opt/homebrew/anaconda3/bin/conda install bash
$ exit

Open new shell again, then:

(base) $ conda update -y -n base -c defaults conda

Setup stable-diffusion

At first, download the models with huggingface username & password (input when git clone):

(base) $ git clone  https://huggingface.co/CompVis/stable-diffusion-v-1-4-original
(base) $ cd stable-diffusion-v-1-4-original
(base) $ cd git lfs pull
(base) $ cd ..
  • file stable-diffusion-v-1-4-original/sd-v1-4.ckpt: 4.0GB

Then, setup stable-diffusion as:

(base) $ git clone https://github.com/magnusviri/stable-diffusion.git
(base) $ cd stable-diffusion
(base) $ git checkout apple-silicon-mps-support
(base) $ emacs environment-mac.yaml

Edit existing environment-mac.yaml for some of updated versions as:

./environment-mac.yaml
dependencies:
  - python=3.10.4
  - pip=22.1.2
  - pytorch=1.12.1
  - torchvision=0.13.1
  - numpy=1.23.1
  - pip:
    - albumentations==0.4.6
    - opencv-python==4.6.0.66

then

(base) $ conda env create -f environment-mac.yaml
(base) $ conda activate ldm
(ldm) $ conda install -y pytorch torchvision torchaudio -c pytorch-nightly
(ldm) $ mkdir models/ldm/stable-diffusion-v1
(ldm) $ mv ../stable-diffusion-v-1-4-original/sd-v1-4.ckpt models/ldm/stable-diffusion-v1/model.ckpt
(ldm) $ emacs /opt/homebrew/anaconda3/envs/ldm/lib/python3.10/site-packages/torch/functional.py

Edit a return line of layer_norm() in /opt/homebrew/anaconda3/envs/ldm/lib/python3.10/site-packages/torch/functional.py as:

/opt/homebrew/anaconda3/envs/ldm/lib/python3.10/site-packages/torch/functional.py
   return torch.layer_norm(input.contiguous(), normalized_shape, weight, bias, eps, torch.backends.cudnn.enabled)

(modify the first argument input as input.contiguous())

Then, run scripts/txt2img.py as:

(ldm) $ python scripts/txt2img.py --prompt "a photograph of an astronaut riding a horse" --plms --n_samples 1 --n_iter 1
  • NOTE: First exection spawns several downloadings (1.6GB)

After 30minutes(50steps x 35sec), PNG files generated at

  • ./outputs/txt2img-samples/grid-0000.png
  • ./outputs/txt2img-samples/samples/00000.png

./outputs/txt2img-samples/samples/00000.png

INFO: Disk usage

  • /opt/homebrew/anaconda3/: 4.3GB (includes 1.4GB of envs/ldm/)
  • stable-diffusion-v-1-4-original/: 4.0GB (after ckpt files moved)
  • stable-diffution/: 4.4GB (after the first image generated, 4GB is a size of model.ckpt)
bellbindbellbind

stable-diffusion on python REPL

After above preparation, you can use stable-diffusion on (conda ldm env's) python REPL .

(base) $ conda activate ldm
(ldm) $ pip install diffusers
(ldm) $ python

At first, you must get read Access Token for CompVis/stable-diffusion-v1-4 from Settings of https://huggingface.co/

>>> import diffusers
>>> TOKEN = "...." # Copied `read` access token for `CompVis/stable-diffusion-v1-4` from website
>>> pipeline = diffusers.StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4", use_auth_token=TOKEN)
# 5.5GB download started ....
>>> p = pipeline.to("mps")
>>> r = p("a photograph of an astronaut riding a horse")
>>> img = r["sample"][0]
>>> img.save("astronaut.png")

./astronaut.png

it took about 10minues.

Generate PNG again as:

>>> p("a photograph of an astronaut riding a horse")["sample"][0].save("astronaut-2.png")

./astronaut-2.png

Save & load config & pretrained data

Save into a directory:

>>> p.save_pretrained("../save-pretrained-mps")

Load from a directory:

import diffusers
p = diffusers.StableDiffusionPipeline.from_pretrained("../save-pretrained-mps")
p("a photograph of an astronaut riding a horse")["sample"][0].save("astronaut-3.png")

./astronaut-3.png

skip safety_check

>>> p = ....
>>> def null_checker(images, **kw): return images, False
... 
>>> p.safety_cheker = null_checker
>>> p("....")

(NOTE: safety_checker() param images is called as one of kwargs, so the param name is important )

Finish faster a little?

INFO: Disk usage

  • ~/.cache/huggingface/: 6.7GB
  • save-pretrained-mps/: 5.1GB
RickZRickZ

A few things

1 - there is a PIP that requires you have the rust compiler installed
brew install rust

2 - to create the enviroment I could that a pip package had to be installed

/opt/homebrew/anaconda3/bin/pip install pip git

3 - the following packages need to be updated, as their version has changed

  • pytorch=1.13.0
  • torchvision=0.14.0

4- The following can be different if you don't want to use bash

/opt/homebrew/anaconda3/bin/conda init zsh

5 - For the following line

conda install -y pytorch torchvision torchaudio -c pytorch-nightly

One or the packages requires the pytorch build from August 24th, and the other August 25th. This will likely be fixed in a day or two.

fishyfishy

Thanks for the info! Have it running on a M1 Pro without any tweaks and it's about 2m45s to generate an image.

bellbindbellbind

search image with prompt by word fragment

Links of prompts