当前位置:   article > 正文

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

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

任务目标

Datawhale AI夏令营第四期学习活动(“AIGC”方向)的任务是学习从零入门AI生图原理&实践,学习方式是通过参与魔搭社区开展的“可图Kolors-LoRA风格故事挑战赛”进行实践。

基础知识

Stable Diffusion model

论文链接:Rombach, Robin, Andreas Blattmann, Dominik Lorenz, Patrick Esser, and Björn Ommer. “High-resolution image synthesis with latent diffusion models.” In Proceedings of the IEEE/CVF conference on computer vision and pattern recognition, pp. 10684-10695. 2022.

Stable Diffusion的原理

1.前向扩散和反向扩散

前向扩散的过程就是对一张图像逐步加上噪声。如图,对一张猫咪的图像从左至右逐步加上噪声,最后形成了一张完全看不出来的噪声图。

Stage1:Foward Diffusion

在这里插入图片描述

Stage2:Reverse Diffusion

反向扩散的过程简单来说就是去噪的过程。对刚刚获得的一张噪声图,逐步地进行去噪,最后得到目标图像。

在这里插入图片描述

2.训练一个噪声预测器的步骤

接上文,问题来了:如何去噪?
解决办法/目的:训练一个噪声预测器

论文中一个简单的步骤如下:
1.选择一张训练图像,比如一张猫咪的图像。
2.生成一张随机噪声图像。
3.在训练图像中加入一定数量的噪声图像,从而破坏训练图像。
4.让噪声预测器告诉我们添加了多少噪声。这可以通过调整权重并向其显示正确答案来实现。

3.Latent Space

在明确了我们的目的就是要训练一个噪声预测器之后,又出现了两个问题:

1.以上diffusion过程在Pixel Space图像域(维度高)中处理,计算极慢
2.无法控制diffusion到底是生成猫还是狗

对于第一个问题,引入了Latent Space(潜在空间)的概念。
和Latent Space对应的是Pixel Space(如下图所示),下图是一个512X512X3的图像域的说明,在图像域汇中计算是非常复杂的,所以我们要压缩维度,压缩到Latent Space中。
在这里插入图片描述

如何理解这里的“压缩维度”呢?
这里我们举个例子,假如你用一句话描述一群人,你可能会说:

A:一个穿着红衣服带着绿帽子黄头发的北京户口的职业是艺术家的…的女人
B:一个穿着白色衬衫棕色围裙黑头发大胡子的职业是咖啡师的…的男人

你会发现用一句话描述一个人实在是太冗杂了,于是你画了一个三维坐标(如下,可类比为人类潜在空间),你干脆这一群人一一对应坐标上的信息,放进去,这时候你就会发现描述一个人变得简单多了。这就是一个压缩维度的过程:

在这里插入图片描述

类比上述过程,我们来看Stable Diffusion的结构,这里面也回答了我们之前提到的第二个问题“如何控制生成的内容”:
在这里插入图片描述

Stable Diffusion框架流程:

1.编码器将图像从Pixel Space压缩到更小维度的Latent Space,捕捉图像本质信息;
2.对潜在空间中的图片添加噪声,进行Diffusion Process;
3.通过 CLIP 文本编码器将输入的描述语转换为去噪过程的条件(Conditioning);
4.基于一些条件对图像进行去噪(Denoising)以获得生成图片的潜在表示,去噪步骤可以灵活地以文本、图像和其他形式为条件(以文本为条件即 text2img)
5.解码器通过将图像从Latent Space转换回Pixel Space来生成最终图像。

“可图Kolors-LoRA风格故事挑战赛”赛题内容

赛事链接: https://tianchi.aliyun.com/s/ce4dc8bf800db1e58d51263ff357d28f

赛事任务

  1. 参赛者需在可图Kolors 模型的基础上训练LoRA 模型,生成无限风格,如水墨画风格、水彩风格、赛博朋克风格、日漫风格…
  2. 基于LoRA模型生成 8 张图片组成连贯故事,故事内容可自定义;基于8图故事,评估LoRA风格的美感度及连贯性
    样例:偶像少女养成日记
    在这里插入图片描述

