Datawhale AI夏令营第四期 魔搭-AIGC方向 task02笔记:精读代码,实战进阶

0.背景

  1. 对所有人来说,定期关注AI生图的最新能力情况都十分重要:
  • 对于普通人来说,可以避免被常见的AI生图场景欺骗,偶尔也可以通过相关工具绘图;
  • 对于创作者来说,通过AI生图的工具可以提效,快速制作自己所需要的内容;
  • 对于技术人来说,了解AI生图的能力的玩法,可以更好地针对自己的业务进行开发和使用,甚至攻克难题开发更实用的工具。
  1. 如何辨别AI生成的图片:
  • 观察图片的细节。仔细检查人物的面部特征,尤其是眼睛和嘴巴;
  • 检查光线和阴影。分析图片中的光源是否一致,阴影的方向是否与光源相符,是否存在不自然的光线或阴影;
  • 分析像素。放大图片,寻找是否有模糊或像素化的部分;
  • 注意背景。检查背景中是否有不协调的元素,比如物体边缘是否平滑,背景中是否有不自然的重复模式。
  1. Kolors(可图)模型(点击即可跳转魔搭模型介绍页) 是快手开源的文本到图像生成模型,该模型具有对英语和汉语的深刻理解,并能够生成高质量、逼真的图像。
    代码开源链接:https://github.com/Kwai-Kolors/Kolors
    模型开源链接:https://modelscope.cn/models/Kwai-Kolors/Kolors
    技术报告链接:https://github.com/Kwai-Kolors/Kolors/blob/master/imgs/Kolors_paper.pdf
    魔搭研习社最佳实践说明:https://www.modelscope.cn/learn/575?pid=543
    魔搭社区还开源了专门的各种风格的可图咒语书(点击即可跳转),可以针对600+种不同风格,完善prompt,生成各种风格图片,可以在我们的学习当中使用。
    可图咒语书
  2. 创意海报生成工具,早已在代码中固定了相应的文字位置和对应的字体,才能进行相应的生成,且大概率是进行了两个步骤——
  • 一个步骤是AI生成背景,
  • 另一个步骤是通过代码将对应的文字显示到对应位置,
  • 然后渲染,合成图片,给到我们。
    创意海报生成

Part1、认识通义千问

通义千问是具有信息查询、语言理解、文本创作等多能力的AI助手。我们可以看到,编程与技术支持能力是它的强项之一。

Part2、从零入门AI生图(精读baseline)

1、baseline代码的框架结构

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

2、分析代码的主体架构

2.1、输入提示词

你是一个优秀的python开发工程师,现在我们需要你帮我们分析这个代码的主体框架,你需要把代码按照工作流分成几部分,用中文回答我的问题。{此处替换前面的代码}

2.2、返回的结果

这段代码可以被分为几个主要的工作流程部分来分析:

  1. 环境准备与依赖安装
    这部分包括了使用 !pip 命令来安装或卸载所需的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
  1. 数据集加载与预处理
    这部分从 ModelScope 加载了一个名为 lowres_anime 的数据集,并将图像文件保存到指定目录,并创建了一个包含元数据的JSONL文件。
from modelscope.msdatasets import MsDataset
# ...
ds = MsDataset.load(
    'AI-ModelScope/lowres_anime',
    subset_name='default',
    split='train',
    cache_dir="/mnt/workspace/kolors/data"
)
# ...
  1. 数据过滤与转换
    这部分使用 Data-Juicer 库来对数据进行过滤(例如确保图像尺寸和宽高比满足特定要求),并生成经过处理的数据集。
import json, os
from data_juicer.utils.mm_utils import SpecialTokens
from tqdm import tqdm
# ...
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
  1. 数据集导出为CSV文件
    这部分将经过处理的数据集导出为CSV格式,方便后续使用。
import pandas as pd
# ...
df.to_csv("./data/data-juicer/output/result.csv", index=False)
  1. 使用CLIP模型进行图像-文本相似度计算
    这部分利用 CLIP 模型来计算图像和描述文本之间的相似度分数。
