当前位置:AIGC资讯 > AIGC > 正文

stable diffusion+LangChain+LLM自动生成图片

最近都在研究和学习stable diffusion和langchain的相关知识,并且看到stable diffusion也是有类似于ChatGLM的api调用方式,那在想有没有可能将stable diffusion也集成到langchain中来呢?看到网上资料比较多的是可以借助chatgpt来辅助stable diffusion提示词的生成,本文就基于此思路来尝试利用LLM+LangChain+stable diffusion实现一句话自动生成图片的功能。

步骤

扩充提示词

使用OpenAI来生成提示词

参照“[AI协同打工,ChatGPT生成提示词+AI作图]”文中的方式生成stable diffusion的提示词

from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
from langchain.chains import LLMChain

_template = """
以下提示用于指导Al绘画模型创建图像。它们包括人物外观、背景、颜色和光影效果,以及图像的主题和风格等各种细节。这些提示的格式通常包括带权重的数字括号,用于指定某些细节的重要性或强调。例如,"(masterpiece:1.4)"表示作品的质量非常重要。以下是一些示例:
1. (8k, RAW photo, best quality, masterpiece:1.2),(realistic, photo-realistic:1.37), ultra-detailed, 1girl, cute, solo, beautiful detailed sky, detailed cafe, night, sitting, dating, (nose blush), (smile:1.1),(closed mouth), medium breasts, beautiful detailed eyes, (collared shirt:1.1), bowtie, pleated skirt, (short hair:1.2), floating hair, ((masterpiece)), ((best quality)),
2. (masterpiece, finely detailed beautiful eyes: 1.2), ultra-detailed, illustration, 1 girl, blue hair black hair, japanese clothes, cherry blossoms, tori, street full of cherry blossoms, detailed background, realistic, volumetric light, sunbeam, light rays, sky, cloud,
3. highres, highest quallity, illustration, cinematic light, ultra detailed, detailed face, (detailed eyes, best quality, hyper detailed, masterpiece, (detailed face), blue hairlwhite hair, purple eyes, highest details, luminous eyes, medium breats, black halo, white clothes, backlighting, (midriff:1.4), light rays, (high contrast), (colorful)

"""

llm = OpenAI(temperature=0)
prompt = PromptTemplate(
    input_variables=["desc"],
    template=_template3,
)

chain = LLMChain(prompt=prompt,llm=llm)

res = chain.run("湖人总冠军")

print(res)

生成的提示词如下:

(masterpiece:1.4), ultra-detailed, 1man, strong, solo, detailed basketball court, detailed stadium, night, standing, celebrating, (fist pump), (smile:1.1), (closed mouth), muscular body, beautiful detailed eyes, (jersey:1.1), shorts, (short hair:1.2), floating hair, (trophy:1.3), (confetti:1.2), (fireworks:1.2), (crowd cheering:1.2), (high contrast), (colorful)

将提示词直接输入到stable diffusion webui中得到结果如下:

格式化输出

为了确保输出的结果可以方便解析,可以再加入一些引导,最终的提示词如下:

_template = """
以下提示用于指导Al绘画模型创建图像。它们包括人物外观、背景、颜色和光影效果,以及图像的主题和风格等各种细节。这些提示的格式通常包括带权重的数字括号,用于指定某些细节的重要性或强调。例如,"(masterpiece:1.4)"表示作品的质量非常重要。以下是一些示例:
1. (8k, RAW photo, best quality, masterpiece:1.2),(realistic, photo-realistic:1.37), ultra-detailed, 1girl, cute, solo, beautiful detailed sky, detailed cafe, night, sitting, dating, (nose blush), (smile:1.1),(closed mouth), medium breasts, beautiful detailed eyes, (collared shirt:1.1), bowtie, pleated skirt, (short hair:1.2), floating hair, ((masterpiece)), ((best quality)),
2. (masterpiece, finely detailed beautiful eyes: 1.2), ultra-detailed, illustration, 1 girl, blue hair black hair, japanese clothes, cherry blossoms, tori, street full of cherry blossoms, detailed background, realistic, volumetric light, sunbeam, light rays, sky, cloud,
3. highres, highest quallity, illustration, cinematic light, ultra detailed, detailed face, (detailed eyes, best quality, hyper detailed, masterpiece, (detailed face), blue hairlwhite hair, purple eyes, highest details, luminous eyes, medium breats, black halo, white clothes, backlighting, (midriff:1.4), light rays, (high contrast), (colorful)

仿照之前的提示,写一段描写如下要素的提示:
{desc}

你应该仅以 JSON 格式响应,如下所述:
返回格式如下:
{{
  "question":"$YOUR_QUESTION_HERE",
  "answer": "$YOUR_ANSWER_HERE"
}}
确保响应可以被 Python json.loads 解析。
"""

