Stable Diffusion 3震撼发布,尝鲜体验2-webui和API接口
laohaibao666
2024年06月16日 16:45

2024年6月12日晚,Stability AI 官方如期发布开源其Stable Diffusion 3 Medium 模型,该模型是其迄今为止最先进的文本到图像开放模型,包含 20 亿个参数。

Stable Diffusion 3 Medium 模型的尺寸较小,这使得它能够在消费级 PC 和笔记本电脑以及企业级 GPU 上良好运行。同时,它的这种尺寸特点也使其有潜力成为文本到图像模型的下一个标准。

主要特性与功能:

  • 图像质量改进:该模型在图像质量上有显著提升,能够生成更高质量、更细腻的图像。

  • 复杂提示理解:改进了对复杂文本提示的理解能力,能够更准确地将文本描述转换为图像。

  • 资源效率:在资源使用方面进行了优化,能够在更少的计算资源下实现较高的性能。

以上是官方提供的10个例子的图片。

上篇文章Stable Diffusion 3震撼发布,尝鲜体验​ 使用官方提供的Stable Diffusion 3 Medium模型 以及ComfyUI_windows 来使用。有的小伙伴可以有想法了,能不能搞个类似stable-diffusion-webui webui以及接口方式对外提供呢,这样就有更多扩展性功能了。

目前stable-diffusion 3 刚开源,后面stable-diffusion-webui 以及其他第三方套壳软件一定会实现这个功能了。不过目前我了解到stable-diffusion-webui 还没有整合SD3功能。其实官方stableAI 官方处理提供Stable Diffusion 3 Medium 模型之外,还提供了一个叫做stable-diffusion-3-medium-diffusers模型

你可以理解就是通过接口方式提供SD3调用的模型。

今天就带大家使用这个模型 通过编写代码的方式来实现webui 以及API 接口调用方式。

1.模型下载

模型首先需要在huggingface 官方网站下载。

下载地址https://huggingface.co/stabilityai/stable-diffusion-3-medium-diffusers#/

这里注意需要有huggingface 官方账号登录并且填写相关授权才可以下载模型,不是免登录就可以下载模型的,这里需要注意一下。

除了官方提供的这个镜像外,有好心的网友将这个模型也克隆了一份。模型下载地址是

https://huggingface.co/v2ray/stable-diffusion-3-medium-diffusers#/

这样就不需要登录授权直接从huggingface 官方网站下载模型了。如果你的网络不好(不能访问huggingface )也可以从国内hf-mirror.com网站上下载这个免登录模型了

地址:https://hf-mirror.com/v2ray/stable-diffusion-3-medium-diffusers

将以上模型下载到本地,具体下载就不详细展开了。下载本地电脑保存模型,比如我电脑上。

2.编写代码

首先我们需要实现webui 方式访问stable-diffusion-3-medium-diffusers,这里我们主要是借助了huggingface 提供的diffusers 依赖包

diffusers 下载地址

https://github.com/huggingface/diffusers.git

目前它最新的版本V0.29.0版本已经支持了SD3模型了。

所以我们借助这个diffusers 依赖包编写代码。 编写的代码如下

app2.py

import gradio as gr

import numpy as np

import random

import torch

from diffusers import StableDiffusion3Pipeline

device = "cuda" if torch.cuda.is_available() else "cpu"

dtype = torch.float16

#repo = "stabilityai/stable-diffusion-3-medium-diffusers"

repo = "F:\\AI\\stable-diffusion-3-medium-diffusers"

pipe = StableDiffusion3Pipeline.from_pretrained(

  repo,

  text_encoder_3=None,

  tokenizer_3=None,

  torch_dtype=torch.float16,

)

print(pipe)

MAX_SEED = np.iinfo(np.int32).max

MAX_IMAGE_SIZE = 1344

# @spaces.GPU

def infer(

  prompt,

  negative_prompt,

  seed,

  randomize_seed,

  width,

  height,

  guidance_scale,

  num_inference_steps,

  progress=gr.Progress(track_tqdm=True),

):

  if randomize_seed:

    seed = random.randint(0, MAX_SEED)

  generator = torch.Generator().manual_seed(seed)

  pipe.enable_sequential_cpu_offload()

  # pipe.enable_model_cpu_offload()

  image = pipe(

    prompt=prompt,

    negative_prompt=negative_prompt,

    guidance_scale=guidance_scale,

    num_inference_steps=num_inference_steps,

    width=width,

    height=height,

    generator=generator,

 ).images[0]

  return image, seed

examples = [

  "A cat holding a sign that says hello world",

  "A cute dog wearing hoodie",

  "A beautiful girl waving hand ",

]

