目录
4.但这是第二次运行成果,第一次出现了一些报错,在下图所示代码下方报错:
task01
从零入门AI生图原理&实践 是Datawhile 2024年AI夏令营第四期AIGC方向学习活动,基于魔搭社区“可图Kolors-LoRA风格故事挑战赛”开展的时间学习。
Datawhile官方速通链接:Datawhale (linklearner.com)https://linklearner.com/activity/14/10/24
下面是学习笔记:
1.开通阿里云PAI-DSW试用并在魔搭社区进行授权;
2.创建PAI实例,以上过程较为简单,略;
3.执行baseline
(1)创建实例后输入以下代码以下载baseline文件:
git lfs install
git clone https://www.modelscope.cn/datasets/maochase/kolors.git
这是为了拉取远程baseline文件,回车运行等待就好
之后打开baseline文件;
(2)安装环境并重启kernel
包括安装 Data-Juicer 和 DiffSynth-Studio
其中Data-Juicer为数据处理和转换工具,旨在简化数据的提取、转换和加载过程
DiffSynth-Studio为高效微调训练大模型工具
不过这一步可能会因为网络问题导致环境安装缺漏,重启是为了防止显存溢出影响后续运行
(3)调整prompt,设置想要的图片风格,依次修改8张图片的描述,包括正面和负面
这里我修改了图1的八个描述想看看能否成功生成想要的大致类型,我将其修改为:
"二次元,一个紫色长发女性,在草地中站着,双手拿着刀,很严肃,全身,粉色汉服”
点击运行后成功运行
4.但这是第二次运行成果,第一次出现了一些报错,在下图所示代码下方报错:
No module named 'data_juicer'
尝试过后发现只需要restart实例并重新运行便可解决
5.而整个模型微调训练过程如下:
首先下载模型、查看训练脚本传入参数,然后开始训练;调参是很重要的环节但学习任务暂时没到所以很期待之后学习内容
6.将结果上传魔搭社区:
创建新的实例并运行:
mkdir /mnt/workspace/kolors/output & cd
cp /mnt/workspace/kolors/models/lightning_logs/version_0/checkpoints/epoch\=0-step\=500.ckpt /mnt/workspace/kolors/output/
cp /mnt/workspace/kolors/1.jpg /mnt/workspace/kolors/output/
之后在output文件夹下载jpg文件和ckpt文件,在魔搭社区创建并上传两个文件即可
7.最后别忘记关闭pai实例,整个过程结束,结尾附高清图:
task02
此任务旨在对baseline的代码有一个更加细致的理解,并学习如何借助AI来提升我们的自学习能力。且通过任务一的学习我们知道数据集的重要性,我们可以在魔搭社区的开源数据集中寻找我们所需要的数据。
下面是正式的学习:
1.认识通义千问
2.精度baseline,从零入门AI生图
task01只是跑了一遍模型,但不知道哪个模块究竟何用,下面将进行系统学习
文生图代码框架如下:
全部代码如下:
!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
(1)向通义千问询问代码整体架构:
这段代码可以分为几个主要的工作流程部分:
### 1. 环境和依赖包安装
首先,代码通过`!pip install`命令安装了一系列的Python包,包括`simple-aesthetics-predictor`, `data-juicer`, `peft`, `lightning`, `pandas`, `torchvision`, 和 `DiffSynth-Studio`。
### 2. 数据集加载与预处理
接着,从ModelScope加载了一个名为`lowres_anime`的数据集,并将数据转换为适合进一步处理的格式。具体步骤包括:
- 将数据集中的图像转换为RGB模式并保存到磁盘。
- 创建一个JSONL文件,其中包含每张图片的路径和相关文本描述。
### 3. 数据清洗与过滤
使用`data-juicer`工具对数据进行清洗,包括尺寸和长宽比的过滤,以确保所有图像满足特定的质量标准。这一步骤是通过读取配置文件`data_juicer_config.yaml`来实现的,该配置文件定义了过滤规则和输出路径。
### 4. 数据整理与特征提取
接下来,代码将处理后的数据集整理成DataFrame格式,并使用CLIP模型提取图像和文本的嵌入向量。这些向量用于计算图像和文本之间的相似度。
### 5. 自定义数据集与数据加载器
创建一个自定义的PyTorch数据集类`CustomDataset`,用于封装DataFrame中的数据,并构建一个数据加载器`DataLoader`,以便在训练模型时高效地提供批处理数据。
### 6. 图像生成
最后,利用`StableDiffusionPipeline`生成二次元风格的图像。这部分代码使用了不同的提示(prompt)和负面提示(negative prompt)来指导图像生成过程,从而创造出符合特定描述的二次元图像。
### 7. 结果展示
代码还包含了将生成的多个图像拼接在一起,形成一个大的图像,用于结果展示或进一步分析。
整个工作流涉及数据集的获取、预处理、特征提取、数据集构建以及基于深度学习的图像生成。
(2)向通义千问请求逐行解释代码:
这段代码执行了一系列的任务,从环境设置、数据集处理到图像生成。下面是对每一部分的逐行分析:
### 环境设置
!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`。同时卸载了旧版本的`pytorch-lightning`,并重新安装。
### 数据集加载与预处理
from modelscope.msdatasets import MsDataset
ds = MsDataset.load(
'AI-ModelScope/lowres_anime',
subset_name='default',
split='train',
cache_dir="/mnt/workspace/kolors/data"
)
这里从ModelScope加载了`lowres_anime`数据集,并指定了缓存目录。
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")
这部分代码创建了两个目录用于存储处理过的图像和元数据文件。然后遍历数据集,将图像转换为RGB模式并保存,同时生成一个JSONL格式的元数据文件,其中包含每张图像的路径和文本描述“二次元”。
### 数据清洗与过滤
data_juicer_config = """
...
"""
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`的配置文件,包括数据集路径、预处理操作(如图像尺寸和长宽比过滤)等。然后运行`dj-process`命令来应用这些预处理操作。
### 数据整理与特征提取
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`创建DataFrame,将数据写入CSV文件,并显示DataFrame的内容。
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模型来计算图像和文本的相似度。
### 自定义数据集与数据加载器
from torch.utils.data import Dataset, DataLoader
class CustomDataset(Dataset):
...
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)
创建自定义的PyTorch数据集和数据加载器,用于批量处理数据,并再次计算图像与文本的相似度。
### 图像生成
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
使用`StableDiffusionPipeline`生成二次元风格的图像,基于不同的提示和负面提示。
### 结果展示
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
最后,将生成的图像拼接成一张大图,用于展示或进一步分析。
整个代码流程涵盖了从数据集的加载和预处理,到特征提取,再到图像生成和展示的完整过程。
(3)追问
pipe
是什么?
pipe
是一个StableDiffusionPipeline
实例,这是一个深度学习模型,能够根据给定的文本描述(prompt
)生成对应的图像。这个模型是在大量数据上预训练的,能够理解和生成与文本相关的视觉内容。
prompt
参数
prompt
是一个字符串,它包含了您想要生成图像的主题描述。例如,"二次元,一个紫色长发小女孩穿着粉色吊带漏肩连衣裙,在练习室练习唱歌,手持话筒"
这个prompt
告诉模型您希望看到的图像内容。
negative_prompt
参数
negative_prompt
也是一个字符串,但它包含了您不希望在生成的图像中出现的元素或属性。例如,"丑陋、变形、嘈杂、模糊、低对比度"
这个negative_prompt
告诉模型避免生成质量差、细节不清楚或有视觉噪音的图像。
guidance_scale
参数
guidance_scale
是一个浮点数,控制生成图像时prompt
和negative_prompt
的影响程度。较高的guidance_scale
意味着模型更严格地遵循prompt
和negative_prompt
,而较低的值则允许更多的随机性和变化。
num_inference_steps
参数
num_inference_steps
是一个整数,表示在生成图像的过程中迭代的次数。更多的步数通常会导致更精细的图像细节,但也会增加生成所需的时间。
height
和width
参数
这两个参数分别设置了输出图像的高度和宽度,单位是像素。在这个例子中,图像的大小被设定为1024x1024像素。
images[0]
pipe
方法返回一个列表,其中包含了生成的图像。由于我们只请求生成一幅图像,所以通过[0]
访问列表中的第一个(也是唯一一个)元素。
综上所述,这行代码的作用是根据提供的prompt
和negative_prompt
生成一幅1024x1024像素的图像,并且通过调整guidance_scale
和num_inference_steps
来控制生成过程的确定性和质量。生成的图像会被保存到变量image
中,之后可以进行保存、显示或进一步处理。
如果您需要查看生成的图像,我们可以使用wand
或者matplotlib
这样的库来显示图像。不过,由于当前的对话环境中无法直接显示图像,您可以运行这段代码在您的本地环境中,并使用适当的图像查看函数来观察结果。如果需要,我也可以帮助您构建一个简单的图像显示脚本。
3.实战演练-基于话剧的连环画制作
基于您的要求,以下是针对每个场景的生图提示词建议,结合古风元素以及场景的描述:
1. **古风,工笔画,一个着汉服的少女,端坐于书斋之中,手执毛笔,凝视着竹简,上半身,周围摆放着砚台和书籍。**
这幅画面聚焦于女主的专注神情和她所在的古典书斋环境,强调了学习的氛围。
2. **古风,淡雅的色彩,同一个少女,趴在桌上,双眸微闭,呼吸轻柔,上半身,身穿蓝色绸缎长袍,桌面上散落着未完成的诗稿。**
描述了少女在课堂上的小憩,画面温柔,突出其安静的睡态。
3. **古风,云雾缭绕的背景,少女站立于青石小径旁,衣袂飘飘,神色迷离,全身,身后是繁花似锦的春景。**
场景转换到了梦中,展现了一种超现实的美感,少女仿佛置身于仙境。
4. **古风,骏马驰骋于林间小道,一位英俊少年骑在马上,眼神坚定,全身,背景是翠绿的山林,阳光透过树梢洒下斑驳光影。**
描述了王子的出场,强调了其英勇的形象和自然的壮丽背景。
5. **古风,二人并肩而立于花园之中,对话亲密无间,全身,背景是盛开的牡丹和精致的亭台楼阁,少女面带微笑,少年神情专注。**
展现了二人在梦中的愉快交谈,场景充满了浪漫的气息。
6. **古风,二人共乘一骑,少女轻倚在少年身后,双手环绕腰际,全身,背景是广阔的田野和远山,夕阳映照天际。**
描述了他们共同旅行的情景,画面温馨且充满动感。
7. **古风,少女突然睁眼,从梦中惊醒,上半身,表情惊讶,身着学习时的素色衣裳,周围是熟悉的教室环境。**
突出了梦醒瞬间的反应,与之前梦幻般的场景形成鲜明对比。
8. **古风,少女重新投入到学习中,与同学们围坐讨论,全身,背景是充满书香气息的教室,桌上堆满卷轴和书籍。**
描述了女主回到现实世界后,继续与同学们共同学习的场景,强调了团结和学术的氛围。
这些提示词试图捕捉每个场景的精髓,同时保持一致的古风艺术风格,既描绘了人物也展现了环境,还融入了动作和情感的表达。希望这些建议能帮助您实现预期的话剧视觉效果。
将上述关键词,简单修改成自己想要的,如我在每句话中都加入了“水墨画”关键词。运用task01的学习过程中:
结果如下:
1.
2.
3.
4.
5.
6.
7.
8.