继task01跑通baseline之后,有时候回想起实例中那些自己摸不着头脑的代码片段,确实有些好奇,task2正好用借助通用大语言模型工具精读了一下这些代码片段,并进行了实战演练一一基于话剧的连环画制作。
(这里学习文档给出的大语言模型是国内的通义千问,但是个人更喜欢用chatgpt-4o,感觉又快又准)
1.精读baseline代码
1.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
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开发工程师,现在我们需要你帮我们分析这个代码的主体框架,你需要把代码按照工作流分成几部分,用中文回答我的问题。{此处替换前面的代码}
Answer:
这个代码的主体框架可以按照工作流分为几个主要部分,每个部分的功能和作用如下:
### 1. **环境准备和依赖安装**
- **代码片段:**
```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
```
- **说明:**
这一部分是进行必要的库和依赖项的安装,为后续的代码运行做好准备。这些库包括图像处理、数据集处理、模型推理等所需的工具。
### 2. **数据集加载与预处理**
- **代码片段:**
```python
from modelscope.msdatasets import MsDataset
ds = MsDataset.load(
'AI-ModelScope/lowres_anime',
subset_name='default',
split='train',
cache_dir="/mnt/workspace/kolors/data"
)
```
- **说明:**
这一部分代码从指定的来源加载数据集,并存储到本地缓存目录中,供后续使用。
### 3. **数据保存与配置文件生成**
- **代码片段:**
```python
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")
```
- **说明:**
这部分代码将数据集中的图像保存到指定目录,并生成相应的元数据文件,用于后续的数据处理工作。
### 4. **数据处理和过滤**
- **代码片段:**
```python
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:
- 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` 工具对数据集进行预处理和过滤,保留符合要求的图像数据。
### 5. **数据处理后的结果保存**
- **代码片段:**
```python
import pandas as pd
import os, json
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)
```
- **说明:**
这部分代码将经过处理的图像和文本数据保存为 CSV 文件,便于后续分析和使用。
### 6. **模型推理与概率计算**
- **代码片段:**
```python
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. **自定义数据集与数据加载**
- **代码片段:**
```python
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)
```
- **说明:**
这部分代码定义了一个自定义数据集,并创建数据加载器,以批量处理数据进行模型推理。
### 8. **生成图片**
- **代码片段:**
```python
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")
```
- **说明:**
这一部分使用 `StableDiffusionPipeline` 生成图像,基于提供的 prompt 和 negative prompt,生成不同内容的二次元风格图片。
### 9. **图片拼接与最终图像生成**
- **代码片段:**
```python
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.2 逐行解释代码
prompt:你是一个优秀的python开发工程师,现在我们需要你帮我们逐行分析这个代码,用中文回答我的问题。{此处替换前面的代码}
Answer:
以下是对给定代码的逐行中文分析:
### 1. **安装依赖库**
```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
```
- **说明**:这一部分代码使用 `pip` 安装了一些需要的 Python 包和库。这些库包括 `simple-aesthetics-predictor`(用于美学评分的预测器)、`data-juicer`(数据处理工具包)、`pytorch-lightning`(一种轻量级的 PyTorch 封装,已卸载并替换为 `lightning`)、`peft`、`pandas`(数据处理库)、`torchvision`(用于计算机视觉的库)以及 `DiffSynth-Studio`(用于图像生成的工具包)。
### 2. **加载数据集**
```python
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` 方法加载一个名为 `lowres_anime` 的低分辨率动漫图像数据集。这个数据集被存储在本地缓存目录 `/mnt/workspace/kolors/data` 中。
### 3. **导入必要的模块**
```python
import json, os
from data_juicer.utils.mm_utils import SpecialTokens
from tqdm import tqdm
```
- **说明**:导入 Python 标准库的 `json` 和 `os` 模块,分别用于处理 JSON 数据和操作系统功能。`SpecialTokens` 是从 `data_juicer` 的 `mm_utils` 中导入的工具类,而 `tqdm` 则用于显示循环进度条。
### 4. **创建文件夹并处理数据集**
```python
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/lora_dataset/train` 和 `./data/data-juicer/input`。然后,遍历数据集 `ds`,将图像转换为 RGB 格式并保存到 `train` 文件夹中。对于每个图像,生成相应的元数据(包括文本标签“二次元”和图像路径),并将这些元数据写入 `metadata.jsonl` 文件中。
### 5. **生成数据处理配置文件**
```python
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` 数据处理的 YAML 配置文件。该配置文件定义了全局参数(如项目名称、数据集路径、并行处理子进程数)、文本和图像键,以及图像过滤器(基于图像的最小宽度、高度和宽高比)。
### 6. **执行数据处理任务**
```python
!dj-process --config data/data-juicer/data_juicer_config.yaml
```
- **说明**:使用 `data-juicer` 命令行工具根据上一步生成的配置文件 `data_juicer_config.yaml` 来处理数据集。处理后的结果将被保存到 `data/data-juicer/output/result.jsonl`。
### 7. **加载处理后的数据并保存为 CSV 文件**
```python
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)
```
- **说明**:从 `result.jsonl` 文件中读取处理后的数据,并提取文本和图像文件名,存储在 `texts` 和 `file_names` 列表中。然后将这些数据保存为 Pandas DataFrame,并导出为 CSV 文件 `result.csv`。
### 8. **使用 CLIP 模型计算图像与文本的相似性**
```python
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` 库中的 CLIP 模型和处理器,并使用 `CLIPModel` 加载预训练的 CLIP 模型。随后,处理图像和文本数据,将其输入模型,计算每张图像与文本之间的相似性得分,并通过 softmax 函数计算得分的概率分布。
### 9. **定义自定义数据集类并使用 DataLoader**
```python
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` 类,用于将文本和图像数据包装成一个 PyTorch 数据集。`__getitem__` 方法返回处理后的图像和文本张量。然后使用 `DataLoader` 进行批量加载,并在每个批次中进行模型推理,计算图像与文本的相似性得分。
### 10. **使用 Stable Diffusion 生成图像**
```python
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` 从预训练的 `stable-diffusion-v-1-4` 模型生成图像。设置随机种子、加载模型到 GPU,并根据提供的 prompt 和 negative prompt 生成图像,最终将图像保存为 `example_image.png`。
### 11. **使用不同的提示词生成更多图像**
```python
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")
```
- **说明**:这段代码生成一系列图像,使用不同的 prompt 和随机种子。每个图像使用相应的 prompt 生成并保存为不同的文件(如 `1.jpg`, `2.jpg` 等等)。每个 prompt 描述了不同的场景或动作。
### 12. **拼接多个图像生成最终结果**
```python
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`,并将生成的八张图像拼接成一个大图。首先,将图像按行拼接,然后将所有行拼接成一个最终的图像,最后将其调整为目标尺寸 `1024x2048`。
这段代码整体上展示了从数据处理、模型推理、图像生成到结果展示的完整流程。
1.3 理解之后加上逐行注释
# 安装简单美学预测器包
!pip install simple-aesthetics-predictor
# 以可编辑模式安装 data-juicer 包,方便进行调试和开发
!pip install -v -e data-juicer
# 卸载 pytorch-lightning 包,并安装特定的库:peft, lightning, pandas, torchvision
!pip uninstall pytorch-lightning -y
!pip install peft lightning pandas torchvision
# 以可编辑模式安装 DiffSynth-Studio 包
!pip install -e DiffSynth-Studio
# 从 ModelScope 加载 MsDataset 数据集类
from modelscope.msdatasets import MsDataset
# 加载 'lowres_anime' 数据集,指定训练集部分,并缓存到指定目录
ds = MsDataset.load(
'AI-ModelScope/lowres_anime',
subset_name='default',
split='train',
cache_dir="/mnt/workspace/kolors/data"
)
# 导入所需的库,包括 JSON 处理、操作系统接口、tqdm 进度条工具,以及 data_juicer 的实用工具
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)
# 打开 metadata.jsonl 文件,以写入模式保存图像的元数据
with open("./data/data-juicer/input/metadata.jsonl", "w") as f:
# 遍历数据集中的每一条数据
for data_id, data in enumerate(tqdm(ds)):
# 将图像转换为 RGB 格式
image = data["image"].convert("RGB")
# 保存图像到指定路径,并以数据ID命名
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"]}
# 将元数据写入 metadata.jsonl 文件中
f.write(json.dumps(metadata))
f.write("\n")
# 定义 data_juicer 的配置文件,包含全局参数和处理流程
data_juicer_config = """
# 全局参数
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:
- 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 # 任意一个条件满足即可
"""
# 将配置文件写入到指定的 YAML 文件中
with open("data/data-juicer/data_juicer_config.yaml", "w") as file:
file.write(data_juicer_config.strip())
# 使用 data-juicer 进行数据处理,依据刚才生成的配置文件
!dj-process --config data/data-juicer/data_juicer_config.yaml
# 导入所需的库,包括 pandas、操作系统接口、JSON 处理、图像处理工具 PIL,以及 tqdm 进度条工具
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)
# 打开结果文件 result.jsonl,读取处理后的元数据
with open("./data/data-juicer/output/result.jsonl", "r") as f:
for line in tqdm(f): # 遍历每一行数据
metadata = json.loads(line) # 将 JSON 字符串解析为字典
texts.append(metadata["text"]) # 将文本添加到文本列表中
file_names.append(metadata["image"][0]) # 将图像路径添加到文件名列表中
# 创建 DataFrame 存储文本和文件名,并保存为 CSV 文件
df = pd.DataFrame({"text": texts, "file_name": file_names})
df.to_csv("./data/data-juicer/output/result.csv", index=False)
# 显示 DataFrame 内容
df
# 从 transformers 库中导入 CLIP 模型和处理器
from transformers import CLIPProcessor, CLIPModel
import torch
# 加载预训练的 CLIP 模型和处理器
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) # 对相似度得分进行 softmax 处理,获得概率分布
# 显示概率分布
probs
# 从 PyTorch 中导入数据集和数据加载器模块
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 # CLIP 处理器
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
# 创建自定义数据集实例,并使用 DataLoader 加载数据集
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 和 Stable Diffusion 管道
import torch
from diffusers import StableDiffusionPipeline
# 设置随机种子以保证生成结果的可重复性
torch.manual_seed(1)
# 加载预训练的 Stable Diffusion 模型,并将其设置为 float16 类型以提高性能
pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v-1-4", torch_dtype=torch.float16)
pipe = pipe.to("cuda") # 将模型加载到 GPU 上
# 定义生成图像的文本提示和负面提示
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
# 导入 PIL 图像处理库
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")
# 导入 NumPy 和 PIL 库,用于图像处理
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
2.实战演练一一基于话剧的连环画制作
2.1 数据准备
Prompt:
你是一个文生图专家,我们现在要做一个实战项目,就是要编排一个文生图话剧 话剧由8张场景图片生成,你需要输出每张图片的生图提示词 具体的场景图片 1、女主正在上课 2、开始睡着了 3、进入梦乡,梦到自己站在路旁 4、王子骑马而来 5、两人相谈甚欢 6、一起坐在马背上 7、下课了,梦醒了 8、又回到了学习生活中 生图提示词要求 1、风格为古风 2、根据场景确定是使用全身还是上半身 3、人物描述 4、场景描述 5、做啥事情 例子: 古风,水墨画,一个黑色长发少女,坐在教室里,盯着黑板,深思,上半身,红色长裙
Answer:
1. 女主正在上课
提示词:
古风,水墨画,一个黑色长发少女,坐在古色古香的课堂里,面前是一本展开的书,正在认真听课,上半身,穿着浅绿色古代长袍。
2. 开始睡着了
提示词:
古风,水墨画,一个黑色长发少女,坐在古色古香的课堂里,眼神逐渐迷离,头微微低下,手轻轻撑着脸颊,睡意渐浓,上半身,浅绿色古代长袍。
3. 进入梦乡,梦到自己站在路旁
提示词:
古风,水墨画,一个黑色长发少女,站在铺满落叶的古道旁,身边是寂静的竹林,神情恍惚,仿佛置身梦境,全身,淡紫色古代长裙。
4. 王子骑马而来
提示词:
古风,水墨画,一个英俊的王子,身穿深蓝色长袍,骑着一匹白色骏马,从远处的山道缓缓而来,手握缰绳,目光温柔,全身,背景是苍翠的群山。
5. 两人相谈甚欢
提示词:
古风,水墨画,一个黑色长发少女,和英俊的王子并肩站在古道旁,两人神情愉悦,正在交谈,背景是青翠的竹林和古道,全身,少女穿着淡紫色古代长裙,王子身穿深蓝色长袍。
6. 一起坐在马背上
提示词:
古风,水墨画,一个黑色长发少女与英俊的王子同乘一匹白马,王子在前,少女轻轻扶着他的肩膀,马儿缓缓前行,背景是夕阳映照下的古道,全身,少女穿着淡紫色古代长裙,王子身穿深蓝色长袍。
7. 下课了,梦醒了
提示词:
古风,水墨画,一个黑色长发少女,突然惊醒,发现自己仍然坐在古色古香的课堂里,双眼睁大,神情微带迷茫,上半身,浅绿色古代长袍,面前是展开的书。
8. 又回到了学习生活中
提示词:
古风,水墨画,一个黑色长发少女,重新专心于书本,手中握着毛笔,正在古色古香的课堂里奋笔疾书,背景是古代书桌和书籍,上半身,浅绿色古代长袍。
2.2 执行Task1的30分钟速通Baseline
中途遇到显存不足的问题,清理缓存之后解决
2.3 提示词修改 生成图片
总结