最终生成的结果如下:

{
  "question":"湖人总冠军",
  "answer": "(masterpiece:1.4), ultra-detailed, 1man, strong, solo, detailed basketball court, detailed stadium, night, standing, celebrating, (fist pump), (smile:1.1), (closed mouth), muscular body, beautiful detailed eyes, (jersey:1.1), shorts, (short hair:1.2), floating hair, (trophy:1.3), (confetti:1.2), (fireworks:1.2), (crowd cheering:1.2), (high contrast), (colorful)"
}

这样我们就可以比较方便的解析数据了

# 解析json
import json
result = json.loads(res)
print("result:",result)
result["answer"]

使用ChatGLM来生成提示词

llm = ChatGLM(temperature=0.1,history=prompt_history)
prompt = PromptTemplate(
    input_variables=["desc"],
    template=_template,
)

chain = LLMChain(prompt=prompt,llm=llm)

ChatGLM基于[ChatGLM 集成进LangChain工具]的封装

最终生成的效果不是很好,这里就不展示了。主要问题包括:1.没有按照指令生成json格式;2.生成的描述很多都是中文形式的。

[MagicPrompt]自动续写SD提示词

from transformers import AutoModelForCausalLM, AutoTokenizer,pipeline

text_refine_tokenizer = AutoTokenizer.from_pretrained("Gustavosta/MagicPrompt-Stable-Diffusion")
text_refine_model = AutoModelForCausalLM.from_pretrained("Gustavosta/MagicPrompt-Stable-Diffusion")
text_refine_gpt2_pipe = pipeline("text-generation", model=text_refine_model, tokenizer=text_refine_tokenizer, device="cpu")

text = "湖人总冠军"

refined_text = text_refine_gpt2_pipe(text)[0]["generated_text"]

print(refined_text)

输出如下:

湖人总冠军 港子 Imoko Ikeda, Minaba hideo, Yoshitaka Amano, Ruan Jia, Kentaro Miura, Artgerm, post processed, concept

纯英文输入,最终的输出如下:

lakers championship winner trending on artstation, painted by greg rutkowski

可见MagicPrompt对于中文输入不是很友好,如果想使用的话,需要将输入先翻译成英文。

调用stable diffusion的api生成图片

参考:[Mikubill/sd-webui-controlnet]。主要代码如下:

import cv2
import requests
import base64
import re

ENDPOINT = "http://localhost:7860"

def do_webui_request(url, **kwargs):
    reqbody = {
        "prompt": "best quality, extremely detailed",
        "negative_prompt": "longbody, lowres, bad anatomy, bad hands, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality",
        "seed": -1,
        "subseed": -1,
        "subseed_strength": 0,
        "batch_size": 1,
        "n_iter": 1,
        "steps": 15,
        "cfg_scale": 7,
        "width": 512,
        "height": 768,
        "restore_faces": True,
        "eta": 0,
        "sampler_index": "Euler a",
        "controlnet_input_images": [],
        "controlnet_module": 'canny',
        "controlnet_model": 'control_canny-fp16 [e3fe7712]',
        "controlnet_guidance": 1.0,
        
    }
    reqbody.update(kwargs)
    print("reqbody:",reqbody)
    r = requests.post(url, json=reqbody)
    return r.json()

调用api
import io
from PIL import Image

prompt = "a cute cat"
resp = do_webui_request(
    url=ENDPOINT + "/sdapi/v1/txt2img",
    prompt=prompt,
)

image = Image.open(io.BytesIO(base64.b64decode(resp["images"][0])))
display(image)

如果需要使用api功能,stable diffusion 需要开启api功能,启动时需要加上--api

结合stable diffusion+LangChain+LLM自动生成图片

stable diffusion+LangChain+OpenAI

封装实现
import io, base64
import uuid
from PIL import Image

class RefinePrompt:
  
    llm = OpenAI(temperature=0)
    prompt = PromptTemplate(
        input_variables=["desc"],
        template=_template,
    )

    chain = LLMChain(prompt=prompt,llm=llm)
    def run(self,text):
        res = self.chain.run(text)
        # 解析json
        result = json.loads(res)
        return result["answer"]

class T2I:
    def __init__(self):
        self.text_refine = RefinePrompt()
        
    def inference(self, text):
        image_filename = os.path.join('output/image', str(uuid.uuid4())[0:8] + ".png")
        refined_text = self.text_refine.run(text)
        print(f'{text} refined to {refined_text}')
        resp = do_webui_request(
            url=ENDPOINT + "/sdapi/v1/txt2img",
            prompt=refined_text,
        )
        image = Image.open(io.BytesIO(base64.b64decode(resp["images"][0])))
        image.save(image_filename)
        print(f"Processed T2I.run, text: {text}, image_filename: {image_filename}")
        return image_filename,image

