μ¬ν κ°λ₯ν νμ΄νλΌμΈ μμ±νκΈ°
[[open-in-colab]]
μ¬νμ±μ ν μ€νΈ, κ²°κ³Ό μ¬ν, κ·Έλ¦¬κ³ μ΄λ―Έμ§ νλ¦¬ν° λμ΄κΈ°μμ μ€μν©λλ€. κ·Έλ¬λ diffusion λͺ¨λΈμ 무μμμ±μ λ§€λ² λͺ¨λΈμ΄ λμκ° λλ§λ€ νμ΄νλΌμΈμ΄ λ€λ₯Έ μ΄λ―Έμ§λ₯Ό μμ±ν μ μλλ‘ νλ μ΄μ λ‘ νμν©λλ€. νλ«νΌ κ°μ μ ννκ² λμΌν κ²°κ³Όλ₯Ό μ»μ μλ μμ§λ§, νΉμ νμ© λ²μ λ΄μμ λ¦΄λ¦¬μ€ λ° νλ«νΌ κ°μ κ²°κ³Όλ₯Ό μ¬νν μλ μμ΅λλ€. κ·ΈλΌμλ diffusion νμ΄νλΌμΈκ³Ό 체ν¬ν¬μΈνΈμ λ°λΌ νμ© μ€μ°¨κ° λ¬λΌμ§λλ€.
diffusion λͺ¨λΈμμ 무μμμ±μ μμ²μ μ μ΄νκ±°λ κ²°μ λ‘ μ μκ³ λ¦¬μ¦μ μ¬μ©νλ λ°©λ²μ μ΄ν΄νλ κ²μ΄ μ€μν μ΄μ μ λλ€.
π‘ Pytorchμ μ¬νμ±μ λν μ μΈλ₯Ό κΌ μ½μ΄λ³΄κΈΈ μΆμ²ν©λλ€:
μμ νκ² μ¬νκ°λ₯ν κ²°κ³Όλ Pytorch λ°°ν¬, κ°λ³μ μΈ μ»€λ°, νΉμ λ€λ₯Έ νλ«νΌλ€μμ 보μ₯λμ§ μμ΅λλ€. λν, κ²°κ³Όλ CPUμ GPU μ€νκ°μ μ¬μ§μ΄ κ°μ seedλ₯Ό μ¬μ©ν λλ μ¬ν κ°λ₯νμ§ μμ μ μμ΅λλ€.
무μμμ± μ μ΄νκΈ°
μΆλ‘ μμ, νμ΄νλΌμΈμ λ Έμ΄μ¦λ₯Ό μ€μ΄κΈ° μν΄ κ°μ°μμ λ Έμ΄μ¦λ₯Ό μμ±νκ±°λ μ€μΌμ€λ§ λ¨κ³μ λ Έμ΄μ¦λ₯Ό λνλ λ±μ λλ€ μνλ§ μ€νμ ν¬κ² μμ‘΄ν©λλ€,
DDIMPipelineμμ λ μΆλ‘ λ¨κ³ μ΄νμ ν μ κ°μ μ΄ν΄λ³΄μΈμ:
from diffusers import DDIMPipeline
import numpy as np
model_id = "google/ddpm-cifar10-32"
# λͺ¨λΈκ³Ό μ€μΌμ€λ¬λ₯Ό λΆλ¬μ€κΈ°
ddim = DDIMPipeline.from_pretrained(model_id)
# λ κ°μ λ¨κ³μ λν΄μ νμ΄νλΌμΈμ μ€ννκ³ numpy tensorλ‘ κ°μ λ°ννκΈ°
image = ddim(num_inference_steps=2, output_type="np").images
print(np.abs(image).sum())
μμ μ½λλ₯Ό μ€ννλ©΄ νλμ κ°μ΄ λμ€μ§λ§, λ€μ μ€ννλ©΄ λ€λ₯Έ κ°μ΄ λμ΅λλ€. λ¬΄μ¨ μΌμ΄ μΌμ΄λκ³ μλ κ±ΈκΉμ?
νμ΄νλΌμΈμ΄ μ€νλ λλ§λ€, torch.randnμ λ¨κ³μ μΌλ‘ λ Έμ΄μ¦ μ κ±°λλ κ°μ°μμ λ Έμ΄μ¦κ° μμ±νκΈ° μν λ€λ₯Έ λλ€ seedλ₯Ό μ¬μ©ν©λλ€.
κ·Έλ¬λ λμΌν μ΄λ―Έμ§λ₯Ό μμ μ μΌλ‘ μμ±ν΄μΌ νλ κ²½μ°μλ CPUμμ νμ΄νλΌμΈμ μ€ννλμ§ GPUμμ μ€ννλμ§μ λ°λΌ λ¬λΌμ§λλ€.
CPU
CPUμμ μ¬ν κ°λ₯ν κ²°κ³Όλ₯Ό μμ±νλ €λ©΄, PyTorch Generatorλ‘ seedλ₯Ό κ³ μ ν©λλ€:
import torch
from diffusers import DDIMPipeline
import numpy as np
model_id = "google/ddpm-cifar10-32"
# λͺ¨λΈκ³Ό μ€μΌμ€λ¬ λΆλ¬μ€κΈ°
ddim = DDIMPipeline.from_pretrained(model_id)
# μ¬νμ±μ μν΄ generator λ§λ€κΈ°
generator = torch.Generator(device="cpu").manual_seed(0)
# λ κ°μ λ¨κ³μ λν΄μ νμ΄νλΌμΈμ μ€ννκ³ numpy tensorλ‘ κ°μ λ°ννκΈ°
image = ddim(num_inference_steps=2, output_type="np", generator=generator).images
print(np.abs(image).sum())
μ΄μ μμ μ½λλ₯Ό μ€ννλ©΄ seedλ₯Ό κ°μ§ Generator
κ°μ²΄κ° νμ΄νλΌμΈμ λͺ¨λ λλ€ ν¨μμ μ λ¬λλ―λ‘ νμ 1491.1711
κ°μ΄ μΆλ ₯λ©λλ€.
νΉμ νλμ¨μ΄ λ° PyTorch λ²μ μμ μ΄ μ½λ μμ λ₯Ό μ€ννλ©΄ λμΌνμ§λ μλλΌλ μ μ¬ν κ²°κ³Όλ₯Ό μ»μ μ μμ΅λλ€.
π‘ μ²μμλ μλλ₯Ό λνλ΄λ μ μκ° λμ μ Generator
κ°μ²΄λ₯Ό νμ΄νλΌμΈμ μ λ¬νλ κ²μ΄ μ½κ° λΉμ§κ΄μ μΌ μ μμ§λ§,
Generator
λ μμ°¨μ μΌλ‘ μ¬λ¬ νμ΄νλΌμΈμ μ λ¬λ μ μλ \λλ€μν\μ΄κΈ° λλ¬Έμ PyTorchμμ νλ₯ λ‘ μ λͺ¨λΈμ λ€λ£° λ κΆμ₯λλ μ€κ³μ
λλ€.
GPU
μλ₯Ό λ€λ©΄, GPU μμμ κ°μ μ½λ μμλ₯Ό μ€ννλ©΄:
import torch
from diffusers import DDIMPipeline
import numpy as np
model_id = "google/ddpm-cifar10-32"
# λͺ¨λΈκ³Ό μ€μΌμ€λ¬ λΆλ¬μ€κΈ°
ddim = DDIMPipeline.from_pretrained(model_id)
ddim.to("cuda")
# μ¬νμ±μ μν generator λ§λ€κΈ°
generator = torch.Generator(device="cuda").manual_seed(0)
# λ κ°μ λ¨κ³μ λν΄μ νμ΄νλΌμΈμ μ€ννκ³ numpy tensorλ‘ κ°μ λ°ννκΈ°
image = ddim(num_inference_steps=2, output_type="np", generator=generator).images
print(np.abs(image).sum())
GPUκ° CPUμ λ€λ₯Έ λμ μμ±κΈ°λ₯Ό μ¬μ©νκΈ° λλ¬Έμ λμΌν μλλ₯Ό μ¬μ©νλλΌλ κ²°κ³Όκ° κ°μ§ μμ΅λλ€.
μ΄ λ¬Έμ λ₯Ό νΌνκΈ° μν΄ π§¨ Diffusersλ CPUμ μμμ λ
Έμ΄μ¦λ₯Ό μμ±ν λ€μ νμμ λ°λΌ ν
μλ₯Ό GPUλ‘ μ΄λμν€λ
randn_tensor()κΈ°λ₯μ κ°μ§κ³ μμ΅λλ€.
randn_tensor
κΈ°λ₯μ νμ΄νλΌμΈ λ΄λΆ μ΄λμμλ μ¬μ©λλ―λ‘ νμ΄νλΌμΈμ΄ GPUμμ μ€νλλλΌλ νμ CPU Generator
λ₯Ό ν΅κ³Όν μ μμ΅λλ€.
μ΄μ κ²°κ³Όμ ν¨μ¬ λ λ€κ°μμ΅λλ€!
import torch
from diffusers import DDIMPipeline
import numpy as np
model_id = "google/ddpm-cifar10-32"
# λͺ¨λΈκ³Ό μ€μΌμ€λ¬ λΆλ¬μ€κΈ°
ddim = DDIMPipeline.from_pretrained(model_id)
ddim.to("cuda")
#μ¬νμ±μ μν generator λ§λ€κΈ° (GPUμ μ¬λ¦¬μ§ μλλ‘ μ‘°μ¬νλ€!)
generator = torch.manual_seed(0)
# λ κ°μ λ¨κ³μ λν΄μ νμ΄νλΌμΈμ μ€ννκ³ numpy tensorλ‘ κ°μ λ°ννκΈ°
image = ddim(num_inference_steps=2, output_type="np", generator=generator).images
print(np.abs(image).sum())
π‘ μ¬νμ±μ΄ μ€μν κ²½μ°μλ νμ CPU generatorλ₯Ό μ λ¬νλ κ²μ΄ μ’μ΅λλ€. μ±λ₯ μμ€μ 무μν μ μλ κ²½μ°κ° λ§μΌλ©° νμ΄νλΌμΈμ΄ GPUμμ μ€νλμμ λλ³΄λ€ ν¨μ¬ λ λΉμ·ν κ°μ μμ±ν μ μμ΅λλ€.
λ§μ§λ§μΌλ‘ UnCLIPPipelineκ³Ό κ°μ λ 볡μ‘ν νμ΄νλΌμΈμ κ²½μ°, μ΄λ€μ μ’ μ’ μ λ° μ€μ°¨ μ νμ κ·Ήλλ‘ μ·¨μ½ν©λλ€. λ€λ₯Έ GPU νλμ¨μ΄ λλ PyTorch λ²μ μμ μ μ¬ν κ²°κ³Όλ₯Ό κΈ°λνμ§ λ§μΈμ. μ΄ κ²½μ° μμ ν μ¬νμ±μ μν΄ μμ ν λμΌν νλμ¨μ΄ λ° PyTorch λ²μ μ μ€νν΄μΌ ν©λλ€.
κ²°μ λ‘ μ μκ³ λ¦¬μ¦
κ²°μ λ‘ μ μκ³ λ¦¬μ¦μ μ¬μ©νμ¬ μ¬ν κ°λ₯ν νμ΄νλΌμΈμ μμ±νλλ‘ PyTorchλ₯Ό ꡬμ±ν μλ μμ΅λλ€. κ·Έλ¬λ κ²°μ λ‘ μ μκ³ λ¦¬μ¦μ λΉκ²°μ λ‘ μ μκ³ λ¦¬μ¦λ³΄λ€ λλ¦¬κ³ μ±λ₯μ΄ μ νλ μ μμ΅λλ€. νμ§λ§ μ¬νμ±μ΄ μ€μνλ€λ©΄, μ΄κ²μ΄ μ΅μ μ λ°©λ²μ λλ€!
λ μ΄μμ CUDA μ€νΈλ¦Όμμ μμ
μ΄ μμλ λ λΉκ²°μ λ‘ μ λμμ΄ λ°μν©λλ€.
μ΄ λ¬Έμ λ₯Ό λ°©μ§νλ €λ©΄ νκ²½ λ³μ CUBLAS_WORKSPACE_CONFIGλ₯Ό :16:8
λ‘ μ€μ ν΄μ
λ°νμ μ€μ μ€μ§ νλμ λ²νΌ ν¬λ¦¬λ§ μ¬μ©νλλ‘ μ€μ ν©λλ€.
PyTorchλ μΌλ°μ μΌλ‘ κ°μ₯ λΉ λ₯Έ μκ³ λ¦¬μ¦μ μ ννκΈ° μν΄ μ¬λ¬ μκ³ λ¦¬μ¦μ λ²€μΉλ§νΉν©λλ€.
νμ§λ§ μ¬νμ±μ μνλ κ²½μ°, λ²€μΉλ§ν¬κ° 맀 μκ° λ€λ₯Έ μκ³ λ¦¬μ¦μ μ νν μ μκΈ° λλ¬Έμ μ΄ κΈ°λ₯μ μ¬μ©νμ§ μλλ‘ μ€μ ν΄μΌ ν©λλ€.
λ§μ§λ§μΌλ‘, torch.use_deterministic_algorithmsμ
True
λ₯Ό ν΅κ³ΌμμΌ κ²°μ λ‘ μ μκ³ λ¦¬μ¦μ΄ νμ±ν λλλ‘ ν©λλ€.
import os
os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":16:8"
torch.backends.cudnn.benchmark = False
torch.use_deterministic_algorithms(True)
μ΄μ λμΌν νμ΄νλΌμΈμ λλ² μ€ννλ©΄ λμΌν κ²°κ³Όλ₯Ό μ»μ μ μμ΅λλ€.
import torch
from diffusers import DDIMScheduler, StableDiffusionPipeline
import numpy as np
model_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionPipeline.from_pretrained(model_id).to("cuda")
pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config)
g = torch.Generator(device="cuda")
prompt = "A bear is playing a guitar on Times Square"
g.manual_seed(0)
result1 = pipe(prompt=prompt, num_inference_steps=50, generator=g, output_type="latent").images
g.manual_seed(0)
result2 = pipe(prompt=prompt, num_inference_steps=50, generator=g, output_type="latent").images
print("L_inf dist = ", abs(result1 - result2).max())
"L_inf dist = tensor(0., device='cuda:0')"