当前位置:AIGC资讯 > AIGC > 正文

【Datawhale X 魔搭AI夏令营】AIGC方向 Task 1+2

目录

写在前面

Task 1

赛题解读——可图Kolors-LoRA风格故事挑战赛

文生图

文生图基础知识

提示词

LoRA

ComfyUI

参考图控制

Task 2

前沿探索:了解AI生图技术的能力和局限

Deepfake

必要性

历史

总结

AI生图的难点和挑战

辨别AI味

探索AI生图前沿

可图模型

魔搭社区

魔搭社区探索

代码解读:使用通义千问

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

Baseline框架

开始▷▷▷

过程中▷▷▷

over▷▷▷

Baseline代码

使用通义千问分析代码的主体架构

输入的Prompt

返回结果

安装和卸载依赖包

加载数据集

数据预处理

使用Data-Juicer进行数据处理

数据整理与训练

图像生成

合并图像

小结

使用通义千问逐行解释代码

输入的问题

返回的结果

使用通义千问对代码疑问处进行追问

实战——基于话剧的连环画制作

1. 数据准备

2. 执行

3. 提示词修改

浅尝scepter webui

有挑战:私有部署

一些参考链接

自分の尝试

写在前面

Datawhale (linklearner.com)

从零入门AI生图原理&实践是 Datawhale 2024 年 AI 夏令营第四期的学习活动(“AIGC”方向),基于魔搭社区“可图Kolors-LoRA风格故事挑战赛”开展的实践学习——

适合想 入门并实践 AIGC文生图、工作流搭建、LoRA微调 的学习者参与

学习内容提要:从通过代码实现AI文生图逐渐进阶,教程偏重图像工作流、微调、图像优化等思路,最后会简单介绍AIGC应用方向、数字人技术(选学)

Task 1

任务一链接:Datawhale (linklearner.com)

赛题解读——可图Kolors-LoRA风格故事挑战赛

赛题链接:可图Kolors-LoRA风格故事挑战赛创新应用大赛天池大赛-阿里云天池的赛制 (aliyun.com)

赛事任务:

参赛者需在可图Kolors 模型的基础上训练LoRA 模型,生成无限风格,如水墨画风格、水彩风格、赛博朋克风格、日漫风格......

基于LoRA模型生成 8 张图片组成连贯故事,故事内容可自定义;基于8图故事,评估LoRA风格的美感度及连贯性 样例:偶像少女养成日记

提交后要求:

此外,我们会核实选手上传的模型文件,赛选手需提交训练的LoRA 模型文件、LORA 模型的介绍、以及使用该模型生成的至少8张图片和对应 prompt,以便我们能够复现生成效果,对于生成效果明显无法复现的,取消获奖资格

任务提交:

将训练好的LoRA 模型上传到魔搭模型库

LoRA模型命名为:队伍名称-可图Kolors训练-xxxxxx

LoRA 上传地址:魔搭社区

作品发布在比赛品牌馆讨论区,魔搭社区

发布标题格式为:天池平台报名队伍名称+LoRA模型链接地址+作品图(8图故事)

数据集分析

官方提供了示例数据集,但我们实际上可以自行寻找所需的数据集,用来训练自己的LoRA模型

文生图

文生图的历程与基石:文生图的历程与基石.pptx · 语雀 (yuque.com)

文生图基础知识

提示词+参考图(可选) → 模型(此处为LoRA)→ 生成图片

提示词

一般写法:主体描述,细节描述,修饰词,艺术风格,艺术家

举个例子

【promts】Beautiful and cute girl, smiling, 16 years old, denim jacket, gradient background, soft colors, soft lighting, cinematic edge lighting, light and dark contrast, anime, super detail, 8k

负向prompts, (text:1.2), deformed, black and white,disfigured, low contrast, cropped, missing fingers*

LoRA

Stable Diffusion中的Lora(LoRA)模型是一种轻量级的微调方法,它代表了“Low-Rank Adaptation”,即低秩适应。

Lora不是指单一的具体模型,而是指一类通过特定微调技术应用于基础模型的扩展应用。

在Stable Diffusion这一文本到图像合成模型的框架下,Lora被用来对预训练好的大模型进行针对性优化,以实现对特定主题、风格或任务的精细化控制

ComfyUI

ComfyUI 是一个工作流工具,主要用于简化和优化 AI 模型的配置和训练过程

通过直观的界面和集成的功能,用户可以轻松地进行模型微调、数据预处理、图像生成等任务,从而提高工作效率和生成效果

在ComfyUI平台的前端页面上,用户可以基于节点/流程图的界面设计并执行AIGC文生图或者文生视频的pipeline

参考图控制

