[[open-in-colab]]
ํ์ด๋ณด๊ธฐ
Diffusion ๋ชจ๋ธ์ ์ด๋ฏธ์ง๋ ์ค๋์ค์ ๊ฐ์ ๊ด์ฌ ์ํ๋ค์ ์์ฑํ๊ธฐ ์ํด ๋๋ค ๊ฐ์ฐ์์ ๋ ธ์ด์ฆ๋ฅผ ๋จ๊ณ๋ณ๋ก ์ ๊ฑฐํ๋๋ก ํ์ต๋ฉ๋๋ค. ์ด๋ก ์ธํด ์์ฑ AI์ ๋ํ ๊ด์ฌ์ด ๋งค์ฐ ๋์์ก์ผ๋ฉฐ, ์ธํฐ๋ท์์ diffusion ์์ฑ ์ด๋ฏธ์ง์ ์๋ฅผ ๋ณธ ์ ์ด ์์ ๊ฒ์ ๋๋ค. ๐งจ Diffusers๋ ๋๊ตฌ๋ diffusion ๋ชจ๋ธ๋ค์ ๋๋ฆฌ ์ด์ฉํ ์ ์๋๋ก ํ๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
๊ฐ๋ฐ์๋ ์ผ๋ฐ ์ฌ์ฉ์๋ ์ด ํ์ด๋ณด๊ธฐ๋ฅผ ํตํด ๐งจ Diffusers๋ฅผ ์๊ฐํ๊ณ ๋น ๋ฅด๊ฒ ์์ฑํ ์ ์๋๋ก ๋์๋๋ฆฝ๋๋ค! ์์์ผ ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์ฃผ์ ๊ตฌ์ฑ ์์๋ ํฌ๊ฒ ์ธ ๊ฐ์ง์ ๋๋ค:
- [
DiffusionPipeline
]์ ์ถ๋ก ์ ์ํด ์ฌ์ ํ์ต๋ diffusion ๋ชจ๋ธ์์ ์ํ์ ๋น ๋ฅด๊ฒ ์์ฑํ๋๋ก ์ค๊ณ๋ ๋์ ์์ค์ ์๋ํฌ์๋ ํด๋์ค์ ๋๋ค. - Diffusion ์์คํ ์์ฑ์ ์ํ ๋น๋ฉ ๋ธ๋ก์ผ๋ก ์ฌ์ฉํ ์ ์๋ ๋๋ฆฌ ์ฌ์ฉ๋๋ ์ฌ์ ํ์ต๋ model ์ํคํ ์ฒ ๋ฐ ๋ชจ๋.
- ๋ค์ํ schedulers - ํ์ต์ ์ํด ๋ ธ์ด์ฆ๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ๊ณผ ์ถ๋ก ์ค์ ๋ ธ์ด์ฆ ์ ๊ฑฐ๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ์ ์ดํ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค.
ํ์ด๋ณด๊ธฐ์์๋ ์ถ๋ก ์ ์ํด [DiffusionPipeline
]์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค ๋ค์, ๋ชจ๋ธ๊ณผ ์ค์ผ์ค๋ฌ๋ฅผ ๊ฒฐํฉํ์ฌ [DiffusionPipeline
] ๋ด๋ถ์์ ์ผ์ด๋๋ ์ผ์ ๋ณต์ ํ๋ ๋ฐฉ๋ฒ์ ์๋ดํฉ๋๋ค.
ํ์ด๋ณด๊ธฐ๋ ๊ฐ๊ฒฐํ ๋ฒ์ ์ ๐งจ Diffusers ์๊ฐ๋ก์ ๋ ธํธ๋ถ ๋น ๋ฅด๊ฒ ์์ํ ์ ์๋๋ก ๋์๋๋ฆฝ๋๋ค. ๋ํจ์ ์ ๋ชฉํ, ๋์์ธ ์ฒ ํ, ํต์ฌ API์ ๋ํ ์ถ๊ฐ ์ธ๋ถ ์ ๋ณด๋ฅผ ์์ธํ ์์๋ณด๋ ค๋ฉด ๋ ธํธ๋ถ์ ํ์ธํ์ธ์!
์์ํ๊ธฐ ์ ์ ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ชจ๋ ์ค์น๋์ด ์๋์ง ํ์ธํ์ธ์:
# ์ฃผ์ ํ์ด์ Colab์ ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์นํ๊ธฐ.
#!pip install --upgrade diffusers accelerate transformers
- ๐ค Accelerate๋ ์ถ๋ก ๋ฐ ํ์ต์ ์ํ ๋ชจ๋ธ ๋ก๋ฉ ์๋๋ฅผ ๋์ฌ์ค๋๋ค.
- ๐ค Transformers๋ Stable Diffusion๊ณผ ๊ฐ์ด ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋๋ diffusion ๋ชจ๋ธ์ ์คํํ๋ ๋ฐ ํ์ํฉ๋๋ค.
DiffusionPipeline
[DiffusionPipeline
] ์ ์ถ๋ก ์ ์ํด ์ฌ์ ํ์ต๋ diffusion ์์คํ
์ ์ฌ์ฉํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์
๋๋ค. ๋ชจ๋ธ๊ณผ ์ค์ผ์ค๋ฌ๋ฅผ ํฌํจํ๋ ์๋ ํฌ ์๋ ์์คํ
์
๋๋ค. ๋ค์ํ ์์
์ [DiffusionPipeline
]์ ๋ฐ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ์๋ ํ์์ ์ง์๋๋ ๋ช ๊ฐ์ง ์์
์ ์ดํด๋ณด๊ณ , ์ง์๋๋ ์์
์ ์ ์ฒด ๋ชฉ๋ก์ ๐งจ Diffusers Summary ํ์์ ํ์ธํ ์ ์์ต๋๋ค.
Task | Description | Pipeline |
---|---|---|
Unconditional Image Generation | generate an image from Gaussian noise | unconditional_image_generation |
Text-Guided Image Generation | generate an image given a text prompt | conditional_image_generation |
Text-Guided Image-to-Image Translation | adapt an image guided by a text prompt | img2img |
Text-Guided Image-Inpainting | fill the masked part of an image given the image, the mask and a text prompt | inpaint |
Text-Guided Depth-to-Image Translation | adapt parts of an image guided by a text prompt while preserving structure via depth estimation | depth2img |
๋จผ์ [DiffusionPipeline
]์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ณ ๋ค์ด๋ก๋ํ ํ์ดํ๋ผ์ธ ์ฒดํฌํฌ์ธํธ๋ฅผ ์ง์ ํฉ๋๋ค.
ํ๊น
ํ์ด์ค ํ๋ธ์ ์ ์ฅ๋ ๋ชจ๋ checkpoint์ ๋ํด [DiffusionPipeline
]์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ด ํ์ด๋ณด๊ธฐ์์๋ text-to-image ์์ฑ์ ์ํ stable-diffusion-v1-5
์ฒดํฌํฌ์ธํธ๋ฅผ ๋ก๋ํฉ๋๋ค.
Stable Diffusion ๋ชจ๋ธ์ ๊ฒฝ์ฐ, ๋ชจ๋ธ์ ์คํํ๊ธฐ ์ ์ ๋ผ์ด์ ์ค๋ฅผ ๋จผ์ ์ฃผ์ ๊น๊ฒ ์ฝ์ด์ฃผ์ธ์. ๐งจ Diffusers๋ ๋ถ์พํ๊ฑฐ๋ ์ ํดํ ์ฝํ
์ธ ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด safety_checker
๋ฅผ ๊ตฌํํ๊ณ ์์ง๋ง, ๋ชจ๋ธ์ ํฅ์๋ ์ด๋ฏธ์ง ์์ฑ ๊ธฐ๋ฅ์ผ๋ก ์ธํด ์ฌ์ ํ ์ ์ฌ์ ์ผ๋ก ์ ํดํ ์ฝํ
์ธ ๊ฐ ์์ฑ๋ ์ ์์ต๋๋ค.
[~DiffusionPipeline.from_pretrained
] ๋ฐฉ๋ฒ์ผ๋ก ๋ชจ๋ธ ๋ก๋ํ๊ธฐ:
>>> from diffusers import DiffusionPipeline
>>> pipeline = DiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")
The [DiffusionPipeline
]์ ๋ชจ๋ ๋ชจ๋ธ๋ง, ํ ํฐํ, ์ค์ผ์ค๋ง ์ปดํฌ๋ํธ๋ฅผ ๋ค์ด๋ก๋ํ๊ณ ์บ์ํฉ๋๋ค. Stable Diffusion Pipeline์ ๋ฌด์๋ณด๋ค๋ [UNet2DConditionModel
]๊ณผ [PNDMScheduler
]๋ก ๊ตฌ์ฑ๋์ด ์์์ ์ ์ ์์ต๋๋ค:
>>> pipeline
StableDiffusionPipeline {
"_class_name": "StableDiffusionPipeline",
"_diffusers_version": "0.13.1",
...,
"scheduler": [
"diffusers",
"PNDMScheduler"
],
...,
"unet": [
"diffusers",
"UNet2DConditionModel"
],
"vae": [
"diffusers",
"AutoencoderKL"
]
}
์ด ๋ชจ๋ธ์ ์ฝ 14์ต ๊ฐ์ ํ๋ผ๋ฏธํฐ๋ก ๊ตฌ์ฑ๋์ด ์์ผ๋ฏ๋ก GPU์์ ํ์ดํ๋ผ์ธ์ ์คํํ ๊ฒ์ ๊ฐ๋ ฅํ ๊ถ์ฅํฉ๋๋ค. PyTorch์์์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ ๋๋ ์ดํฐ ๊ฐ์ฒด๋ฅผ GPU๋ก ์ด๋ํ ์ ์์ต๋๋ค:
>>> pipeline.to("cuda")
์ด์ ํ์ดํ๋ผ์ธ
์ ํ
์คํธ ํ๋กฌํํธ๋ฅผ ์ ๋ฌํ์ฌ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ ๋ค์ ๋
ธ์ด์ฆ๊ฐ ์ ๊ฑฐ๋ ์ด๋ฏธ์ง์ ์ก์ธ์คํ ์ ์์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ์ด๋ฏธ์ง ์ถ๋ ฅ์ PIL.Image
๊ฐ์ฒด๋ก ๊ฐ์ธ์ง๋๋ค.
>>> image = pipeline("An image of a squirrel in Picasso style").images[0]
>>> image
save
๋ฅผ ํธ์ถํ์ฌ ์ด๋ฏธ์ง๋ฅผ ์ ์ฅํฉ๋๋ค:
>>> image.save("image_of_squirrel_painting.png")
๋ก์ปฌ ํ์ดํ๋ผ์ธ
ํ์ดํ๋ผ์ธ์ ๋ก์ปฌ์์ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ์ ์ผํ ์ฐจ์ด์ ์ ๊ฐ์ค์น๋ฅผ ๋จผ์ ๋ค์ด๋ก๋ํด์ผ ํ๋ค๋ ์ ์ ๋๋ค:
!git lfs install
!git clone https://huggingface.co/runwayml/stable-diffusion-v1-5
๊ทธ๋ฐ ๋ค์ ์ ์ฅ๋ ๊ฐ์ค์น๋ฅผ ํ์ดํ๋ผ์ธ์ ๋ก๋ํฉ๋๋ค:
>>> pipeline = DiffusionPipeline.from_pretrained("./stable-diffusion-v1-5")
์ด์ ์ ์น์ ์์์ ๊ฐ์ด ํ์ดํ๋ผ์ธ์ ์คํํ ์ ์์ต๋๋ค.
์ค์ผ์ค๋ฌ ๊ต์ฒด
์ค์ผ์ค๋ฌ๋ง๋ค ๋
ธ์ด์ฆ ์ ๊ฑฐ ์๋์ ํ์ง์ด ์๋ก ๋ค๋ฆ
๋๋ค. ์์ ์๊ฒ ๊ฐ์ฅ ์ ํฉํ ์ค์ผ์ค๋ฌ๋ฅผ ์ฐพ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ์ง์ ์ฌ์ฉํด ๋ณด๋ ๊ฒ์
๋๋ค! ๐งจ Diffusers์ ์ฃผ์ ๊ธฐ๋ฅ ์ค ํ๋๋ ์ค์ผ์ค๋ฌ ๊ฐ์ ์ฝ๊ฒ ์ ํ์ด ๊ฐ๋ฅํ๋ค๋ ๊ฒ์
๋๋ค. ์๋ฅผ ๋ค์ด, ๊ธฐ๋ณธ ์ค์ผ์ค๋ฌ์ธ [PNDMScheduler
]๋ฅผ [EulerDiscreteScheduler
]๋ก ๋ฐ๊พธ๋ ค๋ฉด, [~diffusers.ConfigMixin.from_config
] ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๋ํ์ธ์:
>>> from diffusers import EulerDiscreteScheduler
>>> pipeline = DiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5")
>>> pipeline.scheduler = EulerDiscreteScheduler.from_config(pipeline.scheduler.config)
์ ์ค์ผ์ค๋ฌ๋ก ์ด๋ฏธ์ง๋ฅผ ์์ฑํด๋ณด๊ณ ์ด๋ค ์ฐจ์ด๊ฐ ์๋์ง ํ์ธํด ๋ณด์ธ์!
๋ค์ ์น์
์์๋ ๋ชจ๋ธ๊ณผ ์ค์ผ์ค๋ฌ๋ผ๋ [DiffusionPipeline
]์ ๊ตฌ์ฑํ๋ ์ปดํฌ๋ํธ๋ฅผ ์์ธํ ์ดํด๋ณด๊ณ ์ด๋ฌํ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ์ฌ ๊ณ ์์ด ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด๊ฒ ์ต๋๋ค.
๋ชจ๋ธ
๋๋ถ๋ถ์ ๋ชจ๋ธ์ ๋
ธ์ด์ฆ๊ฐ ์๋ ์ํ์ ๊ฐ์ ธ์ ๊ฐ ์๊ฐ ๊ฐ๊ฒฉ๋ง๋ค ๋
ธ์ด์ฆ๊ฐ ์ ์ ์ด๋ฏธ์ง์ ์
๋ ฅ ์ด๋ฏธ์ง ์ฌ์ด์ ์ฐจ์ด์ธ ๋
ธ์ด์ฆ ์์ฐจ(๋ค๋ฅธ ๋ชจ๋ธ์ ์ด์ ์ํ์ ์ง์ ์์ธกํ๊ฑฐ๋ ์๋ ๋๋ v-prediction
์ ์์ธกํ๋ ํ์ต์ ํฉ๋๋ค)์ ์์ธกํฉ๋๋ค. ๋ชจ๋ธ์ ๋ฏน์ค ์ค ๋งค์นํ์ฌ ๋ค๋ฅธ diffusion ์์คํ
์ ๋ง๋ค ์ ์์ต๋๋ค.
๋ชจ๋ธ์ [~ModelMixin.from_pretrained
] ๋ฉ์๋๋ก ์์๋๋ฉฐ, ์ด ๋ฉ์๋๋ ๋ชจ๋ธ ๊ฐ์ค์น๋ฅผ ๋ก์ปฌ์ ์บ์ํ์ฌ ๋ค์์ ๋ชจ๋ธ์ ๋ก๋ํ ๋ ๋ ๋น ๋ฅด๊ฒ ๋ก๋ํ ์ ์์ต๋๋ค. ํ์ด๋ณด๊ธฐ์์๋ ๊ณ ์์ด ์ด๋ฏธ์ง์ ๋ํด ํ์ต๋ ์ฒดํฌํฌ์ธํธ๊ฐ ์๋ ๊ธฐ๋ณธ์ ์ธ unconditional ์ด๋ฏธ์ง ์์ฑ ๋ชจ๋ธ์ธ [UNet2DModel
]์ ๋ก๋ํฉ๋๋ค:
>>> from diffusers import UNet2DModel
>>> repo_id = "google/ddpm-cat-256"
>>> model = UNet2DModel.from_pretrained(repo_id)
๋ชจ๋ธ ๋งค๊ฐ๋ณ์์ ์ก์ธ์คํ๋ ค๋ฉด model.config
๋ฅผ ํธ์ถํฉ๋๋ค:
>>> model.config
๋ชจ๋ธ ๊ตฌ์ฑ์ ๐ง ๊ณ ์ ๋ ๐ง ๋์ ๋๋ฆฌ๋ก, ๋ชจ๋ธ์ด ์์ฑ๋ ํ์๋ ํด๋น ๋งค๊ฐ ๋ณ์๋ค์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. ์ด๋ ์๋์ ์ธ ๊ฒ์ผ๋ก, ์ฒ์์ ๋ชจ๋ธ ์ํคํ ์ฒ๋ฅผ ์ ์ํ๋ ๋ฐ ์ฌ์ฉ๋ ๋งค๊ฐ๋ณ์๋ ๋์ผํ๊ฒ ์ ์งํ๋ฉด์ ๋ค๋ฅธ ๋งค๊ฐ๋ณ์๋ ์ถ๋ก ์ค์ ์กฐ์ ํ ์ ์๋๋ก ํ๊ธฐ ์ํ ๊ฒ์ ๋๋ค.
๊ฐ์ฅ ์ค์ํ ๋งค๊ฐ๋ณ์๋ค์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
sample_size
: ์ ๋ ฅ ์ํ์ ๋์ด ๋ฐ ๋๋น ์น์์ ๋๋ค.in_channels
: ์ ๋ ฅ ์ํ์ ์ ๋ ฅ ์ฑ๋ ์์ ๋๋ค.down_block_types
๋ฐup_block_types
: UNet ์ํคํ ์ฒ๋ฅผ ์์ฑํ๋ ๋ฐ ์ฌ์ฉ๋๋ ๋ค์ด ๋ฐ ์ ์ํ๋ง ๋ธ๋ก์ ์ ํ.block_out_channels
: ๋ค์ด์ํ๋ง ๋ธ๋ก์ ์ถ๋ ฅ ์ฑ๋ ์. ์ ์ํ๋ง ๋ธ๋ก์ ์ ๋ ฅ ์ฑ๋ ์์ ์ญ์์ผ๋ก ์ฌ์ฉ๋๊ธฐ๋ ํฉ๋๋ค.layers_per_block
: ๊ฐ UNet ๋ธ๋ก์ ์กด์ฌํ๋ ResNet ๋ธ๋ก์ ์์ ๋๋ค.
์ถ๋ก ์ ๋ชจ๋ธ์ ์ฌ์ฉํ๋ ค๋ฉด ๋๋ค ๊ฐ์ฐ์์ ๋ ธ์ด์ฆ๋ก ์ด๋ฏธ์ง ๋ชจ์์ ๋ง๋ญ๋๋ค. ๋ชจ๋ธ์ด ์ฌ๋ฌ ๊ฐ์ ๋ฌด์์ ๋ ธ์ด์ฆ๋ฅผ ์์ ํ ์ ์์ผ๋ฏ๋ก 'batch' ์ถ, ์ ๋ ฅ ์ฑ๋ ์์ ํด๋นํ๋ 'channel' ์ถ, ์ด๋ฏธ์ง์ ๋์ด์ ๋๋น๋ฅผ ๋ํ๋ด๋ 'sample_size' ์ถ์ด ์์ด์ผ ํฉ๋๋ค:
>>> import torch
>>> torch.manual_seed(0)
>>> noisy_sample = torch.randn(1, model.config.in_channels, model.config.sample_size, model.config.sample_size)
>>> noisy_sample.shape
torch.Size([1, 3, 256, 256])
์ถ๋ก ์ ์ํด ๋ชจ๋ธ์ ๋
ธ์ด์ฆ๊ฐ ์๋ ์ด๋ฏธ์ง์ timestep
์ ์ ๋ฌํฉ๋๋ค. 'timestep'์ ์
๋ ฅ ์ด๋ฏธ์ง์ ๋
ธ์ด์ฆ ์ ๋๋ฅผ ๋ํ๋ด๋ฉฐ, ์์ ๋ถ๋ถ์ ๋ ๋ง์ ๋
ธ์ด์ฆ๊ฐ ์๊ณ ๋ ๋ถ๋ถ์ ๋ ์ ์ ๋
ธ์ด์ฆ๊ฐ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ๋ชจ๋ธ์ด diffusion ๊ณผ์ ์์ ์์ ๋๋ ๋์ ๋ ๊ฐ๊น์ด ์์น๋ฅผ ๊ฒฐ์ ํ ์ ์์ต๋๋ค. sample
๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ชจ๋ธ ์ถ๋ ฅ์ ์ป์ต๋๋ค:
>>> with torch.no_grad():
... noisy_residual = model(sample=noisy_sample, timestep=2).sample
ํ์ง๋ง ์ค์ ์๋ฅผ ์์ฑํ๋ ค๋ฉด ๋ ธ์ด์ฆ ์ ๊ฑฐ ํ๋ก์ธ์ค๋ฅผ ์๋ดํ ์ค์ผ์ค๋ฌ๊ฐ ํ์ํฉ๋๋ค. ๋ค์ ์น์ ์์๋ ๋ชจ๋ธ์ ์ค์ผ์ค๋ฌ์ ๊ฒฐํฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ด ๋๋ค.
์ค์ผ์ค๋ฌ
์ค์ผ์ค๋ฌ๋ ๋ชจ๋ธ ์ถ๋ ฅ์ด ์ฃผ์ด์ก์ ๋ ๋ ธ์ด์ฆ๊ฐ ๋ง์ ์ํ์์ ๋ ธ์ด์ฆ๊ฐ ์ ์ ์ํ๋ก ์ ํํ๋ ๊ฒ์ ๊ด๋ฆฌํฉ๋๋ค - ์ด ๊ฒฝ์ฐ 'noisy_residual'.
๐งจ Diffusers๋ Diffusion ์์คํ
์ ๊ตฌ์ถํ๊ธฐ ์ํ ํด๋ฐ์ค์
๋๋ค. [DiffusionPipeline
]์ ์ฌ์ฉํ๋ฉด ๋ฏธ๋ฆฌ ๋ง๋ค์ด์ง Diffusion ์์คํ
์ ํธ๋ฆฌํ๊ฒ ์์ํ ์ ์์ง๋ง, ๋ชจ๋ธ๊ณผ ์ค์ผ์ค๋ฌ ๊ตฌ์ฑ ์์๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ์ ํํ์ฌ ์ฌ์ฉ์ ์ง์ Diffusion ์์คํ
์ ๊ตฌ์ถํ ์๋ ์์ต๋๋ค.
ํ์ด๋ณด๊ธฐ์ ๊ฒฝ์ฐ, [~diffusers.ConfigMixin.from_config
] ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ [DDPMScheduler
]๋ฅผ ์ธ์คํด์คํํฉ๋๋ค:
>>> from diffusers import DDPMScheduler
>>> scheduler = DDPMScheduler.from_config(repo_id)
>>> scheduler
DDPMScheduler {
"_class_name": "DDPMScheduler",
"_diffusers_version": "0.13.1",
"beta_end": 0.02,
"beta_schedule": "linear",
"beta_start": 0.0001,
"clip_sample": true,
"clip_sample_range": 1.0,
"num_train_timesteps": 1000,
"prediction_type": "epsilon",
"trained_betas": null,
"variance_type": "fixed_small"
}
๐ก ์ค์ผ์ค๋ฌ๊ฐ ๊ตฌ์ฑ์์ ์ด๋ป๊ฒ ์ธ์คํด์คํ๋๋์ง ์ฃผ๋ชฉํ์ธ์. ๋ชจ๋ธ๊ณผ ๋ฌ๋ฆฌ ์ค์ผ์ค๋ฌ์๋ ํ์ต ๊ฐ๋ฅํ ๊ฐ์ค์น๊ฐ ์์ผ๋ฉฐ ๋งค๊ฐ๋ณ์๋ ์์ต๋๋ค!
๊ฐ์ฅ ์ค์ํ ๋งค๊ฐ๋ณ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
num_train_timesteps
: ๋ ธ์ด์ฆ ์ ๊ฑฐ ํ๋ก์ธ์ค์ ๊ธธ์ด, ์ฆ ๋๋ค ๊ฐ์ฐ์ค ๋ ธ์ด์ฆ๋ฅผ ๋ฐ์ดํฐ ์ํ๋ก ์ฒ๋ฆฌํ๋ ๋ฐ ํ์ํ ํ์์คํ ์์ ๋๋ค.beta_schedule
: ์ถ๋ก ๋ฐ ํ์ต์ ์ฌ์ฉํ ๋ ธ์ด์ฆ ์ค์ผ์ค ์ ํ์ ๋๋ค.beta_start
๋ฐbeta_end
: ๋ ธ์ด์ฆ ์ค์ผ์ค์ ์์ ๋ฐ ์ข ๋ฃ ๋ ธ์ด์ฆ ๊ฐ์ ๋๋ค.
๋
ธ์ด์ฆ๊ฐ ์ฝ๊ฐ ์ ์ ์ด๋ฏธ์ง๋ฅผ ์์ธกํ๋ ค๋ฉด ์ค์ผ์ค๋ฌ์ [~diffusers.DDPMScheduler.step
] ๋ฉ์๋์ ๋ชจ๋ธ ์ถ๋ ฅ, timestep
, ํ์ฌ sample
์ ์ ๋ฌํ์ธ์.
>>> less_noisy_sample = scheduler.step(model_output=noisy_residual, timestep=2, sample=noisy_sample).prev_sample
>>> less_noisy_sample.shape
less_noisy_sample
์ ๋ค์ timestep
์ผ๋ก ๋๊ธฐ๋ฉด ๋
ธ์ด์ฆ๊ฐ ๋ ์ค์ด๋ญ๋๋ค! ์ด์ ์ด ๋ชจ๋ ๊ฒ์ ํ๋ฐ ๋ชจ์ ์ ์ฒด ๋
ธ์ด์ฆ ์ ๊ฑฐ ๊ณผ์ ์ ์๊ฐํํด ๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ ๋
ธ์ด์ฆ ์ ๊ฑฐ๋ ์ด๋ฏธ์ง๋ฅผ ํ์ฒ๋ฆฌํ์ฌ PIL.Image
๋ก ํ์ํ๋ ํจ์๋ฅผ ๋ง๋ญ๋๋ค:
>>> import PIL.Image
>>> import numpy as np
>>> def display_sample(sample, i):
... image_processed = sample.cpu().permute(0, 2, 3, 1)
... image_processed = (image_processed + 1.0) * 127.5
... image_processed = image_processed.numpy().astype(np.uint8)
... image_pil = PIL.Image.fromarray(image_processed[0])
... display(f"Image at step {i}")
... display(image_pil)
๋ ธ์ด์ฆ ์ ๊ฑฐ ํ๋ก์ธ์ค์ ์๋๋ฅผ ๋์ด๋ ค๋ฉด ์ ๋ ฅ๊ณผ ๋ชจ๋ธ์ GPU๋ก ์ฎ๊ธฐ์ธ์:
>>> model.to("cuda")
>>> noisy_sample = noisy_sample.to("cuda")
์ด์ ๋ ธ์ด์ฆ๊ฐ ์ ์ ์ํ์ ์์ฐจ๋ฅผ ์์ธกํ๊ณ ์ค์ผ์ค๋ฌ๋ก ๋ ธ์ด์ฆ๊ฐ ์ ์ ์ํ์ ๊ณ์ฐํ๋ ๋ ธ์ด์ฆ ์ ๊ฑฐ ๋ฃจํ๋ฅผ ์์ฑํฉ๋๋ค:
>>> import tqdm
>>> sample = noisy_sample
>>> for i, t in enumerate(tqdm.tqdm(scheduler.timesteps)):
... # 1. predict noise residual
... with torch.no_grad():
... residual = model(sample, t).sample
... # 2. compute less noisy image and set x_t -> x_t-1
... sample = scheduler.step(residual, t, sample).prev_sample
... # 3. optionally look at image
... if (i + 1) % 50 == 0:
... display_sample(sample, i + 1)
๊ฐ๋งํ ์์์ ๊ณ ์์ด๊ฐ ์์์ผ๋ก๋ง ์์ฑ๋๋ ๊ฒ์ ์ง์ผ๋ณด์ธ์!๐ป
๋ค์ ๋จ๊ณ
์ด๋ฒ ํ์ด๋ณด๊ธฐ์์ ๐งจ Diffusers๋ก ๋ฉ์ง ์ด๋ฏธ์ง๋ฅผ ๋ง๋ค์ด ๋ณด์ จ๊ธฐ๋ฅผ ๋ฐ๋๋๋ค! ๋ค์ ๋จ๊ณ๋ก ๋์ด๊ฐ์ธ์:
- training ํํ ๋ฆฌ์ผ์์ ๋ชจ๋ธ์ ํ์ตํ๊ฑฐ๋ ํ์ธํ๋ํ์ฌ ๋๋ง์ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
- ๋ค์ํ ์ฌ์ฉ ์ฌ๋ก๋ ๊ณต์ ๋ฐ ์ปค๋ฎค๋ํฐ ํ์ต ๋๋ ํ์ธํ๋ ์คํฌ๋ฆฝํธ ์์๋ฅผ ์ฐธ์กฐํ์ธ์.
- ์ค์ผ์ค๋ฌ ๋ก๋, ์ก์ธ์ค, ๋ณ๊ฒฝ ๋ฐ ๋น๊ต์ ๋ํ ์์ธํ ๋ด์ฉ์ ๋ค๋ฅธ ์ค์ผ์ค๋ฌ ์ฌ์ฉ ๊ฐ์ด๋์์ ํ์ธํ์ธ์.
- Stable Diffusion ๊ฐ์ด๋์์ ํ๋กฌํํธ ์์ง๋์ด๋ง, ์๋ ๋ฐ ๋ฉ๋ชจ๋ฆฌ ์ต์ ํ, ๊ณ ํ์ง ์ด๋ฏธ์ง ์์ฑ์ ์ํ ํ๊ณผ ์๋ น์ ์ดํด๋ณด์ธ์.
- GPU์์ ํ์ดํ ์น ์ต์ ํ ๊ฐ์ด๋์ ์ ํ ์ค๋ฆฌ์ฝ(M1/M2)์์์ Stable Diffusion ๋ฐ ONNX ๋ฐํ์ ์คํ์ ๋ํ ์ถ๋ก ๊ฐ์ด๋๋ฅผ ํตํด ๐งจ Diffuser ์๋๋ฅผ ๋์ด๋ ๋ฐฉ๋ฒ์ ๋ ์์ธํ ์์๋ณด์ธ์.