stable diffusion 모델과 어뎁터 다뤄보기
컴퓨터그래픽스 수업을 수강하고 마지막 과제인 stable diffusion 모델을 사용한 Text-to-Image + Adapter 실습해볼 수 있는 기회가 생겼다. 용어를 정리한 후 코드를 살펴 보도록 하자.
Stable diffusion 이란 AI 기반의 이미지 생성 기술로, 주어진 텍스트 설명을 기반으로 이미지를 생성하는 기술이다. 이 기술은 주로 Generative Adversarial Networks (GANs)와 Variational Autoencoders (VAEs) 같은 딥러닝 모델을 사용한다. 최근에는 Denoising Diffusion Probabilistic Models (DDPMs)를 사용한 Diffusion Models가 주목받고 있다. Diffusion 모델은 이미지 생성 과정에서 점진적으로 잡음을 제거하면서 이미지를 생성하는 방식으로, 매우 높은 품질의 이미지를 생성할 수 있다.
Text-to-Image는 주어진 텍스트 설명(프롬프트)을 기반으로 이미지를 생성하는 AI 기술을 의미한다. 이 분야는 컴퓨터 비전과 자연어 처리(NLP) 기술을 결합하여, 텍스트로 표현된 아이디어를 시각적으로 구현할 수 있게 한다. 주요 응용 분야로는 예술 창작, 광고 디자인, 게임 그래픽 생성 등이 있다. 대표적인 모델로는 OpenAI의 DALL-E, Google의 Imagen 등이 있으며, 이러한 모델들은 텍스트를 이해하고, 그 텍스트에 맞는 이미지를 생성하는 데 매우 뛰어난 성능을 보이는 듯하다.
Adapter는 대규모 딥러닝 모델을 다양한 작업에 쉽게 적용할 수 있게 해주는 방법론이다. 일반적으로 큰 모델을 새로운 작업에 맞게 미세 조정(fine-tuning)하려면 많은 데이터와 시간이 필요하다. Adapter는 이러한 문제를 해결하기 위해 작은 모듈을 모델에 추가하고, 이 모듈만을 학습시킴으로써 효율적으로 새로운 작업에 적응할 수 있게 한다. 이를 통해 원래 모델의 가중치(weights)는 유지하면서도, 새로운 작업에 필요한 적응을 빠르고 효율적으로 할 수 있다.
가장 먼저 Base 모델을 사용하여 간단한 프롬프트를 사용해 이미지를 생성해보자. 다음은 Base 모델을 사용하여 이미지를 생성하는 코드를 실행하여 "A tank firing, 8k" 이라는 프롬프트를 토대로 생성된 이미지이다. stable-diffusion-xl-base-1.0 모델을 사용하여 고해상도로 생성되었다.
전차의 세부적인 디테일과 움직임이 잘 표현되어 있다. 각 이미지마다 Prompt engineering 을 통한 어떤 사물과 행동을 잘 반영했다.
모든 코드는 코랩에서 실행 되었으며, 코랩 유료 버전이 아니라면 고사양 GPU와 많은 메모리를 요구하는 stable-diffusion-xl-base-1.0 대신 stable-diffusion-v1-5 등 다른 모델을 사용하도록 하자.
from diffusers import DiffusionPipeline
import torch
# Base Model 설정
model_id = 'stabilityai/stable-diffusion-xl-base-1.0'
# 모델 로드
pipe = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
# 모델을 GPU로 이동시켜 연산 속도를 높입니다.
pipe = pipe.to("cuda")
# 텍스트 프롬프트 설정
# 'A tank firing, 8k'라는 프롬프트를 사용하여 이미지를 생성합니다.
prompt = 'A tank firing, 8k'
image = pipe(prompt).images[0]
image
다음은, ControlNet을 사용하여 Canny image를 사용해서 다른 이미지를 생성해보겠다. 여기서 Canny image란 Canny edge detection(에지 검출) 기법을 사용해 아웃라인을 검출 하여 만든 이미지이다.
lllyasviel/sd-controlnet-canny IP-Adapter를 사용하여 ControlNet과 연결하였고 뉴진스 해린의 이미지를 input 시켜 새로운 이미지를 생성하였다.
# 필요한 모듈 임포트
from diffusers.utils import load_image, make_image_grid
from PIL import Image
import cv2
import numpy as np
# 이미지 로드
original_image = load_image("/content/98213_133867_1692251606.jpg")
image = np.array(original_image)
# 에지 검출을 위한 임계값 설정
low_threshold = 100
high_threshold = 200
image = cv2.Canny(image, low_threshold, high_threshold)
image = image[:, :, None]
image = np.concatenate([image, image, image], axis=2)
canny_image = Image.fromarray(image)
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel, UniPCMultistepScheduler
import torch
# ControlNet 모델 로드
controlnet = ControlNetModel.from_pretrained(
"lllyasviel/sd-controlnet-canny",
torch_dtype=torch.float16,
use_safetensors=True
)
# Stable Diffusion 파이프라인 로드
pipe = StableDiffusionControlNetPipeline.from_pretrained(
"runwayml/stable-diffusion-v1-5",
controlnet=controlnet,
torch_dtype=torch.float16,
use_safetensors=True
)
# 스케줄러 설정
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
# 모델 CPU 오프로딩 활성화
pipe.enable_model_cpu_offload()
output = pipe(
"haerin photo", image=canny_image
).images[0]
# 원본 이미지, canny 이미지, 생성 이미지 출력
make_image_grid([original_image, canny_image, output], rows=1, cols=3)
다음은 Base Model과 Adapter를 latent-consistency/lcm-lora-sdv1-5 로 설정한 뒤 ControlNet을 모두 연결하여 모델을 구축해보겠다. "Astronaut in space, cartoon, midnight" 라는 프롬프트로 이미지를 생성한 결과이다.
프롬프트인 cartoon, midnight에 어울리는 그림이 생성 되었다.
# 필요한 모듈 임포트
from diffusers import StableDiffusionPipeline, ControlNetModel, AutoPipelineForText2Image
from diffusers.schedulers import LCMScheduler
import torch
# Base model 및 Adapter ID, ControlNet 모델 ID 설정
model_id = "runwayml/stable-diffusion-v1-5"
adapter_id = "latent-consistency/lcm-lora-sdv1-5"
controlnet_model_id = "lllyasviel/sd-controlnet-canny"
# ControlNet 모델 로드
controlnet = ControlNetModel.from_pretrained(controlnet_model_id, torch_dtype=torch.float16)
# Stable Diffusion ControlNet 파이프라인 로드
pipe = AutoPipelineForText2Image.from_pretrained(model_id, torch_dtype=torch.float16, variant="fp16")
# 스케줄러 설정
pipe.scheduler = LCMScheduler.from_config(pipe.scheduler.config)
# 모델을 CUDA로 이동
pipe.to("cuda")
# ControlNet을 파이프라인에 통합
pipe.controlnet = controlnet
# LoRA 가중치 로드 및 통합
pipe.load_lora_weights(adapter_id)
pipe.fuse_lora()
# 프롬프트를 사용하여 이미지 생성
prompt = "astronaut in space, cartoon, midnight"
# 이미지 생성 설정
num_inference_steps = 200 # 더 많은 스텝을 통해 높은 퀄리티의 이미지를 생성
guidance_scale = 7.5 # 높은 값으로 설정하여 프롬프트에 더 충실한 이미지를 생성
# 이미지 생성
image = pipe(prompt=prompt, num_inference_steps=num_inference_steps, guidance_scale=guidance_scale).images[0]
image
다음으론 필요에 의해 스타일화된 어뎁터 예시를 위해 iamkaikai/CUBISM-LORA 를 사용해보자. 프롬프트는 "futuristic cityscape with flying cars, cubism style, detailed" 로 생성하였다.
cubism adapter를 사용했고 프롬프트의 영향 덕분에 역시나 Cubism 스타일로 하늘을 나는 자동차와 함께 현대적인 도시 풍경을 표현하고 있다. 기하학적인 형태와 색상의 조합이 특징이고 건물과 구조물들이 다각형 형태로 표현되어 있으며, 이는 큐비즘 특유의 스타일을 잘 반영하고 있다.
from diffusers import DiffusionPipeline
import torch
# Base model 로드
model_id = "runwayml/stable-diffusion-v1-5"
# Diffusion 파이프라인 로드
pipeline = DiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
# 모델을 CUDA로 이동
pipeline.to("cuda")
# LoRA 가중치 로드
lora_model_id = "iamkaikai/CUBISM-LORA"
pipeline.load_lora_weights(lora_model_id)
# 프롬프트를 사용하여 이미지를 생성합니다.
prompt = "futuristic cityscape with flying cars, cubism style, high quality, detailed"
# 이미지 생성
num_inference_steps = 200 # 더 많은 스텝을 통해 높은 퀄리티의 이미지를 생성
guidance_scale = 7.5 # 높은 값으로 설정하여 프롬프트에 더 충실한 이미지를 생성
image = pipeline(prompt, num_inference_steps=num_inference_steps, guidance_scale=guidance_scale).images[0]
# 생성된 이미지 표시
image
결론
Base 모델에 더해 Adapter를 사용하면 다양한 예술적 표현이나 특정 요구사항에 맞춘 이미지를 생성할 수 있어 응용 범위가 넓어진다. 하지만 Adapter를 사용하지 않고 Base Model만으로도 고품질의 이미지를 생성할 수 있으나, 특정 스타일이나 디테일한 표현에서는 한계가 있을 수 있다. 특정한 예술적 스타일보다는 프롬프트에 따른 일반적인 이미지 생성에 적합하다. 또한, Model은 다양한 프롬프트에 대한 기본적인 이미지 생성 능력을 가지고 있으며, 다양한 상황에 적용 가능하지만, 스타일화된 결과물에서는 부족할 수 있다.
...오늘은 Text-to-image + Adapter 실습을 해보았다