赞
踩
Datawhale AI夏令营第四期学习活动(“AIGC”方向)的任务是学习从零入门AI生图原理&实践,学习方式是通过参与魔搭社区开展的“可图Kolors-LoRA风格故事挑战赛”进行实践。
前向扩散的过程就是对一张图像逐步加上噪声。如图,对一张猫咪的图像从左至右逐步加上噪声,最后形成了一张完全看不出来的噪声图。
Stage1:Foward Diffusion
Stage2:Reverse Diffusion
反向扩散的过程简单来说就是去噪的过程。对刚刚获得的一张噪声图,逐步地进行去噪,最后得到目标图像。
接上文,问题来了:如何去噪?
解决办法/目的:训练一个噪声预测器
论文中一个简单的步骤如下:
1.选择一张训练图像,比如一张猫咪的图像。
2.生成一张随机噪声图像。
3.在训练图像中加入一定数量的噪声图像,从而破坏训练图像。
4.让噪声预测器告诉我们添加了多少噪声。这可以通过调整权重并向其显示正确答案来实现。
在明确了我们的目的就是要训练一个噪声预测器之后,又出现了两个问题:
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来生成最终图像。
赛事链接: https://tianchi.aliyun.com/s/ce4dc8bf800db1e58d51263ff357d28f
其实Datawhale官方的实践手册已经特别详细了,这里会按照实践手册的流程用我自己的方法和经验过一遍流程,并且补充相关原理知识还有可能遇到的问题和解决方法。
这里我选择了魔塔社区的免费GPU环境(你也可以选择任何一个免费的算力平台,都是一样的)
1.注册好账号后,直接选择免费的GPU环境。
当然你也可以在右上角绑定阿里云账号使用阿里云提供的算力资源,但我觉得直接用魔塔是最方便的。
2.启动环境,等待几分钟后,打开notebook
1.新建终端,在终端中下载baseline文件:
git lfs install
git clone https://www.modelscope.cn/datasets/maochase/kolors.git
如图,在终端输入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
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"
)
保存数据集:从数据集中提取图像数据,并将其保存为新的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")
)
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 )
将经过处理的图像数据集和对应的文本标签存储为一个结构化的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
4.训练模型
下载模型
from diffsynth import download_models
download_models(["Kolors", "SDXL-vae-fp16-fix"])
通过命令行调用 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)
以下是该命令的具体参数解释:
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)
其中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")
生成结果:
图片二:
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")
最终效果呈现
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/
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.模型生成的图像人物动作不够丰富:
比如我在第六张图片中的prompt是“一个白色长发红色瞳孔、眼睛下方有一颗泪痣的少女,与她的黑色头发黄色瞳孔的扎马尾的挚友背靠背站立,身处一片战后的废墟中。她们都穿着战斗服,挚友手持银色长剑,目光锐利,少女手握红色的权杖,目光坚定。背景是倒下的敌人和阴暗的天空,预示着新的联盟力量。”其中“手持”“手握”生成得不是很好,甚至有些信息错误和缺失,比如应该是挚友拿着银色的长剑,少女拿着红色的权杖,但变成了挚友拿着红色手柄的银色长剑,少女就只是站着,比较奇怪。如何解决这个问题?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。