ControlNet是一种用于精确控制图像生成过程的技术组件。它是一个附加到预训练的扩散模型(如Stable Diffusion模型)上的可训练神经网络模块

扩散模型通常用于从随机噪声逐渐生成图像的过程,而ControlNet的作用在于引入额外的控制信号,使得用户能够更具体地指导图像生成的各个方面(如姿势关键点、分割图、深度图、颜色等)

参考图控制类型 简介 示例 OpenPose姿势控制 输入是一张姿势图片(或者使用真人图片提取姿势)作为AI绘画的参考图,输入prompt后,之后AI就可以依据此生成一副相同姿势的图片; 画一个小女孩的行走姿势图,然后根据这个姿势生成小女孩走路图 Canny精准绘制 输入是一张线稿图作为AI绘画的参考图,输入prompt后,之后AI就可以根据此生成一幅根据线稿的精准绘制。 画一个乌龟的黑白线稿(说是线稿但是几乎全画完了啊。。)然后非常精准地生成一只彩色乌龟 Hed绘制 Hed是一种可以获取渐变线条的线稿图控制方式,相比canny更加的灵活。 比起Canny更精准的线稿和更加色彩生动的一只鸟 深度图Midas 输入是一张深度图,输入prompt后,之后AI就可以根据此生成一幅根据深度图的绘制。 这个输入图像比上面两种都离谱(一朵有深有浅的黑背景白玫瑰),生成的图也就像根据色度深浅上了个色(一朵深浅有致的粉红玫瑰) 颜色color控制 通过参考图控制和颜色控制,实现更加精准和个性化的图像生成效果。 输入的图像是一张重度马赛克的色块图,然后输出的是根据这个色块分布的一张清晰图画

Task 2

Task2链接:Datawhale (linklearner.com)

前沿探索:了解AI生图技术的能力和局限

Deepfake

从零入门CV图像竞赛(Deepfake攻防)

必要性

to普通人:辨别能力↑ 绘图自用

to创作者:利用AI生图工具提效

to技术人:针对自己的业务进行开发和使用 攻克难题开发更实用的工具

历史

最早:20世纪70年代 哈罗德·科恩(Harold Cohen) AARON 通过机械臂输出作画

现代的AI生图模型: 最早可追溯到2012年 吴恩达 能生成“猫脸”的模型

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

2015年: 谷歌 “深梦”(Deep Dream)图像生成工具

类似一个高级滤镜

可以基于给定的图片生成梦幻版图片

2021 年 1 月: OpenAI DALL-E模型

一个深度学习算法模型

GPT-3 语言处理模型的一个衍生版本

直接从文本提示“按需创造”风格多样的图形设计

质量和速度双重意义上的“秒杀”

总结

AI生图模型 → 多模态机器学习模型

通过海量的图库和文本描述的深度神经网络学习

最终目标

可以根据输入的指示(不管是文本还是图片还是任何)生成符合语义的图片

AI生图的难点和挑战

“不会画'手'的AI”

解决的相关技术:

例如:给手打上标记,清晰标记出手掌、拇指、食指等部位

AI生图模型获得图片生成能力

通过学习图片描述+图片特征

将两者进行对应并存储

输入文字→复现对应图片特征→生成图片

∵每个模型用于训练的数据有限+不相同

∴能匹配的描述和特征也有限

∴在风格、具体事物上,不同模型生成内容会有很大差异

辨别AI味

观察图片的细节

仔细检查人物的面部特征,尤其是眼睛和嘴巴

检查光线和阴影

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

分析像素

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

注意背景

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

探索AI生图前沿

持续更新、持续跟进、持续投入时间的主线

this活动

可图Kolors-LoRA风格故事挑战赛

所用的模型:Kolors(可图)模型

魔搭社区的各类AIGC工具

可图模型

链接:Kolors(可图)模型

是快手开源的文本到图像生成模型

英语汉语都行

代码开源链接:GitHub - Kwai-Kolors/Kolors: Kolors Team

模型开源链接:魔搭社区

技术报告链接:Kolors/imgs/Kolors_paper.pdf at master · Kwai-Kolors/Kolors · GitHub

魔搭研习社最佳实践说明:魔搭社区

prompt格式:可图优质咒语书(点击即可跳转)

魔搭社区

举例:将特定文字生成在图片中

不使用AI完成:

使用PS等图片编辑工具

使用AI:

Task1中 创意海报生成 工具

在代码中固定了相应的文字位置和对应的字体

第一步:AI生成背景

第二步:通过代码将对应的文字显示到对应位置

第三步:渲染,合成图片

魔搭社区探索

使用魔搭社区上感兴趣的工具

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

用的是哪个 AI 模型?

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

