notebook_login()

1.3 導入相關庫

import numpy as np
import torch
import torch.nn.functional as F
import torchvision
from datasets import load_dataset
from diffusers import DDIMScheduler, DDPMPipeline
from matplotlib import pyplot as plt
from PIL import Image
from torchvision import transforms
from tqdm.auto import tqdm
device = (
"mps"
if torch.backends.mps.is_available()
else "cuda"
if torch.cuda.is_available()
else "cpu"
)

二、導入預訓練的擴散模型

下面我們導入人臉生成的擴散模型,觀察一下生成的效果,代碼如下:

image_pipe = DDPMPipeline.from_pretrained("google/ddpm-celebahq-256")
image_pipe.to(device);

查看生成的圖像,代碼如下:

images = image_pipe().images
images[0]

生成的效果雖然不錯,但是速度稍微有點慢,其實有更快的采樣器可以加速這一過程,比如下面介紹的DDIM

三、DDIM-更快的采樣器

? ? ? ?在生成圖像的每一步中,模型都會接收一個帶有噪聲的輸入,并且需要預測這個噪聲,以此來估計沒有噪聲的完整圖像是什么。這個過程被稱為采樣過程,在Diffusers庫中,采樣通過調度器控制的,之前的文章中介紹過DDPMScheduler調度器,本文介紹的DDIMScheduler可以通過更少的迭代周期來產生很好的采樣樣本(1000多步采樣不是必須的)。

# 創建一個新的調度器并設置推理迭代次數
scheduler = DDIMScheduler.from_pretrained("google/ddpm-celebahq-256")
scheduler.set_timesteps(num_inference_steps=40)
scheduler.timesteps
# 輸出
tensor([975, 950, 925, 900, 875, 850, 825, 800, 775, 750, 725,
700, 675, 650, 625, 600, 575, 550, 525, 500, 475, 450, 425,
400, 375, 350, 325, 300, 275, 250, 225, 200, 175, 150,
125, 100, 75, 50, 25, 0])

?? ?下面使用4幅隨機噪聲圖像進行循環采樣,并觀察每一步的輸入與輸出的”去噪“圖像,代碼如下:

# 從隨機噪聲開始
x = torch.randn(4, 3, 256, 256).to(device)
# batch size為4,三通道,長、寬均為256像素的一組圖像
# 循環一整套時間步
for i, t in tqdm(enumerate(scheduler.timesteps)):
 
# 準備模型輸入:給“帶躁”圖像加上時間步信息
model_input = scheduler.scale_model_input(x, t)
 
# 預測噪聲
with torch.no_grad():
noise_pred = image_pipe.unet(model_input, t)["sample"]
 
# 使用調度器計算更新后的樣本應該是什么樣子
scheduler_output = scheduler.step(noise_pred, t, x)
 
# 更新輸入圖像
x = scheduler_output.prev_sample
 
# 時不時看一下輸入圖像和預測的“去噪”圖像
if i % 10 == 0 or i == len(scheduler.timesteps) - 1:
fig, axs = plt.subplots(1, 2, figsize=(12, 5))
 
grid = torchvision.utils.make_grid(x, nrow=4).permute(1, 2, 0)
axs[0].imshow(grid.cpu().clip(-1, 1) * 0.5 + 0.5)
axs[0].set_title(f"Current x (step {i})")
 
pred_x0 = (
scheduler_output.pred_original_sample
)
grid = torchvision.utils.make_grid(pred_x0, nrow=4).
permute(1, 2, 0)
axs[1].imshow(grid.cpu().clip(-1, 1) * 0.5 + 0.5)
axs[1].set_title(f"Predicted denoised images (step {i})")
plt.show()

??第二步生成圖像的采樣器是DDPMScheduler,我們可以使用新的DDIMScheduler來代替DDPMScheduler看看image_pipe生成的效果是否有提升,代碼如下:

image_pipe.scheduler = scheduler
images = image_pipe(num_inference_steps=40).images
images[0]

  上述介紹了生成人臉的擴散模型以及生成的效果,也介紹了更快的采樣器DDIMScheduler,下面我們使用蝴蝶數據集來微調人臉生成擴散模型:

四、微調人臉生成擴散模型

4.1 加載蝴蝶數據集

dataset_name = "huggan/smithsonian_butterflies_subset"
dataset = load_dataset(dataset_name, split="train")
image_size = 256
batch_size = 4
preprocess = transforms.Compose(
[
transforms.Resize((image_size, image_size)),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.5], [0.5]),
]
)
 
def transform(examples):
images = [preprocess(image.convert("RGB")) for image in
examples["image"]]
return {"images": images}
 
dataset.set_transform(transform)
 
