首页
Preview

我是如何构建一个AI文本转艺术生成器的

概述

本文是关于我如何在一周内构建 Text2Art.com 的写作。Text2Art 是一款基于 VQGAN+CLIP 的 AI 艺术生成器,可以从文本输入中生成各种艺术形式,如像素艺术、绘画等。本文跟随我的思路,从尝试 VQGAN+CLIP,使用 Gradio 构建简单的用户界面,切换到 FastAPI 来服务模型,最后使用 Firebase 作为队列系统。你可以跳到你感兴趣的部分。

你可以在 text2art.com 上尝试它,这是 源代码(欢迎为该仓库加星)。

大纲

  • 简介
  • 工作原理
  • 使用代码生成 VQGAN+CLIP 艺术
  • 使用 Gradio 制作用户界面
  • 使用 FastAPI 提供 ML 服务
  • 使用 Firebase 作为队列系统

简介

不久前,生成艺术和 NFT 席卷了整个世界。这是在 OpenAI 在文本到图像生成方面取得重大进展之后实现的。今年早些时候,OpenAI 宣布了 DALL-E,这是一种功能强大的文本到图像生成器。为了说明 DALL-E 的工作原理,这些是 DALL-E 生成的图像,文本提示为“一只专业高质量的长颈鹿龙嵌合体插图。一只长颈鹿模仿龙。一只由龙组成的长颈鹿”。

当给出文本提示“一只专业高质量的长颈鹿龙嵌合体插图。一只长颈鹿模仿龙。一只由龙组成的长颈鹿。”时,DALL-E 生成的图像。[Image by OpenAI with MIT license]

不幸的是,DALL-E 并没有发布给公众使用。但幸运的是,DALL-E 背后的模型 CLIP,已经被发布。CLIP 或对比图像-语言预训练是一种多模态网络,它结合了文本和图像。简而言之,CLIP 能够评分图像与字幕之间的匹配程度。这在引导生成器生成完全匹配文本输入的图像方面非常有用。在 DALL-E 中,CLIP 用于排名生成的图像,并输出得分最高的图像(与文本提示最相似的图像)。

CLIP 对图像和字幕进行评分的示例 [Image by Author]

几个月后,一个名为 VQGAN(向量量化 GAN)的新的转换器图像生成器被发布。将 VQGAN 与 CLIP 结合使用可以获得与 DALL-E 类似的质量。自从预训练的 VQGAN 模型公开以来,社区已经创造了许多令人惊叹的艺术作品。

城市港夜景绘画,许多船只的绘画,战争难民的绘画。[Image Generated by Author]

我对这些结果感到非常惊讶,并想与我的朋友分享。但由于不多的人愿意深入了解代码生成艺术,因此我决定制作 Text2Art.com,一个网站,任何人都可以简单地输入提示并快速生成他们想要的图像,而无需查看任何代码。

工作原理

那么 VQGAN+CLIP 是如何工作的呢?简而言之,生成器将生成一张图像,而 CLIP 将测量图像与图像的匹配程度。然后,生成器使用 CLIP 模型的反馈生成更多“准确”的图像。这个过程将进行多次迭代,直到 CLIP 得分足够高,并且生成的图像与文本匹配。我不会在这里讨论VQGAN或CLIP的内部工作,因为这不是本文的重点。但如果你想深入了解VQGAN、CLIP或DALL-E,你可以参考我发现的这些令人惊叹的资源。

X + CLIP

VQGAN+CLIP只是将图像生成器与CLIP组合在一起的示例。但是,你可以将VQGAN替换为任何类型的生成器,具体取决于生成器,它仍然可以非常好地工作。许多X + CLIP的变体已经出现,例如StyleCLIP(StyleGAN + CLIP)、CLIPDraw(使用矢量艺术生成器)、BigGAN + CLIP等等。甚至有一个使用音频而不是图像的AUDIOCLIP

使用StyleCLIP进行图像编辑 [来源:StyleCLIP论文]

用代码生成VQGAN+CLIP艺术品

我一直在使用dribnet的clipit代码库,它将使用VQGAN+CLIP生成艺术品变成了仅需几行简单的代码(更新:clipit已经迁移到pixray)。

建议在Google Colab上运行,因为VQGAN+CLIP需要相当多的GPU内存。这里有一个Colab笔记本,你可以跟随。

首先,如果你在Colab上运行,请确保你更改运行时类型以使用GPU。

更改Colab运行时类型为GPU的步骤。[作者的图片]

接下来,我们需要首先设置代码库和依赖项。

