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

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

Task1

过程记录

按照教程https://linklearner.com/activity/14/10/24

Step0:开通阿里云PAI-DSW试用

https://free.aliyun.com/?productCode=learn申请试用

https://www.modelscope.cn/my/mynotebook/authorization 选个人云账号去授权,一步步跳转到阿里云授权然后跳回来。

Step1:报名赛事!

https://tianchi.aliyun.com/competition/entrance/532254

出来组队忽略即可

Step2:在魔搭社区创建PAI实例!(点击即可跳转)

创建实例

image-20240809154502559

Step3:30 分钟体验一站式 baseline!

  1. 下载baseline文件**(大约需要2分钟)**

    git lfs install
    git clone https://www.modelscope.cn/datasets/maochase/kolors.git
    
  2. 进入文件夹,打开baseline文件

  3. 安装环境,然后重启kernel

  4. 启动结果:

    image-20240809154714875

下面的代码块按照功能主要分成这几类

  1. 使用Data-Juicer处理数据,整理训练数据文件
  2. 使用DiffSynth-Studio在基础模型上,使用前面整理好的数据文件进行训练微调
  3. 加载训练微调后的模型
  4. 使用微调后的模型,生成用户指定的prompt提示词的图片

问题解决:

1.报错FileNotFoundError: [Errno 2] No such file or directory: ‘data/data-juicer/data_juicer_config.yaml’

解决:

image-20240809153606815

2.上传结果时选择

3c4ed8b1613e4878ddfd80c77447b9c

解决:

3416b9e0b3f1b13fc88dfcbf5bfe63b

9a666496d9ba3eb8f675d8b118abd73

代码阅读

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

Data-Juicer是一个专为大型语言模型(LLMs)设计的一站式多模态数据处理系统

DiffSynth-Studio是一个多功能的创作工具,它可以作为图片和视频处理工具或音乐合成软件使用。

2.下载数据集
from modelscope.msdatasets import MsDataset

ds = MsDataset.load(
    'AI-ModelScope/lowres_anime',
    subset_name='default',
    split='train',
    cache_dir="/mnt/workspace/kolors/data"
)
  1. MsDatasetmodelscope平台提供的一个用于加载数据集的类,它简化了从平台下载、加载和管理数据集的过程。

  2. 加载数据集

    ds = MsDataset.load(
        'AI-ModelScope/lowres_anime',
        subset_name='default',
        split='train',
        cache_dir="/mnt/workspace/kolors/data"
    )
    
    • dataset_name ('AI-ModelScope/lowres_anime'): 这是要加载的数据集的名称。数据集lowres_anime包含了一些低分辨率的动漫图片
    • subset_name ('default'): 这个参数指定了数据集的哪个子集应该被加载。有些数据集可能包含多个子集,比如训练集、验证集和测试集,而subset_name允许你指定要加载哪个子集。
    • split ('train'): 这个参数进一步指定了要加载的子集中的哪一部分。它被设置为'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")
  1. 导入必要的库

    from tqdm import tqdm:导入**tqdm库,用于在循环中添加进度条**,以便用户了解循环的进度。

  2. 创建目录

    • 使用os.makedirs函数创建两个目录(如果它们尚不存在):"./data/lora_dataset/train"用于存储训练图像,"./data/data-juicer/input"用于存储元数据文件。exist_ok=True参数确保如果目录已存在,则不会抛出错误。
  3. 处理数据集并写入元数据

    • 打开(或创建)一个名为"./data/data-juicer/input/metadata.jsonl"的文件用于写入元数据。.jsonl扩展名通常表示JSON Lines格式,即每行一个JSON对象。
    • 使用enumerate(tqdm(ds))遍历数据集ds,其中tqdm用于添加进度条。enumerate函数同时返回每个元素的索引(data_id)和元素本身(data)。
    • 对于数据集中的每个元素,首先将其图像部分转换为RGB格式(假设原始图像可能包含透明度通道),然后保存到"/mnt/workspace/kolors/data/lora_dataset/train/"目录下,文件名由data_id生成。
    • 构造一个包含文本标签(“二次元”)和图像路径的元数据字典metadata
    • 使用json.dumps(metadata)将元数据字典转换为JSON格式的字符串,并写入之前打开的文件中。每个元数据对象后都添加一个换行符"\n",以符合JSON Lines格式。
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

使用了一个魔术命令(以 ! 开头)来调用 dj-process 命令,该命令使用刚刚创建的 YAML 文件作为配置。

保存处理好的数据

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