train_dataloader = torch.utils.data.DataLoader(
dataset, batch_size=batch_size, shuffle=True
)

輸出4幅蝴蝶圖像,便于觀察

print("Previewing batch:")
batch = next(iter(train_dataloader))
grid = torchvision.utils.make_grid(batch["images"], nrow=4)
plt.imshow(grid.permute(1, 2, 0).cpu().clip(-1, 1) * 0.5 + 0.5)

4.2 微調人臉生成擴散模型

num_epochs = 2
lr = 1e-5
grad_accumulation_steps = 2
 
optimizer = torch.optim.AdamW(image_pipe.unet.parameters(), lr=lr)
 
losses = []
 
for epoch in range(num_epochs):
for step, batch in tqdm(enumerate(train_dataloader),
total=len(train_dataloader)):
clean_images = batch["images"].to(device)
# 隨機生成一個噪聲,稍后加到圖像上
noise = torch.randn(clean_images.shape).to(clean_images.
device)
bs = clean_images.shape[0]
 
# 隨機選取一個時間步
timesteps = torch.randint(
0,
image_pipe.scheduler.num_train_timesteps,
(bs,),
device=clean_images.device,
).long()
 
# 根據選中的時間步和確定的幅值,在干凈圖像上添加噪聲
# 此處為前向擴散過程
noisy_images = image_pipe.scheduler.add_noise(clean_images,
noise, timesteps)
 
# 使用“帶噪”圖像進行網絡預測
noise_pred = image_pipe.unet(noisy_images, timesteps,
return_dict=False)[0]
 
# 對真正的噪聲和預測的結果進行比較,注意這里是預測噪聲
loss = F.mse_loss(
noise_pred, noise
)
 
# 保存損失值
losses.append(loss.item())
 
# 根據損失值更新梯度
loss.backward()
 
# 進行梯度累積,在累積到一定步數后更新模型參數
if (step + 1) % grad_accumulation_steps == 0:
optimizer.step()
optimizer.zero_grad()
 
print(
f"Epoch {epoch} average loss: {sum(losses[-len(train_
dataloader):])/len(train_dataloader)}"
)
 
# 畫出損失曲線,效果如圖所示
plt.plot(losses)

4.3?使用微調好的模型生成圖像

x = torch.randn(8, 3, 256, 256).to(device)
for i, t in tqdm(enumerate(scheduler.timesteps)):
model_input = scheduler.scale_model_input(x, t)
with torch.no_grad():
noise_pred = image_pipe.unet(model_input, t)["sample"]
x = scheduler.step(noise_pred, t, x).prev_sample
grid = torchvision.utils.make_grid(x, nrow=4)
plt.imshow(grid.permute(1, 2, 0).cpu().clip(-1, 1) * 0.5 + 0.5)

從圖中可以看出生成的圖像有蝴蝶數據的風格。

4.4 保持微調好的擴散模型,并且上傳到Huggingface Hub中

image_pipe.save_pretrained("my-finetuned-model")
from huggingface_hub import HfApi, ModelCard, create_repo, get_
full_repo_name
# 配置Hugging Face Hub,上傳文件
model_name = "ddpm-celebahq-finetuned-butterflies-2epochs"
# 使用@param 腳本程序對上傳到
# Hugging Face Hub的文件進行命名
local_folder_name = "my-finetuned-model" # @param腳本程序生成的名字,
# 你也可以通過 image_pipe.save_pretrained('savename')自行指定
description = "Describe your model here" # @param
hub_model_id = get_full_repo_name(model_name)
create_repo(hub_model_id)
api = HfApi()
api.upload_folder(
folder_path=f"{local_folder_name}/scheduler",path_in_repo="",
repo_id=hub_model_id )
api.upload_folder(
folder_path=f"{local_folder_name}/unet", path_in_repo="",
repo_id=hub_model_id )
api.upload_file(
path_or_fileobj=f"{local_folder_name}/model_index.json",
path_in_repo="model_index.json",
repo_id=hub_model_id,
)
 
# 添加一個模型卡片,這一步雖然不是必需的,但可以給他人提供一些模型描述信息
 
content = f"""
---
license: mit
tags:
- pytorch
- diffusers
- unconditional-image-generation
- diffusion-models-class
---
# 用法
from diffusers import DDPMPipeline
pipeline = DDPMPipeline.from_pretrained(' {hub_model_id}')
image = pipeline().images[0]
image
'''
"""
card = ModelCard(content)
card.push_to_hub(hub_model_id)

微調Trick:

文章轉自微信公眾號@ArronAI

上一篇:

擴散模型實戰(七):Diffusers蝴蝶圖像生成實戰

下一篇:

擴散模型實戰(九):使用CLIP模型引導和控制擴散模型
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費