css = """

#col-container {

 margin: 0 auto;

 max-width: 580px;

}

"""

with gr.Blocks(css=css) as demo:

  with gr.Column(elem_id="col-container"):

    gr.Markdown(f"""

   # Stable Diffusion 3 Medium (Low VRAM )

    Tested on Nivida RTX 3060 6GB with system RAM 16GB

   """)

    with gr.Row():

      prompt = gr.Text(

        label="Prompt",

        show_label=False,

        max_lines=1,

        placeholder="Enter your prompt",

        container=False,

     )

      run_button = gr.Button("Run", scale=0)

    result = gr.Image(label="Result", show_label=False)

    with gr.Accordion("Advanced Settings", open=False):

      negative_prompt = gr.Text(

        label="Negative prompt",

        max_lines=1,

        placeholder="Enter a negative prompt",

     )

      seed = gr.Slider(

        label="Seed",

        minimum=0,

        maximum=MAX_SEED,

        step=1,

        value=0,

     )

      randomize_seed = gr.Checkbox(label="Randomize seed", value=True)

      with gr.Row():

        width = gr.Slider(

          label="Width",

          minimum=256,

          maximum=MAX_IMAGE_SIZE,

          step=64,

          value=1024,

       )

        height = gr.Slider(

          label="Height",

          minimum=256,

          maximum=MAX_IMAGE_SIZE,

          step=64,

          value=1024,

       )

      with gr.Row():

        guidance_scale = gr.Slider(

          label="Guidance scale",

          minimum=0.0,

          maximum=10.0,

          step=0.1,

          value=5.0,

       )

        num_inference_steps = gr.Slider(

          label="Number of inference steps",

          minimum=1,

          maximum=50,

          step=1,

          value=28,

       )

    gr.Examples(examples=examples, inputs=[prompt])

  gr.on(

    triggers=[run_button.click, prompt.submit, negative_prompt.submit],

    fn=infer,

    inputs=[

      prompt,

      negative_prompt,

      seed,

      randomize_seed,

      width,

      height,

      guidance_scale,

      num_inference_steps,

   ],

    outputs=[result, seed],

 )

demo.launch()

3 安装依赖包

以上代码是python编写的,所以我们需要安装python 运行环境。我电脑上使用的python 环境是3.10版本。 关于python 环境安装,这里就不做详细开展了。 不会的小伙伴可以搜索引擎搜索一下python 环境安装。下面重点讲解本次环境安装

# 创建python虚拟环境

python -m venv venv

# 激活虚拟环境

venv\Scripts\activate.bat

有的小伙伴可能有疑惑了?为什么创建虚拟环境呢,我电脑上安装python后直接运行不可以吗? 当然是可以的。我们这里安装虚拟环境主要是我本地电脑运行python 程序比较多,大家也知道python 版本太多。会导致包冲突,今天安装一个程序运行好好的,下个程序运行依赖另外的依赖包,这样会把前面安装依赖包卸载重新安装,导致之前的配置好的程序又运行不了了。所以建议大家使用python虚拟机环境。

当前程序运行目录下进入虚拟机环境

下一步我们需要安装依赖包。

pip install torch==2.2.0 torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 --upgrade

pip install bitsandbytes==0.43.1 --upgrade

pip install diffusers==0.29.0

pip install gradio transformers accelerate sentencepiece protobuf

将以上依赖包在虚拟机上安装完成。其中torch+cu121 这个依赖包非常大,下载时间比较长(主要是依赖你的网络环境),当然你也可以离线下载

提前先将torch-2.2.0+cu121-cp310-cp310-win_amd64.whl 包提前下载下来。我本地电脑上就保存一份(疑问在线方式下载依赖包并安装很容易网络环境下载失败报错)

提前下载本地 安装的时候只需要输入命令即可。

pip install torch-2.2.0+cu121-cp310-cp310-win_amd64.whl

剩下的依赖包都不大可以直接运行下载并安装。当然如果有的小伙伴遇到下载慢怎么办?

可以借助清华源 加速下载。把上面的pip 安装包改成以下方式

pip install bitsandbytes==0.43.1 --upgrade -i https://pypi.tuna.tsinghua.edu.cn/simple/

pip install diffusers==0.29.0 -i https://pypi.tuna.tsinghua.edu.cn/simple/

pip install gradio transformers accelerate sentencepiece protobuf -i https://pypi.tuna.tsinghua.edu.cn/simple/

也就是所有依赖包屁股后面增加 清华源下载地址。这样速度就上去了。

4.运行程序

我们在上面的依赖包安装好的虚拟机环境下运行

python app2.py

程序启动完成 我们在浏览器输入 以上URL 地址

页面加载成功就是以上界面了。

