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

今天我们的任务是对baseline的代码有一个更加细致的理解,然后我们会学习如何借助AI来提升我们的自学习能力,从而帮助大家在后面的学习工作中如何从容迎接各种挑战。授人以鱼不如授人以渔,你可以从中学大模型的提问技巧来实现快速学习,学会如何制作一个话剧连环画。

自其不变者而观之,则物与我皆无尽也’,拥抱AI、学习AI、运用AI解决各种变化的问题,一起加油!!!

探探前沿:了解一下 AI生图技术 的能力&局限

1、为什么要了解AI生图前沿?

AIGC(AI-Generated Content)是通过人工智能技术自动生成内容的生产方式,很早就有专家指出,AIGC将是未来人工智能的重点方向,也将改造相关行业和领域生产内容的方式。

AI生成图片拿下国际摄影大奖,外媒炸锅……

AI生成图片的快速发展,使诸多领域措手不及,如:摄影、美术等艺术领域正在面临前所未有的颠覆。我们所认为的“有图有真相”,甚至理解的现实也将不断被挑战...

插入一段小常识,提醒大家警惕Deepfake技术

Deepfake是一种使用人工智能技术生成的伪造媒体,特别是视频和音频,它们看起来或听起来非常真实,但实际上是由计算机生成的。这种技术通常涉及到深度学习算法,特别是生成对抗网络(GANs),它们能够学习真实数据的特征,并生成新的、逼真的数据。

Deepfake技术虽然在多个领域展现出其创新潜力,但其滥用也带来了一系列严重的危害。在政治领域,Deepfake可能被用来制造假新闻或操纵舆论,影响选举结果和政治稳定。经济上,它可能破坏企业形象,引发市场恐慌,甚至操纵股市。法律体系也面临挑战,因为伪造的证据可能误导司法判断。此外,深度伪造技术还可能加剧身份盗窃的风险,成为恐怖分子的新工具,煽动暴力和社会动荡,威胁国家安全。

由此衍生的Deepfake攻防技术,我们在今年夏令营的第二期中,有组织学习活动,具体可以查看:从零入门CV图像竞赛(Deepfake攻防)

对所有人来说,定期关注AI生图的最新能力情况都十分重要:

  • 对于普通人来说,可以避免被常见的AI生图场景欺骗,偶尔也可以通过相关工具绘图

  • 对于创作者来说,通过AI生图的工具可以提效,快速制作自己所需要的内容

  • 对于技术人来说,了解AI生图的能力的玩法,可以更好地针对自己的业务进行开发和使用,甚至攻克难题开发更实用的工具

2、再来从工具视角回顾一下AI生图的历史

最早的AI生图可追溯到20世纪70年代,当时由艺术家哈罗德·科恩(Harold Cohen)发明AARON,可通过机械臂输出作画。

现代的AI生图模型大多基于深度神经网络基础上训练,最早可追溯到2012年吴恩达训练出的能生成“猫脸”的模型。

它使用卷积神经网络(CNN)训练,证明了深度学习模型能够学习到图像的复杂特征。

2015年,谷歌推出了“深梦”(Deep Dream)图像生成工具,类似一个高级滤镜,可以基于给定的图片生成梦幻版图片——

2021 年 1 月 OpenAI 推出DALL-E模型(一个深度学习算法模型,是GPT-3 语言处理模型的一个衍生版本),能直接从文本提示“按需创造”风格多样的图形设计——

在当时,就已经被一些媒体评价为:“ 秒杀50%的设计行业打工人应该是没有问题的,而且是质量和速度双重意义上的“秒杀” ”。

一般来说,AI生图模型属于多模态机器学习模型,通过海量的图库和文本描述的深度神经网络学习,最终的目标是可以根据输入的指示(不管是文本还是图片还是任何)生成符合语义的图片

插入一个小八卦

AI生图在很长一段时间很难被人们所广泛接纳,一方面是生成的内容没有可用的生产场景,还有很大程度可能是由于“恐怖谷效应”——其核心观点是:随着仿真物(如机器人、玩偶等)模拟真实性程度的变化,人们对其亲和力也会产生变化,一般规律是亲和力随着仿真程度增高而增高,但当仿真程度达到一个临界点时,人的亲和反应会陡然跌入谷底,突然产生排斥、恐惧、困惑等负面心理。

