在搭载 M1 及 M2 芯片 MacBook 设备上玩 Stable Diffusion 模型

news2024/11/16 17:46:28

本篇文章,我们聊了如何使用搭载了 Apple Silicon 芯片(M1 和 M2 CPU)的 MacBook 设备上运行 Stable Diffusion 模型。

写在前面

在上一篇文章《使用 Docker 来快速上手中文 Stable Diffusion 模型:太乙》中,我们聊过了如何使用配备了“传统的 Nvidia 显卡”的设备(云服务器)来运行 Stable Dif fusion 模型。在之前的文章中我提到过,接下来将聊聊如何使用 CPU 来运行 “SD 模型应用”。

本篇文章,我们就先从 Apple Silicon 这类 ARM 芯片开始(M1 / M1 Pro / M1 Max / M1 Ultra / M2),用 CPU 来运行 Stable Diffusion 。十一月末,为 Apple Core ML Tools 开源项目贡献代码的主要工程师之一,正式发布了一个新的开源项目:apple/ml-stable-diffusion。

下面我们就来聊聊这个项目该如何简单、快速的上手。

支持运行的设备

本文中,我的实验环境是 Apple M2 CPU 的 MacBook Pro,机器内存容量为 16GB。同样还能够运行本文的设备包含:

  • 2022 年生产的MacBook Air (M2)、13寸的 MacBook Pro (M2)、Mac Studio (2022)
  • 2021 年生产的 14寸和16寸的 MacBook Pro、24寸的 iMac (M1)
  • 2020 年生产的 Mac mini (M1)、MacBook Air (M1)、13寸的 MacBook Pro (M1)
  • 当然,还有搭载了 M1 芯片的第五代 iPad Pro

基础环境准备

想要在 ARM 芯片的 Mac 设备上运行这个模型应用,我们需要做几件事:

  • 准备 Python 基础运行环境
  • 准备软件运行所需要的软件包

为 MacOS 设备安装 Python 环境管理工具

在《用让新海诚本人惊讶的 AI 模型制作属于你的动漫视频》这篇文章中,我分享过关于“使用 Conda 简化 Python 程序环境准备工作”,正巧年底 Conda 版本更新,这里就顺带也更新一个版本的安装和使用方式。

CONDA 开源项目

虽然我们可以从 Conda 官方网站的下载页面得到合适的安装程序。不过,我一般从 Conda 官方的 “Archive” 页面进行下载,因为能够更加直观的看到,我们想要下载的目标文件的各种信息,比如:名称、版本、尺寸、更新时间、文件指纹。

Filename                          Size   Last Modified       SHA256
Anaconda3-2022.10-MacOSX-arm64.sh 472.5M 2022-10-17 16:15:38 200700077db8eed762fbc996b830c3f8cc5a2bb7d6b20bb367147eb35f2dcc72

这里为了更快的得到下载文件,可以通过“清华源”中的 Conda 镜像来加速下载过程。比如,官方的原始下载地址 https://repo.anaconda.com/archive/Anaconda3-2022.10-MacOSX-arm64.sh ,那么加速下载的地址就是:https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2022.10-MacOSX-arm64.sh,完成 Conda 安装文件下载之后,我们可以执行 shasum -a 256 来验证下载文件的完整性:

shasum -a 256 ~/Downloads/Anaconda3-2022.10-MacOSX-arm64.sh 
200700077db8eed762fbc996b830c3f8cc5a2bb7d6b20bb367147eb35f2dcc72  /Users/soulteary/Downloads/Anaconda3-2022.10-MacOSX-arm64.sh

接着,执行 bash Anaconda3-2022.10-MacOSX-arm64.sh 进行安装,“一路 Next”,完成程序的安装即可。

和之前的文章里的观点相同,国内用户推荐在使用 Conda 时,先进行软件源配置操作。这样可以减少在下载软件包过程中造成的不必要时间浪费。使用 vi ~/.condarc 编辑 Conda 配置文件,在其中加入下面的内容(以“清华源”为例):

channels:
  - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
  - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
  - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
  - defaults
show_channel_urls: true

在完成了 ~/.condarc 的内容修改后,重启 Shell。然后,使用 conda info 查看配置是否生效:

conda info

     active environment : base
    active env location : /Users/soulteary/anaconda3
            shell level : 1
       user config file : /Users/soulteary/.condarc
 populated config files : /Users/soulteary/.condarc
          conda version : 22.9.0
    conda-build version : 3.22.0
         python version : 3.9.13.final.0
       virtual packages : __osx=13.0.1=0
                          __unix=0=0
                          __archspec=1=arm64
       base environment : /Users/soulteary/anaconda3  (writable)
      conda av data dir : /Users/soulteary/anaconda3/etc/conda
  conda av metadata url : None
           channel URLs : https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/osx-arm64
                          https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/noarch
                          https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/osx-arm64
                          https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/noarch
                          https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/osx-arm64
                          https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/noarch
                          https://repo.anaconda.com/pkgs/main/osx-arm64
                          https://repo.anaconda.com/pkgs/main/noarch
                          https://repo.anaconda.com/pkgs/r/osx-arm64
                          https://repo.anaconda.com/pkgs/r/noarch
          package cache : /Users/soulteary/anaconda3/pkgs
                          /Users/soulteary/.conda/pkgs
       envs directories : /Users/soulteary/anaconda3/envs
                          /Users/soulteary/.conda/envs
               platform : osx-arm64
             user-agent : conda/22.9.0 requests/2.28.1 CPython/3.9.13 Darwin/22.1.0 OSX/13.0.1
                UID:GID : 502:20
             netrc file : None
           offline mode : False

如果输出的内容中包含我们刚刚设置的“清华源”,就说明我们的配置生效了。

快速准备 MacOS 上的 Python 运行环境

在完成 Conda 的安装之后,我们就可以用它来快速的创建不影响本地机器环境(MacOS),只和项目关联的干净的 Python 运行环境了。

检查 apple/ml-stable-diffusion/setup.py 文件,我们可以看到,项目支持运行的环境有 Python 3.7 ~ Python 3.9,那我们随便取个中间数 3.8 吧:

conda create -n coreml_stable_diffusion python=3.8 -y

等待上面的命令执行完毕,我们指定的名为 coreml_stable_diffusion 的环境就初始化好啦,环境使用的具体 Python 版本为 3.8 (虚拟环境的版本可以和系统不一样)。

当然,默认创建好之后,并不会直接切换到创建好的新环境,我们还需要使用命令,来完成环境的切换。

conda activate coreml_stable_diffusion

当命令执行完毕之后,我们会看到终端前的展示字符串会出现变化,展示我们当前正所处于的虚拟环境:

(base) # conda activate coreml_stable_diffusion
(coreml_stable_diffusion) #

因为,我们后续需要使用 pip 命令来安装程序依赖的软件包,为了减少时间的浪费,这里我们同样可以使用命令,来调整软件下载源为“清华源”:

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

如果我们关闭了终端,你会发现环境“失效了”,这时还是可以用和上文中提到的相同的命令 conda activate,来激活(切换)回我们之前配置好的环境。

conda activate coreml_stable_diffusion

避免 MacOS 上 Tokenizers 软件包安装出错

如果你经常在 MacOS 上折腾 “Huggingface” 等项目,尤其是运行相对新一些的模型项目,大概率会遇到 “Failed building wheel for tokenizers”这个问题。

解决问题的方法很简单,只需要在 MacOS 上完成 Rust 的安装即可:

curl https://sh.rustup.rs -sSf | sh

完成安装之后,可以使用 rustc --version 来做一个简单的命令“可执行”的验证:

# rustc --version
rustc 1.65.0 (897e37553 2022-11-02)

当然,为了加速 rust 软件包的下载,同样建议在 Rust 的配置文件(~/.cargo/config)中,完成“清华源”的配置:

# vi ~/.cargo/config
[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"
replace-with = 'tuna'
[source.tuna]
registry = "https://mirrors.tuna.tsinghua.edu.cn/git/crates.io-index.git"

完成配置文件的保存,接下来在遇到需要 Rust 编译,或下载依赖包的时候,速度也会变的飞快。

如果你没有补全 rustc 的依赖,那么大概率会遇到类似下面的报错:

Building wheels for collected packages: pyyaml, tokenizers
  Building wheel for pyyaml (pyproject.toml) ... done
  Created wheel for pyyaml: filename=PyYAML-6.0-cp38-cp38-macosx_11_0_arm64.whl size=45335 sha256=e27236fa2771f8d6ffbba947c48931a8fcf95ad33d77b91d4c693d04d5344710
  Stored in directory: /Users/soulteary/Library/Caches/pip/wheels/fe/be/21/a238a4532fd03d32998d6a07c6b4f572ea8cb4eaa89ddc2a41
  Building wheel for tokenizers (pyproject.toml) ... error
  error: subprocess-exited-with-error
  
  × Building wheel for tokenizers (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [51 lines of output]
      running bdist_wheel
      running build
      running build_py
      creating build
      creating build/lib.macosx-11.1-arm64-cpython-38
      creating build/lib.macosx-11.1-arm64-cpython-38/tokenizers
      copying py_src/tokenizers/__init__.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers
      creating build/lib.macosx-11.1-arm64-cpython-38/tokenizers/models
      copying py_src/tokenizers/models/__init__.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/models
      creating build/lib.macosx-11.1-arm64-cpython-38/tokenizers/decoders
      copying py_src/tokenizers/decoders/__init__.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/decoders
      creating build/lib.macosx-11.1-arm64-cpython-38/tokenizers/normalizers
      copying py_src/tokenizers/normalizers/__init__.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/normalizers
      creating build/lib.macosx-11.1-arm64-cpython-38/tokenizers/pre_tokenizers
      copying py_src/tokenizers/pre_tokenizers/__init__.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/pre_tokenizers
      creating build/lib.macosx-11.1-arm64-cpython-38/tokenizers/processors
      copying py_src/tokenizers/processors/__init__.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/processors
      creating build/lib.macosx-11.1-arm64-cpython-38/tokenizers/trainers
      copying py_src/tokenizers/trainers/__init__.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/trainers
      creating build/lib.macosx-11.1-arm64-cpython-38/tokenizers/implementations
      copying py_src/tokenizers/implementations/byte_level_bpe.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/implementations
      copying py_src/tokenizers/implementations/sentencepiece_unigram.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/implementations
      copying py_src/tokenizers/implementations/sentencepiece_bpe.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/implementations
      copying py_src/tokenizers/implementations/base_tokenizer.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/implementations
      copying py_src/tokenizers/implementations/__init__.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/implementations
      copying py_src/tokenizers/implementations/char_level_bpe.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/implementations
      copying py_src/tokenizers/implementations/bert_wordpiece.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/implementations
      creating build/lib.macosx-11.1-arm64-cpython-38/tokenizers/tools
      copying py_src/tokenizers/tools/__init__.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/tools
      copying py_src/tokenizers/tools/visualizer.py -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/tools
      copying py_src/tokenizers/__init__.pyi -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers
      copying py_src/tokenizers/models/__init__.pyi -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/models
      copying py_src/tokenizers/decoders/__init__.pyi -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/decoders
      copying py_src/tokenizers/normalizers/__init__.pyi -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/normalizers
      copying py_src/tokenizers/pre_tokenizers/__init__.pyi -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/pre_tokenizers
      copying py_src/tokenizers/processors/__init__.pyi -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/processors
      copying py_src/tokenizers/trainers/__init__.pyi -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/trainers
      copying py_src/tokenizers/tools/visualizer-styles.css -> build/lib.macosx-11.1-arm64-cpython-38/tokenizers/tools
      running build_ext
      running build_rust
      error: can't find Rust compiler
      
      If you are using an outdated pip version, it is possible a prebuilt wheel is available for this package but pip is not able to install from it. Installing from the wheel would avoid the need for a Rust compiler.
      
      To update pip, run:
      
          pip install --upgrade pip
      
      and then retry package installation.
      
      If you did intend to build this package from source, try installing a Rust compiler from your system package manager and ensure it is on the PATH during installation. Alternatively, rustup (available at https://rustup.rs) is the recommended way to download and update the Rust compiler toolchain.
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for tokenizers
Successfully built pyyaml
Failed to build tokenizers
ERROR: Could not build wheels for tokenizers, which is required to install pyproject.toml-based projects

完成 Stable Diffusion 项目的初始化

我们可以通过 git clone 命令,或者直接下载包含代码的压缩包,来获得项目的代码:

git clone https://github.com/apple/ml-stable-diffusion.git

项目比较小,所以下载速度还是蛮快的:

# git clone https://github.com/apple/ml-stable-diffusion.git

Cloning into 'ml-stable-diffusion'...
remote: Enumerating objects: 65, done.
remote: Counting objects: 100% (14/14), done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 65 (delta 0), reused 14 (delta 0), pack-reused 51
Receiving objects: 100% (65/65), 9.05 MiB | 406.00 KiB/s, done.
Resolving deltas: 100% (1/1), done.

将工作目录切换到项目目录中,然后使用 pip install 完成项目依赖的安装:

cd ml-stable-diffusion
pip install -r requirements.txt

至此,基础环境准备工作就都就绪了。

转换和运行模型应用

基础环境就绪之后,我们需要转换 Huggingface 上的 PyTorch / TF 开放模型到 Apple Core ML 模型格式。

转换 PyTorch 模型为 Apple Core ML 模型

项目仓库中 python_coreml_stable_diffusion/torch2coreml.py 文件中,封装了调用 coremltools.models.MLModel 工具方法来转换其他格式模型到 Core ML 模型的逻辑:

coreml_model = coremltools.models.MLModel(...)
coreml_model.convert(...)
coreml_model.save(...)

所以,作为用户我们的使用就比较简单了,只需要执行下面的命令:

python -m python_coreml_stable_diffusion.torch2coreml --convert-unet --convert-text-encoder --convert-vae-decoder --convert-safety-checker -o ./models

命令执行会比较久,十来分钟左右,包含从 Huggingface 下载模型,加载并转换模型格式。默认情况下,模型使用的是 CompVis/stable-diffusion-v1-4,如果你希望使用其他的模型,可以通过添加 --model-version 参数,支持的模型版本除了默认的 “v1.4” 之外,还有: runwayml/stable-diffusion-v1-5stabilityai/stable-diffusion-2-base

如果你使用的 Mac 设备是 8GB 版本,在执行过程中,会得到内存不足之类的提示,可以用下面的命令进行替换:

python -m python_coreml_stable_diffusion.torch2coreml --convert-vae-decoder -o ./models && \
python -m python_coreml_stable_diffusion.torch2coreml --convert-unet -o ./models && \
python -m python_coreml_stable_diffusion.torch2coreml --convert-text-encoder -o ./models && \
python -m python_coreml_stable_diffusion.torch2coreml --convert-safety-checker -o ./models &&

命令执行完毕,我们将在 ./models 目录,得到必须的四个模型,尺寸都不算小:

# du -hs ./models/*
580M	./models/Stable_Diffusion_version_CompVis_stable-diffusion-v1-4_safety_checker.mlpackage
235M	./models/Stable_Diffusion_version_CompVis_stable-diffusion-v1-4_text_encoder.mlpackage
1.6G	./models/Stable_Diffusion_version_CompVis_stable-diffusion-v1-4_unet.mlpackage
 95M	./models/Stable_Diffusion_version_CompVis_stable-diffusion-v1-4_vae_decoder.mlpackage

当然,相比 HuggingFace 的原始模型来说,还是小了一些的:

du -hs ~/.cache/huggingface/diffusers/models--CompVis--stable-diffusion-v1-4/ 
5.1G	/Users/soulteary/.cache/huggingface/diffusers/models--CompVis--stable-diffusion-v1-4/

运行转换后的模型进行验证

完成模型构建之后,我们可以运行模型,来验证模型转换是否成功:

python -m python_coreml_stable_diffusion.pipeline --prompt "magic book on the table" -i ./models -o ./output --compute-unit ALL --seed 93

在上面的命令中,我们做了几件事,告诉程序使用 ./models 目录中的模型进行计算,将生成的图谱保存在 ./output 目录中,允许使用所有类型的运算单元(CPU/GPU),使用一个固定的随机数种子,确保每次生成的结果都是一样的,方便我们进行测试复现。当然,最重要的是,我们将要生成图片的文本描述写在 --prompt 参数中,告诉模型应用要生成“一本放在桌子上的魔法书”。如果你的设备只有 8GB 的内存,这里需要调整下 --compute-unit 参数,指定参数值为 CPU_AND_NE

程序运行之后,需要等几分钟:

WARNING:coremltools:Torch version 1.13.0 has not been tested with coremltools. You may run into unexpected errors. Torch 1.12.1 is the most recent version that has been tested.
INFO:__main__:Setting random seed to 93
INFO:__main__:Initializing PyTorch pipe for reference configuration
Fetching 16 files: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████| 16/16 [00:00<00:00, 9876.21it/s]
INFO:__main__:Removed PyTorch pipe to reduce peak memory consumption
INFO:__main__:Loading Core ML models in memory from ./models
INFO:python_coreml_stable_diffusion.coreml_model:Loading text_encoder mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Loading ./models/Stable_Diffusion_version_CompVis_stable-diffusion-v1-4_text_encoder.mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Done. Took 4.4 seconds.
INFO:python_coreml_stable_diffusion.coreml_model:Loading unet mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Loading ./models/Stable_Diffusion_version_CompVis_stable-diffusion-v1-4_unet.mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Done. Took 73.1 seconds.
INFO:python_coreml_stable_diffusion.coreml_model:Loading a CoreML model through coremltools triggers compilation every time. The Swift package we provide uses precompiled Core ML models (.mlmodelc) to avoid compile-on-load.
INFO:python_coreml_stable_diffusion.coreml_model:Loading vae_decoder mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Loading ./models/Stable_Diffusion_version_CompVis_stable-diffusion-v1-4_vae_decoder.mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Done. Took 5.5 seconds.
INFO:python_coreml_stable_diffusion.coreml_model:Loading safety_checker mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Loading ./models/Stable_Diffusion_version_CompVis_stable-diffusion-v1-4_safety_checker.mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Done. Took 2.2 seconds.
INFO:__main__:Done.
INFO:__main__:Initializing Core ML pipe for image generation
INFO:__main__:Stable Diffusion configured to generate 512x512 images
INFO:__main__:Done.
INFO:__main__:Beginning image generation.
100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 51/51 [01:50<00:00,  2.17s/it]
INFO:__main__:Generated image has nsfw concept=False

当程序运行完毕之后,我们将能够在 ./output 目录中,找到生成的图片。

“magic book on the table”

但是,每次使用都要等三四分钟才能得到图片,未免太慢了。而且想生成不同的图,不论是需要调整“随机数种子”,还是要改变“描述文本”,都得在命令行中完成,遇到文本特别长的时候,非常不方便。

有没有什么方法,可以让 ML Stable Diffusion 的生成图片,使用起来方便些呢?

为 ML Stable Diffusion 编写一个 Web UI

在以往和 Python 相关的内容里,我提到过 gradio 这个有趣的工具,能够为 Python 应用,快速创建简洁美观的 Web 界面。Huggingface 中非常多的应用界面都是用它完成的。

Python 应用 WebUI 搭建神器:Gradio

为了解决上面的问题,我们可以用它来创建一个 Web 界面,把 ML Stable Diffusion 的图片生成和 Web 界面“绑定”到一起。实现代码很简单,不到 100 行:

import python_coreml_stable_diffusion.pipeline as pipeline

import gradio as gr
from diffusers import StableDiffusionPipeline

def init(args):
    pipeline.logger.info("Initializing PyTorch pipe for reference configuration")
    pytorch_pipe = StableDiffusionPipeline.from_pretrained(args.model_version,
                                                           use_auth_token=True)

    user_specified_scheduler = None
    if args.scheduler is not None:
        user_specified_scheduler = pipeline.SCHEDULER_MAP[
            args.scheduler].from_config(pytorch_pipe.scheduler.config)

    coreml_pipe = pipeline.get_coreml_pipe(pytorch_pipe=pytorch_pipe,
                                  mlpackages_dir=args.i,
                                  model_version=args.model_version,
                                  compute_unit=args.compute_unit,
                                  scheduler_override=user_specified_scheduler)


    def infer(prompt, steps):
        pipeline.logger.info("Beginning image generation.")
        image = coreml_pipe(
            prompt=prompt,
            height=coreml_pipe.height,
            width=coreml_pipe.width,
            num_inference_steps=steps,
        )
        images = []
        images.append(image["images"][0])
        return images


    demo = gr.Blocks()

    with demo:
        gr.Markdown(
            "<center><h1>Core ML Stable Diffusion</h1>Run Stable Diffusion on Apple Silicon with Core ML</center>")
        with gr.Group():
            with gr.Box():
                with gr.Row():
                    with gr.Column():
                        with gr.Row():
                            text = gr.Textbox(
                                label="Prompt",
                                lines=11,
                                placeholder="Enter your prompt",
                            )
                        with gr.Row():
                            btn = gr.Button("Generate image")
                        with gr.Row():
                            steps = gr.Slider(label="Steps", minimum=1,
                                            maximum=50, value=10, step=1)
                    with gr.Column():
                        gallery = gr.Gallery(
                            label="Generated image", elem_id="gallery"
                        )

            text.submit(infer, inputs=[text, steps], outputs=gallery)
            btn.click(infer, inputs=[text, steps], outputs=gallery)

    demo.launch(debug=True, server_name="0.0.0.0")


if __name__ == "__main__":
    parser = pipeline.argparse.ArgumentParser()

    parser.add_argument(
        "-i",
        required=True,
        help=("Path to input directory with the .mlpackage files generated by "
              "python_coreml_stable_diffusion.torch2coreml"))
    parser.add_argument(
        "--model-version",
        default="CompVis/stable-diffusion-v1-4",
        help=
        ("The pre-trained model checkpoint and configuration to restore. "
         "For available versions: https://huggingface.co/models?search=stable-diffusion"
         ))
    parser.add_argument(
        "--compute-unit",
        choices=pipeline.get_available_compute_units(),
        default="ALL",
        help=("The compute units to be used when executing Core ML models. "
              f"Options: {pipeline.get_available_compute_units()}"))
    parser.add_argument(
        "--scheduler",
        choices=tuple(pipeline.SCHEDULER_MAP.keys()),
        default=None,
        help=("The scheduler to use for running the reverse diffusion process. "
             "If not specified, the default scheduler from the diffusers pipeline is utilized"))

    args = parser.parse_args()
    init(args)

我们将上面的代码保存为 web.py,同样放在项目的 python_coreml_stable_diffusion 目录中。然后执行命令:

python -m python_coreml_stable_diffusion.web -i ./models --compute-unit ALL

命令执行后,我们将得到类似下面的日志:

WARNING:coremltools:Torch version 1.13.0 has not been tested with coremltools. You may run into unexpected errors. Torch 1.12.1 is the most recent version that has been tested.
INFO:python_coreml_stable_diffusion.pipeline:Initializing PyTorch pipe for reference configuration
Fetching 16 files: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████| 16/16 [00:00<00:00, 16396.01it/s]
INFO:python_coreml_stable_diffusion.pipeline:Removed PyTorch pipe to reduce peak memory consumption
INFO:python_coreml_stable_diffusion.pipeline:Loading Core ML models in memory from ./models
INFO:python_coreml_stable_diffusion.coreml_model:Loading text_encoder mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Loading ./models/Stable_Diffusion_version_CompVis_stable-diffusion-v1-4_text_encoder.mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Done. Took 4.4 seconds.
INFO:python_coreml_stable_diffusion.coreml_model:Loading unet mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Loading ./models/Stable_Diffusion_version_CompVis_stable-diffusion-v1-4_unet.mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Done. Took 73.5 seconds.
INFO:python_coreml_stable_diffusion.coreml_model:Loading a CoreML model through coremltools triggers compilation every time. The Swift package we provide uses precompiled Core ML models (.mlmodelc) to avoid compile-on-load.
INFO:python_coreml_stable_diffusion.coreml_model:Loading vae_decoder mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Loading ./models/Stable_Diffusion_version_CompVis_stable-diffusion-v1-4_vae_decoder.mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Done. Took 6.0 seconds.
INFO:python_coreml_stable_diffusion.coreml_model:Loading safety_checker mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Loading ./models/Stable_Diffusion_version_CompVis_stable-diffusion-v1-4_safety_checker.mlpackage
INFO:python_coreml_stable_diffusion.coreml_model:Done. Took 1.9 seconds.
INFO:python_coreml_stable_diffusion.pipeline:Done.
INFO:python_coreml_stable_diffusion.pipeline:Initializing Core ML pipe for image generation
INFO:python_coreml_stable_diffusion.pipeline:Stable Diffusion configured to generate 512x512 images
INFO:python_coreml_stable_diffusion.pipeline:Done.
Running on local URL:  http://0.0.0.0:7860

To create a public link, set `share=True` in `launch()`.

前半段日志是不是很熟悉,和我们运行模型进行验证时,基本一致。但是在日志的结束处,我们看到程序启动了 Web 服务,并监听了 7860 端口。打开浏览器,访问这个地址,我们就能看到预期中的 Web UI 啦。完整的项目代码,可以参考 GitHub 的提交。

一个简洁美观的 Web UI

都能看到界面了,不试一试是不是说不过去,我这里简单输入“colorful startrails” (绚丽星轨),然后点击 “Generate image” ,等待程序进行图片生成,图片生成完毕,将出现在右侧的 “Generated image” 图片展示框内。

测试 “colorful startrails” 图片生成

是不是还挺方便的,想要生成图片只需要调整文本框中的 “prompt” 文本,然后点击 “Generate image” ,等待结果展示在页面上就行了,不用去调整命令行,也不用去翻找文件夹里的图片了。并且,因为我们将程序当服务运行了起来,被模型加载只需要一次,不再需要像上文一样,每次生成图片都要先加载模型,再进行计算,能节约不少时间。

其他:一个低级 Bug

使用过其他版本的图片生成模型的同学,手里一定有“大段咒语”,当我们将超级长的咒语扔到 ML Stable Diffusion 中的时候,大概率会遇到类似下面的报错:

Traceback (most recent call last):
  File "/Users/soulteary/anaconda3/envs/coreml_stable_diffusion2/lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/Users/soulteary/anaconda3/envs/coreml_stable_diffusion2/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/Users/soulteary/ml-stable-diffusion/python_coreml_stable_diffusion/pipeline.py", line 534, in <module>
    main(args)
  File "/Users/soulteary/ml-stable-diffusion/python_coreml_stable_diffusion/pipeline.py", line 485, in main
    out_path = get_image_path(args)
  File "/Users/soulteary/ml-stable-diffusion/python_coreml_stable_diffusion/pipeline.py", line 444, in get_image_path
    os.makedirs(out_folder, exist_ok=True)
  File "/Users/soulteary/anaconda3/envs/coreml_stable_diffusion2/lib/python3.8/os.py", line 223, in makedirs
    mkdir(name, mode)
OSError: [Errno 63] File name too long: './output/.........'

想要避免这个问题,只有两个方法:

  1. 缩短你的 Prompt 文本长度
  2. 修改代码,避免出现超级长的文本

关于如何用代码解决这个问题,我在 GitHub 的这个 PR 中有提到,感兴趣的同学可以自行“复制粘贴”,来修正这个问题。或者,等等看官方是否会合并这个请求,更新程序版本即可解决问题 😄

最后

这篇文章就先写到这里啦。关于 Apple Mac 生态和模型的话题,其实还有不少可以聊的东西,希望后面有机会能够慢慢展开。

–EOF


我们有一个小小的折腾群,里面聚集了一些喜欢折腾的小伙伴。

在不发广告的情况下,我们在里面会一起聊聊软硬件、HomeLab、编程上的一些问题,也会在群里不定期的分享一些技术沙龙的资料。

喜欢折腾的小伙伴,欢迎阅读下面的内容,扫码添加好友。

  • 关于“交友”的一些建议和看法
  • 添加好友,请备注实名和公司或学校、注明来源和目的,否则不会通过审核。
  • 关于折腾群入群的那些事

本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)

本文作者: 苏洋

创建时间: 2022年12月10日
统计字数: 22672字
阅读时间: 46分钟阅读
本文链接: https://soulteary.com/2022/12/10/play-the-stable-diffusion-model-on-macbook-devices-with-m1-and-m2-chips.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/78414.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

传感器和变送器有什么区别?工业网关能用吗?

传感器和变送器在自动控制领域都有重要作用&#xff0c;但很容易混淆掉&#xff0c;两者有区别也有联系。 传感器是可以将感受到的信息转换成电信号或者其他信号&#xff0c;如将温度、压力、物料、气体等信息转换成电信号&#xff0c;从而使得这些数据可以网络中传输。 变送器…

软件测试必须知道的方法和知识

“软件测试技术是软件开发过程中的一个重要组成部分&#xff0c;是贯穿整个软件开发生命周期、对软件产品&#xff08;包括阶段性产品&#xff09;进行验证和确认的活动过程&#xff0c;其目的是尽快尽早地发现在软件产品中所存在的各种问题——与用户需求、预先定义的不一致性…

C++ 实现前缀树

一 、前缀树是什么 前缀树是一种查找结构&#xff0c;常用于指定字符串或是数组、线性表等连续信息的存储和查找。他的作用类似于哈希表&#xff0c;但是它相对于哈希表来说&#xff0c;限制更多&#xff0c;通用性较差&#xff0c;但是它的功能更加强大&#xff0c;可定制性也…

c#入门-字段类型访问权限低于字段本身

字段类型访问权限低于字段本身 现在假设你有一个小兵类&#xff0c;他的访问权限是仅限当前程序集。 internal class 小兵 {public int hp 12;public int atk 10;public int def 5; }然后声明一个兵营&#xff0c;用来创造小兵 public class 兵营 {public 小兵 模板;publ…

深度学习课件-实验1_PyTorch基本操作实验

文章目录一、Pytorch基本操作考察1.11.21.3二、动手实现 logistic 回归2.12.2三、动手实现softmax回归3.13.2一、Pytorch基本操作考察 使用 &#x1d413;&#x1d41e;&#x1d427;&#x1d42c;&#x1d428;&#x1d42b; 初始化一个 &#x1d7cf;&#x1d7d1; 的矩阵 &a…

第五、六章

第五章程序控制结构 5.1switch分支结构 每一个分支结构最后要记得加break;表示退出。 import java.util.Scanner; public class Switch01 { //编写一个 main 方法 public static void main(String[] args) { /* 请编写一个程序&#xff0c;该程序可以接收一个字符&#xff0…

我逛遍各大论坛,分享这份大厂招聘总结:涵盖Java岗位95%+真题

我们程序员这一群体&#xff0c;大家都知道最好的涨薪方法是通过跳槽&#xff0c;在你把一个公司的精华都吸收完之后&#xff0c;有追求的肯定会跳去更好的公司发展自己&#xff0c;特别在金三银四&#xff0c;金九银十这样的招聘旺季里 &#xff0c;会有很多需要准备的面试会有…

Snort入侵检测系统使用示例

1998年&#xff0c;Martin Roesch用C语言开发了开源的入侵检测系统Snort。现如今Snort已发展成为一个具有多平台、实时流量分析、网络IP数据包记录等特性的强大的网络入侵检测/防御系统&#xff0c;是世界最顶尖的开源入侵检测系统。Snort IDS利用一系列的规则去定义恶意网络活…

Qt-数据库开发-QDataWidgetMapper(5)

Qt-数据库开发-使用QDataWidgetMapper将数据库数据映射到小部件 文章目录Qt-数据库开发-使用QDataWidgetMapper将数据库数据映射到小部件1、概述2、实现效果3、主要代码4、完整源代码更多精彩内容&#x1f449;个人内容分类汇总 &#x1f448;&#x1f449;数据库开发 &#x1…

MYSQL数据库-复合查询

MYSQL数据库-复合查询零、前言一、基本查询二、多表查询三、自连接四、子查询1、单行子查询2、多行子查询3、多列子查询3、在from子句中使用子查询五、合并查询1、union2、union all零、前言 本章主要讲解学习MYSQL数据库中的复合查询&#xff0c;前面我们讲解的mysql表的查询都…

嵌入式分享合集119

一、传感器的数据处理算法 在传感器使用中&#xff0c;我们常常需要对传感器数据进行各种整理&#xff0c;让应用获得更好的效果&#xff0c;以下介绍几种常用的简单处理方法&#xff1a; 加权平滑&#xff1a;平滑和均衡传感器数据&#xff0c;减小偶然数据突变的影响。 抽取…

502问题怎么排查?

刚工作那会&#xff0c;有一次&#xff0c;上游调用我服务的老哥说&#xff0c;你的服务报"502错误了&#xff0c;快去看看是为什么吧"。 当时那个服务里正好有个调用日志&#xff0c;平时会记录各种200,4xx状态码的信息。于是我跑到服务日志里去搜索了一下502这个数…

【负荷预测】基于贝叶斯网络的考虑不确定性的短期电能负荷预测(Python代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

408 考研《操作系统》第二章第四节:进程同步和进程互斥

文章目录教程1. 进程同步2. 进程互斥3. 总结4. 进程互斥的软件实现方法4.1 单标志法4.2 双标志先检查法4.3 双标志后检查法4.4 Peterson算法4.5 总结5. 进程互斥的硬件实现方法5.1 中断屏蔽方法5.2 TestAndSet指令5.3 Swap指令5.4 总结教程 进程同步和进程互斥 https://www.bi…

【OpenCV学习】第11课:图像金字塔 - 上采样与降采样(高斯金字塔,放大与缩小图像)

仅自学做笔记用,后续有错误会更改 理论 参考文章链接:https://blog.csdn.net/qq_54185421/article/details/124350723 图像金字塔的概念&#xff1a; 从上往下&#xff08;采样点越来越多&#xff09;&#xff1a;上采样 从下往上&#xff08;采样点越来越少&#xff09;&a…

代码随想录刷题|LeetCode 503.下一个更大元素II 42. 接雨水 84.柱状图中最大的矩形

目录 503.下一个更大元素II 思路 下一个更大元素|| 42. 接雨水 思路 双指针法 动态规划 单调栈 接雨水 双指针法 动态规划 单调栈 84.柱状图中最大的矩形 思路 柱状图最大的矩形 动态规划 单调栈 503.下一个更大元素II 题目链接&#xff1a;力扣 思路 与 739. 每日温度 基本相…

STM32 | hex文件、bin文件、axf文件的区别?

已剪辑自: https://mp.weixin.qq.com/s/1EQRooYYpDeKvHpqguik6w 在STM32开发中&#xff0c;经常会碰到hex文件、bin文件与axf文件&#xff0c;这些都是可以烧写到板子里运行的文件。这三个文件有什么区别呢&#xff1f;在这之前&#xff0c;先来一起回顾一下C语言编译的过程&a…

详解c++---模板(初阶)

这里写目录标题为什么会有模板函数模板如何解决类型不同而导致模板无法实例化的问题类的模板为什么会有模板 c语言在面对同一个功能不同的类型的数据时得创建出来多个不同名的函数来依次达到目的&#xff0c;比如说我们下面的代码&#xff1a; #include<stdio.h> int a…

计算机毕业设计ssm+vue基本微信小程序的手机预约维修系统

项目介绍 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势&#xff1a;对于电脑维修预约当然也不能排除在外,随着网络技术的不断成熟,带动了电脑维修预约,它彻底改变了过去传统的管理方式,不仅使服务管理难度变低了,还提升了管理的灵活…

通俗理解数据治理之主数据

1. 定义 1&#xff09;国家标准GB/T 36073-2018 《数据管理能力成熟度评估模型》中对主数据的定义&#xff1a;主数据是组织中需 要跨系统、跨部门进行共享的核心业务实体数据。 2&#xff09;IBM 公司在其有关主 数据管理的红皮书《Master Data Manangement:Rapid Deploymen…