我们输入提示词测试一下。

bird photography,untitled,in the style of dark black and colorful,(luminous shadows:1.2),flat figuration,high gloss,self-portrait,high detail

页面返回输出结果。有的小伙伴可以觉的效果不咋的。之前代码中我们没有使用text_encoder_3 和tokenizer_3 所以效果不太好。

如果你电脑显卡比较好,超过16GB显存,去掉一下代码。(我加这2行代码是使用低配文本模型加载减少报显存内存溢出)

以上我们就完成了非常简单的webui 方式实现SD3 文本生成图像模型。

5.api 接口方式

运行环境和上面依赖环境类似这里就不说安装了。 编写代码如下

app5.py

from fastapi import FastAPI, Form

from fastapi.responses import JSONResponse

import base64

from io import BytesIO

import torch

from diffusers import StableDiffusion3Pipeline

import random

import numpy as np

from PIL import Image

app = FastAPI()

pipe = StableDiffusion3Pipeline.from_pretrained("F:\\AI\\stable-diffusion-3-medium-diffusers", torch_dtype=torch.float16,text_encoder_3=None,tokenizer_3=None,)

pipe = pipe.to("cuda")

@app.post("/generate_image")

async def generate_image(prompt: str = Form(...),

            negative_prompt: str = Form("bad quality, poor quality, doll, disfigured, jpg, toy, bad anatomy, missing limbs, missing fingers, 3d, cgi"),

            num_inference_steps: int = Form(28),

            guidance_scale: float = Form(7.0),

            width: int = Form(1024),

            height: int = Form(1024)):

  MAX_SEED = np.iinfo(np.int32).max

  seed = random.randint(0, MAX_SEED)

  generator = torch.Generator().manual_seed(seed)

  image = pipe(prompt,

        negative_prompt=negative_prompt,

        num_inference_steps=num_inference_steps,

        guidance_scale=guidance_scale,

        width=width,

        height=height,

        generator=generator,

        ).images[0]

  buffered = BytesIO()

  image.save(buffered, format="JPEG")

  img_str = base64.b64encode(buffered.getvalue()).decode('utf-8')

  return JSONResponse(content={"image": img_str})

if __name__ == "__main__":

  import uvicorn

  uvicorn.run(app, host="0.0.0.0", port=8000)

客户端代码client2.py

import requests

import base64

from PIL import Image

from io import BytesIO

def generate_image(prompt, negative_prompt=None, num_inference_steps=28, guidance_scale=7.0, width=1024, height=1024):

  """

 Sends a request to the server to generate an image.

 Args:

   prompt (str): The text prompt for image generation.

   negative_prompt (str, optional): The negative prompt for image generation. Defaults to None.

   num_inference_steps (int, optional): The number of inference steps. Defaults to 28.

   guidance_scale (float, optional): The guidance scale. Defaults to 7.0.

   width (int, optional): The width of the generated image. Defaults to 1024.

   height (int, optional): The height of the generated image. Defaults to 1024.

 Returns:

   PIL.Image: The generated image.

 """

  url = "http://127.0.0.1:8000/generate_image" # Replace with your server's address

  data = {

    "prompt": prompt,

    "negative_prompt": negative_prompt,

    "num_inference_steps": num_inference_steps,

    "guidance_scale": guidance_scale,

    "width": width,

    "height": height

 }

  print(data) # Print the data dictionary

  response = requests.post(url, data=data) # Send data as form-encoded data

  if response.status_code == 200:

    image_data = response.json()["image"]

    image_bytes = base64.b64decode(image_data)

    image = Image.open(BytesIO(image_bytes))

    return image

  else:

    print(f"Error: {response.status_code}")

    print(response.text) # Print the response text for more details

    return None

if __name__ == "__main__":

  prompt = "A photo of a cat sitting on a table"

  image = generate_image(prompt)

  if image:

    image.show()

我们在虚拟机环境下执行服务端代码python app5.py

以上步骤启动后我们看到接口程序启动了8000端口的服务。

接下来我们在 client2.py 代码程序目录下启动客户端程序( 这里不需要再虚拟机启动,因为客户端代码依赖包少)

python client2.py 启动后,客户端发起HTTP 请求调用服务端,服务端生成图片推理

当推理完成后,我们在浏览器中就打开了创建的图片

推理完成

这样漂亮的小画猫面坐在桌子上就完成了。

6.总结

我们通过huggingface 提供的diffusers 很容易实现一个webui和API 接口调用来生成SD3 文生图功能。我相信随着时间的推理,更多第三方客户端来实现和整合SD3功能。本次时间比较仓促就写了几个简单DEMO 例子,感兴趣的小伙伴可以持续关注我的文章,我们下个文章见。