通过学习大量画家的作品,AI生图模型 往往可以照猫画虎绘制出类似的画作,在2022年8月AI生图真正走进了大众的视野,让各个领域无法忽视

当时让AI生图破圈的是AI绘画作品《太空歌剧院》,该作品在美国科罗拉多州举办的新兴数字艺术家竞赛中获得了比赛“数字艺术/数字修饰照片”类别一等奖,引起了当时“艺术家们 Not Happy”的社会舆论。

3、AI生图的难点和挑战有哪些?

往前一年,AI绘画还不会画“手”——

也因为当时这个情况,产生了很多解决这个问题的相关技术,如:给图片里的人手打上标记,像把手掌、拇指、食指啥的,都给清楚地标出来;

我们现在还可以经常在各类自媒体的文章中看到“AI翻车”的案例,那些往往也是需要解决的难点,某些“翻车”现象,也许在业界已有相关的解决方案。

通俗来说,AI生图模型获得图片生成能力主要是通过 学习 图片描述 以及 图片特征,尝试将这两者进行一一对应,存储在自己的记忆里。

在我们需要的时候,通过输入的文字,复现出来对应的图片特征,从而生成了我们需要的图片。

关于AI是否真正理解了图片背后所代表的世界的特征,是否理解了图片的含义,这个一直是科研界和产业界存在争议的话题,我们唯一可以确定的是——

由于每个模型用于训练的数据是有限的且不一定相同的,它们能匹配的描述和特征也是有限的,所以在风格、具体事物上,不同的模型会有很大的生成差异,且可能存在诸多与现实不符的情况。

而这些问题,就是业界和科研界持续在想办法解决的问题。

在大部分生图场景下,我们可能经常会觉得图片存在“AI味”,这很长一段时间也是科研界和相关从业人员非常头大的问题。

*AI味:AI生成的图片和实际生活场景/艺术家创作的绘画/摄影/三维作品 相比,存在强烈的违和感,或是细节处理,或是画面逻辑性存在问题,一言就能被看出是“AI出品”

目前大部分的模型,已经具备了去除 “AI味” 的能力,且可能存在容易误导他人的情况,这时候我们想辨别可能需要非常仔细地——

  • 观察图片的细节。仔细检查人物的面部特征,尤其是眼睛和嘴巴

  • 检查光线和阴影。分析图片中的光源是否一致,阴影的方向是否与光源相符,是否存在不自然的光线或阴影

  • 分析像素。放大图片,寻找是否有模糊或像素化的部分。

  • 注意背景。检查背景中是否有不协调的元素,比如物体边缘是否平滑,背景中是否有不自然的重复模式。

而这些细节上的AI特性,也许就是我们在某些特定场景下需要解决的挑战。

4、开始探索AI生图前沿

我们要探索AI生图的前沿,就必须有一个持续更新,且我们持续愿意跟进和投入时间的“主线”引导,例如,可以从这次学习活动可图Kolors-LoRA风格故事挑战赛魔搭社区的各类AIGC工具 开始,持续探索、尝试、思考总结、实践,甚至开始持续创作自己的作品/工具

AI生图自破圈以来,被科研界、业界广泛关注,且引发了各大厂商的模型之战,如我们这次学习活动所需要用到的Kolors(可图)模型(点击即可跳转魔搭模型介绍页),就是其中的一个产物——

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

过去文生图主要以 SD 系列基础模型为主,仅支持英文的prompt,但可图是支持中文的文生图模型,文生图的prompt格式较为固定,魔搭社区还开源了专门的各种风格的可图优质咒语书(点击即可跳转),可以针对600+种不同风格,完善prompt,生成各种风格图片,可以在我们的学习当中使用——

5、通过魔搭社区持续探索AI生图前沿

在某些设计的场景中,我们还希望AI能为我们将特定的文字生成在图片当中,比如下面这种海报

但实际上,这种固定文字生成,往往难度较大,一是具体生成在哪些位置,往往需要人为设定,为了更方便地制作类似这样的海报还产生了PS等图片编辑工具,才能实现相应的效果,想要让AI稳定生成相似效果的图片可想而知难度之大。