使用到了哪些 AI 能力?

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

还可以有哪些优化点?

使用建议:

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

代码解读:使用通义千问

对话

提升办公效率的各种小工具

智能体应用市场

通义tongyi.ai_你的全能AI助手 (aliyun.com)

据说通义千问喂的代码多,所以代码方面表现比其他的好

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

Baseline框架
开始▷▷▷

环境准备

安装或卸载所需的Python包

数据集加载与预处理

加载动漫图像数据集

遍历数据集,保存图像并记录元数据

数据清洗与过滤

使用DataJuicer配置文件定义数据处理规则

应用过滤规则处理数据集

过程中▷▷▷

模型微调

使用DiffSynth-Studio进行模型微调

加载微调后的模型

加载微调后的Lora模型

图像生成

设置正负提示词

设置图片尺寸、执行轮数

合并生成的图像

over▷▷▷
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
 ​
使用通义千问分析代码的主体架构
输入的Prompt
 你是一个优秀的python开发工程师,现在我们需要你帮我们分析这个代码的主体框架,你需要把代码按照工作流分成几部分,用中文回答我的问题。{此处替换前面的代码}
返回结果
安装和卸载依赖包
 # simple-aesthetics-predictor, data-juicer, peft, lightning, pandas, torchvision, 和 DiffSynth-Studio 的安装
 !pip install simple-aesthetics-predictor
 ​
 !pip install -v -e data-juicer
 ​
 !pip install peft lightning pandas torchvision
 ​
 !pip install -e DiffSynth-Studio
 ​
 # 卸载 pytorch-lightning(使用 -y 自动确认卸载)
 !pip uninstall pytorch-lightning -y
加载数据集
 使用 ModelScope 的 MsDataset 类加载名为 AI-ModelScope/lowres_anime 的数据集,并指定子集名称为 default 和分割为 train,缓存目录设置为 /mnt/workspace/kolors/data
 ds = MsDataset.load(
     'AI-ModelScope/lowres_anime',
     subset_name='default',
     split='train',
     cache_dir="/mnt/workspace/kolors/data"
 )
