Diffusers를 이용한 Stable Diffusion

TL;DR

Hugging Face는 🤗 Diffusers 라이브러리를 사용하여 Stable Diffusion v1‑4(및 이후 버전)를 실행하는 가이드를 공개했으며, 설치 방법, 라이선스, 추론 코드 및 기본 잠재 확산 아키텍처에 대해 자세히 설명합니다.

라이선스 요구 사항

Stable Diffusion 모델은 (1) 불법 또는 해로운 생성 금지, (2) 생성된 출력에 대한 완전한 권리를 사용자에게 부여하되 책임을 묻고, (3) 동일한 제한이 하위 사용자에게 전달되는 경우 상업적 사용 및 가중치 재배포를 허용하는 라이선스로 배포됩니다.

Diffusers 빠른 시작

  • 필요한 패키지를 설치합니다:
pip install diffusers==0.10.2 transformers scipy ftfy accelerate
  • 파이프라인을 로드합니다 (v1‑4 예시; 1.5, 2, 2.1 등 다른 버전도 유사하게 동작합니다):
from diffusers import StableDiffusionPipeline
pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4")
pipe.to("cuda")
  • 메모리가 10 GB 미만인 GPU의 경우 fp16 체크포인트를 로드합니다:
pipe = StableDiffusionPipeline.from_pretrained(
    "CompVis/stable-diffusion-v1-4", revision="fp16", torch_dtype=torch.float16
)
  • 이미지를 생성합니다:
prompt = "a photograph of an astronaut riding a horse"
image = pipe(prompt).images[0]
  • torch.Generator에 시드를 설정하고 파이프라인에 전달하면 결정적인 출력을 얻을 수 있습니다.
  • guidance_scale 매개변수(기본값 7.5)는 classifier‑free guidance를 제어합니다; 7~8.5 사이의 값을 권장합니다.
  • 디노이징 단계 수(num_inference_steps)는 기본값 50이며, 단계 수를 줄이면 품질이 감소하는 대신 생성 속도가 빨라집니다.
  • heightwidth를 지정하여 비정사각형 이미지를 만들 수 있습니다(두 값 모두 8의 배수여야 함). 한 차원에 512를 사용하고 다른 차원에 8의 더 큰 배수를 사용하면 최상의 결과를 얻을 수 있습니다.

Stable Diffusion 아키텍처 이해

Stable Diffusion은 잠재 확산 모델로, 압축된 잠재 공간(8×8 공간 축소, 즉 512×512 이미지가 64×64 잠재 텐서가 됨)에서 작동하여 메모리와 연산량을 줄입니다. 세 가지 핵심 구성 요소로 이루어져 있습니다:

  1. Variational Auto‑Encoder (VAE) – 이미지를 잠재 공간으로 인코딩하고 잠재를 픽셀 공간으로 디코딩합니다; 추론 시에는 디코더만 필요합니다.
  2. U‑Net – 각 확산 단계에서 노이즈 잔차를 예측합니다; 텍스트 임베딩을 조건으로 하는 교차‑어텐션 레이어를 포함합니다.
  3. 텍스트 인코더 – 프롬프트를 77×768 임베딩으로 변환하는 사전 학습된 CLIP 텍스트 모델(CLIPTextModel)이며, 학습 중에는 인코더가 고정됩니다.

추론 시, 무작위 잠재 시드와 텍스트 임베딩이 U‑Net에 입력되며, 스케줄러(기본 PNDM, 대안으로 DDIM 및 K‑LMS)를 사용해 약 50단계에 걸쳐 잠재를 반복적으로 디노이징합니다. 최종 잠재는 VAE에 의해 디코딩되어 512×512 이미지가 생성됩니다.

파이프라인 커스터마이징

고급 사용자는 subfolder 인자를 사용해 모델 저장소에서 개별 구성 요소(VAE, 스케줄러, UNet 등)를 로드하여 교체할 수 있습니다:

from diffusers import AutoencoderKL, UNet2DConditionModel, PNDMScheduler
vae = AutoencoderKL.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="vae")
unet = UNet2DConditionModel.from_pretrained("CompVis/stable-diffusion-v1-4", subfolder="unet")
scheduler = LMSDiscreteScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", num_train_timesteps=1000)

블로그 예제는 K‑LMS 스케줄러, classifier‑free guidance, 수동 잠재 처리 등을 사용한 전체 추론 루프를 보여줍니다.

실용적인 팁

  • 메모리가 제한된 GPU에서는 torch.float16을 사용합니다.
  • height/width를 8의 배수로 설정하여 형태 불일치를 방지합니다.
  • 프롬프트 준수를 강화하려면 guidance_scale을 높이세요. 다만 다양성은 감소할 수 있습니다.
  • 더 빠른 결과를 원하면 num_inference_steps를 줄이고, 높은 품질을 원하면 늘립니다.
  • 파이프라인은 imagesnsfw_content_detected 플래그를 포함한 딕셔너리를 반환합니다.

리소스

인용

@article{patil2022stable,
  author = {Patil, Suraj and Cuenca, Pedro and Lambert, Nathan and von Platen, Patrick},
  title = {Stable Diffusion with 🧨 Diffusers},
  journal = {Hugging Face Blog},
  year = {2022},
  note = {https://huggingface.co/blog/stable_diffusion}
}

Sources