目录
step3: Scepter 和 Web UI 工具箱的使用
Task2的主要任务为精读代码,实战进阶。
因为笔者已经对大模型的使用比较熟练,因此直接开干!
Step1: 尝试理解baseline代码
1.代码结构
这里附上完整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
2. baseline解析
(1)安装python 包
simple-aesthetics-predictor
用于美学预测
data-juicer
用于数据处理
peft
用于参数高效微调
lightning
(pytorch-lightning)用于简化PyTorch模型训练
pandas
用于数据分析
torchvision
用于图像处理
DiffSynth-Studio
,是与扩散模型相关的库
!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)数据集加载
from modelscope.msdatasets import MsDataset
#加载数据集
ds = MsDataset.load(
'AI-ModelScope/lowres_anime', #这个字符串指定了要加载的数据集的名称,我们要加载的是名为lowres_anime的数据集,它位于ModelScope平台的AI-ModelScope组织下
subset_name='default', #子集的名称 ,一般来讲都是有train,test ,但是我们这里设置成了default,那么表示我们加载默认的子集,一般是指全部数据
split='train', #指定了数据集的特定分割部分
cache_dir="/mnt/workspace/kolors/data" #指定缓存目录
)
总之,大致的加载数据集的思路就是,找到相关目录下的数据集文件,选择加载哪个子集,加载子集中的什么部分(train or test ??),加载好的数据集文件下载在哪
(3)数据集预处理
import json, os
from data_juicer.utils.mm_utils import SpecialTokens
from tqdm import tqdm
json
用于处理JSON格式的数据。os
用于操作系统相关功能,如文件和目录操作。SpecialTokens
用于处理特殊标记。tqdm
是一个进度条库,用于显示循环的进度。
这里扩展一些笔者不曾用到过的库,做些补充:
其一,tqdm库
tqdm是阿拉伯语"taqaddum"的缩写,意为“进步”,同时在西班牙语中,是“te quiero demasiado”的缩写,意为,“I love you so much"
tqdm是一个快速、可扩展的Python进度条,可以在Python长循环中添加一个进度提示信息,用户只需要封装任意的迭代器tqdm(iterator)。它可以帮助我们监测程序运行的进度,估计运行的时长,甚至可以协助debug。对于在长时间运行的任务中显示进度很有用,因为它可以让用户知道任务正在进行。
有点意思,因此笔者决定亲自使用,一探究竟,这是tqdm库的Github地址,有需要的小伙伴可以进行学习:https://github.com/tqdm/tqdm
基本使用:
在本地使用了这个库,效果如下:
可变情况下:
手动情况下:
使用with进行手动控制
with tqdm(total=100) as pbar:
for i in range(10):
sleep(0.1)
pbar.update(10)
如果提供了可选变量total(或具有len()的可迭代对象),则显示预测统计信息。
不使用with:
With也只是一个可选项,如果不想使用with,可以把tqdm()赋值给一个变量,但在这种情况下,不要忘记在末尾del或close()
pbar = tqdm(total=100)
for i in range(10):
sleep(0.1)
pbar.update(10)
pbar.close()
进度条定制:
1. 设置描述信息
可以通过desc参数为进度条添加描述信息。
2.自定义进度条长度
使用ncols参数可以自定义进度条的长度。
3. 改变进度条样式
bar_format 使用不同的字符来改变进度条的样式。
pbar = tqdm(total=100,desc="Processing")
for i in range(10):
sleep(0.1)
pbar.update(10)
pbar.close()
其二,data-juicer系统
这是对应的github地址,有感兴趣的小伙伴可以进行学习
https://github.com/modelscope/data-juicerhttps://github.com/modelscope/data-juicerData-Juicer 是一个一站式多模态数据处理系统,旨在为大语言模型 (LLM) 提供更高质量、更丰富、更易“消化”的数据。
2024年2月15日,OpenAI正式对外发布了Sora。
2024年3月23日的全球开发者先锋大会上,阿里云的魔搭社区宣布了一个新计划:“ModelScope-Sora开源计划”。
在Data-Juicer的主页上逛了逛,心情激荡,尽管外国发展人工智能的速度很快,技术很领先,但是我们从来不会去放弃追赶,尤其是对于像阿里这样的国内顶尖企业,承担了很大的社会责任。
为了便于开发者学习,魔搭提供了可以在浏览器使用data-Juicer的notebook, 有感兴趣的小伙伴可以关注data-Juice进行学习。
在数据集的预准备阶段:
我们需要把图片信息转为Jsonl 文件,看来是需要使用Jsonl类型的图像数据,才方便进一步处理的。
其三,图像格式转换以及筛选
1. 创建两个目录
os.makedirs("./data/lora_dataset/train", exist_ok=True)#用于存储处理过的图像。
os.makedirs("./data/data-juicer/input", exist_ok=True)#用于存放输入给Data-Juicer的数据文件
2. 遍历数据集ds中的每一项,并使用进度条展现进程情况,把图像转换成RGB格式数据,然后建立一个字典,里面格式为:
“text”:"二次元",“image”: RGB图像地址
3. 然后写入metadata.jsonl
文件
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' # 你前面生成的数据的索引文件
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
的配置文件,并将其写入到data_juicer_config.yaml
中:
project_name
指定了项目名称。dataset_path
指定了输入数据集的路径,即前面创建的metadata.jsonl
文件的路径。np
设置了处理数据集时使用的子进程数量。text_keys
和image_key
分别指定了文本和图像数据在输入数据中的键名。image_special_token
是一个特殊的标记,用于表示图像位置。export_path
指定了处理后输出数据的路径。process
列出了对数据集进行过滤的具体规则,包括:image_shape_filter
用于过滤宽度和高度都不小于1024像素的图像。image_aspect_ratio_filter
用于过滤宽高比在0.5到2.0之间的图像。
补充:
enumerate() : 对于一个可迭代的(iterable)/可遍历的对象(如列表、字符串),enumerate将其组成一个索引序列,利用它可以同时获得索引和值,因此我们在这 获取 data_id 和 data ,如果原始数据中没有设置索引,则会自己从0 ,1, 2 开始
(4)使用CLIP模型编码数据集
1.提取出图像数据和描述信息
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)
- 打开
result.jsonl
文件进行读取。 - 使用
tqdm
库显示读取文件的进度条。 - 对于文件中的每一行,将其解析为JSON格式,并从中提取出文本描述和图像文件路径。
- 将提取出来的文本描述和图像文件路径分别添加到
texts
和file_names
列表中。 - 将提取到的文本描述和图像文件路径转化为DataFrame,并将其保存为CSV文件
2. 使用CLIP模型来计算处理后的图像数据与对应文本描述之间的相似度,并将处理过程的结果保存为CSV文件。
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 # 从输出中提取logits_per_image,这是图像和文本之间的相似度分数
probs = logits_per_image.softmax(dim=1) #得到每个图像对于其对应文本描述的概率
补充:
CLIP模型(由Open AI 提出)训练思路
CLIP预训练图像编码器和文本编码器,以预测数据集中哪些图像与哪些文本配对。然后,使用这种行为将CLIP转换为zero-shot分类器。将数据集的所有类转换为文本,例如“一张狗的照片”,并预测CLIP估计的标题类与给定图像的最佳配对。
(5)可图Lora训练
可图使用了基于U-Net架构的隐空间扩散模型,并创新性地引入了大语言模型进行文本表征。
github地址:GitHub - Kwai-Kolors/Kolors: Kolors Team
在最近的智源FlagEval文生图模型评测榜单中,可图(Kolors)凭借其卓越表现,主观综合评分全球第二,仅次于闭源的DALL-E 3。尤其在主观图像质量上,可图(Kolors)表现突出,显著优于其他开源和闭源模型,评分排名第一。——引自快手技术CSDN博客
# 执行可图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训练
梯度检查点技术是啥?
梯度检查点技术(Gradient Checkpointing)是一种在深度学习模型训练过程中节省内存的方法。在训练深度神经网络时,特别是在使用反向传播算法进行梯度计算时,需要存储大量的中间激活值(即前向传播过程中的输出)。这些激活值在反向传播阶段用来计算梯度,这对于更新网络权重至关重要。然而,随着网络层数的增加,这些中间激活值可能会占用大量的显存空间,导致显存不足的问题。
梯度检查点技术通过在训练过程中有选择性地丢弃一些中间激活值,并在需要时重新计算它们,从而减少内存使用。这种方法的核心思想是,在前向传播阶段不保存所有层的激活值,而是在反向传播时重新计算那些被丢弃的激活值。
具体来说,梯度检查点技术的工作流程如下:
- 选择检查点:在模型中选择某些层或模块作为检查点,这些检查点之间的激活值不会被保存。
- 前向传播:正常进行前向传播,但在到达检查点时,只保存检查点处的激活值。
- 反向传播:在反向传播时,当遇到一个检查点时,如果需要某个已经被丢弃的激活值,则重新从前向传播开始执行到该检查点,从而计算出所需的激活值。
- 梯度计算:一旦得到所需的激活值,就可以计算梯度,并继续反向传播过程。
这种方法的优势在于,它可以在一定程度上减少内存需求,因为不是所有的中间激活值都需要存储。但是,重新计算激活值会增加计算时间,因此这是一种时间和空间的权衡。
在您的代码中,
--use_gradient_checkpointing
参数指示训练脚本在训练过程中启用梯度检查点技术,这意味着在训练过程中将会有选择性地丢弃某些中间激活值,并在需要时重新计算它们,以此来节省内存资源。这对于处理大规模模型尤其有用,因为在GPU内存有限的情况下,这种技术可以使得训练更大的模型成为可能。
(6)加载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权重的文件路径
)
Step2 :进行提示词创作并文生图
1.提示词以及生成图
-
开场:古色古香的小镇
- 古镇黄昏时分,炊烟袅袅升起,一群孩童在街道上追逐嬉戏,远处可见一座宏伟的城门。
-
主角登场:白马少年
- 骑着一匹雪白骏马的少年身着青衣,眉宇间英气逼人,正从林间小道缓缓走出,阳光透过树叶洒在他的身上。
-
神秘相遇:月下湖畔
- 月光如水,湖面波光粼粼,少年与一位手持长笛的少女不期而遇,两人目光交汇,周围似乎弥漫着淡淡的雾气。
-
危机四伏:密林追击
- 密林之中,枝叶繁茂,少年带领众人躲避追兵,身后尘土飞扬,前路不明。
-
秘密基地:山洞内部
- 山洞内部布置得温馨且充满神秘感,墙壁上挂着各式各样的武器和地图,火把照亮了洞内的每一个角落。
-
决斗:古战场遗迹
- 在一处荒废的古战场遗址,少年与敌人展开激烈的对决,背景是断壁残垣,天空乌云密布。
-
情感高潮:悬崖边的誓言
- 少年与少女站在悬崖边,背后是夕阳西下的壮丽景色,二人紧紧相拥,誓言永远不分离。
-
结局:和平归来的庆典
- 小镇上举办盛大的庆典活动庆祝和平归来,人们载歌载舞,彩旗飘扬,少年和少女手牵手走在人群之中,脸上洋溢着幸福的笑容。
2.一点思考
通过不断地调整prompt ,发现还存在以下问题:
(1)对于在图片中添加文字的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")
(2)对于人种的混淆使用比较突出
torch.manual_seed(7)
image = pipe(
prompt="中国风,英俊的青年与女人站在悬崖边,背后是夕阳西下的壮丽景色,二人紧紧相拥,誓言永远不分离",
negative_prompt="丑陋、变形、嘈杂、模糊、低对比度",
cfg_scale=4,
num_inference_steps=50, height=1024, width=1024,
)
image.save("7.jpg")
(3)因为要构建完整的故事结构,应该是要人物协调的
比如说,男主幼年,青年,中年的相貌应有相似之处,当我前面生成了一张青年图,但是需要变换场景时,我希望模型能够保留之前的记忆,而不是出现一个新的人像。但是现在的结果显然不乐观,甚至故事的结局是两个女生的场景。
step3: Scepter 和 Web UI 工具箱的使用
使用了一下Scepter,感觉还是没有驯服这个工具,生图效果一般