数据预处理
 os.makedirs("./data/lora_dataset/train", exist_ok=True)
 os.makedirs("./data/data-juicer/input", exist_ok=True)
 ​
 # 将数据集中的图像转换为 RGB 模式,并保存到指定目录
 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")
 ​
         
 # 创建包含图像路径和文本描述的元数据文件 metadata.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
 """
 ​
 # 编写并保存 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 命令根据配置文件对数据进行过滤和处理,生成 result.jsonl 文件
 !dj-process --config data/data-juicer/data_juicer_config.yaml
 ​
 ​
数据整理与训练
 texts, file_names = [], []
 os.makedirs("./data/data-juicer/output/images", exist_ok=True)
 ​
 # 读取 result.jsonl 文件中的数据
 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])
 ​
 # 将其转换为 Pandas DataFrame,然后保存为 CSV 文件
 # 并且将图片保存到./data/lora_dataset_processed/train文件夹下(这行没找着?)
 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
 ​
 # 下载模型download_models(["Kolors", "SDXL-vae-fp16-fix"])
 # 在前面模型的基础上,执行Lora微调训练
 # 加载微调后的模型
 ↑↑↑↑没找到???T T
图像生成
 # 设置正向提示词,反向提示词,执行次数,图片尺寸
 ​
 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")  # 将图片保存为.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")
 ​
合并图像
# 将生成的多个图像合并成一个大图像
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))  # 并调整大小
小结

整个流程涵盖了:

数据加载 | 预处理 | 特征提取 | 模型预测 | 图像生成等多个方面

每一部分都有其特定的功能,共同构成了一个完整的二次元图像处理和生成的工作流

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

(不是合着我前面没看到这里所以白猜了半天??淦!)

已破防,已老实)

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

安装和卸载一些Python包。

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

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

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

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

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

加载Lora微调后的模型

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

# 安装 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  # 输出最终生成的图像对象,用于显示图像
使用通义千问对代码疑问处进行追问
我对其中{替换成你的问题}还是不太理解,给我再详细介绍一下

实战——基于话剧的连环画制作

1. 数据准备
你是一个文生图专家,我们现在要做一个实战项目,就是要编排一个文生图话剧
话剧由8张场景图片生成,你需要输出每张图片的生图提示词

具体的场景图片
1、女主正在上课
2、开始睡着了
3、进入梦乡,梦到自己站在路旁
4、王子骑马而来
5、两人相谈甚欢
6、一起坐在马背上
7、下课了,梦醒了
8、又回到了学习生活中

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

例子:
古风,水墨画,一个黑色长发少女,坐在教室里,盯着黑板,深思,上半身,红色长裙

在询问的基础上进行多次调整,打磨出最佳提示词

最后的话剧场景

图片编号 场景描述 正向提示词 图片1 女主正在上课 古风,水墨画,一个黑色长发少女,坐在教室里,盯着黑板,深思,上半身,红色长裙 图片2 开始睡着了 古风,水墨画,一个黑色长发少女,坐在教室里,趴在桌子上睡着了,上半身,红色长裙 图片3 进入梦乡,梦到自己站在路旁 古风,水墨画,一个黑色长发少女,站在路边,上半身,红色长裙 图片4 王子骑马而来 古风,水墨画,一个英俊少年,骑着白马,上半身,白色衬衫 图片5 两人相谈甚欢 古风,水墨画,一个英俊少年,白色衬衫,一个黑色长发少女,红色长裙,两个人一起聊天,开心,上半身 图片6 一起坐在马背上 古风,水墨画,一个英俊少年,白色衬衫,一个黑色长发少女,红色长裙,两个人一起骑着马,全身 图片7 下课了,梦醒了 古风,水墨画,一个黑色长发少女,坐在教室里,下课铃声响了,同学们开始走动,从睡梦中醒来,深思,上半身,红色长裙 图片8 又回到了学习生活中 古风,水墨画,一个黑色长发少女,坐在教室里,盯着黑板,认真上课,上半身,红色长裙
2. 执行

在从零入门AI生图原理&实践 的基础上

3. 提示词修改

双击进入baseline文件

找到生成图像的板块

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

浅尝scepter webui

魔搭体验网址:魔搭社区

核心组件

生成训练和推理框架

轻松实施流行方法

交互式用户界面:SCEPTER Studio

有挑战:私有部署

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

github地址:GitHub - modelscope/scepter: SCEPTER is an open-source framework used for training, fine-tuning, and inference with generative models.

突然想起上个月买的还不太会用的华为云服务器(提醒一下自分T T

一些参考链接

壹沓AI观察:DALL-E——人工智能让“达利”再世

《AIGC未来已来》

AI时代不得不提的“恐怖谷”

AI绘画的发展历史(GAN、diffusion、VAE…) 

AI绘画很快就能骗过整个互联网了。。。

自分の尝试

根据以前的梦境编了一个故事,没想到给的提示词和画面描述还挺切合(笑

(碎碎念:看到一个玄学:当某个人进入梦中,说明此生再无缘分啦>-<

图片编号 场景描述 正向提示词 图片1 女主正在躲避追杀,进入一座小楼 现代,二次元,赛博朋克,年轻女性,黑色长发,穿着战斗装备,眼神警惕,昏暗的街道,霓虹灯闪烁,一座破旧的小楼入口,快速闪入楼内,回头一瞥 图片2 女主在逃跑中,看到楼上的灯光 现代,二次元,赛博朋克,年轻女性,黑色长发,战斗装备,表情紧张,阴暗的街道,远处高楼窗户透出的微弱灯光,奔跑中抬头看光 图片3 跑到二楼,看见想见到的人 现代,二次元,赛博朋克,年轻女性与男性,均着战斗装备,表情惊喜,二楼走廊,灯光昏暗,屏幕发出蓝光,停下脚步,惊讶地看向对方 图片4 两人从缝隙中望向楼下,已经是一片战后的残骸 现代,二次元,赛博朋克,年轻女性与男性,战斗装备,眼神凝重,二楼的隐蔽角落,通过缝隙可以看到楼下的废墟,蹲伏,透过缝隙向下窥视 图片5 两人相对而坐,确认对方的安全,眼里有泪 现代,二次元,赛博朋克,年轻女性与男性,战斗装备,眼含泪水,一间破旧的房间,窗外是探测器的红光,房间内仅有微弱的光线,面对面坐着,彼此确认安全 图片6 两个人手牵着手,坐在地面上,疲倦而安静 现代,二次元,赛博朋克,年轻女性与男性,战斗装备,疲惫表情,一间简陋的避难所,周围是电子设备和武器,手牵手,坐在地上,身体放松 图片7 在通往二楼的道路上响起枪炮声,两人静静等待结局 现代,二次元,赛博朋克,年轻女性与男性,战斗装备,表情坚定,狭窄的楼梯间,墙壁破损,背靠墙壁,保持沉默 图片8 梦醒,有点失落 现代,二次元,赛博朋克,年轻女性,黑色短发,穿着睡衣,神情忧郁,一间简陋的卧室,窗外是霓虹闪烁的城市夜景,坐在床边,低头沉思

评价:有点人工智障。。。。

总结

更新时间 2024-09-25