这段代码主要执行了几个步骤,用于处理和准备一个数据集,特别是为了机器学习或深度学习模型(如基于Stable Diffusion的LORA模型)的训练。以下是代码的详细解释:

  1. 导入必要的库

    • pandas as pd:用于数据处理和分析。
    • os:提供了与操作系统交互的功能,比如文件和目录的管理。
    • json:用于解析和生成JSON数据。
    • PIL.Image(来自Pillow库):用于图像的打开、保存和处理。
    • tqdm:用于在循环中显示进度条,使长时间运行的程序更加用户友好。
  2. 初始化变量

    • texts, file_names = [], []:分别用于存储文本数据和对应的文件名。
  3. 创建目录

    • 使用os.makedirs("./data/lora_dataset_processed/train", exist_ok=True)确保目标目录存在。如果目录已存在且exist_ok=True,则不会抛出错误。
  4. 读取和处理JSONL文件

    • 打开一个JSON Lines(JSONL)文件"./data/data-juicer/output/result.jsonl"进行读取。JSONL是一种每行一个JSON对象的格式。
    • 使用enumerate(tqdm(file.readlines()))在读取文件时显示进度条,enumerate用于获取每行的索引(即data_id)和内容(即每行的JSON字符串)。
    • 使用json.loads(data)将每行的JSON字符串解析为Python字典。
    • 从解析后的字典中提取textimage信息。
    • 使用Pillow库中的Image.open(data["image"][0])打开图像文件。注意这里假设data["image"]是一个包含图像文件路径的列表,且只取第一个元素。
    • 将图像保存到"./data/lora_dataset_processed/train/"目录下,文件名为{data_id}.jpg
    • 将文件名添加到file_names列表中,将文本添加到texts列表中。
  5. 创建DataFrame并保存为CSV文件

    • 使用pd.DataFrame()创建一个空的DataFrame。
    • 向DataFrame中添加两列:file_name(包含处理后的文件名)和text(包含对应的文本数据)。
    • 使用data_frame.to_csv(...)将DataFrame保存为CSV文件,文件名为"./data/lora_dataset_processed/train/metadata.csv",并设置index=False以避免将索引作为一列写入文件,encoding="utf-8-sig"确保文件编码兼容Excel等程序。
  6. 最后的data_frame

    • 最后一行代码data_frame只是简单地引用了前面创建的DataFrame对象,实际上并没有执行任何操作。在脚本的上下文中,这行代码可能是多余的,除非它在后续的代码块中有用。

总的来说,这段代码的目的是从一个JSONL文件中读取文本和图像信息,将图像保存到指定目录,并将文本和对应的文件名保存到CSV文件中,以便后续用于训练机器学习或深度学习模型。

4.训练模型

下载模型

from diffsynth import download_models

download_models(["Kolors", "SDXL-vae-fp16-fix"])

查看训练脚本的输入参数

!python DiffSynth-Studio/examples/train/kolors/train_kolors_lora.py -h

开始训练

提示:

  1. 在训练命令中填入 --modelscope_model_id xxxxx 以及 --modelscope_access_token xxxxx 后,训练程序会在结束时自动上传模型到 ModelScope
  2. 部分参数可根据实际需求调整,例如 lora_rank 可以控制 LoRA 模型的参数量
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)

它使用os模块的system函数来执行一个字符串命令。**这个命令是一个长字符串,被分成了多行以提高可读性。**这个命令是调用Python脚本来训练一个LoRA(Low-Rank Adaptation)模型,这通常用于微调大型预训练模型,如Stable Diffusion等文本到图像的模型。

让我们分解这个命令及其参数:

  • python DiffSynth-Studio/examples/train/kolors/train_kolors_lora.py:这是要执行的Python脚本的路径,它负责训练LoRA模型。

  • --pretrained_unet_path models/kolors/Kolors/unet/diffusion_pytorch_model.safetensors:这个参数指定了预训练的U-Net模型的路径。U-Net是Stable Diffusion等模型中的一部分,用于从潜在空间生成图像。

  • --pretrained_text_encoder_path models/kolors/Kolors/text_encoder:这个参数指定了预训练的文本编码器的路径,文本编码器负责将文本提示转换为模型可以理解的向量。

  • --pretrained_fp16_vae_path models/sdxl-vae-fp16-fix/diffusion_pytorch_model.safetensors:这个参数指定了预训练的FP16 VAE(变分自编码器)模型的路径。VAE在这里可能用于潜在空间的压缩或变换。

  • --lora_rank 16:这个参数设置了LoRA层的秩(rank),秩的大小影响LoRA模型的复杂度和表现能力。

  • --lora_alpha 4.0:这个参数设置了LoRA层相对于原始预训练模型的缩放因子(alpha),它决定了LoRA层对最终模型输出的影响程度。

  • --dataset_path data/lora_dataset_processed:这个参数指定了训练数据集的路径,数据集应该是经过处理的,以符合训练脚本的要求。

  • --output_path ./models:这个参数指定了训练好的模型(包括LoRA层)的保存路径。

  • --max_epochs 1:这个参数设置了训练的最大轮次(epoch)为1,这意味着整个数据集将被遍历一次以进行训练。

  • --center_crop:这个参数可能指示训练脚本在预处理图像时使用中心裁剪的方式。

  • --use_gradient_checkpointing:这个参数启用了梯度检查点(gradient checkpointing),这是一种节省内存的技术,允许训练更大的模型,尽管它会略微增加计算时间。

  • --precision "16-mixed":这个参数指定了训练的精度为混合精度(16位),这可以加速训练过程并减少内存使用。