使用封装的类,并且展示图片(在python的notebook中展示)
t2i = T2I()
image_filename,image = t2i.inference("湖人总冠军")
print("filename:",image_filename)
display(image)

stable diffusion+MagicPrompt

封装实现
from transformers import AutoModelForCausalLM, AutoTokenizer, CLIPSegProcessor, CLIPSegForImageSegmentation
from transformers import pipeline, BlipProcessor, BlipForConditionalGeneration, BlipForQuestionAnswering
import io, base64
import uuid
from PIL import Image

class T2I:
    def __init__(self, device):
        print("Initializing T2I to %s" % device)
        self.device = device
        self.text_refine_tokenizer = AutoTokenizer.from_pretrained("Gustavosta/MagicPrompt-Stable-Diffusion")
        self.text_refine_model = AutoModelForCausalLM.from_pretrained("Gustavosta/MagicPrompt-Stable-Diffusion")
        self.text_refine_gpt2_pipe = pipeline("text-generation", model=self.text_refine_model, tokenizer=self.text_refine_tokenizer, device=self.device)
        
    def inference(self, text,image_path=None):
        image_filename = os.path.join('output/image', str(uuid.uuid4())[0:8] + ".png")
        refined_text = self.text_refine_gpt2_pipe(text)[0]["generated_text"]
        print(f'{text} refined to {refined_text}')
        resp = do_webui_request(
            url=ENDPOINT + "/sdapi/v1/txt2img",
            prompt=refined_text,
            controlnet_input_images=[readImage(image_path) if image_path else None], 
        )
        image = Image.open(io.BytesIO(base64.b64decode(resp["images"][0])))
        image.save(image_filename)
        print(f"Processed T2I.run, text: {text}, image_filename: {image_filename}")
        return image_filename,image


使用封装的类,并且展示图片(在python的notebook中展示)
t2i = T2I("cpu")
image_filename,image = t2i.inference("lakers championship")
print("filename:",image_filename)
display(image)

总结

本文使用了stable diffusion+LangChain+LLM来实现一句话自动生成图片的功能,虽然最终的效果还不是很满意,但是可以看出来方案可行的。如果还需要优化效果的话,可以尝试:1.针对特不同模型需要输入该模型的更多的示例来辅助和优化最终模型的生成;2.尝试结合controlnet来更好的控制最终图片的生成。

ps:在学习和参考[Mikubill/sd-webui-controlnet]的代码时,发现了其中有一个模仿“Visual ChatGPT”的示例代码,还挺有意思的,接下来也会进一步分析其实现,敬请期待。

总结

### 文章内容总结
本文探讨了如何利用Stable Diffusion、LangChain和大型语言模型(如OpenAI或ChatGLM)来实现一句话自动生成图片的功能。主要步骤包括:
1. **扩充提示词**:
- **使用OpenAI生成提示词**:通过LangChain工具 结合 OpenAI 的API,根据输入的描述生成Stable Diffusion的提示词。示例中展示了如何为“湖人总冠军”主题生成详细的图像提示词。
- **格式化输出**:为了便于后续解析,通过调整模板确保生成的提示词以JSON格式返回,从而简化数据处理过程。
- **尝试ChatGLM**:虽然尝试了使用ChatGLM进行提示词生成,但由于结果未完全符合预期(如未严格生成JSON格式、生成的描述含较多中文),未做详细展示。
- **MagicPrompt**:利用专门的MagicPrompt模型对简单的输入进行优化,生成更适合Stable Diffusion的提示词。但对于中文输入效果不佳,建议翻译后使用。
2. **调用Stable Diffusion的API生成图片**:
- 参考`sd-webui-controlnet`项目,通过编写一个Python脚本来封装API调用逻辑,实现根据提示词生成图片。
- 需要确保Stable Diffusion已配置并开启了API服务。
3. **结合Stable Diffusion+LangChain+LLM自动生成图片**:
- 通过封装类实现完整的流程,包括文本到图像的提示词转换和图像生成两部分。
- 展示了如何通过定义好的类,轻松实现基于任意描述生成对应图像,并保存展示。
### 展望与优化建议
虽然当前的实现已具备基本功能,但还有以下优化建议:
- **优化提示词生成**:针对不同模型提供更详细、更贴切的示例,以提高最终图像的质量。
- **结合ControlNet**:通过ControlNet进一步控制图像的细节和风格,从而实现更精准的图像生成效果。
- **探索更多模型**:尝试将不同的大模型或特定领域的模型引入生成流程,以扩展生成图像的种类和风格。
文章还提及了对Visual ChatGPT示例代码的兴趣,预示着未来可能对这一新兴领域进行更深入的研究与探索。

更新时间 2024-08-23