from IPython.utils import io
with io.capture_output() as captured:
  !git clone https://github.com/openai/CLIP
  # !pip install taming-transformers
  !git clone https://github.com/CompVis/taming-transformers.git
  !rm -Rf clipit
  !git clone https://github.com/mfrashad/clipit.git
  !pip install ftfy regex tqdm omegaconf pytorch-lightning
  !pip install kornia
  !pip install imageio-ffmpeg   
  !pip install einops
  !pip install torch-optimizer
  !pip install easydict
  !pip install braceexpand
  !pip install git+https://github.com/pvigier/perlin-numpy

  # ClipDraw deps
  !pip install svgwrite
  !pip install svgpathtools
  !pip install cssutils
  !pip install numba
  !pip install torch-tools
  !pip install visdom

  !pip install gradio

  !git clone https://github.com/BachiLi/diffvg
  %cd diffvg
  # !ls
  !git submodule update --init --recursive
  !python setup.py install
  %cd ..
  
  !mkdir -p steps
  !mkdir -p models

(注意:“!”是google Colab中的特殊命令,它意味着它将在bash中运行命令而不是python”)

安装完库后,我们只需导入clipit并运行以下几行代码即可使用VQGAN+CLIP生成你的艺术品。只需更改文本提示,即可生成图像。此外,你还可以给clipit添加选项,例如迭代次数、宽度、高度、生成器模型、是否要生成视频等等。你可以阅读源代码了解可用选项的更多信息。

使用VQGAN+CLIP生成艺术品的代码

运行代码后,它将生成一张图像。对于每次迭代,生成的图像将更接近文本提示。

基于“水下城市”的较长迭代次数的结果改进。[作者的图片]

更长的迭代

如果你想要生成更长的迭代,只需使用iterations选项并将其设置为所需长度即可。例如,如果你想要运行500次迭代。

clipit.add_settings(iterations=500)

生成视频

由于我们需要为每次迭代生成图像,因此我们可以保存这些图像并创建一个动画,展示AI如何生成图像。要做到这一点,只需在应用设置之前添加make_video=True即可。

clipit.add_settings(make_video=True)

它将生成以下视频。

生成的“水下城市”GIF [作者的图片]

自定义图像大小

你还可以通过添加size=(width, height)选项来修改图像。例如,我们将生成一个分辨率为800x200的横幅图像。请注意,更高的分辨率将需要更高的GPU内存。

clipit.add_settings(size=(800, 200))

使用提示“Fantasy Kingdom #artstation”生成的800x200图像 [作者的图片]

生成像素艺术

clipit还有一个选项可以生成像素艺术。它在幕后使用CLIPDraw渲染器进行一些工程处理,以强制限制调色板颜色、像素化等像素艺术风格。要使用像素艺术选项,只需启用use_pixeldraw=True选项即可。

clipit.add_settings(use_pixeldraw=True)

使用提示“骑士装甲#像素艺术”(左)和“一个中国幻想游戏的世界#像素艺术”(右)生成的图像 [作者的图片]## VQGAN+CLIP 关键词修改器

由于 CLIP 的偏见,将某些关键词添加到提示文本中可能会对生成的图像产生某种效果。例如,将“虚幻引擎”添加到文本提示中往往会生成逼真或高清风格的图像。添加某些网站名称,例如“deviantart”、“artstation”或“flickr”通常会使结果更具美感。我的最爱是使用“artstation”关键词,因为我发现它可以生成最好的艺术品。

关键词比较 [图片由 kingdomakrillic 提供]

此外,你还可以使用关键词来调整艺术风格。例如,关键词“铅笔素描”、“低多边形”甚至是艺术家的名字,例如“Thomas Kinkade”或“James Gurney”。

艺术风格关键词比较。[图片由 kingdomakrillic 提供]

要了解更多关键词的各种效果,你可以查看 kingdomakrillic 的完整实验结果,该结果显示使用相同的 4 个主题的 200 多个关键词结果。

使用 Gradio 构建 UI

我部署 ML 模型的第一个计划是使用 Gradio。Gradio 是一个简化了几行代码就能构建 ML 演示的 Python 库。使用 Gradio,你可以在不到 10 分钟的时间内构建演示。此外,你可以在 Colab 中运行 Gradio,并且它将生成一个使用 Gradio 域的可共享链接。你可以立即与你的朋友或公众分享此链接,让他们尝试你的演示。Gradio 仍然存在一些限制,但我发现当你只想演示单个功能时,它是最合适的库。

Gradio UI [图片由作者提供]

这是我编写的为 Text2Art 应用程序构建简单 UI 的代码。我认为代码相当自说明,但如果你需要更多的解释,你可以阅读 Gradio 文档

构建 Gradio UI 的代码

在 Google Colab 或本地运行此代码后,它将生成一个可共享的链接,使你的演示可公开访问。我发现这非常有用,因为我不需要像在自己的机器上使用 SSH 隧道(如 Ngrok)一样来分享我的演示。此外,Gradio 还提供了一个托管服务,你可以永久托管你的演示,每月仅需 7 美元。

Gradio 演示的可共享链接。[图片由作者提供]

但是,Gradio 仅适用于演示单个功能。创建具有附加功能(例如画廊、登录或仅自定义 CSS)的自定义网站相当受限制或根本不可能。

