DataWhaleX魔搭_AI夏令营_四期AIGC方向_task02 学习笔记
接上文。
本次的任务是利用AI继续精读代码、利用AI完成一次比赛任务。
AI生图前沿
在仔细阅读Task02所给的教程之后,我内心其实是有一些震惊的。在上一篇学习笔记中,我也大量地提到了AI生图目前的局限性——我提到了细节绘图能力不行、画不好手等等,但教程中的信息告诉我,这都是一年多前的老黄历了,目前业界已有相当多的解决方案。
给图片里的人手打上标记,像把手掌、拇指、食指啥的,都给清楚地标出来
是的,这个解决方案在我的上一篇笔记中也设想过……虽然麻烦,但是确实是有效的。
过去文生图主要以 SD 系列基础模型为主,仅支持英文的prompt,但可图是支持中文的文生图模型,文生图的prompt格式较为固定,魔搭社区还开源了专门的各种风格的可图优质咒语书,可以针对600+种不同风格,完善prompt,生成各种风格图片,可以在我们的学习当中使用。
这样一来,我们对于prompt的使用不局限于第三方工具了。同时,我经过测试发现,靠前的prompt似乎权重更大。
在我的上一篇文章中,还提到了AI生成图片时一般无法正确生成文字的问题。看过教程后我发现,这一点竟然也已经有了解决方案。
在某些设计的场景中,我们还希望AI能为我们将特定的文字生成在图片当中,比如下面这种海报——
但实际上,这种固定文字生成,往往难度较大,一是具体生成在哪些位置,往往需要人为设定,为了更方便地制作类似这样的海报还产生了PS等图片编辑工具,才能实现相应的效果,想要让AI稳定生成相似效果的图片可想而知难度之大。
像我们Task1中介绍的创意海报生成工具,早已在代码中固定了相应的文字位置和对应的字体,才能进行相应的生成,且大概率是进行了两个步骤——
- 一个步骤是AI生成背景,
- 另一个步骤是通过代码将对应的文字显示到对应位置,
- 然后渲染,合成图片,给到我们。
这真的让我比较吃惊了,虽然是通过曲线救国的方式,但确实解决了一大难题,使得AI生图能在更多更广的领域派上用场。
总之,我发现我对于AI生图的理解(上一篇笔记中聊到的)竟然相当过时了。我确实是在23年年底一段时间关注该领域相当多,但我没想到技术发展这么快,很多当时认为的难点都已经早早攻克了。我对AI生图,包括AI生成视频(我得也再多多关注一下生成视频的新发展)原本是不报有很大的希望的,认为短时间内它们还不能取代人类工作者,但现在我认为在一般的领域,它们已经完全可以胜任工作了。上面那张海报真的让我看傻了,直接给我的话,我绝对是分辨不出来的。这一顿吃多少画师啊。
魔搭社区在学习方面确实有着相当丰富的资料,这些工具也相当好用啊。
写笔记写到这里,我也去试了试魔搭的海报生成工具。效果其实还算中规中矩吧,并没有上图宣传的那么震撼,也可能是我的prompt描述不到位。但是这个工具集成了AI扩展文本描述和扩展提示词,有几种风格可以选择,还可以提升结果分辨率和做细节修复,总的来说呢还是很好用的,应付一般需求是足够的。
我是顺手拿这个工具做了两张海报。
总之,可以直接使用,就算不太满意,上PS稍微调一调、多加点元素绝对没问题了。
向AI提问、精读代码
杂谈
本次Task主要任务是通过提问AI的方式来精读baseline代码,夏令营使用的是通义千问大语言模型。
我日常使用大语言模型还是比较频繁的,主要使用的是文心一言、讯飞星火和ChatGPT。ChatGPT我身边很多同学使用国内不知道哪儿找的,应该是调用的接口,也可以正常使用。我是魔法上网在官网用的,当初GPT推出以后没多久就搞了国外临时手机号注册的,不知道现在那方法还能不能用。这样算有利有弊吧,利的方面来说我可以肯定我这是ChatGPT,而我同学们使用的,我仔细观察总觉得是骗人的,看着还挺智障的,并且我没花钱(搞国外临时手机号花了一点点来着)(可能他们那种也没花钱,这要看搞这东西的人的良心的)。弊的方面来讲,我是永远不会使用新的GPT的,一直只用了3.5,是因为没精力搞,也是因为没钱,而我的同学们那种呢,反正宣传上是4.0。是不是真的4.0呢?可能吧~
关于各厂家的大语言模型实际使用体验怎么样,我也不在这里多说。其实我认为,用着顺手的就是好的。平常不太重要的事情我就问讯飞星火了,我爸公司经常需要做PPT,我爸也不会,我也准备给他推荐讯飞星火了。涉及一些有风险的事情,我就去魔法上网问问ChatGPT,
代码
代码在Task02任务文档中给出。
- 以下代码为方便大家阅读理解,故放在了一起。但不能一键运行跑通,如何跑通代码,请直接参考task1中的内容。
代码内容比较长,并且在本篇文章中我们不需要人为的去一字一句看代码,因此我将其放入folding中以便展开和收起。
代码点这里
!pip install simple-aesthetics-predictor
!pip install -v -e data-juicer
!pip uninstall pytorch-lightning -y
!pip install peft lightning pandas torchvision
!pip install -e DiffSynth-Studio
from modelscope.msdatasets import MsDataset
ds = MsDataset.load(
'AI-ModelScope/lowres_anime',
subset_name='default',
split='train',
cache_dir="/mnt/workspace/kolors/data"
)
import json, os
from data_juicer.utils.mm_utils import SpecialTokens
from tqdm import tqdm
os.makedirs("./data/lora_dataset/train", exist_ok=True)
os.makedirs("./data/data-juicer/input", exist_ok=True)
with open("./data/data-juicer/input/metadata.jsonl", "w") as f:
for data_id, data in enumerate(tqdm(ds)):
image = data["image"].convert("RGB")
image.save(f"/mnt/workspace/kolors/data/lora_dataset/train/{data_id}.jpg")
metadata = {"text": "二次元", "image": [f"/mnt/workspace/kolors/data/lora_dataset/train/{data_id}.jpg"]}
f.write(json.dumps(metadata))
f.write("\n")
data_juicer_config = """
# global parameters
project_name: 'data-process'
dataset_path: './data/data-juicer/input/metadata.jsonl' # path to your dataset directory or file
np: 4 # number of subprocess to process your dataset
text_keys: 'text'
image_key: 'image'
image_special_token: '<__dj__image>'
export_path: './data/data-juicer/output/result.jsonl'
# process schedule
# a list of several process operators with their arguments
process:
- image_shape_filter:
min_width: 1024
min_height: 1024
any_or_all: any
- image_aspect_ratio_filter:
min_ratio: 0.5
max_ratio: 2.0
any_or_all: any
"""
with open("data/data-juicer/data_juicer_config.yaml", "w") as file:
file.write(data_juicer_config.strip())
!dj-process --config data/data-juicer/data_juicer_config.yaml
import pandas as pd
import os, json
from PIL import Image
from tqdm import tqdm
texts, file_names = [], []
os.makedirs("./data/data-juicer/output/images", exist_ok=True)
with open("./data/data-juicer/output/result.jsonl", "r") as f:
for line in tqdm(f):
metadata = json.loads(line)
texts.append(metadata["text"])
file_names.append(metadata["image"][0])
df = pd.DataFrame({"text": texts, "file_name": file_names})
df.to_csv("./data/data-juicer/output/result.csv", index=False)
df
from transformers import CLIPProcessor, CLIPModel
import torch
model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
images = [Image.open(img_path) for img_path in df["file_name"]]
inputs = processor(text=df["text"].tolist(), images=images, return_tensors="pt", padding=True)
outputs = model(**inputs)
logits_per_image = outputs.logits_per_image # this is the image-text similarity score
probs = logits_per_image.softmax(dim=1) # we can take the softmax to get the probabilities
probs
from torch.utils.data import Dataset, DataLoader
class CustomDataset(Dataset):
def __init__(self, df, processor):
self.texts = df["text"].tolist()
self.images = [Image.open(img_path) for img_path in df["file_name"]]
self.processor = processor
def __len__(self):
return len(self.texts)
def __getitem__(self, idx):
inputs = self.processor(text=self.texts[idx], images=self.images[idx], return_tensors="pt", padding=True)
return inputs
dataset = CustomDataset(df, processor)
dataloader = DataLoader(dataset, batch_size=8)
for batch in dataloader:
outputs = model(**batch)
logits_per_image = outputs.logits_per_image
probs = logits_per_image.softmax(dim=1)
print(probs)
import torch
from diffusers import StableDiffusionPipeline
torch.manual_seed(1)
pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v-1-4", torch_dtype=torch.float16)
pipe = pipe.to("cuda")
prompt = "二次元,一个紫色长发小女孩穿着粉色吊带漏肩连衣裙,在练习室练习唱歌,手持话筒"
negative_prompt = "丑陋、变形、嘈杂、模糊、低对比度"
guidance_scale = 4
num_inference_steps = 50
image = pipe(
prompt=prompt,
negative_prompt=negative_prompt,
guidance_scale=guidance_scale,
num_inference_steps=num_inference_steps,
height=1024,
width=1024,
).images[0]
image.save("example_image.png")
image
from PIL import Image
torch.manual_seed(1)
image = pipe(
prompt="二次元,日系动漫,演唱会的观众席,人山人海,一个紫色短发小女孩穿着粉色吊带漏肩连衣裙坐在演唱会的观众席,舞台上衣着华丽的歌星们在唱歌",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("1.jpg")
torch.manual_seed(1)
image = pipe(
prompt="二次元,一个紫色短发小女孩穿着粉色吊带漏肩连衣裙坐在演唱会的观众席,露出憧憬的神情",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度,色情擦边",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("2.jpg")
torch.manual_seed(2)
image = pipe(
prompt="二次元,一个紫色短发小女孩穿着粉色吊带漏肩连衣裙坐在演唱会的观众席,露出憧憬的神情",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度,色情擦边",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("3.jpg")
torch.manual_seed(5)
image = pipe(
prompt="二次元,一个紫色短发小女孩穿着粉色吊带漏肩连衣裙,对着流星许愿,闭着眼睛,十指交叉,侧面",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度,扭曲的手指,多余的手指",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("4.jpg")
torch.manual_seed(0)
image = pipe(
prompt="二次元,一个紫色中等长度头发小女孩穿着粉色吊带漏肩连衣裙,在练习室练习唱歌",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("5.jpg")
torch.manual_seed(1)
image = pipe(
prompt="二次元,一个紫色长发小女孩穿着粉色吊带漏肩连衣裙,在练习室练习唱歌,手持话筒",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("6.jpg")
torch.manual_seed(7)
image = pipe(
prompt="二次元,紫色长发少女,穿着黑色连衣裙,试衣间,心情忐忑",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("7.jpg")
torch.manual_seed(0)
image = pipe(
prompt="二次元,紫色长发少女,穿着黑色礼服,连衣裙,在台上唱歌",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("8.jpg")
import numpy as np
from PIL import Image
images = [np.array(Image.open(f"{i}.jpg")) for i in range(1, 9)]
image = np.concatenate([
np.concatenate(images[0:2], axis=1),
np.concatenate(images[2:4], axis=1),
np.concatenate(images[4:6], axis=1),
np.concatenate(images[6:8], axis=1),
], axis=0)
image = Image.fromarray(image).resize((1024, 2048))
image
首先我们来直观感知下这个文生图代码的框架结构:
分析代码的主体架构
依然还是老样子,我们需要一个prompt。
你是一个优秀的python开发工程师,现在我们需要你帮我们分析这个代码的主体框架,你需要把代码按照工作流分成几部分,用中文回答我的问题。{此处替换前面的代码}
打开(随便一个)大语言模型,输入上面的prompt。
等一下,我突然发现一件事:我现在使用的不是3.5,而是ChatGPT 4o mini。不过这不是什么重要的事情了。
来看看它的输出。因为有大标题小标题啥的,而且直接复制也是MarkDown形式,我使用外部.md文件的形式来呈现。
输出
这个代码的主体框架可以分为几个主要的工作流部分,每一部分承担不同的任务。以下是代码的主要部分及其功能:
1. 环境准备和库安装
!pip install simple-aesthetics-predictor
!pip install -v -e data-juicer
!pip uninstall pytorch-lightning -y
!pip install peft lightning pandas torchvision
!pip install -e DiffSynth-Studio
这部分代码主要用于安装所需的Python库和工具包,包括simple-aesthetics-predictor
、data-juicer
、peft
、lightning
、pandas
、torchvision
以及DiffSynth-Studio
。这些库和工具将在后续步骤中使用。
2. 数据加载和预处理
from modelscope.msdatasets import MsDataset
ds = MsDataset.load(
'AI-ModelScope/lowres_anime',
subset_name='default',
split='train',
cache_dir="/mnt/workspace/kolors/data"
)
import json, os
from data_juicer.utils.mm_utils import SpecialTokens
from tqdm import tqdm
os.makedirs("./data/lora_dataset/train", exist_ok=True)
os.makedirs("./data/data-juicer/input", exist_ok=True)
with open("./data/data-juicer/input/metadata.jsonl", "w") as f:
for data_id, data in enumerate(tqdm(ds)):
image = data["image"].convert("RGB")
image.save(f"/mnt/workspace/kolors/data/lora_dataset/train/{data_id}.jpg")
metadata = {"text": "二次元", "image": [f"/mnt/workspace/kolors/data/lora_dataset/train/{data_id}.jpg"]}
f.write(json.dumps(metadata))
f.write("\n")
这一部分的代码负责加载数据集,并将数据集中的图像和相关信息处理成指定的格式保存到指定的路径。使用了MsDataset
来加载数据,并使用json
和PIL
库处理图像数据。
3. 数据处理配置和执行
data_juicer_config = """
# global parameters
project_name: 'data-process'
dataset_path: './data/data-juicer/input/metadata.jsonl' # path to your dataset directory or file
np: 4 # number of subprocess to process your dataset
text_keys: 'text'
image_key: 'image'
image_special_token: '<__dj__image>'
export_path: './data/data-juicer/output/result.jsonl'
# process schedule
# a list of several process operators with their arguments
process:
- image_shape_filter:
min_width: 1024
min_height: 1024
any_or_all: any
- image_aspect_ratio_filter:
min_ratio: 0.5
max_ratio: 2.0
any_or_all: any
"""
with open("data/data-juicer/data_juicer_config.yaml", "w") as file:
file.write(data_juicer_config.strip())
!dj-process --config data/data-juicer/data_juicer_config.yaml
这部分代码定义了data-juicer
的数据处理配置,并运行了数据处理任务。data_juicer_config.yaml
文件包含了对图像数据进行筛选和处理的规则,并将处理后的数据保存到指定的文件。
4. 数据转换和存储
import pandas as pd
import os, json
from PIL import Image
from tqdm import tqdm
texts, file_names = [], []
os.makedirs("./data/data-juicer/output/images", exist_ok=True)
with open("./data/data-juicer/output/result.jsonl", "r") as f:
for line in tqdm(f):
metadata = json.loads(line)
texts.append(metadata["text"])
file_names.append(metadata["image"][0])
df = pd.DataFrame({"text": texts, "file_name": file_names})
df.to_csv("./data/data-juicer/output/result.csv", index=False)
df
在这一部分,代码读取data-juicer
处理后的数据,将其转换为DataFrame,并保存为CSV文件。这部分代码负责将数据从JSONL格式转换为CSV格式,以便进一步分析和处理。
5. 文本-图像相似度计算
from transformers import CLIPProcessor, CLIPModel
import torch
model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
images = [Image.open(img_path) for img_path in df["file_name"]]
inputs = processor(text=df["text"].tolist(), images=images, return_tensors="pt", padding=True)
outputs = model(**inputs)
logits_per_image = outputs.logits_per_image # this is the image-text similarity score
probs = logits_per_image.softmax(dim=1) # we can take the softmax to get the probabilities
probs
这一部分代码使用CLIP模型计算图像与文本的相似度。通过将图像和文本输入到CLIP模型中,代码计算出图像-文本对的相似度得分,并通过softmax函数转换为概率分布。
6. 数据集和数据加载
from torch.utils.data import Dataset, DataLoader
class CustomDataset(Dataset):
def __init__(self, df, processor):
self.texts = df["text"].tolist()
self.images = [Image.open(img_path) for img_path in df["file_name"]]
self.processor = processor
def __len__(self):
return len(self.texts)
def __getitem__(self, idx):
inputs = self.processor(text=self.texts[idx], images=self.images[idx], return_tensors="pt", padding=True)
return inputs
dataset = CustomDataset(df, processor)
dataloader = DataLoader(dataset, batch_size=8)
for batch in dataloader:
outputs = model(**batch)
logits_per_image = outputs.logits_per_image
probs = logits_per_image.softmax(dim=1)
print(probs)
这里定义了一个自定义的数据集类CustomDataset
,用于将数据加载到DataLoader中,以便批量处理图像和文本对。代码通过DataLoader遍历数据集并计算每个批次的图像-文本相似度。
7. 生成图像
import torch
from diffusers import StableDiffusionPipeline
torch.manual_seed(1)
pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v-1-4", torch_dtype=torch.float16)
pipe = pipe.to("cuda")
prompt = "二次元,一个紫色长发小女孩穿着粉色吊带漏肩连衣裙,在练习室练习唱歌,手持话筒"
negative_prompt = "丑陋、变形、嘈杂、模糊、低对比度"
guidance_scale = 4
num_inference_steps = 50
image = pipe(
prompt=prompt,
negative_prompt=negative_prompt,
guidance_scale=guidance_scale,
num_inference_steps=num_inference_steps,
height=1024,
width=1024,
).images[0]
image.save("example_image.png")
image
这部分代码使用稳定扩散模型(Stable Diffusion)生成图像。给定文本提示和负面提示,代码生成并保存图像。
8. 生成多个图像并拼接
import numpy as np
from PIL import Image
images = [np.array(Image.open(f"{i}.jpg")) for i in range(1, 9)]
image = np.concatenate([
np.concatenate(images[0:2], axis=1),
np.concatenate(images[2:4], axis=1),
np.concatenate(images[4:6], axis=1),
np.concatenate(images[6:8], axis=1),
], axis=0)
image = Image.fromarray(image).resize((1024, 2048))
image
最后这部分代码生成多个图像,并将它们拼接成一个大的图像。这是为了更好地展示生成的图像结果,将多个图像排列在一起。
以上是代码的主体框架及其功能划分。每部分代码都在完成特定的任务,从环境设置、数据处理、模型训练和评估,到最终的图像生成。
逐行解释代码
prompt:
你是一个优秀的python开发工程师,现在我们需要你帮我们逐行分析这个代码,用中文回答我的问题。{此处替换前面的代码}
输出
这段代码主要完成了以下几个任务:数据处理、模型训练与评估、图像生成、以及图像拼接。下面是逐行分析:
1. 安装和卸载相关包
!pip install simple-aesthetics-predictor
!pip install -v -e data-juicer
!pip uninstall pytorch-lightning -y
!pip install peft lightning pandas torchvision
!pip install -e DiffSynth-Studio
- 安装
simple-aesthetics-predictor
,一个可能用于图像美学评分的包。 - 安装
data-juicer
,并启用详细模式,通常是一个数据处理库。 - 卸载
pytorch-lightning
,用于深度学习的库。 - 安装
peft
,lightning
,pandas
, 和torchvision
,这些是用于深度学习、数据处理和图像处理的库。 - 安装
DiffSynth-Studio
,用于生成和处理图像的工具。
2. 数据加载
from modelscope.msdatasets import MsDataset
ds = MsDataset.load(
'AI-ModelScope/lowres_anime',
subset_name='default',
split='train',
cache_dir="/mnt/workspace/kolors/data"
)
- 从
modelscope
中加载MsDataset
数据集,指定了数据集名称为lowres_anime
,加载训练集,数据缓存目录为/mnt/workspace/kolors/data
。
3. 数据处理
import json, os
from data_juicer.utils.mm_utils import SpecialTokens
from tqdm import tqdm
os.makedirs("./data/lora_dataset/train", exist_ok=True)
os.makedirs("./data/data-juicer/input", exist_ok=True)
with open("./data/data-juicer/input/metadata.jsonl", "w") as f:
for data_id, data in enumerate(tqdm(ds)):
image = data["image"].convert("RGB")
image.save(f"/mnt/workspace/kolors/data/lora_dataset/train/{data_id}.jpg")
metadata = {"text": "二次元", "image": [f"/mnt/workspace/kolors/data/lora_dataset/train/{data_id}.jpg"]}
f.write(json.dumps(metadata))
f.write("\n")
- 创建目录以存储处理后的数据。
- 遍历数据集
ds
,将每张图片转换为 RGB 格式,保存为 JPEG 格式,并写入包含文本和图像路径的 JSONL 文件metadata.jsonl
。
4. 配置和运行 data-juicer
数据处理
data_juicer_config = """
# global parameters
project_name: 'data-process'
dataset_path: './data/data-juicer/input/metadata.jsonl'
np: 4
text_keys: 'text'
image_key: 'image'
image_special_token: '<__dj__image>'
export_path: './data/data-juicer/output/result.jsonl'
# process schedule
process:
- image_shape_filter:
min_width: 1024
min_height: 1024
any_or_all: any
- image_aspect_ratio_filter:
min_ratio: 0.5
max_ratio: 2.0
any_or_all: any
"""
with open("data/data-juicer/data_juicer_config.yaml", "w") as file:
file.write(data_juicer_config.strip())
!dj-process --config data/data-juicer/data_juicer_config.yaml
- 创建
data-juicer
配置文件data_juicer_config.yaml
,设置数据处理的全局参数和处理计划,包括图像过滤条件。 - 使用
dj-process
命令运行数据处理。
5. 读取处理后的数据
import pandas as pd
import os, json
from PIL import Image
from tqdm import tqdm
texts, file_names = [], []
os.makedirs("./data/data-juicer/output/images", exist_ok=True)
with open("./data/data-juicer/output/result.jsonl", "r") as f:
for line in tqdm(f):
metadata = json.loads(line)
texts.append(metadata["text"])
file_names.append(metadata["image"][0])
df = pd.DataFrame({"text": texts, "file_name": file_names})
df.to_csv("./data/data-juicer/output/result.csv", index=False)
df
- 从
result.jsonl
文件中读取处理后的数据,提取文本和图像路径,并保存到result.csv
文件中。
6. 图像和文本的相似性评估
from transformers import CLIPProcessor, CLIPModel
import torch
model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
images = [Image.open(img_path) for img_path in df["file_name"]]
inputs = processor(text=df["text"].tolist(), images=images, return_tensors="pt", padding=True)
outputs = model(**inputs)
logits_per_image = outputs.logits_per_image
probs = logits_per_image.softmax(dim=1)
probs
- 加载 CLIP 模型和处理器。
- 对图像和文本进行处理和模型推理,计算图像-文本的相似性分数,并通过 softmax 获取概率。
7. 定义自定义数据集并进行批量处理
from torch.utils.data import Dataset, DataLoader
class CustomDataset(Dataset):
def __init__(self, df, processor):
self.texts = df["text"].tolist()
self.images = [Image.open(img_path) for img_path in df["file_name"]]
self.processor = processor
def __len__(self):
return len(self.texts)
def __getitem__(self, idx):
inputs = self.processor(text=self.texts[idx], images=self.images[idx], return_tensors="pt", padding=True)
return inputs
dataset = CustomDataset(df, processor)
dataloader = DataLoader(dataset, batch_size=8)
for batch in dataloader:
outputs = model(**batch)
logits_per_image = outputs.logits_per_image
probs = logits_per_image.softmax(dim=1)
print(probs)
- 定义了一个自定义数据集
CustomDataset
用于批量处理图像和文本。 - 使用
DataLoader
加载数据并进行模型推理,打印每个批次的图像-文本相似性概率。
8. 使用 Stable Diffusion 生成图像
import torch
from diffusers import StableDiffusionPipeline
torch.manual_seed(1)
pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v-1-4", torch_dtype=torch.float16)
pipe = pipe.to("cuda")
prompt = "二次元,一个紫色长发小女孩穿着粉色吊带漏肩连衣裙,在练习室练习唱歌,手持话筒"
negative_prompt = "丑陋、变形、嘈杂、模糊、低对比度"
guidance_scale = 4
num_inference_steps = 50
image = pipe(
prompt=prompt,
negative_prompt=negative_prompt,
guidance_scale=guidance_scale,
num_inference_steps=num_inference_steps,
height=1024,
width=1024,
).images[0]
image.save("example_image.png")
image
- 使用 Stable Diffusion 模型生成图像。设置了种子、模型、提示词和负面提示词,并保存生成的图像。
9. 生成更多图像
from PIL import Image
torch.manual_seed(1)
image = pipe(
prompt="二次元,日系动漫,演唱会的观众席,人山人海,一个紫色短发小女孩穿着粉色吊带漏肩连衣裙坐在演唱会的观众席,舞台上衣着华丽的歌星们在唱歌",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("1.jpg")
torch.manual_seed(1)
image = pipe(
prompt="二次元,一个紫色短发小女孩穿着粉色吊带漏肩连衣裙坐在演唱会的观众席,露出憧憬的神情",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度,色情擦边",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("2.jpg")
torch.manual_seed(2)
image = pipe(
prompt="二次元,一个紫色短发小女孩穿着粉色吊带漏肩连衣裙坐在演唱会的观众席,露出憧憬的神情",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度,色情擦边",
cfg_scale=4,
num_inference_steps=50, height=1024, width=102
4,
)
image.save("3.jpg")
torch.manual_seed(5)
image = pipe(
prompt="二次元,一个紫色短发小女孩穿着粉色吊带漏肩连衣裙,对着流星许愿,闭着眼睛,十指交叉,侧面",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度,扭曲的手指,多余的手指",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("4.jpg")
torch.manual_seed(0)
image = pipe(
prompt="二次元,一个紫色中等长度头发小女孩穿着粉色吊带漏肩连衣裙,在练习室练习唱歌",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("5.jpg")
torch.manual_seed(1)
image = pipe(
prompt="二次元,一个紫色长发小女孩穿着粉色吊带漏肩连衣裙,在练习室练习唱歌,手持话筒",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("6.jpg")
torch.manual_seed(7)
image = pipe(
prompt="二次元,紫色长发少女,穿着黑色连衣裙,试衣间,心情忐忑",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("7.jpg")
torch.manual_seed(0)
image = pipe(
prompt="二次元,紫色长发少女,穿着黑色礼服,连衣裙,在台上唱歌",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("8.jpg")
- 使用 Stable Diffusion 模型生成多张图像,每张图像使用不同的提示词和种子,以生成不同的图像并保存。
10. 图像拼接
import numpy as np
from PIL import Image
images = [np.array(Image.open(f"{i}.jpg")) for i in range(1, 9)]
image = np.concatenate([
np.concatenate(images[0:2], axis=1),
np.concatenate(images[2:4], axis=1),
np.concatenate(images[4:6], axis=1),
np.concatenate(images[6:8], axis=1),
], axis=0)
image = Image.fromarray(image).resize((1024, 2048))
image
- 读取生成的多张图像,并将它们拼接成一张大图。使用
np.concatenate
将图像水平和垂直拼接,最后调整图像大小并显示。
实战演练
这次我选择魔搭平台GPU免费Notebook实例。
让ChatGPT帮我选的故事主题、写的故事梗概、写的prompt,自己稍微调整了一下prompt。
故事主题:时间旅行的笑话-主角偶然发现了一个时间旅行的装置,但每次使用都会发生搞笑的意外情况。
内容:
故事内容详述
画面:一个不起眼的车库里,一名主角(可以是一个有点邋遢的科学家或发明家)在摆弄一个看起来非常复杂的机器。机器上贴满了“警告”和“试验中”的标签。
文字:主角自言自语:“今天是大日子,我终于完成了我的时间旅行机!”
画面:主角激动地按下机器上的大按钮,机器开始发出闪烁的灯光和奇怪的声音。
文字:主角兴奋地说:“让我们看看未来有什么有趣的事物吧!”
画面:机器在闪烁光芒中开始旋转,主角突然消失,周围的物品也跟着闪烁。
文字:旁白:“经过一阵强烈的光芒,主角进入了未来。”
画面:主角出现在一个看起来很平常的现代办公室里,四周是高科技设备和未来风格的办公桌。
文字:主角满怀期待地观察四周:“哇!这是未来吗?!”
画面:一位未来的办公室职员(穿着超前卫的工作服)看到主角,表现出困惑和惊讶。
文字:职员说:“你是从哪里来的?今天不是穿越时空的日子。”
画面:主角挠头,尴尬地解释:“呃,我好像搞错了日期,我以为这是未来的日子。”
画面:职员微笑着,递给主角一个现代的日历和时光机的使用手册。
文字:职员说:“时间旅行有时需要准确的计划。这里是正确的时间表和使用指南。”
画面:主角看着手中的日历和手册,一脸的无奈和搞笑的困惑。背景是未来办公室的职员们在窃笑。
文字:主角叹气道:“看来我得先学会时间管理了!”
prompt
prompt
未调整:一个车库里,一名邋遢的科学家正在操作一个复杂的时间旅行机器。机器上贴满了‘警告’和‘试验中’的标签,科学家神情兴奋,车库里充满了各种工具和零件。
调整后:漫画风,美漫,一个车库里,一名邋遢的科学家正在头操作一个复杂的时间旅行机器,科学家只出现侧影,科学家胡子较长、头发是暗黄色的,体格壮实,大约四五十岁,佝偻着背,机器上贴满了标签,科学家神情兴奋,车库里充满了各种工具和零件。
未调整:不要画一个干净整洁的实验室或现代化的研究环境,也不要画出没有标签和警告的机器。
调整后:二次元,不要出现科学家的正脸,不要出现歪曲的手指、膨大的关节,不要画一个干净整洁的实验室或现代化的研究环境,也不要画出没有标签和警告的机器。
未调整:科学家激动地按下时间旅行机器上的大按钮,机器开始发出闪烁的灯光和奇怪的声音。画面中可以看到按钮被按下,机器发出光芒。
调整后:漫画风,美漫,一个车库里,一名邋遢的科学家正在头操作一个复杂的时间旅行机器,科学家只出现侧影,科学家胡子较长、头发是暗黄色的,体格壮实,大约四五十岁,佝偻着背,机器上贴满了标签,科学家激动地按下时间旅行机器上的大按钮,机器发出光芒。
未调整:不要画出没有任何动作的机器,或是科学家没有进行任何操作的画面。
调整后:二次元,不要出现科学家的正脸,不要出现歪曲的手指、膨大的关节,不要画一个干净整洁的实验室或现代化的研究环境,也不要画出没有标签和警告的机器,不要画出没有任何动作的机器,或是科学家没有进行任何操作的画面。
未调整:时间旅行机器在闪烁光芒中旋转,科学家和周围的物品一起被包裹在光芒中,画面中显示出物品和科学家被传送的效果。
调整后:漫画风,美漫,一个车库里,一名邋遢的科学家正在头操作一个复杂的时间旅行机器,科学家只出现侧影,科学家胡子较长、头发是暗黄色的,体格比一般人略微壮实一些,大约四五十岁,佝偻着背,机器上贴满了标签,时间旅行机器在剧烈的闪烁白色光芒中旋转,科学家和周围的物品一起被包裹在白色光芒中,画面中显示出物品和科学家被传送的效果。
未调整:不要画出没有时间旅行效果的画面,也不要画出科学家静止不动的情况。
调整后:二次元,不要出现科学家的正脸,不要画一个肥胖的科学家,不要出现歪曲的手指、膨大的关节,不要画一个干净整洁的实验室或现代化的研究环境,也不要画出没有标签和警告的机器,不要画出没有时间旅行效果的画面,也不要画出科学家静止不动的情况。
未调整:科学家出现在一个现代办公室,办公室里有高科技设备和未来风格的办公桌。科学家看起来惊讶和好奇。
调整后:漫画风,美漫,画风写实、粗犷,一名邋遢的科学家出现在一个现代办公室,科学家胡子较长、头发是暗黄色的,体格壮实,大约四五十岁,佝偻着背,办公室里有高科技设备和未来风格的办公桌。科学家看起来惊讶和好奇。
未调整:不要画传统或普通的办公室环境,也不要画出科学家没有表现出惊讶或好奇的情况。
调整后:二次元,不要出现歪曲的手指、膨大的关节,不要画传统或普通的办公室环境,也不要画出科学家没有表现出惊讶或好奇的情况。
未调整:一位未来风格的办公室职员穿着超前卫的工作服,看到科学家后表现出困惑和惊讶,背景是现代化的办公室。
调整后:漫画风,美漫,两个人面对面相隔较远,画出全身。一名邋遢的科学家,科学家胡子较长、头发是暗黄色的,体格壮实,大约四五十岁,佝偻着背,表情十分惊讶;一位未来风格的男性办公室职员,穿着超前卫的工作服,看到科学家后表现出一丝困惑和惊讶,背景是现代化的办公室。
未调整:不要画穿着普通衣服的职员,也不要画出职员没有表现出困惑和惊讶的情景。
调整后:二次元,不要出现歪曲的手指、膨大的关节,不要画传统或普通的办公室环境,也不要画出科学家没有表现出惊讶或好奇的情况。不要画穿着普通衣服的职员,也不要画出职员没有表现出困惑和惊讶的情景。
未调整:科学家挠头,尴尬地解释自己的误会。画面中可以看到科学家手舞足蹈,职员则听着他的解释。
调整后:漫画风,美漫,两个主要人物。一名邋遢的科学家科学家挠头,科学家胡子较长、头发是暗黄色的,体格壮实,大约四五十岁,佝偻着背,画面中可以看到科学家手舞足蹈;另一名职员冷静地听着他的解释。背景是白色的未来风办公室。
未调整:不要画出科学家没有任何动作或表情的画面,也不要画出职员没有听科学家解释的情况。
调整后:二次元,不要画出科学家没有任何动作或表情的画面,也不要画出职员没有听科学家解释的情况。
未调整:职员微笑着,递给科学家一个现代的日历和时间旅行机的使用手册。科学家看起来有些困惑但接受了这些物品。
调整后:漫画风,美漫,两个人面对面相隔较远,画出全身。一名职员微笑着,递给科学家一个现代的日历和一本使用手册;一名科学家,看起来有些困惑,接受了职员给的这些物品。科学家胡子较长、头发是暗黄色的,体格壮实,大约四五十岁,佝偻着背
未调整:不要画出职员没有递送物品或科学家没有接受物品的画面。
调整后:二次元,不要画出职员没有递送物品或科学家没有接受物品的画面。
未调整:科学家看着手中的日历和手册,表现出无奈和搞笑的困惑,背景中职员们在窃笑。画面充满幽默感。
调整后:漫画风,美漫,科学家看着手中的日历和手册,表现出无奈和搞笑的困惑,背景中职员们在窃笑。画面充满幽默感。
未调整:不要画出科学家没有任何情绪表现的画面,也不要画出背景中职员们没有表现出窃笑的情况。
调整后:二次元,不要画出科学家没有任何情绪表现的画面,也不要画出背景中职员们没有表现出窃笑的情况。
感觉似乎ChatGPT并不是十分理解什么是文生图prompt。而且为了上下图中人物长相的一致性,我们还需要增添许多细节描述。
结果展示
额,后面的搞丢了。我会抽时间重新跑一遍的。