from transformers import CLIPProcessor, CLIPModel
import torch
# ...
outputs = model(**inputs)
logits_per_image = outputs.logits_per_image
probs = logits_per_image.softmax(dim=1)
  1. 创建自定义数据集类和数据加载器
    这部分定义了一个 CustomDataset 类用于封装数据集,并创建了一个 PyTorch 的 DataLoader 对象以批量加载数据。
from torch.utils.data import Dataset, DataLoader
# ...
dataloader = DataLoader(dataset, batch_size=8)
  1. 生成图像
    这部分使用了 StableDiffusionPipeline 来根据不同的提示生成一系列的二次元风格图像。
from diffusers import StableDiffusionPipeline
# ...
image = pipe(
    prompt=prompt,
    negative_prompt=negative_prompt,
    guidance_scale=guidance_scale,
    num_inference_steps=num_inference_steps,
    height=1024,
    width=1024,
).images[0]
  1. 合并生成的图像
    最后,将生成的多个图像合并成一个大图像,并调整大小。
import numpy as np
from PIL import Image
# ...
image = Image.fromarray(image).resize((1024, 2048))

整个流程涵盖了从数据加载、预处理、特征提取、模型训练到结果生成等多个方面。希望这个分析能够帮助您更好地理解这段代码的结构和功能。

2.3 执行过程

输入问题
返回结果

3、逐行解释代码

3.1、输入提示词

你是一个优秀的python开发工程师,现在我们需要你帮我们逐行分析这个代码,用中文回答我的问题。{此处替换前面的代码}

3.2、返回的结果

这段代码主要分为几个部分:安装依赖包、数据处理和图像生成。下面我会逐步解释每部分的功能。
安装依赖包
首先,通过 !pip 命令安装或卸载一些Python包:
安装 simple-aesthetics-predictor:这是一个用于预测美学评分的简单工具。
安装 data-juicer:这是一个用于数据清洗和预处理的工具,这里使用了 -v 参数来显示详细的安装信息,-e 参数表示以可编辑模式安装(通常用于开发环境中)。
卸载 pytorch-lightning:卸载已有的 pytorch-lightighting 包。
安装 peft, lightning, pandas, 和 torchvision:这些是用于深度学习模型训练和数据处理的库。
安装 DiffSynth-Studio:这似乎是一个特定于项目的包,同样使用了 -e 参数进行可编辑模式安装。
数据处理
接下来的部分涉及到数据集的加载、处理以及过滤。

加载数据集:

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 的数据集,并指定缓存目录为 /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")

该段代码将数据集中每个样本的图片转换为RGB格式,并保存到指定路径下。同时将图片路径和描述性文本写入JSONL文件中。
配置并运行数据清洗:

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

此处定义了一个配置文件,用于指定数据清洗的参数,如最小宽度、高度等,并使用 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文件。
使用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

使用预训练的CLIP模型计算图像和文本之间的相似度得分。
定义数据集类并创建数据加载器:


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)

定义了一个自定义的数据集类,并使用PyTorch的DataLoader来批量处理数据。
图像生成
最后,使用Stable Diffusion模型根据不同的提示生成图像。

加载Stable Diffusion模型:


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")

加载了Stable Diffusion v1.4模型,并将其移动到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
使用不同的提示生成图像,并设置一些参数如 guidance_scale 和 num_inference_steps 控制生成过程。
拼接多个图像:
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

最后将多个生成的图像拼接成一张大图,并调整大小。
以上就是整个代码的概述及分析。如果需要更详细的信息或有其他具体问题,请随时告诉我。

3.3 执行过程

输入问题
返回结果
ps:如果对代码还有疑问,可以继续提问。例如我对其中{替换成你的问题}还是不太理解,给我再详细介绍一下

Part3:实战演练一一基于话剧的连环画制作

1、执行Task1的30分钟速通Baseline

参考上一篇笔记:https://mp.csdn.net/mp_blog/creation/editor/141095380

2、提示词修改

  1. 双击进入baseline文件
  2. 找到生成图像的板块
  3. 依次替换8张图片的正向提示词和反向提示词

3、结果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值