当前位置:AIGC资讯 > AIGC > 正文

Datawhale X 魔搭AI夏令营 第四期-AIGC文生图lora方向 Task2笔记

        继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 提示词修改 生成图片

总结

更新时间 2024-08-26