os.system(cmd)调用实际上会执行这个命令,就好像在命令行中手动输入并运行它一样。

加载模型

from diffsynth import ModelManager, SDXLImagePipeline
from peft import LoraConfig, inject_adapter_in_model
import torch

# 接收秩、权重、权重文件的路径。
def load_lora(model, lora_rank, lora_alpha, lora_path):
    # 使用 `LoraConfig` 配置 LoRA 适配器,指定要修改的目标模块(这里为 Transformer 层的查询(`to_q`)、键(`to_k`)、值(`to_v`)和输出(`to_out`)部分)。
    lora_config = LoraConfig(
        r=lora_rank,
        lora_alpha=lora_alpha,
        init_lora_weights="gaussian",
        target_modules=["to_q", "to_k", "to_v", "to_out"],
    )
    # 使用 `inject_adapter_in_model` 将配置好的 LoRA 适配器注入到模型中。
    model = inject_adapter_in_model(lora_config, model)
    # 使用 `torch.load` 加载 LoRA 权重文件,并将这些权重加载到模型中。
    state_dict = torch.load(lora_path, map_location="cpu")
    
    model.load_state_dict(state_dict, strict=False)
    # 返回加载了 LoRA 权重的模型。
    return model


# Load models
# 使用 ModelManager 创建一个模型管理器实例
# 指定数据类型(torch.float16)、设备(cuda)和包含模型文件的路径列表。
model_manager = ModelManager(torch_dtype=torch.float16, device="cuda",
                             file_path_list=[
                                 "models/kolors/Kolors/text_encoder",
                                 "models/kolors/Kolors/unet/diffusion_pytorch_model.safetensors",
                                 "models/kolors/Kolors/vae/diffusion_pytorch_model.safetensors"
                             ])
# 使用 `SDXLImagePipeline.from_model_manager` 从模型管理器创建图像生成管道(pipe)。
pipe = SDXLImagePipeline.from_model_manager(model_manager)

# Load LoRA
#调用 `load_lora` 函数,将 LoRA 权重加载到 `pipe.unet`(即 U-Net 模型)中。
# 这里指定了 LoRA 的秩(`lora_rank=16`)、LoRA 的权重(`lora_alpha=2.0`)和 LoRA 权重文件的路径(`lora_path`)。
pipe.unet = load_lora(
    pipe.unet,
    lora_rank=16, # This parameter should be consistent with that in your training script.
    lora_alpha=2.0, # lora_alpha can control the weight of LoRA.
    lora_path="models/lightning_logs/version_0/checkpoints/epoch=0-step=500.ckpt"
)

基于 Diffusion Models 的图像生成框架(这里使用 diffsynth)中加载和使用 LoRA(Low-Rank Adaptation)权重。**LoRA 是一种轻量级的方法,用于微调预训练模型,而不需要修改模型的所有权重。**这在计算资源有限的情况下特别有用,因为它只修改模型的一小部分参数。

5.生成图像
torch.manual_seed(0)
image = pipe(
    prompt="二次元,一个紫色短发小女孩,在家中沙发上坐着,双手托着腮,很无聊,全身,粉色连衣裙",
    negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
    cfg_scale=4,
    num_inference_steps=50, height=1024, width=1024,
)
image.save("1.jpg")
6.尝试生成其他图片

写一个新的,重新运行

image-20240809162204040

image-20240809162236813

image-20240809162222950

7.上传数据

1.移动结果文件

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

image-20240809163425155

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文件夹,分别下载两个文件到本地

image-20240809163520038

3.创建并上传模型所需内容

image-20240809163736419

image-20240809163941497

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值