实践步骤

其实Datawhale官方的实践手册已经特别详细了,这里会按照实践手册的流程用我自己的方法和经验过一遍流程,并且补充相关原理知识还有可能遇到的问题和解决方法。

注册并使用算力平台

这里我选择了魔塔社区的免费GPU环境(你也可以选择任何一个免费的算力平台,都是一样的)

1.注册好账号后,直接选择免费的GPU环境。
在这里插入图片描述
当然你也可以在右上角绑定阿里云账号使用阿里云提供的算力资源,但我觉得直接用魔塔是最方便的。
在这里插入图片描述
2.启动环境,等待几分钟后,打开notebook
在这里插入图片描述在这里插入图片描述

代码文件下载

1.新建终端,在终端中下载baseline文件:

git lfs install
git clone https://www.modelscope.cn/datasets/maochase/kolors.git
  • 1
  • 2

在这里插入图片描述
如图,在终端输入Git代码,下载文件。

在这里插入图片描述
生成kolors文件夹,注意点开检查一下文件夹是否齐全。

在这里插入图片描述

2.打开下载的文件夹kolors下的baseline.ipynb文件,进行实践内容。

环境安装及代码解读

打开baseline.ipynb文件,看到每个cell的代码都分块列出。

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述
2.下载并保存数据集

使用 MsDataset 类的 load 方法来加载指定的数据集,并将数据集存储在本地的缓存目录中。

‘AI-ModelScope/lowres_anime’: 这是要加载的数据集的名称。

subset_name=‘default’: 这是指定要加载的数据集子集的名称。

split=‘train’: 这个参数指定了要加载的数据集的部分,通常一个数据集会分为训练集(train)、验证集(validation)和测试集(test)。这里指定的是训练集。

cache_dir=“/mnt/workspace/kolors/data”: 这是本地缓存数据集的路径。数据集下载后会被保存到这个目录,以便后续使用时可以直接从本地加载,而不必再次从网络下载。

from modelscope.msdatasets import MsDataset

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

在这里插入图片描述
保存数据集:从数据集中提取图像数据,并将其保存为新的JPEG格式文件,同时生成一个JSONL格式的元数据文件,描述这些图像的相关信息。

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")
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述

3.数据处理
为数据处理任务创建一个配置文件,然后使用 Data-Juicer 工具根据该配置文件处理数据。

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
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

在这里插入图片描述

将经过处理的图像数据集和对应的文本标签存储为一个结构化的CSV文件,方便后续使用。

import pandas as pd
import os, json
from PIL import Image
from tqdm import tqdm


texts, file_names = [], []
os.makedirs("./data/lora_dataset_processed/train", exist_ok=True)
with open("./data/data-juicer/output/result.jsonl", "r") as file:
    for data_id, data in enumerate(tqdm(file.readlines())):
        data = json.loads(data)
        text = data["text"]
        texts.append(text)
        image = Image.open(data["image"][0])
        image_path = f"./data/lora_dataset_processed/train/{data_id}.jpg"
        image.save(image_path)
        file_names.append(f"{data_id}.jpg")
data_frame = pd.DataFrame()
data_frame["file_name"] = file_names
data_frame["text"] = texts
data_frame.to_csv("./data/lora_dataset_processed/train/metadata.csv", index=False, encoding="utf-8-sig")
data_frame
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这里插入图片描述

4.训练模型
下载模型

from diffsynth import download_models

download_models(["Kolors", "SDXL-vae-fp16-fix"])
  • 1
  • 2
  • 3

在这里插入图片描述

通过命令行调用 train_kolors_lora.py 脚本来训练一个基于LoRA(Low-Rank Adaptation)的图像生成模型。整个过程涉及到设置训练所需的参数和路径,然后通过 os.system(cmd) 执行训练命令。

import os