像我们Task1中介绍的 创意海报生成 工具,早已在代码中固定了相应的文字位置和对应的字体,才能进行相应的生成,且大概率是进行了两个步骤——

  • 一个步骤是AI生成背景,

  • 另一个步骤是通过代码将对应的文字显示到对应位置,

  • 然后渲染,合成图片,给到我们。

事实上,我们可以通过魔搭社区上感兴趣的工具,尝试思考——

  • 可以用在哪些业务里?有哪些行业在使用?

  • 用的是哪个 AI 模型?

  • 是自己部署的AI模型,还是用的API?

  • 使用到了哪些 AI 能力?

  • 如果要复现,需要做哪些额外的设置和开发?

  • 还可以有哪些优化点?

最方便的是,我们还可以直接点到空间文件,进行相关代码的查看甚至下载在 本地/云服务器 复现,以验证思考 & 学习相关的设计开发:

魔搭社区还有各种资料,可以供我们学习&探索AI生图的前沿——

比如图像生成的技术的前沿你还可以查看魔搭社区出品这个视频:

1.2最新图像生成技术研究方向-介绍与分析_哔哩哔哩_bilibili

Part1:磨刀准备一一认识通义千问

通义tongyi.ai_你的全能AI助手

1. 通义千问的自我介绍

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

接下来我们把场景聚焦到编程与技术支持这个方向,让他详细介绍下自己可以如何帮助大家编程。(P2:编程能力介绍)。

          

      通义千问的自我介绍                       编程能力介绍

2. 抱走你的AI学习助教

3. 使用操作指南

官方链接:https://tongyi.aliyun.com/qianwen/

step1 注册账号

step2 通义主要功能模块

Part2:精读baseline——从零入门AI生图

在task1的任务中, 我们拿到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

1. 分析代码的主体架构

1.1 输入的Prompt

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

1.2 返回的结果

1. 安装和卸载依赖包

这部分代码使用 !pip 命令来安装或卸载所需的Python包。

1!pip install simple-aesthetics-predictor
2!pip install -v -e data-juicer
3!pip uninstall pytorch-lightning -y
4!pip install peft lightning pandas torchvision
5!pip install -e DiffSynth-Studio

2. 加载数据集

这里从ModelScope加载了一个名为 lowres_anime 的数据集,并将其保存到指定的目录中。

1from modelscope.msdatasets import MsDataset
2
3ds = MsDataset.load(
4    'AI-ModelScope/lowres_anime',
5    subset_name='default',
6    split='train',
7    cache_dir="/mnt/workspace/kolors/data"
8)

3. 准备训练数据

这部分代码将数据集中的图像文件保存到磁盘上,并创建一个JSONL文件,其中包含每张图像的路径和相应的文本描述。

1import json, os
2from data_juicer.utils.mm_utils import SpecialTokens
3from tqdm import tqdm
4
5# 创建目录并写入数据
6os.makedirs("./data/lora_dataset/train", exist_ok=True)
7os.makedirs("./data/data-juicer/input", exist_ok=True)
8with open("./data/data-juicer/input/metadata.jsonl", "w") as f:
9    for data_id, data in enumerate(tqdm(ds)):
10        image = data["image"].convert("RGB")
11        image.save(f"/mnt/workspace/kolors/data/lora_dataset/train/{data_id}.jpg")
12        metadata = {"text": "二次元", "image": [f"/mnt/workspace/kolors/data/lora_dataset/train/{data_id}.jpg"]}
13        f.write(json.dumps(metadata))
14        f.write("\n")

4. 数据处理配置与执行

这部分定义了一个配置文件,用于设置数据处理的参数,并调用 data-juicer 工具来过滤和处理图像数据。

1data_juicer_config = """..."""  # 配置字符串
2with open("data/data-juicer/data_juicer_config.yaml", "w") as file:
3    file.write(data_juicer_config.strip())
4
5!dj-process --config data/data-juicer/data_juicer_config.yaml

5. 处理输出数据

这部分代码读取经过 data-juicer 处理后的输出,并将其转换为Pandas DataFrame,然后保存为CSV文件。