我能想到的一个快速解决方案是通过将我的演示网站与 Gradio UI 分开来创建。然后,我可以使用 iframe 元素在网站上嵌入 Gradio UI。我最初尝试了这种方法,但后来意识到一个重要的缺点,即我无法个性化需要与 ML 应用程序本身交互的任何部分。例如,输入验证、自定义进度条等等,这些都是 iframe 无法实现的。这就是我决定构建 API 的原因。

使用 FastAPI 提供 ML 模型服务

我一直在使用 FastAPI 而不是 Flask 快速构建我的 API。主要原因是我发现 FastAPI 的编写速度更快(代码更少),而且它还自动生成文档(使用 Swagger UI),这使我可以使用基本的 UI 测试 API。此外,FastAPI 支持异步函数,据说比 Flask 更快

通过在 URL 中添加 /docs/ 访问 Swagger UI [图片由作者提供]

在 Swagger UI 中测试 API [图片由作者提供]

这是我编写的将我的 ML 函数作为 FastAPI 服务器提供的代码。

API 服务器的代码

定义服务器后,我们可以使用 uvicorn 运行它。此外,由于 Google Colab 仅允许通过 Colab 接口访问其服务器,我们必须使用 Ngrok 将 FastAPI 服务器暴露给公众。

运行和暴露服务器的代码

运行服务器后,我们可以转到 Swagger UI(通过在生成的 ngrok URL 上添加“/docs”)并测试 API。

在 FastAPI Swagger UI 中生成“水下城堡”[图片由作者提供]

在测试 API 时,我意识到推断可能需要花费 3-20 分钟,具体取决于质量/迭代次数。对于 HTTP 请求来说,3 分钟本身已经被认为是非常长的时间,用户可能不想在网站上等待那么长时间。我决定将推断设置为后台任务,并在结果完成后向用户发送电子邮件,这可能更适合于长时间的推断时间。

既然我们已经决定了计划,我们首先将编写发送电子邮件的函数。我最初使用 SendGrid 邮件 API 来执行此操作,但是在使用免费配额(每天 100 封电子邮件)用完之后,我转而使用 Mailgun API,因为它是 GitHub 学生开发者包的一部分,并且为学生提供每月 20,000 封电子邮件的额度。

因此,这是使用 Mailgun API 发送带有图像附件的电子邮件的代码。

使用 Mailgun API 发送电子邮件的代码接下来,我们将修改我们的服务器代码,使用FastAPI中的后台任务,并在后台通过电子邮件发送结果。

通过上面的代码,服务器将快速回复请求,并显示“任务正在后台处理”消息,而不是等待生成过程完成并回复图像。

一旦处理完成,服务器将通过电子邮件向用户发送结果。

向用户发送图像和视频结果。[图片来自作者]

现在看起来一切都在正常运行,我构建了前端,并与我的朋友分享了这个网站。然而,当我用多个用户进行测试时,发现存在并发问题。

当第二个用户在第一个任务仍在处理时向服务器发出请求时,某种方式会终止当前进程而不是创建并行进程或排队。我不确定是什么原因导致了这个问题,可能是在clipit代码中使用了全局变量,也可能不是。我没有花太多时间进行调试,因为我意识到我需要实现一个消息队列系统。

经过一些关于消息队列系统的谷歌搜索,大多数人推荐RabbitMQ或Redis。但是,我不确定RabbitMQ或Redis是否可以安装在Google Colab上,因为它似乎需要sudo权限。最终,我决定使用Google Firebase作为队列系统,因为我想尽快完成项目,而Firebase是我最熟悉的系统。

基本上,当用户在前端尝试生成艺术品时,它将在名为“queue”的集合中添加一个描述任务(提示、图像类型、大小等)的条目。另一方面,我们将在Google Colab上运行一个脚本,不断监听“queue”集合中的新条目,并逐个处理任务。

处理任务并持续监听队列的后端代码

在前端,我们只需要在队列中添加一个新任务。但是,请确保在前端上已经完成了适当的Firebase设置

db.collection("queue").add({
        prompt: prompt,
        email: email,
        quality: quality,
        type: type,
        aspect: aspect,
        created_at: firebase.firestore.FieldValue.serverTimestamp(),
})

就这样!现在,当用户在前端尝试生成艺术品时,它将在队列中添加一个新任务。Colab服务器上的工作脚本将逐个处理队列中的任务。

你可以查看Github仓库来查看完整的代码(随时点赞)。

在前端中向队列添加新任务 [图片来自作者]

Firebase中的队列内容 [图片来自作者]

参考文献:

[1] https://openai.com/blog/dall-e/

[2] https://openai.com/blog/clip/

[3] https://ljvmiranda921.github.io/notebook/2021/08/08/clip-vqgan/

[4] https://github.com/orpatashnik/StyleCLIP

[5] https://towardsdatascience.com/understanding-flask-vs-fastapi-web-framework-fe12bb58ee75

译自:https://towardsdatascience.com/how-i-built-an-ai-text-to-art-generator-a0c0f6d6f59f

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
alivne
复杂的问题简单化

评论(0)

添加评论