cmd = """
python DiffSynth-Studio/examples/train/kolors/train_kolors_lora.py \
  --pretrained_unet_path models/kolors/Kolors/unet/diffusion_pytorch_model.safetensors \
  --pretrained_text_encoder_path models/kolors/Kolors/text_encoder \
  --pretrained_fp16_vae_path models/sdxl-vae-fp16-fix/diffusion_pytorch_model.safetensors \
  --lora_rank 16 \
  --lora_alpha 4.0 \
  --dataset_path data/lora_dataset_processed \
  --output_path ./models \
  --max_epochs 1 \
  --center_crop \
  --use_gradient_checkpointing \
  --precision "16-mixed"
""".strip()

os.system(cmd)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在这里插入图片描述
以下是该命令的具体参数解释:

python DiffSynth-Studio/examples/train/kolors/train_kolors_lora.py:
运行的Python脚本路径,该脚本是用于训练LoRA模型的。

–pretrained_unet_path:
指定了预训练的UNet模型路径,模型文件是 diffusion_pytorch_model.safetensors。

–pretrained_text_encoder_path:
指定了预训练的文本编码器路径,该路径是一个目录,里面包含了文本编码器的权重文件。

–pretrained_fp16_vae_path:
指定了预训练的VAE(Variational Autoencoder)模型路径,该模型支持FP16(16-bit浮点数),用于提升训练效率。

–lora_rank 16:
LoRA的秩(rank),控制了LoRA模块的参数量,秩越高,模型越复杂。

–lora_alpha 4.0:
LoRA的 alpha 值,用于调整LoRA模块的学习率或缩放因子。

–dataset_path data/lora_dataset_processed:
数据集路径,指向之前处理过的LoRA数据集。

–output_path ./models:
输出路径,训练好的模型将会保存到该目录中。

–max_epochs 1:
最大训练轮数,设置为1,表示训练只进行一轮。

–center_crop:
开启中心裁剪,图像会在训练前被裁剪到中心部分。

–use_gradient_checkpointing:
使用梯度检查点,减少内存占用,有助于在较小的GPU上训练大型模型。

–precision “16-mixed”:
设置训练精度为16位浮点数和32位浮点数的混合模式,以节省显存。

加载经过LoRA(Low-Rank Adaptation)微调的扩散模型,并将其整合到一个用于图像生成的管道中。

import os

cmd = """
python DiffSynth-Studio/examples/train/kolors/train_kolors_lora.py \
  --pretrained_unet_path models/kolors/Kolors/unet/diffusion_pytorch_model.safetensors \
  --pretrained_text_encoder_path models/kolors/Kolors/text_encoder \
  --pretrained_fp16_vae_path models/sdxl-vae-fp16-fix/diffusion_pytorch_model.safetensors \
  --lora_rank 16 \
  --lora_alpha 4.0 \
  --dataset_path data/lora_dataset_processed \
  --output_path ./models \
  --max_epochs 1 \
  --center_crop \
  --use_gradient_checkpointing \
  --precision "16-mixed"
""".strip()

os.system(cmd)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

在这里插入图片描述
其中load_lora是一个加载LoRA微调模型的函数,以下是具体步骤:

(1)创建 LoraConfig 对象:

r=lora_rank: 设置LoRA的秩(rank),控制微调的参数量。
lora_alpha=lora_alpha: 控制LoRA的缩放因子,影响微调的权重。
init_lora_weights=“gaussian”: 初始化LoRA权重为高斯分布。
target_modules=[“to_q”, “to_k”, “to_v”, “to_out”]: 指定LoRA微调的目标模块,这些通常是Transformer中的关键层。

(2)注入LoRA配置到模型中: inject_adapter_in_model 函数将LoRA配置注入到给定的模型中。

(3)加载LoRA权重: 使用 torch.load 从指定路径加载LoRA微调后的模型权重。

(4)更新模型状态: 使用 load_state_dict 函数,将加载的权重应用到模型中,并返回更新后的模型。

5.生成图像

输入prompt生成图像,这里我想讲一个很火的网络重生文的故事(我是土狗爱看土文),简单想了一个故事的提纲:

故事剧情

背叛与死亡:她曾是家族的骄傲,却在家族争权中被至亲背叛,最终含恨而死。
重生之夜:她在神秘的夜晚重生,决心逆袭人生。
崛起的开始:她隐忍蓄力,默默在黑暗中积蓄力量。
夺回权力:她开始一步步收回曾属于她的权力。
复仇的盛宴:她设计了一场宴会,将曾背叛她的人一网打尽。
失而复得的盟友:她与挚友重新联合,共同对抗敌人。
最终决战:她与最大的敌人在古老的宫殿里展开最后的决斗。
荣耀加身:她登上王座,成为万民敬仰的女王。

图片一:

torch.manual_seed(0)
image = pipe(
    prompt="二次元,一个白色头发红色瞳孔、眼睛下方有一颗泪痣的少女躺在地上,身着破碎的华丽长裙,长发散乱,她的脸色苍白,双眼微闭,脸上带着一丝不甘的泪痕。周围是冷灰色的阴影和破碎的家族徽章。",
    negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
    cfg_scale=4,
    num_inference_steps=50, height=1024, width=1024,
)
image.save("1.jpg")

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

生成结果:

在这里插入图片描述

图片二:

torch.manual_seed(1)
image = pipe(
    prompt="二次元,一个白色长发红色瞳孔、眼睛下方有一颗泪痣的少女,在一个神秘的夜晚重生。她站在古老的石台上,四周是蓝紫色的神秘光芒,长发随风飘动,双眼闪烁着坚定的光芒。她身着白色轻纱裙,背后隐隐浮现出光辉的翅膀。",
    negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
    cfg_scale=4,
    num_inference_steps=50, height=1024, width=1024,
)
image.save("2.jpg")

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

图片三:

torch.manual_seed(2)
image = pipe(
    prompt="二次元,一个白色长发红色瞳孔、眼睛下方有一颗痣的少女,站在一座高塔上,侧脸俯瞰着被夜幕笼罩的城市,身穿黑色斗篷。她的眼神坚定,背景是一轮银白色的满月,城市的灯火点点在远处闪烁,预示着她的力量正在慢慢苏醒。",
    negative_prompt="丑陋、变形、嘈杂、模糊、低对比度,色情擦边",
    cfg_scale=4,
    num_inference_steps=50, height=1024, width=1024,
)
image.save("3.jpg")

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

图片四:

torch.manual_seed(5)
image = pipe(
    prompt="二次元,一个白色长发红色瞳孔、眼睛下方有一颗泪痣的少女,站在华丽的宫殿大厅中央,身着金色的华服,手握一把闪亮的权杖。她的目光冷峻,面前跪倒着惊恐的敌人。背景是金色的灯火和闪耀的王座,象征着她重新掌控的权力。",
    negative_prompt="丑陋、变形、嘈杂、模糊、低对比度,扭曲的手指,多余的手指",
    cfg_scale=4,
    num_inference_steps=50, height=1024, width=1024,
)
image.save("4.jpg")

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

图片五:

torch.manual_seed(0)
image = pipe(
    prompt="二次元,在一座辉煌的大厅中,一个白色长发红色瞳孔、眼睛下方有一颗泪痣的少女,坐在长桌的主位,身穿深红色的晚礼服,双手优雅地握着酒杯。她的表情冷酷,眼神犀利,周围是燃烧的火焰和面露惊恐的宾客。背景是一座燃烧的古老城堡。",
    negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
    cfg_scale=4,
    num_inference_steps=50, height=1024, width=1024,
)
image.save("5.jpg")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述

图片六:

torch.manual_seed(1)
image = pipe(
    prompt="二次元,一个白色长发红色瞳孔、眼睛下方有一颗泪痣的少女,与她的黑色头发黄色瞳孔的扎马尾的挚友背靠背站立,身处一片战后的废墟中。她们都穿着战斗服,挚友手持银色长剑,目光锐利,少女手握红色的权杖,目光坚定。背景是倒下的敌人和阴暗的天空,预示着新的联盟力量。",
    negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
    cfg_scale=4,
    num_inference_steps=50, height=1024, width=1024,
)
image.save("6.jpg")

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