1import pandas as pd
2import os, json
3from PIL import Image
4from tqdm import tqdm
5
6texts, file_names = [], []
7os.makedirs("./data/data-juicer/output/images", exist_ok=True)
8with open("./data/data-juicer/output/result.jsonl", "r") as f:
9    for line in tqdm(f):
10        metadata = json.loads(line)
11        texts.append(metadata["text"])
12        file_names.append(metadata["image"][0])
13
14df = pd.DataFrame({"text": texts, "file_name": file_names})
15df.to_csv("./data/data-juicer/output/result.csv", index=False)

6. 使用CLIP模型进行特征提取

这部分代码使用预训练的CLIP模型来计算图像和文本之间的相似度分数。

1from transformers import CLIPProcessor, CLIPModel
2import torch
3
4model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
5processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32")
6
7# 处理数据
8images = [Image.open(img_path) for img_path in df["file_name"]]
9inputs = processor(text=df["text"].tolist(), images=images, return_tensors="pt", padding=True)
10
11outputs = model(**inputs)
12logits_per_image = outputs.logits_per_image
13probs = logits_per_image.softmax(dim=1)

7. 构建自定义数据集

这部分创建了一个PyTorch数据集类,并使用它来构建一个数据加载器。

1from torch.utils.data import Dataset, DataLoader
2
3class CustomDataset(Dataset):
4    def __init__(self, df, processor):
5        # 初始化数据集
6        ...
7    
8    def __len__(self):
9        return len(self.texts)
10    
11    def __getitem__(self, idx):
12        # 获取数据项
13        ...
14
15dataset = CustomDataset(df, processor)
16dataloader = DataLoader(dataset, batch_size=8)
17
18# 迭代数据加载器
19for batch in dataloader:
20    outputs = model(**batch)
21    logits_per_image = outputs.logits_per_image
22    probs = logits_per_image.softmax(dim=1)
23    print(probs)

8. 生成图像

这部分代码使用 diffusers 库中的 StableDiffusionPipeline 来根据给定的提示生成图像,并保存这些图像。

1from diffusers import StableDiffusionPipeline
2
3# 初始化模型
4torch.manual_seed(1)
5pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v-1-4", torch_dtype=torch.float16)
6pipe = pipe.to("cuda")
7
8# 生成图像
9prompt = "二次元,一个紫色长发小女孩穿着粉色吊带漏肩连衣裙,在练习室练习唱歌,手持话筒"
10negative_prompt = "丑陋、变形、嘈杂、模糊、低对比度"
11guidance_scale = 4
12num_inference_steps = 50
13
14image = pipe(
15    prompt=prompt,
16    negative_prompt=negative_prompt,
17    guidance_scale=guidance_scale,
18    num_inference_steps=num_inference_steps,
19    height=1024,
20    width=1024,
21).images[0]
22
23image.save("example_image.png")

9. 合并图像

这部分代码将生成的多个图像合并成一个大的图像,并调整大小以便查看。

1import numpy as np
2from PIL import Image
3
4# 加载图像
5images = [np.array(Image.open(f"{i}.jpg")) for i in range(1, 9)]
6
7# 合并图像
8image = np.concatenate([
9    np.concatenate(images[0:2], axis=1),
10    np.concatenate(images[2:4], axis=1),
11    np.concatenate(images[4:6], axis=1),
12    np.concatenate(images[6:8], axis=1),
13], axis=0)
14image = Image.fromarray(image).resize((1024, 2048))

以上就是整个代码的主要工作流程。每一步都有其特定的任务和目的,从加载数据到最终生成和合并图像。

1.3 执行过程

2. 逐行解释代码

2.1 输入的问题

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

2.2 返回的结果

这段代码主要完成以下功能:

  1. 安装和卸载一些Python包。

  2. 从ModelScope加载一个名为lowres_anime的数据集,并保存图像到指定目录。

  3. 创建并处理一个用于数据清洗的JSONL文件。

  4. 使用data-juicer工具过滤和处理数据集。

  5. 将处理后的数据集转换为CSV格式。

  6. 根据数据集通过DiffSynth做Lora微调

  7. 加载Lora微调后的模型

  8. 设置提示词,用微调后的模型生成图片

# 安装 Data-Juicer 和 DiffSynth-Studio
!pip install simple-aesthetics-predictor # 安装simple-aesthetics-predictor
!pip install -v -e data-juicer # 安装data-juicer
!pip uninstall pytorch-lightning -y # 卸载pytorch-lightning
!pip install peft lightning pandas torchvision # 安装 peft lightning pandas torchvision
!pip install -e DiffSynth-Studio # 安装DiffSynth-Studio

