baseline的流程图
Baseline代码
!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
主体框架工作流
环境准备和依赖安装: 使用pip命令安装所需的Python库,包括simple-aesthetics-predictor
、data-juicer
、pytorch-lightning
、peft
、lightning
、pandas
、torchvision
和DiffSynth-Studio
。
数据集加载:
从modelscope.msdatasets
加载名为AI-ModelScope/lowres_anime
的数据集,并指定子集和分割类型。
数据预处理:
创建保存图片和元数据的目录。
遍历数据集,将图片保存为JPEG格式,并生成包含文本和图片路径的元数据文件。
配置数据处理:
定义data_juicer的配置文件,包括项目名称、数据集路径、进程数、文本和图片键、特殊标记以及导出路径。
写入配置文件并使用dj-process
命令行工具处理数据。
数据处理结果分析:
读取处理后的数据,提取文本和文件名,并将它们保存到CSV文件中。
模型加载和推理:
加载CLIP模型和处理器,对图片和文本进行编码,获取图像-文本相似度得分。
自定义数据集和数据加载器:
定义自定义数据集类CustomDataset
,用于封装处理后的图片和文本数据。
创建数据加载器DataLoader
,用于批量加载数据。
模型训练/推理循环:
遍历数据加载器中的批次,进行模型推理,获取每个批次的图像-文本相似度得分。
生成图像:
使用Stable Diffusion模型根据给定的提示生成图像,并保存到文件。
图像拼接:
将生成的多张图像拼接成一张长图,并调整大小。
逐行代码解释
安装所需的Python包!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
:安装数据处理工具包,使用可编辑模式安装(-e
)。
卸载已有的pytorch-lightning
版本。
安装peft
(参数高效微调)、lightning
(新的PyTorch Lightning库)、pandas
(数据处理)和torchvision
(计算机视觉工具包)。
安装DiffSynth-Studio
,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"
)
从modelscope.msdatasets
导入MsDataset
类。
使用MsDataset.load
方法加载名为'AI-ModelScope/lowres_anime'
的数据集,指定使用默认子集('default'
),数据划分为训练集('train'
),并将数据缓存到指定目录。
准备数据处理
import json, os
from data_juicer.utils.mm_utils import SpecialTokens
from tqdm import tqdm
导入必要的库:json
(处理JSON数据)、os
(文件系统操作)、tqdm
(进度条显示)。
从data_juicer
的工具模块中导入SpecialTokens
(用于处理特殊标记)。
创建必要的目录
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")
打开一个名为metadata.jsonl
的文件,用于写入每个图像的元数据。
遍历数据集中的每一条数据:
将图像转换为RGB格式。
将图像保存到指定目录,文件名为数据的索引。
创建元数据字典,包含文本描述"二次元"
和图像路径。
将元数据以JSON格式写入文件,每条记录占一行。
配置data_juicer
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())
定义data_juicer
的配置,内容包括:
全局参数,如项目名称、数据集路径、并行处理的子进程数量等。
指定文本和图像的键,以及特殊的图像标记。
输出路径。
处理流程,包括图像尺寸过滤(最小宽度和高度为1024)和图像长宽比过滤(比例在0.5到2.0之间)。
将配置写入data_juicer_config.yaml
文件。
运行data_juicer
处理数据
!dj-process --config data/data-juicer/data_juicer_config.yaml
使用data_juicer
的命令行工具,根据配置文件处理数据集。
读取处理后的数据并创建DataFrame
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
导入必要的库:pandas
(数据处理)、os
、json
、PIL.Image
(图像处理)和tqdm
。
创建用于存储图像的输出目录。
打开处理后的结果文件result.jsonl
,逐行读取:
解析每行的JSON数据,提取文本和图像路径,分别存储到列表中。
使用pandas
创建一个包含文本和图像文件名的DataFrame。
将DataFrame保存为CSV文件。
显示DataFrame的内容。
使用CLIP模型计算图像和文本的相似度
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
从transformers
库中导入CLIPProcessor
和CLIPModel
,以及torch
。
加载预训练的CLIP模型和处理器。
打开DataFrame中所有的图像文件。
使用处理器将文本和图像进行预处理,返回PyTorch张量,并进行适当的填充。
将预处理后的数据输入模型,获得输出。
提取每个图像与文本的相似度分数(logits_per_image
)。
对相似度分数应用softmax,得到概率分布。
显示计算得到的概率。
定义自定义数据集和数据加载器
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)
从torch.utils.data
中导入Dataset
和DataLoader
。
定义CustomDataset
类:
在初始化时,存储文本列表、打开的图像列表和处理器。
实现__len__
方法,返回数据集的大小。
实现__getitem__
方法,对指定索引的数据进行处理,并返回处理后的输入。
创建数据集和数据加载器,设置批次大小为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
导入torch
和StableDiffusionPipeline
。
设置随机种子为1,确保生成的图像可重复。
加载预训练的Stable Diffusion模型,并将其移动到GPU上,设置为半精度浮点数以节省显存。
定义正向和负向提示词,以及指导尺度和推理步数。
使用提示词生成图像,指定图像的高度和宽度为1024像素。
保存生成的图像为example_image.png
,并显示图像。
生成更多图像并保存
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")
使用不同的随机种子和提示词,生成多张图像,并分别保存为1.jpg
至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
导入numpy
和PIL.Image
。
打开之前生成的8张图像,将其转换为numpy数组。
将图像按照行和列拼接,形成一个大的图像网格:
每行拼接两张图像,共四行。
将拼接后的图像调整大小为1024x2048像素。
显示最终的拼接图像。
利用AI生成剧本(以kimi为例)
提示词1:你是一个古风漫画家,我们现在要做一个古风仙侠漫,现在要写一个故事简介
提示词2:根据故事简介,写一个故事大纲
提示词3:展开第四章:修仙大会,并把漫画具体的场景描绘出来
提示词4:
你是一个文生图专家,我们现在要做一个实战项目,就是要根据刚才展开的修仙大会内容编排一个文生图,
由8张场景图片生成,你需要输出每张图片的生图提示词
生图提示词要求
1、风格为古风
2、根据场景确定是使用全身还是上半身
3、人物描述
4、场景描述
5、做啥事情
例子:
古风,水墨画,一个黑色长发少女,坐在教室里,盯着黑板,深思,上半身,红色长裙
修仙大会的提示词(AI生成)
AI生成的提示词微调后整理如下:
编号 场景 正向提示词 负向提示词 结果 1 大会前夕 古风,水墨画,市集繁华,一个笑容甜美的少女(笑笑),背影转头,穿梭在人群中,好奇地打量着各种摊位,全身,身着简单朴素的布衣。 丑陋,变形,嘈杂,模糊,低对比度 2 报名处的混乱 古风,水墨画,报名处人潮汹涌,一个表情轻松的少女(笑笑)站在人群中,用幽默化解紧张气氛,上半身,身着带有些许修仙特色的服饰。 丑陋,变形,嘈杂,模糊,低对比度 3 大会开幕式 古风,水墨画,宏伟的主会场,一个少女(笑笑)和其他修仙者一起,仰头观看开幕式,全身,身着节日盛装。 丑陋,变形,嘈杂,模糊,低对比度 4 比武大会 古风,水墨画,比武台上,一个少女(笑笑)正在进行灵力控制比赛,全身,身着便于活动的修仙服饰,脸上带着自信的微笑。 丑陋,变形,嘈杂,模糊,低对比度 5 夜晚的庆祝 古风,水墨画,夜市灯火通明,一个少女(笑笑)和她的队友们围坐一桌,品尝美食,享受烟火表演,上半身,身着轻便的夜行衣。 丑陋,变形,嘈杂,模糊,低对比度 6 意外的挑战 古风,水墨画,夜市角落,一个少女(笑笑)面对神秘人物,准备接受挑战,全身,身着带有一些神秘符号的服饰,表情认真。 丑陋,变形,嘈杂,模糊,低对比度 7 智慧的较量 古风,水墨画,僻静角落,一个少女(笑笑)和神秘人物进行灵力与智慧的较量,上半身,身着代表智慧的服饰,手中拿着棋子或类似道具。 丑陋,变形,嘈杂,模糊,低对比度 8 大会的落幕 古风,水墨画,主会场,一个少女(笑笑)和她的队友们站在领奖台上,接受“最具潜力新人奖”,全身,身着带有荣誉象征的服饰,脸上洋溢着喜悦和自豪。 丑陋,变形,嘈杂,模糊,低对比度总结