图片七:

torch.manual_seed(7)
image = pipe(
    prompt="二次元,一个白色长发红色瞳孔、眼睛下方有一颗泪痣的少女,与敌人在一座古老的宫殿中对峙,四周闪耀着红色的电光。少女身着银白色的战甲,长发飞扬,手中长剑直指对方的咽喉。背景是一座破败的王座和倒塌的石柱,象征着激烈的战斗。",
    negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
    cfg_scale=4,
    num_inference_steps=50, height=1024, width=1024,
)
image.save("7.jpg")

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

图片八:

torch.manual_seed(0)
image = pipe(
    prompt="二次元,一个白色长发红色瞳孔、眼睛下方有一颗痣的少女,身披金色华丽长袍,头戴王冠,站在高高的王座前,俯瞰着万民朝拜的景象。她的表情庄严,眼中闪耀着掌控一切的光芒。背景是辉煌的宫殿和洒满阳光的蓝天,象征着她的最终胜利与荣耀。",
    negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
    cfg_scale=4,
    num_inference_steps=50, height=1024, width=1024,
)
image.save("8.jpg")

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述最终效果呈现
在这里插入图片描述

上传结果

1.创建terminal,粘贴如下命令,回车执行

mkdir /mnt/workspace/kolors/output & cd 
cp /mnt/workspace/kolors/models/lightning_logs/version_0/checkpoints/epoch\=0-step\=500.ckpt /mnt/workspace/kolors/output/
cp /mnt/workspace/kolors/1.jpg /mnt/workspace/kolors/output/

  • 1
  • 2
  • 3
  • 4

2.下载结果文件

找到output文件夹里的ckpt文件,下载到本地

3.创建并上传模型所需内容
点击魔搭链接,创建模型:
在这里插入图片描述
4. 来到创空间,查看自己的模型是否发布:
在这里插入图片描述在这里插入图片描述

在这里插入图片描述成功发布!大功告成!

遇到的问题:

在整个过程中还算顺利,但也遇到了一些小问题,因为看到群里也有朋友在问同样的问题,所以来记录一下:

1.no NVIDIA:

在这里插入图片描述原因及解决:选错了环境,一开始选择的是魔塔的CPU环境,正确应该选取GPU环境。

2.ModuleNotFoundError: No module named ‘data_juicer’
在这里插入图片描述
原因:因为卡顿重启了平台,平台重启只会留下ipynb文件,导致data_juicer文件全部丢失。
解决:在终端中重新下载文件。

git lfs install
git clone https://www.modelscope.cn/datasets/maochase/kolors.git
  • 1
  • 2

其他待思考的问题:
1.模型无法细致化地生成主人公:
比如我想生成的女主是带着泪痣的女主,但是模型似乎不能理解“泪痣”的含义,多数图片没有生成泪痣,或者直接生成了眼泪(我在测试中发现的,没有放图进来),如何解决这个问题?

2.模型生成的图像人物动作不够丰富:
比如我在第六张图片中的prompt是“一个白色长发红色瞳孔、眼睛下方有一颗泪痣的少女,与她的黑色头发黄色瞳孔的扎马尾的挚友背靠背站立,身处一片战后的废墟中。她们都穿着战斗服,挚友手持银色长剑,目光锐利,少女手握红色的权杖,目光坚定。背景是倒下的敌人和阴暗的天空,预示着新的联盟力量。”其中“手持”“手握”生成得不是很好,甚至有些信息错误和缺失,比如应该是挚友拿着银色的长剑,少女拿着红色的权杖,但变成了挚友拿着红色手柄的银色长剑,少女就只是站着,比较奇怪。如何解决这个问题?

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/秋刀鱼在做梦/article/detail/1011725
推荐阅读
相关标签
  

闽ICP备14008679号