# 从魔搭数据集中下载数据集AI-ModelScope/lowres_anime
from modelscope.msdatasets import MsDataset  #引入数据集模块msdatasets
ds = MsDataset.load(
    'AI-ModelScope/lowres_anime',
    subset_name='default',
    split='train',
    cache_dir="/mnt/workspace/kolors/data" # 指定缓存目录
) # 从魔搭数据集中下载数据集AI-ModelScope/lowres_anime,赋值给参数ds

# 生成数据集
import json, os # 导入json和os模块
from data_juicer.utils.mm_utils import SpecialTokens # 导入SpecialTokens
from tqdm import tqdm # 导入tqdm进度条管理
os.makedirs("./data/lora_dataset/train", exist_ok=True) # 创建文件夹./data/lora_dataset/train
os.makedirs("./data/data-juicer/input", exist_ok=True) # 创建文件夹./data/data-juicer/input
with open("./data/data-juicer/input/metadata.jsonl", "w") as f:
    for data_id, data in enumerate(tqdm(ds)): # 遍历数据集ds
        image = data["image"].convert("RGB") # 将数据集的图片转换为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)) # 将索引数据写入文件./data/data-juicer/input/metadata.jsonl
        f.write("\n")

# 配置data-juicer,并进行数据筛选过滤
# 配置过滤的规则
data_juicer_config = """
# global parameters
project_name: 'data-process' # 名称
dataset_path: './data/data-juicer/input/metadata.jsonl'  # 你前面生成的数据的索引文件
np: 4  # 线程数

text_keys: 'text' # 文件./data/data-juicer/input/metadata.jsonl的描述的字段名
image_key: 'image' # 文件./data/data-juicer/input/metadata.jsonl的图片字段名
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 # 最小宽度1024
        min_height: 1024 # 最小高度1024
        any_or_all: any # 符合前面条件的图片才会被保留
    - image_aspect_ratio_filter: # 图片长宽比过滤
        min_ratio: 0.5 # 最小长宽比0.5
        max_ratio: 2.0 # 最大长宽比2.0
        any_or_all: any # 符合前面条件的图片才会被保留
"""

# 保存data-juicer配置到data/data-juicer/data_juicer_config.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


# 通过前面通过data-juicer筛选的图片索引信息./data/data-juicer/output/result.jsonl,生成数据集
import pandas as pd # 导入pandas
import os, json # 导入os和json
from PIL import Image # 导入Image
from tqdm import tqdm # 导入tqdm进度条管理
texts, file_names = [], [] # 定义两个空列表,分别存储图片描述和图片名称
os.makedirs("./data/lora_dataset_processed/train", exist_ok=True) # 创建文件夹./data/lora_dataset_processed/train
with open("./data/data-juicer/output/result.jsonl", "r") as file: # 打开前面data-juicer筛选的图片索引文件./data/data-juicer/output/result.jsonl
    for data_id, data in enumerate(tqdm(file.readlines())): # 遍历文件./data/data-juicer/output/result.jsonl
        data = json.loads(data) # 将json字符串转换为对象
        text = data["text"] # 获取对象中的text属性,也就是图片的描述信息
        texts.append(text) # 将图片的描述信息添加到texts列表中
        image = Image.open(data["image"][0]) # 获取对象中的image属性,也就是图片的路径,然后用这个路径打开图片
        image_path = f"./data/lora_dataset_processed/train/{data_id}.jpg" # 生成保存图片的路径
        image.save(image_path) # 将图片保存到./data/lora_dataset_processed/train文件夹中
        file_names.append(f"{data_id}.jpg") # 将图片名称添加到file_names列表中
data_frame = pd.DataFrame() # 创建空的DataFrame
data_frame["file_name"] = file_names # 将图片名称添加到data_frame中
data_frame["text"] = texts # 将图片描述添加到data_frame中
data_frame.to_csv("./data/lora_dataset_processed/train/metadata.csv", index=False, encoding="utf-8-sig") # 将data_frame保存到./data/lora_dataset_processed/train/metadata.csv
data_frame # 查看data_frame


