Spaces:
Runtime error
ํจ๊ณผ์ ์ด๊ณ ํจ์จ์ ์ธ Diffusion
[[open-in-colab]]
ํน์ ์คํ์ผ๋ก ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๊ฑฐ๋ ์ํ๋ ๋ด์ฉ์ ํฌํจํ๋๋ก[DiffusionPipeline]์ ์ค์ ํ๋ ๊ฒ์ ๊น๋ค๋ก์ธ ์ ์์ต๋๋ค. ์ข
์ข
๋ง์กฑ์ค๋ฌ์ด ์ด๋ฏธ์ง๋ฅผ ์ป๊ธฐ๊น์ง [DiffusionPipeline]์ ์ฌ๋ฌ ๋ฒ ์คํํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ฌด์์ ์ ๋ฅผ ์ฐฝ์กฐํ๋ ๊ฒ์ ํนํ ์ถ๋ก ์ ๋ฐ๋ณตํด์ ์คํํ๋ ๊ฒฝ์ฐ ๊ณ์ฐ ์ง์ฝ์ ์ธ ํ๋ก์ธ์ค์
๋๋ค.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ํ์ดํ๋ผ์ธ์์ ๊ณ์ฐ(์๋) ๋ฐ ๋ฉ๋ชจ๋ฆฌ(GPU RAM) ํจ์จ์ฑ์ ๊ทน๋ํํ์ฌ ์ถ๋ก ์ฃผ๊ธฐ ์ฌ์ด์ ์๊ฐ์ ๋จ์ถํ์ฌ ๋ ๋น ๋ฅด๊ฒ ๋ฐ๋ณตํ ์ ์๋๋ก ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์ด ํํ ๋ฆฌ์ผ์์๋ [DiffusionPipeline]์ ์ฌ์ฉํ์ฌ ๋ ๋น ๋ฅด๊ณ ํจ๊ณผ์ ์ผ๋ก ์์ฑํ๋ ๋ฐฉ๋ฒ์ ์๋ดํฉ๋๋ค.
stable-diffusion-v1-5/stable-diffusion-v1-5 ๋ชจ๋ธ์ ๋ถ๋ฌ์์ ์์ํฉ๋๋ค:
from diffusers import DiffusionPipeline
model_id = "stable-diffusion-v1-5/stable-diffusion-v1-5"
pipeline = DiffusionPipeline.from_pretrained(model_id)
์์ ํ๋กฌํํธ๋ "portrait of an old warrior chief" ์ด์ง๋ง, ์์ ๋กญ๊ฒ ์์ ๋ง์ ํ๋กฌํํธ๋ฅผ ์ฌ์ฉํด๋ ๋ฉ๋๋ค:
prompt = "portrait photo of a old warrior chief"
์๋
๐ก GPU์ ์ก์ธ์คํ ์ ์๋ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ์ GPU ์ ๊ณต์ ์ฒด์์ ๋ฌด๋ฃ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค!. Colab
์ถ๋ก ์๋๋ฅผ ๋์ด๋ ๊ฐ์ฅ ๊ฐ๋จํ ๋ฐฉ๋ฒ ์ค ํ๋๋ Pytorch ๋ชจ๋์ ์ฌ์ฉํ ๋์ ๊ฐ์ ๋ฐฉ์์ผ๋ก GPU์ ํ์ดํ๋ผ์ธ์ ๋ฐฐ์นํ๋ ๊ฒ์ ๋๋ค:
pipeline = pipeline.to("cuda")
๋์ผํ ์ด๋ฏธ์ง๋ฅผ ์ฌ์ฉํ๊ณ ๊ฐ์ ํ ์ ์๋์ง ํ์ธํ๋ ค๋ฉด Generator๋ฅผ ์ฌ์ฉํ๊ณ ์ฌํ์ฑ์ ๋ํ ์๋๋ฅผ ์ค์ ํ์ธ์:
import torch
generator = torch.Generator("cuda").manual_seed(0)
์ด์ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ ์ ์์ต๋๋ค:
image = pipeline(prompt, generator=generator).images[0]
image
์ด ํ๋ก์ธ์ค๋ T4 GPU์์ ์ฝ 30์ด๊ฐ ์์๋์์ต๋๋ค(ํ ๋น๋ GPU๊ฐ T4๋ณด๋ค ๋์ ๊ฒฝ์ฐ ๋ ๋น ๋ฅผ ์ ์์). ๊ธฐ๋ณธ์ ์ผ๋ก [DiffusionPipeline]์ 50๊ฐ์ ์ถ๋ก ๋จ๊ณ์ ๋ํด ์ ์ฒด float32 ์ ๋ฐ๋๋ก ์ถ๋ก ์ ์คํํฉ๋๋ค. float16๊ณผ ๊ฐ์ ๋ ๋ฎ์ ์ ๋ฐ๋๋ก ์ ํํ๊ฑฐ๋ ์ถ๋ก ๋จ๊ณ๋ฅผ ๋ ์ ๊ฒ ์คํํ์ฌ ์๋๋ฅผ ๋์ผ ์ ์์ต๋๋ค.
float16์ผ๋ก ๋ชจ๋ธ์ ๋ก๋ํ๊ณ ์ด๋ฏธ์ง๋ฅผ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค:
import torch
pipeline = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
pipeline = pipeline.to("cuda")
generator = torch.Generator("cuda").manual_seed(0)
image = pipeline(prompt, generator=generator).images[0]
image
์ด๋ฒ์๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ ๋ฐ ์ฝ 11์ด๋ฐ์ ๊ฑธ๋ฆฌ์ง ์์ ์ด์ ๋ณด๋ค 3๋ฐฐ ๊ฐ๊น์ด ๋นจ๋ผ์ก์ต๋๋ค!
๐ก ํ์ดํ๋ผ์ธ์ ํญ์ float16์์ ์คํํ ๊ฒ์ ๊ฐ๋ ฅํ ๊ถ์ฅํ๋ฉฐ, ์ง๊ธ๊น์ง ์ถ๋ ฅ ํ์ง์ด ์ ํ๋๋ ๊ฒฝ์ฐ๋ ๊ฑฐ์ ์์์ต๋๋ค.
๋ ๋ค๋ฅธ ์ต์
์ ์ถ๋ก ๋จ๊ณ์ ์๋ฅผ ์ค์ด๋ ๊ฒ์
๋๋ค. ๋ณด๋ค ํจ์จ์ ์ธ ์ค์ผ์ค๋ฌ๋ฅผ ์ ํํ๋ฉด ์ถ๋ ฅ ํ์ง ์ ํ ์์ด ๋จ๊ณ ์๋ฅผ ์ค์ด๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค. ํ์ฌ ๋ชจ๋ธ๊ณผ ํธํ๋๋ ์ค์ผ์ค๋ฌ๋ compatibles ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ [DiffusionPipeline]์์ ์ฐพ์ ์ ์์ต๋๋ค:
pipeline.scheduler.compatibles
[
diffusers.schedulers.scheduling_lms_discrete.LMSDiscreteScheduler,
diffusers.schedulers.scheduling_unipc_multistep.UniPCMultistepScheduler,
diffusers.schedulers.scheduling_k_dpm_2_discrete.KDPM2DiscreteScheduler,
diffusers.schedulers.scheduling_deis_multistep.DEISMultistepScheduler,
diffusers.schedulers.scheduling_euler_discrete.EulerDiscreteScheduler,
diffusers.schedulers.scheduling_dpmsolver_multistep.DPMSolverMultistepScheduler,
diffusers.schedulers.scheduling_ddpm.DDPMScheduler,
diffusers.schedulers.scheduling_dpmsolver_singlestep.DPMSolverSinglestepScheduler,
diffusers.schedulers.scheduling_k_dpm_2_ancestral_discrete.KDPM2AncestralDiscreteScheduler,
diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler,
diffusers.schedulers.scheduling_pndm.PNDMScheduler,
diffusers.schedulers.scheduling_euler_ancestral_discrete.EulerAncestralDiscreteScheduler,
diffusers.schedulers.scheduling_ddim.DDIMScheduler,
]
Stable Diffusion ๋ชจ๋ธ์ ์ผ๋ฐ์ ์ผ๋ก ์ฝ 50๊ฐ์ ์ถ๋ก ๋จ๊ณ๊ฐ ํ์ํ [PNDMScheduler]๋ฅผ ๊ธฐ๋ณธ์ผ๋ก ์ฌ์ฉํ์ง๋ง, [DPMSolverMultistepScheduler]์ ๊ฐ์ด ์ฑ๋ฅ์ด ๋ ๋ฐ์ด๋ ์ค์ผ์ค๋ฌ๋ ์ฝ 20๊ฐ ๋๋ 25๊ฐ์ ์ถ๋ก ๋จ๊ณ๋ง ํ์๋ก ํฉ๋๋ค. ์ ์ค์ผ์ค๋ฌ๋ฅผ ๋ก๋ํ๋ ค๋ฉด [ConfigMixin.from_config] ๋ฉ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค:
from diffusers import DPMSolverMultistepScheduler
pipeline.scheduler = DPMSolverMultistepScheduler.from_config(pipeline.scheduler.config)
num_inference_steps๋ฅผ 20์ผ๋ก ์ค์ ํฉ๋๋ค:
generator = torch.Generator("cuda").manual_seed(0)
image = pipeline(prompt, generator=generator, num_inference_steps=20).images[0]
image
์ถ๋ก ์๊ฐ์ 4์ด๋ก ๋จ์ถํ ์ ์์์ต๋๋ค! โก๏ธ
๋ฉ๋ชจ๋ฆฌ
ํ์ดํ๋ผ์ธ ์ฑ๋ฅ ํฅ์์ ๋ ๋ค๋ฅธ ํต์ฌ์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ์ค์ด๋ ๊ฒ์ธ๋ฐ, ์ด๋น ์์ฑ๋๋ ์ด๋ฏธ์ง ์๋ฅผ ์ต๋ํํ๋ ค๊ณ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง๊ธฐ ๋๋ฌธ์ ๊ฐ์ ์ ์ผ๋ก ๋ ๋น ๋ฅธ ์๋๋ฅผ ์๋ฏธํฉ๋๋ค. ํ ๋ฒ์ ์์ฑํ ์ ์๋ ์ด๋ฏธ์ง ์๋ฅผ ํ์ธํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ OutOfMemoryError(OOM)์ด ๋ฐ์ํ ๋๊น์ง ๋ค์ํ ๋ฐฐ์น ํฌ๊ธฐ๋ฅผ ์๋ํด ๋ณด๋ ๊ฒ์
๋๋ค.
ํ๋กฌํํธ ๋ชฉ๋ก๊ณผ Generators์์ ์ด๋ฏธ์ง ๋ฐฐ์น๋ฅผ ์์ฑํ๋ ํจ์๋ฅผ ๋ง๋ญ๋๋ค. ์ข์ ๊ฒฐ๊ณผ๋ฅผ ์์ฑํ๋ ๊ฒฝ์ฐ ์ฌ์ฌ์ฉํ ์ ์๋๋ก ๊ฐ Generator์ ์๋๋ฅผ ํ ๋นํด์ผ ํฉ๋๋ค.
def get_inputs(batch_size=1):
generator = [torch.Generator("cuda").manual_seed(i) for i in range(batch_size)]
prompts = batch_size * [prompt]
num_inference_steps = 20
return {"prompt": prompts, "generator": generator, "num_inference_steps": num_inference_steps}
๋ํ ๊ฐ ์ด๋ฏธ์ง ๋ฐฐ์น๋ฅผ ๋ณด์ฌ์ฃผ๋ ๊ธฐ๋ฅ์ด ํ์ํฉ๋๋ค:
from PIL import Image
def image_grid(imgs, rows=2, cols=2):
w, h = imgs[0].size
grid = Image.new("RGB", size=(cols * w, rows * h))
for i, img in enumerate(imgs):
grid.paste(img, box=(i % cols * w, i // cols * h))
return grid
batch_size=4๋ถํฐ ์์ํด ์ผ๋ง๋ ๋ง์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์๋นํ๋์ง ํ์ธํฉ๋๋ค:
images = pipeline(**get_inputs(batch_size=4)).images
image_grid(images)
RAM์ด ๋ ๋ง์ GPU๊ฐ ์๋๋ผ๋ฉด ์์ ์ฝ๋์์ OOM ์ค๋ฅ๊ฐ ๋ฐํ๋์์ ๊ฒ์
๋๋ค! ๋๋ถ๋ถ์ ๋ฉ๋ชจ๋ฆฌ๋ cross-attention ๋ ์ด์ด๊ฐ ์ฐจ์งํฉ๋๋ค. ์ด ์์
์ ๋ฐฐ์น๋ก ์คํํ๋ ๋์ ์์ฐจ์ ์ผ๋ก ์คํํ๋ฉด ์๋นํ ์์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ์ฝํ ์ ์์ต๋๋ค. ํ์ดํ๋ผ์ธ์ ๊ตฌ์ฑํ์ฌ [~DiffusionPipeline.enable_attention_slicing] ํจ์๋ฅผ ์ฌ์ฉํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค:
pipeline.enable_attention_slicing()
์ด์ batch_size๋ฅผ 8๋ก ๋๋ ค๋ณด์ธ์!
images = pipeline(**get_inputs(batch_size=8)).images
image_grid(images, rows=2, cols=4)
์ด์ ์๋ 4๊ฐ์ ์ด๋ฏธ์ง๋ฅผ ๋ฐฐ์น๋ก ์์ฑํ ์๋ ์์์ง๋ง, ์ด์ ๋ ์ด๋ฏธ์ง๋น ์ฝ 3.5์ด ๋ง์ 8๊ฐ์ ์ด๋ฏธ์ง๋ฅผ ๋ฐฐ์น๋ก ์์ฑํ ์ ์์ต๋๋ค! ์ด๋ ์๋ง๋ ํ์ง ์ ํ ์์ด T4 GPU์์ ๊ฐ์ฅ ๋น ๋ฅธ ์๋์ผ ๊ฒ์ ๋๋ค.
ํ์ง
์ง๋ ๋ ์น์
์์๋ fp16์ ์ฌ์ฉํ์ฌ ํ์ดํ๋ผ์ธ์ ์๋๋ฅผ ์ต์ ํํ๊ณ , ๋ ์ฑ๋ฅ์ด ์ข์ ์ค์ผ์ค๋ฌ๋ฅผ ์ฌ์ฉํ์ฌ ์ถ๋ก ๋จ๊ณ์ ์๋ฅผ ์ค์ด๊ณ , attention slicing์ ํ์ฑํํ์ฌ ๋ฉ๋ชจ๋ฆฌ ์๋น๋ฅผ ์ค์ด๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์ ์ต๋๋ค. ์ด์ ์์ฑ๋ ์ด๋ฏธ์ง์ ํ์ง์ ๊ฐ์ ํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์ง์ค์ ์ผ๋ก ์์๋ณด๊ฒ ์ต๋๋ค.
๋ ๋์ ์ฒดํฌํฌ์ธํธ
๊ฐ์ฅ ํ์คํ ๋จ๊ณ๋ ๋ ๋์ ์ฒดํฌํฌ์ธํธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. Stable Diffusion ๋ชจ๋ธ์ ์ข์ ์ถ๋ฐ์ ์ด๋ฉฐ, ๊ณต์ ์ถ์ ์ดํ ๋ช ๊ฐ์ง ๊ฐ์ ๋ ๋ฒ์ ๋ ์ถ์๋์์ต๋๋ค. ํ์ง๋ง ์ต์ ๋ฒ์ ์ ์ฌ์ฉํ๋ค๊ณ ํด์ ์๋์ผ๋ก ๋ ๋์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์๋ ๊ฒ์ ์๋๋๋ค. ์ฌ์ ํ ๋ค์ํ ์ฒดํฌํฌ์ธํธ๋ฅผ ์ง์ ์คํํด๋ณด๊ณ , negative prompts ์ฌ์ฉ ๋ฑ ์ฝ๊ฐ์ ์กฐ์ฌ๋ฅผ ํตํด ์ต์์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ด์ผ ํฉ๋๋ค.
์ด ๋ถ์ผ๊ฐ ์ฑ์ฅํจ์ ๋ฐ๋ผ ํน์ ์คํ์ผ์ ์ฐ์ถํ ์ ์๋๋ก ์ธ๋ฐํ๊ฒ ์กฐ์ ๋ ๊ณ ํ์ง ์ฒดํฌํฌ์ธํธ๊ฐ ์ ์ ๋ ๋ง์์ง๊ณ ์์ต๋๋ค. Hub์ Diffusers Gallery๋ฅผ ๋๋ฌ๋ณด๊ณ ๊ด์ฌ ์๋ ๊ฒ์ ์ฐพ์๋ณด์ธ์!
๋ ๋์ ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ ์์
ํ์ฌ ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ ์์๋ฅผ ์ต์ ๋ฒ์ ์ผ๋ก ๊ต์ฒดํด ๋ณผ ์๋ ์์ต๋๋ค. Stability AI์ ์ต์ autodecoder๋ฅผ ํ์ดํ๋ผ์ธ์ ๋ก๋ํ๊ณ ๋ช ๊ฐ์ง ์ด๋ฏธ์ง๋ฅผ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค:
from diffusers import AutoencoderKL
vae = AutoencoderKL.from_pretrained("stabilityai/sd-vae-ft-mse", torch_dtype=torch.float16).to("cuda")
pipeline.vae = vae
images = pipeline(**get_inputs(batch_size=8)).images
image_grid(images, rows=2, cols=4)
๋ ๋์ ํ๋กฌํํธ ์์ง๋์ด๋ง
์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ ๋ฐ ์ฌ์ฉํ๋ ํ ์คํธ ํ๋กฌํํธ๋ prompt engineering์ด๋ผ๊ณ ํ ์ ๋๋ก ๋งค์ฐ ์ค์ํฉ๋๋ค. ํ๋กฌํํธ ์์ง๋์ด๋ง ์ ๊ณ ๋ คํด์ผ ํ ๋ช ๊ฐ์ง ์ฌํญ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ์์ฑํ๋ ค๋ ์ด๋ฏธ์ง ๋๋ ์ ์ฌํ ์ด๋ฏธ์ง๊ฐ ์ธํฐ๋ท์ ์ด๋ป๊ฒ ์ ์ฅ๋์ด ์๋๊ฐ?
- ๋ด๊ฐ ์ํ๋ ์คํ์ผ๋ก ๋ชจ๋ธ์ ์ ๋ํ๊ธฐ ์ํด ์ด๋ค ์ถ๊ฐ ์ธ๋ถ ์ ๋ณด๋ฅผ ์ ๊ณตํ ์ ์๋๊ฐ?
์ด๋ฅผ ์ผ๋์ ๋๊ณ ์์๊ณผ ๋ ๋์ ํ์ง์ ๋ํ ์ผ์ ํฌํจํ๋๋ก ํ๋กฌํํธ๋ฅผ ๊ฐ์ ํด ๋ด ์๋ค:
prompt += ", tribal panther make up, blue on red, side profile, looking away, serious eyes"
prompt += " 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta"
์๋ก์ด ํ๋กฌํํธ๋ก ์ด๋ฏธ์ง ๋ฐฐ์น๋ฅผ ์์ฑํฉ๋๋ค:
images = pipeline(**get_inputs(batch_size=8)).images
image_grid(images, rows=2, cols=4)
๊ฝค ์ธ์์ ์
๋๋ค! 1์ ์๋๋ฅผ ๊ฐ์ง Generator์ ํด๋นํ๋ ๋ ๋ฒ์งธ ์ด๋ฏธ์ง์ ํผ์ฌ์ฒด์ ๋์ด์ ๋ํ ํ
์คํธ๋ฅผ ์ถ๊ฐํ์ฌ ์กฐ๊ธ ๋ ์กฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค:
prompts = [
"portrait photo of the oldest warrior chief, tribal panther make up, blue on red, side profile, looking away, serious eyes 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta",
"portrait photo of a old warrior chief, tribal panther make up, blue on red, side profile, looking away, serious eyes 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta",
"portrait photo of a warrior chief, tribal panther make up, blue on red, side profile, looking away, serious eyes 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta",
"portrait photo of a young warrior chief, tribal panther make up, blue on red, side profile, looking away, serious eyes 50mm portrait photography, hard rim lighting photography--beta --ar 2:3 --beta --upbeta",
]
generator = [torch.Generator("cuda").manual_seed(1) for _ in range(len(prompts))]
images = pipeline(prompt=prompts, generator=generator, num_inference_steps=25).images
image_grid(images)
๋ค์ ๋จ๊ณ
์ด ํํ ๋ฆฌ์ผ์์๋ ๊ณ์ฐ ๋ฐ ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ๋์ด๊ณ ์์ฑ๋ ์ถ๋ ฅ์ ํ์ง์ ๊ฐ์ ํ๊ธฐ ์ํด [DiffusionPipeline]์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์ ์ต๋๋ค. ํ์ดํ๋ผ์ธ์ ๋ ๋น ๋ฅด๊ฒ ๋ง๋๋ ๋ฐ ๊ด์ฌ์ด ์๋ค๋ฉด ๋ค์ ๋ฆฌ์์ค๋ฅผ ์ดํด๋ณด์ธ์:
- PyTorch 2.0 ๋ฐ
torch.compile์ด ์ด๋ป๊ฒ ์ถ๋ก ์๋๋ฅผ 5~300% ํฅ์์ํฌ ์ ์๋์ง ์์๋ณด์ธ์. A100 GPU์์๋ ์ถ๋ก ์๋๊ฐ ์ต๋ 50%๊น์ง ๋นจ๋ผ์ง ์ ์์ต๋๋ค! - PyTorch 2๋ฅผ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ, xFormers๋ฅผ ์ค์นํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ธ ์ดํ ์ ๋ฉ์ปค๋์ฆ์ PyTorch 1.13.1๊ณผ ํจ๊ป ์ฌ์ฉํ๋ฉด ์๋๊ฐ ๋นจ๋ผ์ง๊ณ ๋ฉ๋ชจ๋ฆฌ ์๋น๊ฐ ์ค์ด๋ญ๋๋ค.
- ๋ชจ๋ธ ์คํ๋ก๋ฉ๊ณผ ๊ฐ์ ๋ค๋ฅธ ์ต์ ํ ๊ธฐ๋ฒ์ ์ด ๊ฐ์ด๋์์ ๋ค๋ฃจ๊ณ ์์ต๋๋ค.