# 下载可图模型
from diffsynth import download_models # 导入download_models
download_models(["Kolors", "SDXL-vae-fp16-fix"]) # 下载可图模型
# DiffSynth-Studio提供了可图的Lora训练脚本,查看脚本信息
!python DiffSynth-Studio/examples/train/kolors/train_kolors_lora.py -h


# 执行可图Lora训练
import os
cmd = """
python DiffSynth-Studio/examples/train/kolors/train_kolors_lora.py \ # 选择使用可图的Lora训练脚本DiffSynth-Studio/examples/train/kolors/train_kolors_lora.py
  --pretrained_unet_path models/kolors/Kolors/unet/diffusion_pytorch_model.safetensors \ # 选择unet模型
  --pretrained_text_encoder_path models/kolors/Kolors/text_encoder \ # 选择text_encoder
  --pretrained_fp16_vae_path models/sdxl-vae-fp16-fix/diffusion_pytorch_model.safetensors \ # 选择vae模型
  --lora_rank 16 \ # lora_rank 16 表示在权衡模型表达能力和训练效率时,选择了使用 16 作为秩,适合在不显著降低模型性能的前提下,通过 LoRA 减少计算和内存的需求
  --lora_alpha 4.0 \ # 设置 LoRA 的 alpha 值,影响调整的强度
  --dataset_path data/lora_dataset_processed \ # 指定数据集路径,用于训练模型
  --output_path ./models \ # 指定输出路径,用于保存模型
  --max_epochs 1 \ # 设置最大训练轮数为 1
  --center_crop \ # 启用中心裁剪,这通常用于图像预处理
  --use_gradient_checkpointing \ # 启用梯度检查点技术,以节省内存
  --precision "16-mixed" # 指定训练时的精度为混合 16 位精度(half precision),这可以加速训练并减少显存使用
""".strip()
os.system(cmd) # 执行可图Lora训练


# 加载lora微调后的模型
from diffsynth import ModelManager, SDXLImagePipeline # 导入ModelManager和SDXLImagePipeline
from peft import LoraConfig, inject_adapter_in_model # 导入LoraConfig和inject_adapter_in_model
import torch # 导入torch
# 加载LoRA配置并注入模型
def load_lora(model, lora_rank, lora_alpha, lora_path):
    lora_config = LoraConfig(
        r=lora_rank, # 设置LoRA的秩(rank)
        lora_alpha=lora_alpha, # 设置LoRA的alpha值,控制LoRA的影响权重
        init_lora_weights="gaussian", # 初始化LoRA权重为高斯分布
        target_modules=["to_q", "to_k", "to_v", "to_out"], # 指定要应用LoRA的模块
    )
    model = inject_adapter_in_model(lora_config, model) # 将LoRA配置注入到模型中
    state_dict = torch.load(lora_path, map_location="cpu") # 加载LoRA微调后的权重
    model.load_state_dict(state_dict, strict=False) # 将权重加载到模型中,允许部分权重不匹配
    return model # 返回注入LoRA后的模型
# 加载预训练模型
model_manager = ModelManager(
    torch_dtype=torch.float16, # 设置模型的数据类型为float16,减少显存占用
    device="cuda", # 指定使用GPU进行计算
    file_path_list=[
        "models/kolors/Kolors/text_encoder", # 文本编码器的路径
        "models/kolors/Kolors/unet/diffusion_pytorch_model.safetensors", # UNet模型的路径
        "models/kolors/Kolors/vae/diffusion_pytorch_model.safetensors" # VAE模型的路径
    ]
)
# 初始化图像生成管道
pipe = SDXLImagePipeline.from_model_manager(model_manager) # 从模型管理器中加载模型并初始化管道
# 加载并应用LoRA权重到UNet模型
pipe.unet = load_lora(
    pipe.unet, 
    lora_rank=16, # 设置LoRA的秩(rank),与训练脚本中的参数保持一致
    lora_alpha=2.0, # 设置LoRA的alpha值,控制LoRA对模型的影响权重
    lora_path="models/lightning_logs/version_0/checkpoints/epoch=0-step=500.ckpt" # 指定LoRA权重的文件路径
)


# 生成图像
torch.manual_seed(0) # 设置随机种子,确保生成的图像具有可重复性。如果想要每次生成不同的图像,可以将种子值改为随机值。
image = pipe(
    prompt="二次元,一个紫色短发小女孩,在家中沙发上坐着,双手托着腮,很无聊,全身,粉色连衣裙", # 设置正向提示词,用于指导模型生成图像的内容
    negative_prompt="丑陋、变形、嘈杂、模糊、低对比度", # 设置负向提示词,模型会避免生成包含这些特征的图像
    cfg_scale=4, # 设置分类自由度 (Classifier-Free Guidance) 的比例,数值越高,模型越严格地遵循提示词
    num_inference_steps=50, # 设置推理步数,步数越多,生成的图像细节越丰富,但生成时间也更长
    height=1024, width=1024, # 设置生成图像的高度和宽度,这里生成 1024x1024 像素的图像
)
image.save("1.jpg") # 将生成的图像保存为 "1.jpg" 文件


# 图像拼接,展示总体拼接大图
import numpy as np  # 导入numpy库,用于处理数组和数值计算
from PIL import Image  # 导入PIL库中的Image模块,用于图像处理
images = [np.array(Image.open(f"{i}.jpg")) for i in range(1, 9)]  # 读取1.jpg到8.jpg的图像,转换为numpy数组,并存储在列表images中
image = np.concatenate([  # 将四组图像在垂直方向上拼接
    np.concatenate(images[0:2], axis=1),  # 将第1组(images[0:2])的两张图像在水平方向上拼接
    np.concatenate(images[2:4], axis=1),  # 将第2组(images[2:4])的两张图像在水平方向上拼接
    np.concatenate(images[4:6], axis=1),  # 将第3组(images[4:6])的两张图像在水平方向上拼接
    np.concatenate(images[6:8], axis=1),  # 将第4组(images[6:8])的两张图像在水平方向上拼接
], axis=0)  # 将四组拼接后的图像在垂直方向上拼接
image = Image.fromarray(image).resize((1024, 2048))  # 将拼接后的numpy数组转换为图像对象,并调整大小为1024x2048像素
image  # 输出最终生成的图像对象,用于显示图像

2.3 执行过程

3. 代码还有疑问

3.1 向AI追问

在刚刚逐行解析结果页后面继续追问,如图,通义给了我们更加细致的问题解释,大家可以举一反三,多操作一下

我对其中{替换成你的问题}还是不太理解,给我再详细介绍一下

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

1. 数据准备(哈哈哈,还得是通义)

1.1 提示词

你是一个文生图专家,我们现在要做一个实战项目,就是要编排一个克里斯蒂亚诺·罗纳尔多2026年世界杯,带领葡萄牙足球队夺冠的场景。
场景由8张场景图片生成,你需要输出每张图片的生图提示词

具体的场景图片
1、2026年国际足联世界杯,葡萄牙国家队小组赛第一场,主裁判开场哨响起,克里斯蒂亚诺·罗纳尔多CR7奋力向前奔跑,传统红色球衣
2、2026年国际足联世界杯,葡萄牙小组赛第二场,主裁判终场哨响起,最终比分2比0战胜中国队,克里斯蒂亚诺·罗纳尔多CR7瘫倒在草坪上
3、2026年国际足联世界杯,葡萄牙小组赛第三场,克里斯蒂亚诺·罗纳尔多,白色球衣,帽子戏法并打入关键进球,比分3比0战胜西班牙队
4、2026年国际足联世界杯,十六强赛,克里斯蒂亚诺·罗纳尔多奋力拼抢足球,对手是克罗地亚队,场面非常激烈,比分最终锁定在2比1
5、2026年国际足联世界杯,八强赛,克里斯蒂亚诺·罗纳尔多头球破门,红色传统足球队队服,跳的特别高,力压对手后卫和门将,对手是冰岛队
6、2026年国际足联世界杯,半决赛,克里斯蒂亚诺·罗纳尔多点球破门,非常冷静,眼神坚定,打入致胜一球,比分1比0淘汰英格兰队
7、2026年国际足联世界杯,决赛常规时间,克里斯蒂亚诺·罗纳尔多任意球破门,打入扳平比分的一球,对手阿根廷队,比分1比1
8、2026年国际足联世界杯,决赛加时赛,克里斯蒂亚诺·罗纳尔多助攻队友破门,佩佩头球破门,比分锁定2比1,葡萄牙夺冠,C罗圆梦世界杯

生图提示词要求
1、风格为现代足球
2、根据场景确定是使用全身还是上半身
3、人物描述
4、场景描述
5、做啥事情

例子:
现代足球,高清画面,克里斯蒂亚诺·罗纳尔多,在世界杯足球场,奋力进攻,全身,葡萄牙传统红色队服

1.2 询问通义

自己在通义的返回的基础上,多多调整,争取打磨出一个最佳的提示词

1.3 最后的话剧场景

结合AI内容,自己在AI结果上做一些调整,最终整理出来场景表格

场景 1

现代足球,高清画面,克里斯蒂亚诺·罗纳尔多CR7,在世界杯足球场,奋力向前奔跑,全身,葡萄牙传统红色球衣,主裁判开场哨响起,准备开始比赛。

场景 2

现代足球,高清画面,克里斯蒂亚诺·罗纳尔多CR7,在世界杯足球场,上半身,葡萄牙传统红色球衣,主裁判终场哨响起,最终比分2比0战胜中国队,CR7瘫倒在草坪上庆祝胜利。

场景 3

现代足球,高清画面,克里斯蒂亚诺·罗纳尔多,在世界杯足球场,全身,白色球衣,完成帽子戏法并打入关键进球,比分3比0战胜西班牙队,庆祝动作,背景是兴奋的队友和观众。

场景 4

现代足球,高清画面,克里斯蒂亚诺·罗纳尔多,在世界杯足球场,全身,葡萄牙传统红色球衣,奋力拼抢足球,对手是克罗地亚队,场面非常激烈,比分最终锁定在2比1。

场景 5

现代足球,高清画面,克里斯蒂亚诺·罗纳尔多,在世界杯足球场,全身,红色传统足球队队服,头球破门,跳得特别高,力压对手后卫和门将,对手是冰岛队,背景是观众欢呼。

场景 6

现代足球,高清画面,克里斯蒂亚诺·罗纳尔多,在世界杯足球场,上半身,葡萄牙传统红色球衣,点球破门,非常冷静,眼神坚定,打入致胜一球,比分1比0淘汰英格兰队,庆祝动作。

场景 7

现代足球,高清画面,克里斯蒂亚诺·罗纳尔多,在世界杯足球场,全身,葡萄牙传统红色球衣,任意球破门,打入扳平比分的一球,对手阿根廷队,比分1比1,庆祝动作,背景是激动的队友。

场景 8

现代足球,高清画面,克里斯蒂亚诺·罗纳尔多,在世界杯足球场,上半身,葡萄牙传统红色球衣,助攻队友破门,佩佩头球破门,比分锁定2比1,葡萄牙夺冠,C罗圆梦世界杯,庆祝胜利。

2. 执行Task1的30分钟速通Baseline

Docs

3. 提示词修改

  1. 双击进入baseline文件

  2. 找到生成图像的板块

  3. 依次替换8张图片的正向提示词和反向提示词

修改提示词,提示词,图片名称设置好以后,点击执行按钮

4. 结果展示

5. 测试美学打分

比之前的好看一些

Part4:更多的选择一一浅尝scepter webui

1. 浅尝功能

魔搭体验网址:https://www.modelscope.cn/studios/iic/scepter_studio

2. 官方定义

SCEPTER is an open-source code repository dedicated to generative training, fine-tuning, and inference, encompassing a suite of downstream tasks such as image generation, transfer, editing. SCEPTER integrates popular community-driven implementations as well as proprietary methods by Tongyi Lab of Alibaba Group, offering a comprehensive toolkit for researchers and practitioners in the field of AIGC. This versatile library is designed to facilitate innovation and accelerate development in the rapidly evolving domain of generative models.

3. 核心组件

4. 私有部署(挑战型

魔搭社区提供的体验地址里面缺失了微调模型的功能,如果大家希望能使用secpter完整的功能,我们可以将其私有部署到我们自己的服务器。

github地址:https://github.com/modelscope/scepter

可以通过官方readme文件中的教程进行操作,该模块对基础有一定的要求,适合学有余力的同学

PS:如果在安装中遇到各种问题,别忘了这节课的老朋友,尽管向通义等AI工具提问~~~~~

2.1Scepter与WebUI,一站式生成编辑工具箱_哔哩哔哩_bilibili

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值