no image
[SD] Stable Diffusion 구현 - 1
Diffusers : 모든 메모리, 컴퓨팅, 품질 개선과 함꼐 안정적인 Diffusion을 실행할 수 있는 간단한 API를 제공한다. Stable Diffusion을 이 Diffusers를 이용해 추론(inference)을 위한 pipeline을 차례로 구축해볼 수 있었다. 참고한 자료는 아래와 같다. The Stable Diffusion Guide 🎨 (huggingface.co) The Stable Diffusion Guide 🎨 Taking Diffusers Beyond Images huggingface.co Prompt Engineering 추론에서 Stable diffusion을 실행할 때는 일반적으로 특정 타입 또는 스타일의 이미지를 생성한 다음 이를 개선하고자 한다. 이전에 생성된 이미지를 ..
2024.04.09
no image
[논문 리뷰] IP-Adapter: Text Compatible Image Prompt Adapter for Text-to-Image Diffusion Models
Paper : 2308.06721.pdf (arxiv.org) github : tencent-ailab/IP-Adapter: The image prompt adapter is designed to enable a pretrained text-to-image diffusion model to generate images with image prompt. (github.com) IP-Adapter (Image Prompt Adapter)는 이미지를 프롬프트로 사용할 수 있는 stable diffusion 애드온이다. IP-Adapter를 사용하면 참조 이미지로부터 스타일, 구도, 얼굴을 복사할 수 있다. IP-Adapter의 경우 2023년 8월 중순에 릴리즈해 9월 5일에 WebUI에서 사용할 수 있게 된..
2024.04.08
no image
[논문 리뷰] SDXL : Improving Latent Diffusion Models for High-Resolution Image Synthesis
paper : https://arxiv.org/pdf/2307.01952.pdf Abstract SDXL은 이전 버전의 Stable diffusion에 비해 아래와 같은 차별점을 가진다. 3배 더 큰 UNet 백본 사용 모델 파라미터 수의 증가 (35억개 -> 66억개) 두 번째 텍스트 encoder를 사용하여 더 많은 attention block과 더 큰 cross-attention context를 사용하기 때문 기존의 LDMs보다 더 다양한 단어를 인지하고 사실적인 디테일 표현 가능 (편의성 뛰어남) 여러가지 conditioning 체계를 설계 & 여러 측면에 대해 SDXL를 훈련함 간단하면서도 효과적인 두 가지 추가 컨디셔닝 기법 존재 정제 모델(refinement model) 도입 -> 사후 im..
2024.03.28
no image
[논문 리뷰] U-Net: Convolutional Networks for Biomedical Image Segmentation
- 기본 용어와 개념 Image Segmentation & Image Classification image segmentation : 이미지의 모든 pixel이 어떤 카테고리에 속하는지 분류하는 것 image classification : 이미지 전체에 대해 단일 카테고리를 예측하는 것. 이에 비해 이미지 세그멘테이션은 pixel 단위의 분류를 수행하므로 일반적으로 더 어려운 문제로 인식되고 있다. 이미지 세그멘테이션은 의료 이미지 분석, 자율주행 차량, 증강현실과 같은 광범위한 분야에서 사용되고 있다. 이때, UNet은 매우 적은 수의 학습 데이터로도 정확한 이미지 세그멘테이션을 보여주었다! Patch 쉽게 이해하자면 이미지 인식 단위라 할 수 있다. 위 논문에서는 sliding window처럼 이미지..
2024.03.26
no image
[논문 리뷰] Latent Diffusion : High-Resolution Image Synthesis with Latent Diffusion Models
paper : [2112.10752] High-Resolution Image Synthesis with Latent Diffusion Models (arxiv.org)  High-Resolution Image Synthesis with Latent Diffusion ModelsBy decomposing the image formation process into a sequential application of denoising autoencoders, diffusion models (DMs) achieve state-of-the-art synthesis results on image data and beyond. Additionally, their formulation allows for a guidin..
2024.03.22
[PyTorch] Functional API
Sequential API는 직관적이고 편리하지만 단순히 층을 쌓는 것만으로는 여러층을 공유하거나 다양한 종류의 입력과 출력을 사용하는 등의 복잡한 모델을 만드는 일에는 한계가 존재한다. 따라서 Functional API를 사용한다. Functional API - 각 층을 일종의 함수로 정의 - 각 함수를 조합하기 위한 연산자를 제공하는데, 이를 이용해 신경망을 설계함 - 입력의 크기(shape)를 명시한 입력층(input layer)을 모델의 앞단에 정의해주어야 함 from tensorflow.keras.layers import Input, Dense from tensorflow.keras.models import Model inputs = Input(shape = (10, )) hidden1 = De..
2024.03.21
no image
[PyTorch] Sequential API - tokenizer(), Sequential(), Dense()
keras는 딥러닝을 쉽게 할 수 있는 파이썬 라이브러리로, 유저가 손쉽게 딥러닝을 구현할 수 있도록 도와주는 상위 레벨의 인터페이스다. 1. 전처리(Preprocessing) > Tokenizer() : 토큰화 & 정수 인코딩을 위해 사용 - 토큰화 : 문장을 이루는 단위는 여러가지가 있을 수 있으며 여기서 문장을 다시 일정한 단위로 끊어 컴퓨터가 받아들이도록 하는 작업 - 영어의 경우 NLTK, 한국어의 경우 KoNLpy, ETRI OPEN API 등으로 토큰화를 진행한다 - corpus(말뭉치) : 토큰화하기에 앞서 여러 문장들로 된, 토큰화 할 하나의 큰 대상 - 가장 쉬운 토큰화 : 공백을 기반으로 한 토큰화. 띄어쓰기로 인해 생기는 공백으로 끊어 각각의 조각(토큰)을 사전으로 만드는 것 - 사..
2024.03.21
no image
[PyTorch] 과적합(Overfitting) 방지 - Dropout
과적합을 방지하기 위한 방법으로는 1. 데이터의 양을 늘리기 (Data Augmentation) 2. 모델의 복잡도 줄이기 3. 가중치 규제 (Regularization) 4. 드롭아웃 (Dropout) 등이 존재한다. 그중 드롭아웃이란 학습 과정에서 신경망의 일부를 사용하지 않는 방법이다. 모델에 드롭아웃 레이어를 추가해서 무작위로 선택된 은닉층의 일부 unit이 동작하지 않게 하여 overfitting 되는 것을 방지한다. 위 그림은 은닉층에 50% 드롭아웃을 적용한 경우로, 첫번째 hidden layer에서 50%의 unit만 다음에 오는 hidden layer에 데이터를 전달하는 것이다. 드롭아웃을 적용하며 실행할 때마다 무작위로 레이어의 unit이 삭제되기 때문에 실행할 때마다 서로 다른 신경망..
2024.03.21

Diffusers : 모든 메모리, 컴퓨팅, 품질 개선과 함꼐 안정적인 Diffusion을 실행할 수 있는 간단한 API를 제공한다. 

Stable Diffusion을 이 Diffusers를 이용해 추론(inference)을 위한 pipeline을 차례로 구축해볼 수 있었다. 

참고한 자료는 아래와 같다. 

 

The Stable Diffusion Guide 🎨 (huggingface.co)

 

The Stable Diffusion Guide 🎨

Taking Diffusers Beyond Images

huggingface.co

 


Prompt Engineering

추론에서 Stable diffusion을 실행할 때는 일반적으로 특정 타입 또는 스타일의 이미지를 생성한 다음 이를 개선하고자 한다. 이전에 생성된 이미지를 개선한다는 것은 만족할 때까지 다른 프롬프트와 잠재적으로 다른 seed를 사용하여 추론을 반복해 실행하는 것을 의미한다. 따라서 우선은 SD의 속도를 최대한 높여 주어진 시간 내에 최대한 많은 사진을 생성하는 것이 가장 중요하다. 이는 계산 효율성(속도)과 메모리 효율성(GPU RAM)을 개선함으로써 달성할 수 있다.

model_id = "runwayml/stable-diffusion-v1-5" # 예시 모델 ID

 

runwayML에서개발한 SD의 1.5 version이다. 

 

Speed Optimization

from diffusers import StableDiffusionPipeline

pipe = StableDiffusionPipeline.from_pretrained(model_id)

 

  • StableDiffusionPipeline.from_pretrained(model_id) : 사전 훈련된 stable diffusion 모델을 로드함. 모델의 가중치와 설정이 로컬 환경 또는 지정된 경로에 저장됨. 로드된 모델을 바탕으로 "StableDiffusionPipeline" 객체가 초기화됨.
    • pipe : 텍스트-이미지 변환 모델의 파이프라인을 나타내는 객체. 프롬프트로 텍스트 입력을 받아 이미지를 생성하는 전체 과정(데이터 전처리, 모델 추론, 후처리 등)을 캡슐화함.
prompt = "portrait photo of a old warrior chief"

pipe = pipe.to("cuda") # GPU 사용을 위해 GPU로 pipe 객체 이동시킴

 

위의 텍스트 프롬프트를 바탕으로 이미지를 생성할 예정이다. 

generator = torch.Generator("cuda").manual_seed(0)

 

모든 call에서 거의 동일한 이미지를 재현할 수 있도록 하기 위해 generator를 사용한다. PyTorch에서 사용되는 난수 생성기(torch.Generator)를 초기화하고, 이를 seed 0으로 고정한다. 

  • torch.Generator("cuda") : cuda 환경(즉, NVIDIA GPU)에서 작동하는 새로운 난수 생성기 인스턴스를 사용함. 
  • manual_seed(0) : generator의 시드값을 0으로 설정함으로써 실험의 재현성을 보장함. 
image = pipe(prompt, generator = generator).images[0]
image

 

사용자가 입력한 텍스트 설명에 따라 생성된 이미지들 중 첫 번째 이미지를 선택해 image 변수에 할당한다.

  • images[0] : pipe 함수가 반환하는 객체에서 이미지 리스트를 참조하고, 그 중 첫번째 이미지를 선택하는 것 의미함.
  • pipe : 입력된 프롬프트를 기반으로 하나 이상의 이미지를 생성하고, 이 이미지들이 .images라는 리스트 또는 배열 안에 저장됨. 딥러닝 모델, 특히 자연어 처리나 이미지 생성과 같은 과제에서 사용되는 고수준의 API.
    • pipe 함수는 특별히 생성할 이미지의 수를 지정하는 매개변수(예: num_image)를 설정하지 않는 경우, 대부분의 구현에서는 기본적으로 하나의 이미지만 생성함.
      • inference_step은 생성 과정에서 모델이 거치는 추론 단계의 수를 의미하는 것임. 디폴트는 50으로, 이는 한 번의 이미지 생성 요청에 대해 모델이 50번의 연산을 수행한다는 것을 의미함! 생성할 이미지 수와는 다른 개념임.
      • inference_step은 하나의 이미지를 생성하는 데 있어서의 추론 과정의 복잡성 또는 깊이를 나타내는 것.
    • .images[0]은 생성된 유일한 이미지에 접근하는 것을 의미함!

 

float32, inference_step = 50

 

 

여기까지 수행한 기본 실행은 전체 float32 정밀도를 사용하고, 기본 inference_step을 50으로 사용한 형태이다(50이 디폴트값임). 여기서 더 쉽게 속도를 높이는 방법은 float16(또는 절반) 정밀도를 사용하고 추론 단계를 더 적게 실행하는 것이다. 아래는 모델을 float16으로 로드한 것이다. 

pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype = torch.float16)
pipe = pipe.to("cuda")

generator = torch.Generator("cuda").manual_seed(0)

image = pipe(prompt, generator = generator).images[0]
image

inference_step = 50, float16

float32인 경우보다 거의 3배나 빠른 속도이다. 이때까지 float16으로 인해 품질이 저하되는 경우는 거의 없었으므로 항상 float16으로 파이프라인을 실행할 것을 권장한다. 

 

+ ) hugging face의 결과는 동일한 이미지가 생성되는 것이었는데, 나의 경우 float32일 때와 float16일 때의 이미지가 서로 다르게 생성되었다. float16을 사용할 때의 속도 향상은 명확하지만, 이는 정밀도의 손실과 수치 안정성의 감소를 수반할 수 있으며 이로 인해 최종 생성된 이미지에 차이가 발생할 수 있다고 한다. 이에 고정된 시드 값에도 불구하고 다른 이미지가 생성된 것이다. 

 

추가로 inference step을 50으로 사용해야 하는지, 훨씬 더 적은 단계를 사용해도 되는지를 살펴볼 수 있다. 

추론 단계의 수는 우리가 사용하는 denoising scheduler과 관련이 있다. 보다 효율적인 scheduler를 사용하면 step 수를 줄이는 데에 도움이 될 수 있다. 

inference step이 많을수록 모델은 더 많은 계산을 수행해 이미지의 세부 사항을 더욱 정교하게 만들 수 있으나, 그만큼 처리 시간도 더 길어진다. 반대로 inference step을 줄이면 이미지 생성 속도는 빨라지지만, 결과 이미지의 품질이 떨어질 수 있다.

 

pipe.schedulers.compatibles
[diffusers.schedulers.scheduling_ddim.DDIMScheduler,
 diffusers.utils.dummy_torch_and_torchsde_objects.DPMSolverSDEScheduler,
 diffusers.schedulers.scheduling_edm_euler.EDMEulerScheduler,
 diffusers.schedulers.scheduling_deis_multistep.DEISMultistepScheduler,
 diffusers.schedulers.scheduling_euler_discrete.EulerDiscreteScheduler,
 diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler,
 diffusers.schedulers.scheduling_euler_ancestral_discrete.EulerAncestralDiscreteScheduler,
 diffusers.schedulers.scheduling_ddpm.DDPMScheduler,
 diffusers.schedulers.scheduling_k_dpm_2_ancestral_discrete.KDPM2AncestralDiscreteScheduler,
 diffusers.schedulers.scheduling_dpmsolver_multistep.DPMSolverMultistepScheduler,
 diffusers.schedulers.scheduling_lms_discrete.LMSDiscreteScheduler,
 diffusers.schedulers.scheduling_dpmsolver_singlestep.DPMSolverSinglestepScheduler,
 diffusers.schedulers.scheduling_unipc_multistep.UniPCMultistepScheduler,
 diffusers.schedulers.scheduling_pndm.PNDMScheduler,
 diffusers.schedulers.scheduling_k_dpm_2_discrete.KDPM2DiscreteScheduler]

 

위 코드를 통해 사용할 수 있는 모든 scheduler를 볼 수 있다.

 

현재 SD에서는 일반적으로 PNDMScheduler를 사용하고 있는데, 이는 약 50 단계의 추론을 요구한다. 그러나 DPMSolverMultistepSheduler 또는 DPMSolverSinglestepsScheduler와 같은 다른 스케줄러는 약 20~25개의 추론 단계를 요구한다. config 함수를 통해 다른 스케줄러로 설정할수 있다.

from diffusers import DPMSolverMultistepScheduler

pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)

generator = torch.Generator("cuda").manual_seed(0)

image = pipe(prompt, generator = generator, num_inference_steps = 20).images[0]
image

inference_step = 20

 

이미지는 50 step의 경우보다는 달라졌으나 여전히 고품질이다. 또한 inference 시간이 4초로 단축되었다. 

 

Memory Optimization

간접적으로 generation에 사용되는 메모리가 적다는 것은 더 속도가 빠르다는 것을 의미한다. 이는 초당 생성할 수 있는 이미지 수를 최대화하려고 하는 경우가 많기 때문이다. 일반적으로 추론 실행 당 이미지 수가 많을수록 초당 이미지 수도 많아진다.

 

한 번에 얼마나 많은 이미지를 생성할 수 있는지 확인하는 가장 쉬운 방법은 간단히 시도해보고 '메모리 부족(OOM)' 오류가 발생하는지 확인하는 것이다. 

 

프롬프트와 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 }

 

  • manual_seed(batch_size)가 아닌, for i in range(batch_size)를 사용하는 이유

: 여기서 batch_size는 생성할 이미지의 수를 나타낸다. 루프를 사용해 각 난수 생성기에 고유한 시드 값을 ("i") 제공함으로써, 각 생성기는 서로 다른 난수 시퀀스를 생성하게 된다.

만약 manual_seed(batch_size)를 사용하게 되면, 모든 난수 생성기에 대해 동일한 시드 값을 설정하게 되므로, 각각의 난수 생성기가 동일한 난수 시퀀스를 생성하게된다. 이는 배치 처리 과정에서 각 요청 또는 항목에 대해 고유한 난수 시퀀스를 제공하고자 할 때 문제가 될 수 있다.

예로, 이미지 생성 작업에서 각 이미지에 약간의 변화를 주기 위해 난수를 사용한다고 가정할 수 있다. 만약 모든 난수 생성기에 동일한 시드 값을 사용한다면, 모든 이미지에 동일한 변화가 적용되어 다양성이 감소할 것이다. 

  • promts = batch_size * [prompt] : 주어진 prompt 문자열을 batch_size 만큼 반복해 리스트를 생성함. 이로써 prompts에는 동일한 텍스트 프롬프트가 batch_size 개수만큼 포함됨
    • prompt : 이미지 생성이나 다른 작업을 위해 모델에 전달될 텍스트
    • [prompt] : prompt 문자열을 단일 요소로 가지는 리스트 생성. 
    • batch_size * [prompt]: [prompt] 리스트를 batch_size만큼 반복하여 확장함. 예를 들어, batch_size가 3이라면, 결과는 ["a landscape with mountains", "a landscape with mountains", "a landscape with mountains"]와 같은 리스트가 됨. 
    • 생성된 prompts 리스트는 후속 처리 과정에서 모델의 입력으로 사용될 수도 있으며, 이를 통해 모델은 리스트에 포함된각 프롬프트에 대해 동일한 작업을 수행하게 됨.

 

아래의 함수는 프롬프트 목록과 generator 목록을 반환하므로 원하는 결과를 생성한 generator를 재사용할 수 있다. 또한 이미지의 배치를 쉽게 표시할 수 있는 method도 필요하다. 

from PIL import Image

def image_grid(imgs, rows = 2, cols = 2):
  w, h = imgs[0].size # 첫번째 이미지의 너비(w)와 높이(h)를 가져옴.
  grid = Image.new("RGB", size = (cols * w, rows * h)) # 새로운 'RGB' 이미지 생성

  for i, img in enumerate(imgs): # 각 이미지(img)와 해당 인덱스(i) 가져옴
    grid.paste(img, box = (i%cols*w, i//cols*h)) # 각 이미지를 그리드의 적절한 위치에 붙여넣음
  return grid # 하나의 큰 그리드 이미지를 반환

 

  • image_grid : 주어진 이미지 리스트 imgs를 사용해 그리드 형태로 배열된 하나의 큰 이미지를 생성하는 함수
    • imgs : 합성할 이미지 객체의 리스트
    • rows : 그리드에 포함될 행의 수. 기본값은 2임
    • cols : 그리드 포함될 열의 수. 기본값은 2임

1. 그리드 이미지 생성

  • w, h = imgs[0].size : 첫번째 이미지(imgs[0])의 너비(w)와 높이(h)를 가져옴
    • 모든 이미지가 동일한 크기를 가지고 있다고 가정함
  • grid = Image.new('RGB', size = (cols * w, rows * h)) : cols * w와 rows * h를 크기로 하는 새로운 'RGB' 이미지 생성함
    • 이 이미지는 개별 이미지들을 배치할 그리드 역할을 함

2. 이미지 배치

  • grid.paste(img, box=(i%cols*w, i//cols*h)): 각 이미지를 그리드의 적절한 위치에 붙여넣음.
    • i%cols*w : 열 내에서 이미지의 x 좌표를 결정함
    • i//cols*h : 행 내에서 이미지의 y 좌표를 결정함. 이 계산들을 통해 각 이미지는 그리드 내에서 올바른 위치에 배치됨

3. 결과 반환 

  • return grid : 모든 이미지를 포함하는 하나의 큰 그리드 이미지를 반환함

위 함수는 여러 이미지를 한 번에 시각적으로 표시하고 싶을 때 유용하게 사용할 수 있다. 그 예로, 이미지 처리 과정의 중간 결과나 여러 샘플 이미지를 한눈에 비교하기 위한 용도로 사용할 수 있다. 

 

아래 코드로 batch_size= 4로 설정해 얼마나 많은 메모리를 사용할 수 있는지 살펴볼 수 있다. 

imgaes = pipe(**get_inputs(batch_size = 4)).images
image_grid(images)

 

 

 

노트북의 T4 GPU에서는 batch_size가 4를 초과하면 오류가 발생한다. 또한 초당 이미지 생성 속도가 이전에 비해 약간 더 빨라진 것을 볼 수 있다. 

커뮤니티에서 메모리 제약을 더 개선할 수 있는 몇 가지의 유용한 방법을 더 찾아냈는데, 그 중 하나가 바로 아래의 enable_attention_slicing을 호출해 활성화하는 것이다. 

지금까지 대부분의 메모리는 cross-attention layers가 차지하는데, 이 작업을 일괄적으로 실행하는 대신 순차적으로 실행하면 상당한 양의 메모리를 절약할 수 있는 것이다. 

pipe.enable_attention_slicing()

 

attention slicing이 활성화되었으므로 배치 크기를 두 배로 늘려서 실행해볼 수 있다. 

images = pipe(**get_inputs(batch_size = 8)).images
image_grid(images, rows = 2, cols = 4)

 

속도 향상이 그리 크지는 않지만, 품질 저하 없이 T4로 얻을 수 있는 가장 빠른 속도이다. 

 

Quality Improvements

위에서 이미지 생성 pipeline의 속도를 개선시키는 방법을 알아보았는데, 이제 이미지 품질을 극대화하는 방법을 알아볼 수 있다. 

 

이미지의 quality는 지극히 주관적이기에 일반적인 주장을 하기에는 어려움이 있으나, 화질을 개선하기 위한 가장 확실한 방법은 더 나은 checkpoints를 사용하는 것이다. SD가 릴리즈된 이후 많은 개선된 버전들이 출시되었는데, 최신 버전이라고 해서 무조건적으로 동일한 매개변수에서 더 나은 이미지 품질을 제공하는 것은 아님을 명심해야 한다. (그 예로 일부 프롬프트의 경우 2.0이 1.5보다 약간 더 나쁘다는 의견이 있지만, 올바른 프롬프트 엔지니어링을 고려하면 2.0과 2.1이 더 나은 것 같다는 의견이 존재한다.) 따라서 전반적으로 모델을 사용해보고 온라인에서 여러 어드바이스들을 참고하는 것이 좋다. (예: 2.0과 2.1에서 가능한 최고의 품질을 얻으려면 부정적인 프롬프트를 사용하는 것이 좋다.)

 

아래의 코드에서는 새로운 auto-decoder를 사용한다. 

from diffusers import AutoencoderKL

vae = AutoencoderKL.from_pretrained("stabilityai/sd-vae-ft-mse", torch_dtype = torch.float16).to("cuda")
pipe.vae = vae

 

vae를 pipeline으로 사용해 이미지를 생성하면 아래와 같다. 

images = pipe(**get_inputs(batch_size = 8)).images
image_grid(images, rows = 2, cols = 4)

 

아주 사소한 차이인 것 같지만, pipeline으로 vae를 사용했을 때의 이미지가 더 선명하게 생성된 것을 볼 수 있다. 

 

프롬프트 엔지니어링에 대해 조금 더 살펴보면, 이전까지 사용한 원래의 목표는 "portrait photo of an old warrior chief"의 사진을 생성하는 것이었다. 이렇게 생성된 사진보다 좀 더 색을 입히고 인상적인 사진을 만들기 위해선 단서와 더 많은 세부 정보를 추가해 프롬프트를 개선할 수 있다. 

 

프롬프트 엔지니어링을 할 때 기본적으로 생각해야 할 사안은 아래와 같다. 

1. 내가 원하는 사진이나 비슷한 사진이 인터넷에 있는가?

2. 내가 원하는 스타일로 모델을 조정하려면 어떤 디테일을 추가해야하는가?

 

# 프롬프트엔지니어링

prompt += ", tribal panther make up, blue on red, side profile, looking away, serious eyes" # detail
prompt += " 50mm portrait photography, hard rim lighting photography--beta --ar 2:3  --beta --upbeta"  # cues                                                                                                                                    
prompt

 

디테일과 단서들을 프롬프트에 추가해서 다시 이미지를 생성했을 때, 높은 퀄리티의 이미지가 생성됨을 볼 수 있다. 

  • detail : 이미지의 구체적인 시각적 특성이나 요소 지정
  • cue : 이미지 생성 과정에 추가적인 지시를 제공하는 힌트나 신호. 카메라 설정, 조명 방식, 이미지 비율 등

 

 

이제 위의 프롬프트의 "oldest warrior", "old" 등의 키워드 속 "old"를 "young"으로 바꿔 이미지를 생성해보았다. 

 

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 ligting 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))]
  • 각 프롬프트에 대응하는 난수 생성기 인스턴스를 사용해 모든 generator에 동일한 시드(1) 값을 사용해 난수 시퀀스를 일정하게 유지함
images = pipe(prompt=prompts, generator=generator, num_inference_steps=25).images                                                                                                                                                             
image_grid(images)

 

 


 

이거 말고도 다른 hugging face도 구현해보면 좋을 거 같다! 

구현해본 파일은 아래 깃허브로 볼 수 있다.

https://github.com/alswjd131313/Stable-Diffusion/blob/main/SD_1.ipynb

 

Stable-Diffusion/SD_1.ipynb at main · alswjd131313/Stable-Diffusion

Contribute to alswjd131313/Stable-Diffusion development by creating an account on GitHub.

github.com

 

'구현' 카테고리의 다른 글

[SD] IP-Adapter with multiple image  (0) 2024.05.08
[SD] IP-Adapter with ControlNet  (0) 2024.05.08
[SD] SD with Diffusers  (0) 2024.05.01

Paper : 2308.06721.pdf (arxiv.org)

github : tencent-ailab/IP-Adapter: The image prompt adapter is designed to enable a pretrained text-to-image diffusion model to generate images with image prompt. (github.com)


 

IP-Adapter (Image Prompt Adapter)는 이미지를 프롬프트로 사용할 수 있는 stable diffusion 애드온이다. IP-Adapter를 사용하면 참조 이미지로부터 스타일, 구도, 얼굴을 복사할 수 있다. 

IP-Adapter의 경우 2023년 8월 중순에 릴리즈해 9월 5일에 WebUI에서 사용할 수 있게 된 어댑터이다.

  • 애드온(add-on) : 컴퓨터의 성능을 향상시키기 위해 회로나 메모리를 추가하는 것

기존에는 퀄리티 좋은 그림을 뽑아 내기 위해 아주 힘들게 positive, negative prompt를 직접 작성하거나, 그것도 안되면 어디서 PNG 정보를 긁어오거나 해야만 했다. 그렇게하여 이미지를 생성한다 하더라도, 원하는 화풍과 구도로 입맛에 맞는 그림을 뽑아 내기란 쉽지 않다. 

하지만 IP-Adapter 기능을 사용하면, 직접 생성 혹은 촬영한 이미지 뿐만 아니라 인터넷에 있는 수많은 이미지를 prompt화 할 수 있으며, 원한다면 여기에 text prompt를 추가해 text-to-image, image-to-image, inpainting 탭에서 퀄리티 있는 그림을 손쉽게 뽑아낼 수 있게 되는 것이다. 

추가로 기존의 베이스모델(SDXL 버전까지 지원), 그리고 파인튜닝된 커스텀 모델들 또한 사용 가능하다는 점이 장점이다 .

 


 

Abstract

최근 몇 년 동안 대규모의 text-to-image diffusion model은 고화질 이미지 생성에 강력한 성능을 보임이 입증되었다. 하지만 text prompt만 사용해 원하는 이미지를 생성하는 것은 복잡한 프롬프트 엔지니어링을 수반하는 경우가 많기에 매우 까다로운 작업이다. 이때 text prompt의 대안으로 사용되는 것이 image prompt이다. 

기존의 방법은 pretrained model에서 직접 fine-tuning을 거치는 것으로, 효과적이지만 대규모 컴퓨팅 리소스가 필요하고 다른 기본 모델과 text prompt, structural control과 호환되지 않는다는 단점이 있었다. 이때 위 논문은 pretrained text-to-image diffusion model의 image prompt의 기능을 향상시키기 위한 IP-Adapter를 소개한다. 

 

IP-Adapter의 핵심 설계로는 text feature과 image feature에 대한 cross-attention layer를 분리하는 cross-attention 메커니즘이다. 이 방식은 간단할 뿐만 아니라 2200만 개에 불과한 파라미터로 완전히 미세 조정된 (fully fine-tuned) image prompt model과 비슷하거나 더 나은 성능을 달성할 수 있다는 장점을 가진다. 기존의 pretrained diffusion model은 고정되어 사용되는데, 이와 달 IP-Adapter는 base model에서 fine-tuned된 다른 custom model 뿐만 아니라 기존의 제어 가능한 도구들을 이용해 제어 가능한 생성에도 일반화해서 사용할 수 있다는 이점을 가진다. 분리된 cross-attention 전략은 멀티모달 이미지 생성에도 사용될 수 있다. 

  • '기존의 pretrained diffusion model은 고정되어 사용된다' = 'pretrained diffusion model의 가중치를 변경하지 않고 고정한다' -> 모델의 핵심 구조와 학습된 패턴을 유지할 수 있음. 
  • '기존의 제어 가능한 도구' = '특정 속성을 조절하는 메커니즘'.
    ex) 특정 색상, 스타일 또는 이미지 내 객체의 배열과 같은 요소들을 사용자가 직접 조정하고 조절할 수 있음을 의미함.

 

Introduction

사용자는 강력한 text-to-image diffusion model (ex: GLIDE, DALL-E, Imagen, Stable Diffusion, eDIFF-I, RAPHAEL 등)을 사용해 text prompt를 작성해 이미지를 생성할 수 있다. 하지만 원하는 이미지를 생성하기 위해서 좋은 text prompt를 작성하는 것은 쉽지 않다. 복잡한 프롬프트 엔지니어링이 필요한 경우도 많고, 또한 텍스트만으로 복잡한 장면이나 개념을 표현하기에는 정보가 부족할 수도 있기 때문이다. 

이러한 text prompt의 단점을 극복하기 위해 사용될 수 있는 것이 바로 image prompt이다. 이미지는 텍스트에 비해 더 많은 내용과 디테일들을 표현할 수 있기 때문이다. "이미지는 천 마디 말보다 가치 있다"는 말처럼 말이다. 

그러나 대부분의 기존 text-to-image diffusion model은 텍스트에서 이미지를 생성하기 위해 텍스트를 조건화(conditioned)한다. 그 예로 SD model은 고정된 CLIP text encoder에서 추출한 text feature를 조건화한다. 이 때 위 논문의 IP-Adapter는 이러한 text-to-image diffusion model에 image prompt를 사용해 간단한 방식으로 생성 기능을 활성화하려고 시도한다. 

  • 고정된 CLIP text encoder를 사용하면, 인코더의 가중치나 파라미터가 학습 과정에서 업데이트 되지 않고 초기 상태 그대로 유지된다. 인코더의 학습이 더 이상 진행되지 않는 이러한 접근 방식은 특정 도메인이나 맥락에 대해 더 잘 최적화될 수 있는 기회를 제한시킬 수 있다. (유연성의 제한)

 

prior work

1) SD Image Variations2 & StableunCLIP3

: image prompt의 구현을 향상시키기 위햇는 이미지 임베딩에 직접 text-conditioned diffusion model을 fine-tuning하는 것이 효과적이다는 사실이 드러났다. 하지만 이러한 방식은 다음과 같은 단점이 존재한다. 

  • 텍스트를 사용해 이미지를 생성하는 원래의 기능이 제거되고, 이러한 fine-tuning에는 많은 컴퓨팅 리소스가 필요한 경우가 많다.
  • fine-tuning된 model은 재사용할 수 없다.
    • fine-tuning된 text-to-image model은 특정 작업에 대해서는 우수한 성능을 보이지만, 그 능력이 다른 custom model로 쉽게 전달되거나 재사용되기 어려움
  • 새로운 모델은 downstream application에 상당한 문제를 야기할 수 있다. 
    • downstream application : 특정 기술, 프로세스, 데이터셋 또는 시스템을 기반으로 개발된 응용 프로그램이나 작업. 'downstream'이라는 용어는 원래의 출발점이나 기본 기술로부터 파생된 후속 작업을 의미함.

이러한 fine-tuning의 단점 때문에 일부 연구에서는 diffusion model의 fine-tuning을 피하면서 text encoder를 image encoder로 대체하는 방법을 선택하기도 한다. 

 

2) Prompt-free diffusion: Taking" text" out of text-to-image diffusion models

: fine-tuning의 단점 때문에 diffusion model의 fine-tuning을 피하면서 text encoder를 image encoder로 대체하는 방법을 선택한 연구이다. 하지만 이러한 방식도 아래와 같은 단점이 존재한다 .

  • 처음에는 image prompt만 지원되므로 사용자가 텍스트와 이미지 prompt 둘을 동시에 사용해 이미지를 만들 수 없다.
  • image encoder를 fine-tuning하는 것만으로는 이미지의 품질을 보장할 수 없고, 일반화 문제가 발생할 수 있다. 

 

따라서 위 IP-Adapter 논문에서는 원본 text-to-image model을 수정하지 않고도 image prompt 기능을 구현할 수 있는지에 의문을 가졌다. 기존의 다른 adapter들의 연구에서 얻을 수 있는 내용은 아래와 같다. 

 

 

3) ControlNet & T2I-adapter

: text-to-image diffusion model에 추가적인 네트워크를 효과적으로 연결해 이미지 생성을 더 효과적으로 할 수 있게끔 해주었다. 특히 레퍼런스 이미지에서 제공하는 스타일이나 콘텐츠를 적용한 이미지 생성에도 성공적으로 사용된다. 이러한 작업을 위해 CLIP image encoder엣 추출한 image feature를 학습 가능한 network를 통해서 새로운 feature에 매핑한 다음, text feature와 연결한다. 이렇게 원본 text feature를 대체함으로써 병합된 feature들은 diffusion model의 UNet에 공급되어 이미지 생성을 안내한다. 이러한 adapter는 image prompt를 사용할 수 있는 기능으로 볼 수 있지만, 생성된 이미지는 image prompt로 제시된 원본 이미지의 특정 측면만을 반영하고 전체적으로는 다를 수도 있다. 

  • ControlNet : SD 기반으로 구축된 인공신경망 모델. SD의 가장 기본적인 형태는 text-to-image로 텍스트 프롬프트에 조건부여(conditioning)로서 입력하면, 이를 바탕으로 이미지를 생성하는 것임. ControlNet은 조건부여를 하나 더 추가하는 것. 

 

 

위 논문에서는 위 방법들의 주 문제점은 text-to-image diffusion model의 cross-attention 모듈에 있다고 주장한다. pretrained 된 diffusion model에서 cross-attention layer의 key와 value 값을 정사영하는 가중치는 텍스트의 피쳐를 잘 적용하도록 학습된다. 그 결과 이미지 특징(파쳐)과 텍스트 특징을 cross-attention layer에 병합하면 이미지 피쳐를 텍스트 피쳐에 정렬하는 작업만 수행되지만, 일부 이미지별 정보가 누락될 가능성이 있으며 결국에는 reference image로 제어 가능한 세분화된 정보(예: 이미지 스타일)만 생성될 수 있다. 

 

이러한 단점을 피하기 위해 논문에선 IP-Adapter라는 이미지 프롬프트 어댑터를 제안한다. IP-Adapter는 가볍지만 효율적인데, 아래와 같은 특징을 지닌다. 

  • 텍스트 피쳐와 이미지 피쳐에 대해 분리된(decoupled) cross-attention 메커니즘 사용
    • diffusion model 속 UNet의 모든 cross-attention layer에 대해 이미지 피쳐에 대해서만 추가적인 cross-attention layer를 추가함.
    • 훈련 단계에서 새로운 cross-attention layer의 파라미터만 훈련되고, 원래의 UNet 모델은 고정된 상태로 유지됨.
    • 이미지 프롬프트와 텍스트 프롬프트가 호한되어 멀티모달 이미지 생성이 가능함.
  • 2200만 개의 매개변수만 존재 -> 성능은 text-to-image diffusion model에서 완전히 finetuned된 이미지 프롬프트 모델과 비슷함.
  • 일반화 기능이 뛰어나고 text prompt와 호환됨. 
  • ControlNet과 같은 다른 제어 가능한 어댑터와 호환됨.

pretrained text-to-image diffusion model에 제안한 IP-Adapter를 적용한 다양한 스타일의 이미지 합성

 

 

Related Work

Text-to-Image Diffusion Models

대규모의 text-to-image model은 크게 autoregressive model과 diffusion model의 두 가지 범주로 나뉜다. 

1. Autoregressive model - ex) DALLE, CogView, Make-A-Scene

: VQ-VAE와 같은 이미지 tokenizer를 사용해 이미지를 token으로 변환한 다음, text token을 조건으로 하는 autoregressive transformer(자동 회귀 트랜스포머)를 학습시켜 이미지 token을 예측한다. 하지만 고품질 이미지를 생성하기 위해 많은 양의 파라미터와 컴퓨팅 리소스가 필요한 경우가 많다. 

 

2. Diffusion model - ex) GLIDE, DALL-E 2, Imagen, Re-Imagen, SD

: 현재 텍스트만 조건으로 하는 text-to-image diffusion model에 이미지 프롬프트를 지원하기 위한 작업이 진행중이다. fine-tuning model은 이미지 프롬프트를 사용해 이미지를 성공적으로 생성할 수 있지만 상대적으로 많은 학습 비용이 필요하고, 기존 도구(예: ControlNet)과 호환되지 않는 경우가 많다. 

 

Adapters for Large Models

사전 학습된 대규모 모델을 fine-tuning하는 것은 비효율적이므로, 훈련 가능한 매개변수를 몇 개 추가하되 원래 모델을 고정하는 어댑터를 사용하는 것이 그에 대한 대안이 될 수 있다. 어댑터(Adapter)는 NLP 분야에서 오랫동안 사용되어 왔는데, 최근에는 대규모 언어 모델에 대한 시각 언어 이해를 달성하기 위해 사용되고 있다. 

또한 최근 text-to-image model이 인기를 끌면서 text-to-image model 생성을 위한 추가적인 control을 제공하는 데도 어댑터가 사용되었다. 

  • ControlNet : pretrained text-to-image diffusion model로 어댑터를 훈련해 작업별 입력 조건을 학습할 수 있음을 증명함. 사용자가 제공한 이미지로 생성 유도 & 학습 없이 간단한 피쳐 삽입을 통해 SD 모델에서 이미지 변형 가능
  • T2I-adapter : 생성된 이미지의 색상과 구조를 간단한 어댑터로 제어 가능함을 증명함. 스타일 어댑터가 CLIP Image encoder에서 추출한 이미지 피쳐에 텍스트 피쳐를 추가해 reference image를 사용해 생성된 이미지의 스타일을 제어할 수 있도록 설계됨
  • Uni-ControlNet : fine-tuning 비용을 줄이기 위해 multi-scale condition injection 전략을 제시 

어댑터는 위의 구조 제어용 역할 외에도 제공된 이미지의 콘텐츠와 스타일에 따라 제어 가능한 생성을 위해서도 사용된다. 위의 어댑터들은 가볍지만 fine-tunedimage prompt model과 성능면에서 한참 떨어진다. IP-Adapter의 decoupled cross-attention mechanism은 간단하고 작지만 이전 어댑터 방법보다 성능이 뛰어나고 심지어 fine-tuned model과 비슷한 성능을 보인다. 

 

 

Method

Prelimiaries

Diffusion model은 두 가지의 프로세스로 구성된 생성 모델의 한 종류로, 고정된 Markov chain의 T step을 사용해 데이터에 가우시안 분포를 점진적으로 추가하는 diffusion process(forward process)와 학습 가능한 모델을 사용해 가우시안 노이즈에서 샘플을 생성하는 denoising process로 구성된다. 이때 diffusion model은 text-to-image diffusion model의 경우 텍스트와 같은 다른 입력에 따라 조건이 설정될 수도 있다. 

일반적으로 노이즈를 예측하는 diffusion model의 training object(훈련 목표)는 ϵ_θ로 표시되며, 이는 변형 바운드(variatioal bound)의 단순화라고 정의된다. 

 

  • 변형 바운드(variational bound) 

 

  • x_0 : 추가 조건 c가 있는 실제 데이터
  • t∈ [0, T] : diffusion process의 time step
  • xt = αtx0 + σtϵ : t step의 noisy data
    • αt , αx : diffusion process를 결정하는 predefined functions

모델 ϵ_θ가 trained되면 random noise로부터 이미지를 생성한다. 일반적으로 inference 단계에서는 생성 과정을 가속화하기 위해 DDIM, PNDM, DPM-Solver등의 고속 sampler를 사용한다.

 

conditional diffusion model에서의 classifier guidance는 별도로 trained된 분류기의 기울기를 활용해 이미지의 충실도와 샘플 다양성의 균형을 맞추는 데 사용되는 간단한 기법이다 .분류기를 독립적으로 훈련할 필요를 없애기 위해 분류기 없는 guidance(classifier free guidance)가 대체 방법으로 사용된다. 

  • classifier-free guidance : conditional diffusion model과 unconditional diffusion model을 jointly trained(동시에 훈련)하는 과정에서 훈련 중에 무작위로 c(예: 텍스트 설명)를 생략함으로써 독립적인 분류기를 훈련할 필요가 없어짐
    • 조건부 확산 모델 : 특정 조건(예: 텍스트 설명)에 기반하여 샘플(예: 이미지)를 생성하는 모델
    • 비조건부 확산 모델 : 조건 없이 샘플을 생성하는 모델. 일반적인 데이터 분포에서 샘플 생성
    • text-to-image diffusion model에서 classifier free guidance는 생성된 샘플의 image-text alignment를 향상시키는 데 중요한 역할을 함

classifier-free guidance에서 조건부와 비조건부 예측을 가중 평균해 최종 예측을 얻는 formulation

 

  • w : guidance weight(scale)
    • 조건 c에 따라 정렬을 조정하는 스칼라
  •  ϵ_θ(x_t,c, t) : 조건 c가 주어졌을 때의 예측
  • ϵ_θ(x_t, t) : 조건 없이 만들어진 예측

본 연구의 IP-Adapter는 오픈 소스 SD 모델을 기본 모델로 활용해 구현됐다. SD는 고정된 CLIP 텍스트 인코더에서 추출한 텍스트 특징에 다라 조건이 설정된 latent diffusion model을 의미한다. architecture는 UNet을 기반으로 하고, Imagen과 같은 pixel-based 확산 모델에 비해 pretrained auto-encoder의 latent space에 구축되기에 더 효율적이다. 

 

Image Prompt Adapter

image prompt adapter : pretrained text-to-image diffusion model이 image prompt가 있는이미지를 생성할 수 있도록 설계되었다. 

현재의 어댑터는 fine-tuned image prompt model이나 처음부터 trained된 모델의 성능을 따라잡는 데 어려움을 겪고 있다. 그 가장 큰 이유로는 사전 학습된 모델에 이미지 피쳐를 효과적으로 임베드할 수 없기 때문이다. 대부분의 방법은 단순히 연결된 피쳐를 고정된 cross-attention layer에 공급하기 때문에 diffusion model이 image prompt에서 세분화된 특징을 포착하지 못한다. 이 문제를 해결하기 위해 IP-Adapter는 새로 추가된 cross-attention layer에 이미지 피쳐를 임베드하는 decoupled cross-attention (분리된 cross-attention) 전략을 제시한다.

  • decoupled cross-attention mechanism : 텍스트 피쳐와 이미지 피쳐에 대한 cross-attention layer를 분리
    • 텍스트와 이미지 프롬프트를 모두 사용해 이미지 생성 과정을 유도하는 다중 모드 이미지 생성에 유용함
    • 사전 훈련된 텍스트에서 이미지로 변환하는 확산 모델에 이미지 프롬프트 기능을 제공하기 위해 설계

IP-Adapter의 전체 아키텍처

 

IP-Adapter는 Image encoder과 decoupled cross attention이 적용된 모듈 두 부분으로 크게 구성되어있다. 

  • Image encoder : 이미지 프롬프트에서 이미지 피쳐 추출
  • decoupled cross-attention : 이미지 피쳐를 pretrained text-to-image diffusion model에 임베드 

 

1. Image Encoder

 

IP-Adapter는 pretrained된 CLIP image encoder model을 사용해 이미지 프롬프트에서 이미지 feature를 추출한다. CLIP image encoder의 global image embedding을 활용하는데, 이는 이미지의 풍부한 콘텐츠와 스타일을 표현할 수 있게 해준다. 

  • CLIP model : 이미지와 텍스트 쌍이 포함된 대규모 데이터 세트에 대해 대조 학습으로 훈련된 멀티모달 모델. 이미지를 고차원 벡터로 변환하는 역할을 함. 
    • global image embedding : 이미지가 변환된 고차원 벡터. 이미지의 전체적인 내용과 구조를 압축적으로 담고 있음. 이미지와 텍스트 사이의 의미적 유사성을 학습하고 이를 기반으로 임지를 분류하거나 특정 쿼리와 관련된 이미지를 검색하는 데 활용될 수 있음. 

학습 단계에서는 CLIP image encoder가 고정된다. global image embedding을 효과적으로 분해하기 위해 훈련가능한 작은 projection network를 사용해 임베딩을 길이 N의 특징 시퀀스로 투영한다. 이때 이미지 피쳐의 차원은 pretrained diffusion model의 텍스트 피쳐의 차원과 동일하다. 본 연구에서는 N=4로 설정했으며, projection network는 linear layer과 Layer normalization으로 구성된다. 

 

2. Decoupled Cross-Attention

이미지 피쳐는 decoupled cross-attention modeule에 적응된 pretrained된 UNet model에 통합된다. 원래의 SD 모델에서는 CLIP text encoder의 텍스트 피쳐가 cross-attention layer에 공급되고 UNet 모델에 연결된다. cross-attention output Z ′는 아래와 같다. 

text cross attention output

  • Z : 쿼리 피쳐
  • c_t : 텍스트 피쳐
  • Q, K, V : attention 연산의 쿼리,키, 값 행렬
  • W_q, W_k, W_v : 훈련가능한 linear projection layer

이미지 피쳐를 넣는 가장 간단한 방법은 이미지 피쳐와 텍스트 피쳐를 연결한 다음 cross-attention layer에 공급하는 것이다. 하지만 논문에서 제안한 decoupled cross-attention mechnism은 이미지 피쳐에 대한 cross-attention layer를 분리한다.

기존 UNet 모델에 이미지 피처를 삽입하기 위해 각 cross-attention layer에 새로운 cross-attention layer를 추가한다. 이미지 피처 c_i가 주어지면 새로운 cross-attention output Z ′은 아래와 같다. 

image cross-attention에도 text cross-attention과 동일한 쿼리(Q)를 사용한다는 점을 유의해야 한다. 이에 따라 각 cross-attention layer에도  W ′ _k, W ′ _v 두 개의 매개변수만 추가하면 된다. 수렴 속도를 높이기 위해 두 매개변수는 W_k, W_v에서 초기화된다. 

  • 동일한 쿼리를 사용하는 이유? -> 이미지와 텍스트 정보를 모두 통합하여 처리할 때 모델의 일관성을 유지하면서도 두 유형의 데이터 간의 상호작용을 효과적으로 학습할 수 있게 도와줌

 

 

image cross attention output

 

그 후 최종 decoupled cross-attention 공식은 아래와 같이 Z ′와 Z ′′의 합으로 구성된다.

 

 

 

 

3. Training and Inference

training은 pretrained diffusion model의 파라미터를 고정한 상태로 유지하면서 IP-Adapter만 최적화한다. 또한 원본 SD와 동일한 training objective를 사용해 image-text pairs1으로 데이터 세트에 대해 훈련된다. 

변형바운드

 

inference 단계에서 classifier-free guidance로 training할 수 있도록 image conditions를 무작위로 drop한다. 

 

여기서는 이미지 condition이 삭제되면 CLIP image embedding을 0으로 처리한다. 

text cross-attention과 image cross-attention이 분리되어 있기 때문에 inference 단계에서 아래와 같이 이미지 조건의 가중치를 조정할 수도 있다. 

 

  • λ : 가중치 계수. λ=0이면 원본 text-to-image diffusion model(Attention(Q, K, V)이 된다. 

 

Experiments

 

 

 

 

 

 

IP-Adapter: 너무 많아서 정리한다 (internetmap.kr)

 

IP-Adapter: 너무 많아서 정리한다

IP-adapter(Image Prompt adapter)는 이미지를 프롬프트로 사용할 수 있는 스테이블 디퓨전 애드온입니다. IP-adapter를 사용하면 참조 이미지로부터 스타일, 구도, 얼굴을 복사할 수 있습니다. 이 글에서는

www.internetmap.kr

스테이블디퓨전 IP-Adapter 완벽 튜토리.. : 네이버블로그 (naver.com)

 

스테이블디퓨전 IP-Adapter 완벽 튜토리얼 1편

안녕하세요. 오늘은 스테이블디퓨전 WebUI 에 최근 추가된 어뎁터인 IP-Adapter의 기능에 대해 설명...

blog.naver.com

ControlNet 익스텐션 - 이미지 생성 AI 활용 (wikidocs.net)

 

ControlNet 익스텐션

[ControlNet](https://github.com/lllyasviel/ControlNet)은 복잡한 모델을 제어하는 신경망 구조다. 사용자가 원하는 추가 입력 조건을 받아…

wikidocs.net

Stable diffusion, Control.. : 네이버블로그 (naver.com)

 

Stable diffusion, ControlNet 용어공부

ComfyUI 가지고 깨작깨작하다가 남의 노드 갖다 쓰려니 아는게 없어서 공부 중 뭐하나 수정하면 에러를 ...

blog.naver.com

 

paper : https://arxiv.org/pdf/2307.01952.pdf


Abstract

SDXL은 이전 버전의 Stable diffusion에 비해 아래와 같은 차별점을 가진다. 

  • 3배 더 큰 UNet 백본 사용
  • 모델 파라미터 수의 증가 (35억개 -> 66억개)
    • 두 번째 텍스트 encoder를 사용하여 더 많은 attention block과 더 큰 cross-attention context를 사용하기 때문
    • 기존의 LDMs보다 더 다양한 단어를 인지하고 사실적인 디테일 표현 가능 (편의성 뛰어남)
  • 여러가지 conditioning 체계를 설계 & 여러 측면에 대해 SDXL를 훈련함
    • 간단하면서도 효과적인 두 가지 추가 컨디셔닝 기법 존재
  • 정제 모델(refinement model) 도입 -> 사후 image-to-image 기법을 사용해 시각적 충실도 개선
  • 별도의 확산 기반 세분화

즉, SDXL은 stable diffusion을 이미지에 초점을 맞춰 대폭 개선한 버전이라고 볼 수 있다. LDMs에 비해 텍스트 설명에서 고품질 이미지를 생성하는 기능이 강화된 text-to-image 합성에 보다 집중된 접근 방식을 제공한다. 

또한 LDMs는 latent space에서 작동하고 conditional 이미지 생성이 가능하지만 SDXL은 명시적인 지침이 거의 필요 없는 photorealism과 복잡한 프롬프트를 해석하고 렌더링하는 기능에 중점을 둔다. 

더불어 SDXL은 대규모 파라미터 모델과 refinement process를 활용해 속도 저하나 과도한 컴퓨팅 리소스 요구 없이 robust한 이미지 생성이 가능하다. 

 

Introdction

이미지와 같은 시각 미디어 제작 분야에서 LDMs는 최첨단 블랙박스 이미지 생성 모델이 아키텍처의 불투명성으로 인해 그 성능을 충실히 평가하고 검증할 수 없다는 문제점을 가지고 있었다. 불투명성으로 인해 재현성이 감소하고, 혁신이 저해됐으며, 커뮤니티가 이러한 모델을 기반으로 과학과 예술의 발전을 도모하는데 방해가 되었다. 또한 비공개 소스 전략으로 인해 이미지 생성형 모델의 편견과 한계를 객관적인 방식으로 평가할 수 없었다. SDXL은 블랙박스 이미지 생성 모델과 경쟁할 수 있는 개방형 이미지 생성 모델로의 역할을 한다. 

 

Improving Stable Diffusion

LDMs의 확장으로 구현되었지만, 대부분 pixel space에도 적용이 가능하다. 

LDMs와 SDXL의 비교

 

 

SDXL은 Stable Diffusion보다 성능이 기본적으로도 월등히 뛰어나지만, 추가적인 개선을 통해 더 성능을 향상시킬 수 있다. 

 

pipeline 시각화

 

 

  • SDXL을 사용하여 128 * 128의 초기 latent image 생성 -> 특화된 high-resolution refinement model 활용 & 동일한 프롬프트 사용해서 첫 번째 단계에서 생성된 latent image에 SDEdit 적용  

프롬프트 입력 시 기본 Base 모델을 사용해 latent 이미지를 생성하고 최종 노이즈 제거 단계에 특수한 Refiner 모델을 사용해 추가적인 처리를 거친 후 높은 해상도의 이미지를 생성한다. 

기존 Stable Diffusion에서 생성한 이미지를 확대하면 퀄리티가 떨어지던 문제를 이제는 더이상 업스케일링 할 필요 없이, 한 번에 고퀄리티의 이미지를 생성할 수 있게 된 것이다. 

 

1. Architecture & Scale

컨볼루션 UNet architecture는 diffusion-based 이미지 합성을 위한 독보적인 아키텍처로 사용되어 왔다. 그러나 기본 DMs의 개발과 함께 기본 아키텍처 또한 지속적으로 발전해왔다.

기존 stable diffusion과 SDXL 비교

 

1. Transformer blocks

: Transformer 계산을 UNet의 하위 레벨 기능으로 이동시: UNet 내에서 transformer blocks의 이질적인 분포를 활용함

  • 효율성을 위해 가장 높은 피처 레벨에서 transformer block을 생략함 
    • 가장 높은 피처 레벨 : 입력 이미지가 가장 많이 downsampling된 상태. 이미지의 전체적인 구조와 가장 추상적인 특징들이 표현됨
    • transformer block은 상대적으로 많은 계산 자원을 요구하는데, 따라서 가장 높은 피처 레벨에서 transformer block을 생략함으로써 모델의 전체적인 계산 부담을 줄이고 효율성을 높일 수 있음
  •  낮은 레벨(=입력 이미지에 가까운 초기 레이어)에서 2개와 10개의 transformer block을 사용함
  • UNet architecture에서 가장 낮은 레벨(8*downsampling)을 완전히 제거함
    • UNet의 인코딩 단계(축소 경로) 전체를 거치지 않는다는게 아니라 인코딩 단계 중 가장 깊은 부분, 즉 이미지가 가장 많이 축소되는 마지막 단계나 레벨을 제외시킨다는 의미임!

UNet의 downsampling 구조

 

 

2. Channel mult (채널 확장 비율)

: SDXL이 feature map의 채널 수를 조정하는 데 [1, 2, 4]의 비율을 사용함. 모델이 깊어질수록(더 깊은 레이어로 갈수록) 특징 맵의 채널 수가 이 비율에 따라 증가함.

  • 기본값 [1] : 모델의 초기 레이어나 블록에서는 기본 채널 수를 사용함 (예: c)
  • 첫 번째 확장 [2] : 다음 레벨의 레이어나 블록에서는 채널 수를 2배로 증가시킴 (예: 2c)
  • 두 번째 확장 [4] : 더 깊은 레이어나 블록에서는 초기 채널 수의 4배로 증가시킴 (예: 4c)

채널의 확장은 모델이 깊어질수록 더 많은 특징을 포착할 수 있도록 돕는다. 채널 수를 조정함으로써 모델은 계산 효율성을 유지하면서도 feature map의 복잡도를 증가시킬 수 있다. 

SD는 [1, 2, 4, 4]의 비율을 이용하는데, 세 번째 레벨에서 채널 수를 4배로 증가시키고, 마지막 레벨에서 채널 수를 4배로 유지시킨다. 이는 마지막 두 레벨에서 채널 수의 증가를 멈추고 모델의 깊이가 더해짐에도 불구하고 채널 수를 일정하게 유지하며 계산 효율성을 높이고 과적합을 방지할 수 있다는 의미이다. 

SDXL의 [1, 2, 4]는 모델이 더 깊어질수록 채널 수가 계속 증가하는 경향을 보이는데, 이는 모델의 더 깊은 레벨에서도 복잡한 특징을 효과적으로 포착하고자 하는 의도를 반영한다. SD의 [1, 2, 4, 4]는 비교적 초기 단계에서 채널의 수를 빠르게 증가시키고 마지막 두 단계에서는 채널 수의 증가를 멈춘다. 이는 더 깊은 레벨에서는 채널 수를 고정시키고 계산 리소스를 보다 효율적으로 사용하려는 의도로 해석할 수 있다. 

 

 

3. Text Encoder

: 텍스트 conditioning에 T사용하는 더 강력한 사전 학습된 text encoder를 선택하였다. 두 번째 텍스트 인코더 출력을 채널 축을 따라 연결하는 CLIP ViT-L과 함께 OpenCLIP ViT-bigG를 사용한다. cross-attention layer를이용해 텍스트 입력에 대한 모델을 컨디셔닝 하는 것 외에도 OpenCLIP 모델에서 풀링된 텍스트 임베딩에 대한 모델을 추가로 컨디셔닝 했다. 이로 인해 UNet 모델의 크기는 2.6억개 파라미터가 된다. 

 

2. Micro-Conditioning

Conditioning the Model on Image Size

latent diffusion model의 가장 큰 단점으로는 2단계의 아키텍처로 인해 모델 학습에 사용되는 이미지가 일정 크기 이상이어야 한다는 것이었다. 이 문제를 해결하기 위해서는 아래의 두 가지 방법이 존재한다. 

1. 최소 해상도 이하의 모든 훈련 이미지를 버린다. - 예: stable diffusion 1.4/1.5는 512 pixel 이하의 모든 이미지를 버림

: 원하는 해상도에 따라 다르지만 학습 데이터의 상당 부분이 버려져 성능이 저하되고 일반화에 문제가 생길 수 있다. 

2. 너무 작은 이미지를 upscaling한다. 

: 일반적으로 최종 출력 이미지에 업스케일링 결함이 발생해 이미지가 흐릿해지는 등의 문제가 발생할 수 있다. 

 

대신 위 논문에서는 원본 이미지의 해상도에 따라 훈련 중에 간단하게 사용할 수 있는 UNet 모델에 condition을 제안한다. 특히 이미지의 원본(리스케일링 전) 높이와 너비를 모델 c_size = (h_original, w_original)에 대한 추가 conditioning으로 제안한다. 각 구성 요소는 푸리에 피쳐 인코딩을 사용해 독립적으로 임베딩되며, 이러한 인코딩은 단일 벡터로 연결되고, 이를 timestep 임베딩에 추가해 모델에 공급한다. 

 

inference시 사용자는 이 size-conditioning으로 원하는 이미지의 겉보기 해상도를 설정할 수 있다. 

 

 

Conditioning the Model on Cropping Parameters

 

stable diffusion은 모델 학습 중에 random cropping을 사용하기 때문에 object가 잘린 형태로 만들어질 수 있다. 

위의 두 줄이 잘린 object(머리 잘린 고양이)

 

PyTorch는 동일한 크기의 텐서를 필요로하고, 동일한 크기가 아닐 경우엔 일반적으로 1) 가장 짧은 크기가 원하는 목표 크기와 일치하도록 이미지 크기를 조정한 다음 2) 더 긴 축을 따라 임의로 이미지를 무작위로 자른다 의 파이프라인을 따른다. 무작위로 자르는 것은 자연스러운 data augmentation이지만, 생성된 sample에 좋지 못한 효과를 유발할 수 있다.

 

이 문제를 해결하기 위해 위 논문에서는 데이터 로딩 중에 푸리에 임베딩을 통해 크롭 좌표 c_top, c_left를 균일하게 샘플링해 모델의 conditioning parameter로 공급한다.

  • c_top, c_left : 각각 수평 축 및 수직 축을 따라 왼쪽 상단 모서리에 잘린 pixel의 양을 지정하는 정수

그 후 연결된 임베딩인 c_crop을 추가적인 conditioning parameter로 사용한다. 

 

결합할 때 c_crop과 c_size를 샘플링하는 방법

 

  • D : 이미지 학습 데이터세트, s : 목표 이미지 사이즈
  • R : resizing 함수, C : cropping 함수
  • 작은 이미지를 목표 크기 s로 resize시키고 uniform discrete 분포에서 c_left와 c_top을 샘플링한다. 
  • (c_top, c_left)의 좌표를 이용해 이미지를 크기 s로 크롭한다. 
  • c_size와 c_crop으로 conditioned된 모델을 학습한다.

 

대규모의 데이터세트는 평균적으로 object가 중심이라는 점을 고려하면 inference 중 (c_top, c_left) = (0, 0)으로 설정해 학습된 모델에서 객체 중심 샘플을 얻을 수 있다. 

이러한 방법은 data bucketing과 같은 다른 방법과 달리 crop으로 인한 data augmentation의 이점을 활용하면서 생성 프로세스에 누출되지 않도록 보장할 수 있다는 장점을 갖는다. 또한 구현이 간편하고 추가적인 데이터 전처리 없이 훈련 중 온라인 방식으로 적용할 수 있다. 

 

 

3. Multi-Aspect Training

실제 데이터 세트에는 size와 aspect-ratio(종횡비)가 매우 다양한 이미지들을 포함한다. 따라서 여러 종횡비를 동시에 처리할 수 있도록 모델을 세밀하게 조정했다. 일반적인 관행을 따라 데이터를 다양한 종횡비의 bucket으로 분할해 pixel 수를 가능한 한 10242 pixel에 가깝게 유지하고, 그에 다라 높이와 너비를 여러 배수로 변경한다. 

최적화 과정에서 training batch는 동일한 bucket(그룹)의 이미지로 구성되고, 각 훈련 단계마다 bucket size를 번갈아 가며 사용한다. 또한 모델은 bucket size(또는 target size)를 정수 c_ar = (h_tgt, w_tgt)의 튜플의 형태로 conditioning 부여를 받아 푸리에 공간에 포함시킨다. 

실제에서는 고정 종횡비 및 해상도로 모델을 사전 학습시킨 후 미세 조정 단계로 다중 종횡비 학습을 적용하고, 채널 축을 다라 연결해 앞의 conditioning 기법과 결합한다. 

 

 

4. Improved Autoencoder

stable diffusion은 autoencoder의 pretrained, learned(and fixed) latent space에서 작동하는 LDM(latent diffusion model)이다. semantic composition의 대부분은 LDM이 수행하지만, 이 autoencoder를 개선함으로써 생성된 이미지의 local, high-frequency detail을 향상시킬 수 있다. 

이를 위해 원래의 SD의 더 큰 batch size(256 vs 9)에서 사용했던 동일한 autoencoder architecture를 훈련하고 지수 이동 평균으로 가중치를 추가적으로 추적한다.

 

 

5. Putting Everything Together

SDXL의 최종 모델은 multi-stage 절차를 통해 훈련된다. SDXL은 4의 autoencoder과 discrete-time diffusion schedule을 사용한다. 

 

Refinement Stage - 이 단계는 선택 사항이지만, 세부적인 배경과 사람의 얼굴에 대한 샘플 품질을 향상시킨다. 

결과 모델은 때때로 부분적으로 품질이 낮은 샘플을 생성할 수 있다. 샘플 품질의 개선을 위해 우리는 동일한 latent space에서 별도의 LDM을 훈련한다. 이 LDM은 고품질, 고해상도 데이터에 특화되어있으며 SDEdit에서 도입한 noise-denoising process를 사용한다. inference 동안 base SDXL 모델에 latent를 렌더링하고, 동일한 text input을 사용해 refinement model에 대해 latent space에서 직접적으로 diffuse와 denoise를 직접 진행한다. 

LDMs와 SDXL의 비교

 

SDXL과 SDXL(with Refiner), stable diffusion 1.5 & 2.1의 네 가지 모델 중 Refiner이 포함된 SDXL 모델이 가장 높은 평가를 받았으며, stable diffusion 1.5 & 2.1을 큰 차이로 능가하는 것으로 나타났다.

cfg scale에 따른 FID와 CLIP score 비교

 

하지만 FID 및 CLIP 등 고전적인 성능 지표를 사용할 경우, SDXL의 개선 사항이 뚜렷하게 나타나지는 않았다. SDXL은CLIP score로 측정한 text 정렬이 이전 버전에 비해 약간 개선되었지만, 인간의 판단과는 일치하지 않는 것으로 나타났다. 

  • CFG Scale : DALL-E, Stable Diffusion과 같은 조건부 생성 모델에서 사용되는 하이퍼파라미터. 값이 높을수록 모델은 입력 조건을 더 강하게 반영해 이미지를 생성하려고 시도하며, 낮을수록 더 자유로운, 혹은 입력 조건과는 다소 독립적인 이미지를 생성하게 됨. 

 

Future Work

모델이 더 개선될 수 있다고 생각되는 측면들은 아래와 같다. 

  • Single stage : 현재는 2단계 접근 방식을 사용하고 있는데, 이를 하나의 단계로 통합하는 방법을 연구할 예정이다.
  • Text Synthesis : 더 큰 규모의 텍스트 인코더를 사용하였으나, 바이트 수준의 tokenizer를 통합하거나 단순히 모델을 더 큰 크기로 확장하면 더 성능이 개선될 것이라고 판단된다.
  • architecture : UViT, DiT와 같은 transformer 기반 아키텍처를 간단히 실험했지만, 하이퍼파라미터에 대한 연구를 더 수행하면 더 큰 규모의 transformer 기반 아키텍처로 확장할 수 잇을 것이라고 기대된다. 
  • Distillation : 기존의 SD model에 비해 개선된 점은 많지만, 추론 비용이 증가하는 대가가 필요하기에 개선이 필요하다. 
  • discrete-time formulation으로 학습을 시켰는데 이 과정에서 오프셋 잡음이 요구된다. continuous-time formulation으로 학습하면 샘플링 유연성이 향상되고 잡음 스케줄 보정이 필요치 않을 것이다. 

 

 

 

 

 

SDXL : 고해상도 이미지 합성을 위한 디퓨전 모델 개선 (internetmap.kr)

 

SDXL : 고해상도 이미지 합성을 위한 디퓨전 모델 개선

스테이블 디퓨전의 후속모델인 SDXL 이 공개되었습니다. 베타버전에 이어 0.9 버전이 공개되었으며, 조만간 정식으로 공개될 예정으로 있습니다. 이 글은 0.9에서 어떤 부분을 개선했는지에 대한 s

www.internetmap.kr

 

[논문리뷰] SDXL: Improving Latent Diffusion Models for High-Resolution Image Synthesis - 전생했더니 인공지능이었던 건에 대하여 (kimjy99.github.io)

 

[논문리뷰] SDXL: Improving Latent Diffusion Models for High-Resolution Image Synthesis

SDXL 논문 리뷰

kimjy99.github.io

 

- 기본 용어와 개념

Image Segmentation & Image Classification

image segmentation : 이미지의 모든 pixel이 어떤 카테고리에 속하는지 분류하는 것

image classification : 이미지 전체에 대해 단일 카테고리를 예측하는 것.

이에 비해 이미지 세그멘테이션은 pixel 단위의 분류를 수행하므로 일반적으로 더 어려운 문제로 인식되고 있다. 이미지 세그멘테이션은 의료 이미지 분석, 자율주행 차량, 증강현실과 같은 광범위한 분야에서 사용되고 있다. 

다양한 task들 존

 

이때, UNet은 매우 적은 수의 학습 데이터로도 정확한 이미지 세그멘테이션을 보여주었다!

 

Patch

쉽게 이해하자면 이미지 인식 단위라 할 수 있다. 위 논문에서는 sliding window처럼 이미지를 잘라 인식하는 단위를 만들었는데, 이게 patch이다. 

Context 

이웃한 pixel들 간의 관계 정도로 표현 가능하다. 글을 읽고 문맥(context)를 파악하듯 이미지 일부를 보고 이미지의 문맥을 파악하는 것을 생각하면 된다. 

 

kernel (= filter = mask)

일반적으로 3*3, 5*5 크기를 갖고 있다. 이미지 위를 일정 간격씩 이동하면서 특징을 추출한다.  

 

합성곱 산술

- stride : 커널의 이동 간격을 결정. 필터를 이동시킬 때 pixel을 (stride 수) * pixel 씩 옮기면서 계산한다. 

- padding : 입력 데이터의 가장자리에 0을 추가해 필터 적용 시 가장자리 정보 손실을 방지하는 역할을 한다. 

- channel : 이미지의 깊이. 각 채널별로 별도의 합성곱 연산을 수행한다.

 

Convolution

합성곱. 데이터의 특징을 추출하는 연산이다. 

 

Convolutional Layer

특징 맵(feature map)을 생성하는 레이어이다. 이미지에서 특징을 추출하고 필터(커널)을 사용 데이터의 특성을 학습한다. 

 

Pooling Layer

특징 맵(feature map)의 크기를 줄여주는 레이어이다. 풀링 층은 채널은 유지하되 이미지의 크기를 줄여주기에 메모리 연산량을 줄일 수 있다. 과적합을 방지하고 계산량을 감소시킨다. 

- Max pooling : 사용자가 지정한 영역에서 최대의 값을 추출하는 방법 . 중요한 정보는 유지한 상태로 해상도(너비와 높이)를 감소시키는 방법. (채널 사이즈는 증가시킴) 피쳐맵에서 가장 큰 특징을 출력함으로써 관련이 낮은 정보들을 지울 수 있음. 

Stride: 2 * 2로 설정

 

Fully Connected layer

모든 뉴런이 이전 레이어의 모든 뉴런과 연결돼있다. 학습된 특징 기반으로 분류 또는 회귀를 수행한다. 

 


Abstract

deep network를 성공적으로 훈련하려면 수천 개의 training sample이 필요하다. 위 논문에서는 data augmentation을 사용해 sample들을 더 효율적으로 사용하기 위한 전략을 제시하고 있다.

  • 아키텍처는 context 캡처를 위해 contracting path(축소 경로) & 정확한 위치 파악을 가능케 하는 symmetric한 expanding path(대칭 확장 경로)로 구성됨
    • 이러한 네트워크는 적은 수의 이미지로 end-to-end 학습을 가능케 하고, sliding-window convolutional network보다 성능이 뛰어나다는 것을 보여줌
    • 속도가 빠름

이 UNet 네트워크는 의약쪽에서 탁월한 효과를 보이는 Segmentation network이다. 기존의 CNN들은 단순 classification에서 주로 쓰였다면, UNet은 classification + localization에서 주로 쓰인다. 

  • localization : 이미지나 객체가 이미지 내의 어디에 위치하는지 알아내는 task. 

 

Introduction

deep convolutional network(CNN)는 이미 오랫동안 사용되었으나, 사용 가능한 훈련 세트의 크기와 고려되는 네트워크의 크기로 인해 성공이 제한적이었다.

CNN은 일반적으로 classification 작업에 사용된다. 특히 visual recognition task에 강점을 가지고 있었는데, 이러한 network의 task는 특히 이미지로부터 하나의 클래스를 예측하는 것이었다. 하지만 biomedical image processing과 같은 visual task에서는 localization을 포함한 출력이 필요했다. 

기존에는 이러한 biomedical image processing을 위한 localization 정보를 얻기 위해서 sliding window 방법을 사용했다.

  • Sliding Window : 사진을 윈도 사이즈에 맞춰 나눈 다음 매 윈도우로 잘린 이미지를 input 값으로 모델을 통과해 결과를 얻는 방법 
  • Sliding-window 방법을 적용해 local region을 제공해 각 pixel의 label을 예측함 = sliding window setup에서 네트워크를 훈련시켜 해당 픽셀 주변의 local 영역(patch)를 input으로 제공함으로써 각 픽셀의 클래스 라벨을 예측하는 방법이다. 

하지만 기존의 위 방법은 아래와 같은 단점이 존재했다. 

 

1. 전체 이미지를 작은 이미지(patch)로 쪼개 모든 영역에 대해 네트워크를 개별적으로 실행하기 때문에 속도 매우 느림

  - 내가 이미 사용한 patch 구역을 다음 sliding window에서 다시 검증 => patch가 겹쳐 중복되는 부분이 많음

  - 이 과정은  이미 검증이 끝난 부분을 다시 검증하는 것이기 때문에 똑같은 일을 반복하는 것이라고 할 수 있음

 

2. patch size에 따라 locaization의 정확도와 context 인식에서 trade-off 관계가 존재

  - patch size가 커진다면 더 넓은 범위의 이미지를 한 번에 인식하는 것이므로 context 인식에는 탁월한 효과가 있으나, localization에서 패널티를 가지게 됨 (patch가 클수록 더 많은 max-pooling layer가 필요하므로 localization 정확도가 떨어지는 것)

  - 너무 넓은 범위를 한 번에 인식하다보니 localization에서 약한 모습을 보이는 것

  - patch size가 작아지면 반대 효과를 가짐 (patch가 작아지면 network에서 context를 거의 볼 수 없음)

 

UNet은 여러 layer의 output을 동시에 검증하면서 localization과 context 인식 두 마리의 토끼를 다 잡을 수 있다!

 

UNet network architecture

UNet은 "fully convolutional network"를 기반으로 아키텍처가 구성된다. 아래 그림에서 contracting path인 왼쪽 파트(down sampling part)와 expansive path인 오른쪽 파트(upsampling part)로 구분할 수 있는데, 왼쪽 파트가 fully connected network를 기반으로 구성된 파트이고, 오른쪽이 UNet에서 변형된 부분이라고 할 수 있다.  UNet의 구조는 데이터의 차원을 축소했다가 다시 확장하는 방식으로 인코더-디코더 기반 모델에 속한다. 따라서 autoencoder와도 유사한 점이 존재한다. 

  • autoencoder : 데이터를 압축해 작은 차원의 표현을 얻기 위한 인공신경망 모델. 데이터를 압축해 중요한 요소를 추출하는 인코더와 이를 다시 복원해 원본을 얻는 디코더 구조로 구성됨. 입력값을 출력값으로 최대한 같게 내보내는 신경망 모델이라고 할 수 있음. 

 

+) autoencoder?

보통 인코딩 단계에서는 입력 이미지의 특징을 포착할 수 있도록 채널의 수를 늘리면서 차원을 축소해나가며, 디코딩 단계에서는 저차원으로 인코딩된 정보만 이용해 채널의 수를 줄이고 차원을 늘려 고차원의 이미지를 복원한다. 하지만 인코딩 단계에서 차원 축소를 거치면서 이미지 객체에 대한 자세한 위치 정보를 잃게 되고, 디코딩 단계에서도 저차원의 정보만을 이용하기 때문에 위치 정보 손실을 회복하지 못하게 된다. 

 

 

 

 

 

UNet의 메인 아이디어는 pooling 연산자가 upsampling 연산자로 대체되는 연속적인 레이어를 추가하는 것이다. 이러한 레이어는 출력의 해상도를 높인다. UNet의 인코더 또는 축소경로(contracting path)와 디코더 또는 확장경로(expending path)는 서로 대칭적이다. 인코더와 디코더를 연결하는 부분을 브릿지(bridge)라고 한다. 

> Contracting part (인코더, downsampling) : 입력 이미지를 점차 축소해 고차원의 특징 추출

 

그림에서 세로 방향의 숫자는 맵(map)의 차원을 표시하고, 가로 방향의 숫자는 채널의 수를 표시한다. 예로 세로 방향 숫자 256 * 256과 가로 방향 숫자 128은 해당 레이어의 이미지가 256 * 256 * 128임을 의미한다. 입력 이미지는 512 * 512 * 3으로 RGB 3개의 채널을 갖고 크기가 512 * 512인 이미지를 나타낸다. 

파란색 박스가 인코더의 각 단계마다 반복되어 나타나는데, 이 박스는 3*3 convolution, Batch Normalization, ReLU 활성화 함수가 차례로 배치된 것을 나타낸다. 이 박스 두 개를 하나로 묶어 한 개의 레이어 블록으로 구현해 사용하면 편리한데, 이 블록 이름을 ConvBlock이라고 한다. 

ConvBlock

 

보라색 박스 안에 한 개의 ConvBlock이 있고 이 박스가 인코더의 각 단계마다 나타난다. 이 박스에서 나오는 출력은 2개로, 하나는 UNet의 디코더로 복사하기 위한 연결선이고, 또 하나는 2*2 max pooilng으로 downsampling하여 인코더의 다음 단계로 내보내는 빨간색 화살선이다. 이 박스도 하나의 레이어 블록으로 구현하여 사용하면 편리한데, 이를 EncoderBlock이라고 한다. 

 

 

 

1. input에서 activaton funnction(ReLU)를 연산 (파란색 화살표)

  • CNN의 연산은 필터(커널)가 슬라이딩 하면서 이루어지는데, 이를 통해 feature map을 형성하게 된다. 필터의 사이즈를 고려할 때 너비와 높이는 달라지지만, 채널의 개수는 동일하게 맞춰줘야 한다. 이 논문에서는 3(높이) * 3(너비) convolution을 2개 이용하였다. 3 * 3 사이즈의 필터를 사용해 슬라이딩 방식으로 계산하므로 계산된 feature map은 input size에서 2씩 감소한 사이즈를 가진다. 

2. max-pooling operation (빨간색 화살표)

  • max-pooling을 진행할 때마다 feature channel를 두 배 증가시켰다. max-pooling이란 중요한 정보는 유지한 상태로 해상도(너비와 높이)를 감소시키는 방법이다. 

Contracting part에서는 Conv 연산들 -> ReLU -> Max Pooing 순서를 반복 진행한다. 

브릿지는 두 개의 파란색 박스로만 구성되어 있으므로 1개의 ConvBlock 레이어로 표현할 수 있다. 

 

downsampling 구조

 

> Expansive part (디코더, upsampling) : 특징들 이용해 원본 이미지의 해상도로 점차 확장하며 세부 정보 재구성

 

 

UNet의 기본 아이디어는 저차원 뿐만 아니라 고차원의 정보도 이용해 이미지의 특징을 추출함과 동시에 정확한 위치 파악도 가능하게 하자는 것이다. 이를 위해서 인코딩 단계의 각 레이어에서 얻은 특징을 디코딩 단계의 각 레이어에 합치는(concatenation) 방법을 사용한다. 인코더 레이어와 디코더 레이어의 직접 연결을 스킵 연결(skip connection)이라고 한다.

 

초록색 박스는 스킵 연결을 통해 인코더에 있는 map을 복사한 것이다. 노란색 박스는 디코더의 하위 단계에서 transposed convolution을 통해 맵의 차원을 두배로 늘리면서 채널의 수를 반으로 줄인 것이다. 두 개의 맵을 서로 합쳐서(concatenation) 저차원 이미지 정보 뿐만 아니라 고차원 정보도 이용할 수 있다. 

디코더의 회색 박스를 한 개의 레이어 블록으로 구현해 사용할 수 있으며, 이를 DecoderBlock이라고 한다. 

 

디코더 그림의 맨 상단의 오른쪽 부분은 UNet의 출력으로 1 * 1 convolution으로 특징 맵을 처리해 입력 이미지의 각 픽셀을 분류하는 세그멘테이션 맵을 생성하는 부분이다. 최종 레이어에서는 1 * 1 convolution을 사용해 각 64개의 component feature vector를 원하는 수의 class에 매핑한다. 컨볼루션 필터의 개수는 분류할 class(카테고리)의 개수이며 활성 함수로는 class 수가 1개라면 sigmoid, 여러 개라면 softmax 함수를 사용한다. 

 

upsampling 구조

 

> strategy

 

UNet은 논문에서 나와있듯 Fully connected layer가 없다. 각 컨볼루션의 유효한 부분, 즉 입력 이미지에서 전체 context를 사용할 수 있는 pixel만 포함된 segmentation map(노란색 박스)만 사용한다. 이러한 overlap-tile strategy는 임의의 큰 이미지를 매끄럽게 분할할 수 있다. 

  • overlap-tile strategy : 큰 이미지를 겹치는 여러 타일(작은 패치)로 분할해 입력으로 사용함. 각 타일을 독립적으로 처리한 뒤 결과를 다시 합치는 방법

 

파란 영역 크기로 이미지를 패치 단위로 잘라 입력으로 사용하면 노란 영역의 segmentation 결과를 얻는다. 타일이 이동하면서 다음 타일에 대한 segmentation을 얻기 위해 이전 입력의 일부분이 포함되기 때문에 overlap-tile이라고 한다. 

Fig.2를 보면 노란색 부분의 segmentation을 예측하기 위해 파란색 부분을 같이 사용한다. 

 

 

  • mirroring extrapolation

input image를 UNet에 통과시켜 나오는 output과 사이즈 측면에서 비교한 것으로, 위 논문에서는 input image size가 572 * 572인 반면 output size는 388 * 388이다. 이는 contracting path에서 padding이 없었기 때문에 점점 이미지 외곽 부분이 없어진 결과이다. 그렇다보니 이미지가 단순 작아진 것이 아니라, 외곽 부분이 잘려나간 것과 가게 되었다. 이를 해결하기 위한 방안으로 mirroring을 택했다. 

 

 

원본 이미지의 경계 부분이 거울에 반사된 것처럼 확장되는 것으로, 맨 바깥쪽 없어지는 부분이 안쪽 이미지와 형태는 같고 거울에 반사된 형태를 가진다. 이처럼 사라지는 부분이 zero-padding이 아닌 mirror padding의 형태로 채워져서 없어진 부분에 대한 보상을 해준다.  

 

 

  • elastic deformation

같은 clas인 object들이 맞닿아 있는 경우 이를 분리하기 위한 문제는 cell segmentation에서 자주 다루어지는 문제이다. 이를 위해 object가 맞닿아 있는 경계의 background에 강한 weighted loss를 줘서 분리한다. 손실함수에 큰 가중치를 부여한다. 

 

 

class ConvBlock(tf.keras.layers.Layer):
  def __init__(self, n_filters):
    super(ConvBlock, self).__init__()

    self.conv1 = Conv2D(n_filters, 3, padding = "same")
    self.conv2 = Conv2D(n_filters, 3, padding = "same")

    self.bn1 = BatchNormalization()
    self.bn2 = BatchNormalization()

    self.activation = Activation("relu")

  def call(self, inputs):
    x = self.conv1(inputs)
    x = self.bn1(x)
    x = self.activation(x)

    x = self.conv2(x)
    x = self.bn2(x)
    x = self.activation(x)

    return x
    
    
class EncoderBlock(tf.keras.layers.Layer):
  def __init__(self, n_filters):
    super(EncoderBlock, self).__init__()

    self.conv_blk = ConvBlock(n_filters)
    self.pool = MaxPooling2D((2, 2))

  def call(self, inputs):
    x = self.conv_blk(inputs)
    p = self.pool(x)
    return x, p
    
    
class DecoderBlock(tf.keras.layers.Layer):
  def __init__(self, n_filters):
    super(DecoderBlock, self).__init__()

    self.up = Conv2DTranspose(n_filters, (2,2),stride =2, padding ="same")
    self.conv_blk = ConvBlock(n_filters)

  def call(self, inputs, skip):
    x = self.up(inputs)
    x = Concatenate()([x, skip])
    x = self.conv_blk(x)

    return x
    
    
 class UNET(tf.keras.Model):
  def __init__(self, n_classes):
    super(UNET, self).__init__()

    self.e1 = EncoderBlock(64)
    self.e2 = EncoderBlock(128)
    self.e3 = EncoderBlock(256)
    self.e4 = EncoderBlock(512)

    self.b = ConvBlock(1024)

    self.d1 = DecoderBlock(512)
    self.d2 = DecoderBlock(256)
    self.d3 = DecoderBlock(128)
    self.d4 = DecoderBlock(64)

    if n_classes == 1:
      activation = "sigmoid"
    else:
      activation = "softmax"

    self.outputs = Conv2D(n_classes, 1, padding = "same", activation = activation)

  def call(self, inputs):
    s1, p1 = self.e1(inputs)
    s2, p2 = self.e2(p1)
    s3, p3 = self.e3(p2)
    s4, p4 = self.e4(p3)

    b = self.b(p4)

    d1 = self.d1(b, s4)
    d2 = self.d2(d1, s3)
    d3 = self.d3(d2, s2)
    d4 = self.d4(d3, s1)

    outputs = self.outputs(d4)

    return outputs

 

 

 

 

[연구실 스터디]3주차 : Segmentati.. : 네이버블로그 (naver.com)

 

[연구실 스터디]3주차 : Segmentation, Localization, Detection

2023년 2월 6일 3주차 스터디 다양한 task들 존재 1. Semantic Segmentation segmentation: 분할 semanti...

blog.naver.com

 

[U-Net] U-Net 구조 (tistory.com)

 

[U-Net] U-Net 구조

이미지 세그멘테이션(image segmentation)은 이미지의 모든 픽셀이 어떤 카테고리(예를 들면 자동차, 사람, 도로 등)에 속하는지 분류하는 것을 말한다. 이미지 전체에 대해 단일 카테고리를 예측하는

pasus.tistory.com

 

[DL] Object Detection (Sliding Windows, YOLO) (tistory.com)

 

[DL] Object Detection (Sliding Windows, YOLO)

Object Detection에는 여러가지 Algorithm이 존재합니다. Sliding Windows Detection YOLO Detection 하나하나 다뤄보겠습니다. Sliding Windows Detection 자동차 감지 알고리즘을 만들고 싶다고 가정해봅시다. 그렇다면,

wooono.tistory.com

 

[바람돌이/딥러닝] UNet 이론 및 코드 리뷰 : 네이버 블로그 (naver.com)

 

[바람돌이/딥러닝] UNet 이론 및 코드 리뷰

안녕하세요. 오늘은 Image Segmentation에 강점을 가지고 있는 U-Net에 대한 이론과 pytorch로 구현한 ...

blog.naver.com

 

paper : [2112.10752] High-Resolution Image Synthesis with Latent Diffusion Models (arxiv.org)

 

High-Resolution Image Synthesis with Latent Diffusion Models

By decomposing the image formation process into a sequential application of denoising autoencoders, diffusion models (DMs) achieve state-of-the-art synthesis results on image data and beyond. Additionally, their formulation allows for a guiding mechanism t

arxiv.org


 

Stabe Diffusion은 2022년 발표된 text-to-image 딥러닝 모델이다. Stable Diffusion은 Latent Diffusion model(LDMs)의 일종이고, 위의 연구를 기반으로 만들어졌다. LDMs가 일반적으로 latent space에서의 확산 과정을 통해 이미지를 생성하는 방식을 사용한다면, Stable Diffusion은 이러한 기본 아이디어에서 추가적으로 사용자 친화적인 기능, 향상된 품질 및 효율성 등의 차별점을 가진다. 

 

+) Stable diffusion과 Latent diffusion은 엄밀히 말하면 다른 개념이다! Latent diffusion은 diffusion model의 한 종류로, latent space에서 denoising diffusion process를 수행하는 방법론을 의미하고, Stable diffusion은 Latent diffusion을 기반으로 학습된 text-to-image 모델의 이름이다. 즉, Latent diffusion은 방법론의 이름이고, Stable diffusion은 Latent diffusion 방법론을 활용해 만든 특정 모델 이름이라고 볼 수 있다. 

 

- LDMs의 핵심 아이디어 : pixel space에서 latent space로의 전환

기존의 Diffusion Model(DM)은 데이터 그 자체에 대해 노이즈를 주고 빼는 것으로 구성되어 있다. 이러한 모델들은 이미지 합성에 큰 성과를 얻었으나, pixel space 내에서 직접 작동하기에 훈련 과정과 inference 과정에서 계산 비용이 많이 발생한다는 단점을 가지고 있었다. 이에 제한된 컴퓨터 자원 안에서 퀄리티와 다양성을 유지하며 훈련시키기 위한 방법으로 사전 학습 되어있는 autoencoder들의 latent space(저차원 공간) 내에서 DM을 적용시켜보자는 주장이 대두되었고, latent diffusion model의 기본 아이디어로 자리잡혔다. 

  • 머신러닝에서의 autoencoder : 입력 차원과 출력 차원이 동일한 모델 구조
  • LDMs에서의 autoencoder : 입력 데이터를 낮은 차원의 잠재 공간(latent space)으로 인코딩하고, 이 잠재 공간에서 원래 입력 데이터를 디코딩해 복원하는 인공 신경망 구조

+) DM은 이미지 공간에서 작동하는데, 이미지 공간은 크기가 엄청나게 크다. 3개의 RGB 채널이 있는 512 * 512 이미지라며느 786,462차원을 필요로한다. Stable Diffusion은 이러한 문제를 latent space로 이미지를 압축한 뒤 연산을 수행해 이러한 문제를 해결한 것이다. latent space는 image space에 비해 48배나 작은 4 * 64 * 64(16,384)이기 때문에 연산이 빨라진다. stable diffusion에서 순방향 디퓨전 및 역방향 디퓨전이 모두 이 latent space상에서 이루어진다. 

 


 

- 일반 생성모델 : 이미지를 두 단계로 학습한다. 

Step 1) Perceptual Compression(지각적 압축) - 인간의 지각에 중점을 둔다

high-frequency details을 제거하지만, 적은 의미적 변동을 학습하는 단계이다. Semantic Compression은 유지되는 구간이다. 주로 이미지나 비디오를 저장하거나 전송할 때, 인간의 시각 체계에 기반해 중요한 정보는 보존하고 데이터를 압축하는 기술을 의미한다. 일반적으로 DM은 이 단계에서 과도한 시간이 걸린다는 특징이 있다. 

Step 2) Semantic Compression(의미적 압축) - 데이터의 의미적 정보에 중점을 둔다

이미지나 데이터의 의미적 및 개념적 구성을 학습하는 단계이다. 이미지나 데이터의 이미적 정보를 보존하면서 압축하는 기술을 의미한다. 

 

두 단계를 거쳐 지각적으로는 동등하지만 계산적으로 더 적합한 공간을 찾아내 DMs를 훈련시킨다. 정리하면, 생성 모델은 처음에 학습을 할 때 Perceptual Compression에서 이미지에 대한 전반적인 형채에 대해 학습하게 되고, 다음으로 Semantic Compression에서 실제 데이터의 본질이 학습되는 것이다. 

 

bit rate에 따른 loss를 바탕으로 GAN, Autoencoder와 LDM을 비교한 그래프

 

 

Bit Rate가 작아질수록 사람의 눈에는 인지가 안되는 부분을 의미한다. GAN과 Autoencoder는 Bit Rate가 비교적 큰 Perceptual한 부분을 학습하는 데에 주력하며, Latent Diffusion Model은 Bit Rate가 작은 Non Perceptual한 부분을 학습하는데에 초점을 맞춘다. 사람 눈에 이 부분은 그다지 중요하지 않은 부분으로, 따라서 Stable Diffusion은 이러한 부분을 개선하여 Perceptual 한 부분에 초점을 맞춰 학습하는 Diffusion Model을 제안한다. 

 

본 논문에서 제안된 모델의 전체적인 구조는

1) Autoencoder + GAN을 통한 원본 이미지의 Perceptual Compression 과정

2) LDM을 통한 Semantic Compression 과정

으로 구성된다. 

1)과 2)는 각각 학습된다. 이는 이전 연구들이 encoder / decoder 아키텍처를 diffusion에 사용했을 때 둘을 score-based 평가 지표를 통해 함께 최적화하던 것에 비해 효율적이다. 

 

디지털 이미지에서 대부분의 bits는 사람이 인지할 수 없는 것들로, DM이 의미 상 필요없는 정보를 제거해 불필요한 계산을 최소화하려고 해도 학습이나 추론 시에 모든 픽셀에 대한 평가를 해야하기 때문에 불필요한 계산이 요구된다. LDMs은 이때 인간이 지각할 수 없는 영역을 제거하는 압축 단계(compressive)를 분리한다. LDMs는 눈에 띄지 않는 세부 사항만을 제거하는 별도의 약한 압축 단계를 포함한다. 

 

- Method

고해상도 이미지 합성에서의 DM의 training 계산 요구를 위해 DM이 loss term을 다운샘플링해 지각적으로 관련이 없는 디테일들을 무시할 수 있게 하더라도, 픽셀 공간에서 비용이 많이 드는 함수의 평가를 필요로 하며, 이는 큰 계산 시간과 에너지 자원이 요구된다. 

  • 고해상도 이미지 = pixel 수 많음 -> 손실 함수 계산에 높은 비용 요구됨
  • 관련이 없는 디테일 무시 & 다운샘플링으로 loss 계산 -> 계산 비용 줄이기 가능
    • 다운샘플링 : 이미지를 축소해 pixel 수를 감소시키는 작업. 이 문장에서의 다운샘플링은 손실 함수 계산에 적용되는 것

위 단점을 피하기 위해서, LDMs에서는 compressive와 generative learning 단계를 명시적으로 분리하는 것을 제안한다. 이미지 공간과 지각적으로 동등한 공간을 학습하면서도 계산 복잡성이 크게 감소한 오토인코딩 모델을 활용한다. 

  • '지각적으로 동등' : 원본 이미지의 주요한 시각적 특성이나 구조를 유사하게 보존한다는 것

 

이런 구조를 통해 얻을 수 있는 장점은 아래와 같다. 

1. 고차원 원본 이미지 공간을 떠남으로써 훨씬 더 효율적인 모델을 만들 수 있다. (이미지 생성(sampling)이 저차원 공간에서 수행되기 때문)

2. DMs이 UNet 아키텍처를 사용하는 것으로부터 얻는 inductive bias를 활용해 공간적인 구조(spartial structure)를 더 잘 활용할 수 있다. 이전에 1차원으로 압축했던 시도들에 비해 좋은 퀄리티를 얻을 수 있다. 

  •  inductive bias : 주어지지 않은 입력의 출력을 예측하는 것. 일반화의 성능을 높이기 위해 만약의 상황에 대한 추가적인 가정(Additional Assumptions)라고 볼 수 있음. 
  • UNet 아키텍처는 이미지 내의 공간적인 구조를 효과적으로 학습하는 inductive bias를 내재하고 있음.
    • UNet : 주로 이미지 분할(image segmentation) 작업에서 사용되는 신경망 구조. 대칭적인 형태를 가지며, 네트워크의 앞부분(encoder)에서는 입력 이미지의 차원을 줄이며 중요한 특징을 추출하고, 뒷부분(decoder)에서는 이 특징들을 확장해 원본 이미지의 크기로 복원함

3. 다른 generative model들을 훈련시키거나 다른 종류의 downstream application에도 활용할 수 있다. (autoencoder의 재사용이 가능하다.)

 

1. Perceptual Image Compression :  autoencoder를 학습하는 과정

perceptual compression model은 perceptual loss(지각적 손실)와 patch-based loss adversarial objective로 훈련된 오토인코더를 사용한다. 이는 local realism을 강화하고 L2와 L1와 같은 pixel space의 손실만을 사용하는 것의 한계를 극복해 블러 현상 피하게 해준다. 

  • 기존의 DMs에서는 loss term(손실항)을 최소화함으로써 의미 없는 정보를 억제할 수 있었는데, gradient와 neural network backbone은 여전히 모든 픽셀에서 계산되어야 했다. 이는 불필요한 계산과 많은 비용이 드는 최적화(optimizer)와 추론(inference)로 이어졌다. 

latent space의 고분산을 피하기 위해 KL-reg를 적용하고, decoder에서 VQ-reg를 적용한다. 기존의 DM은 임의의 1D latent을 사용하지만 LDM은 2D의 latent space를 사용해 가벼운 압축률과 detail한 정보를 보존해 매우 좋은 재현성을 달성할 수 있다. 

 

2. Latent Diffusion Models

Diffusion Models

DMs은 데이터 분포 p(x)를 학습하기 위해 설계된 확률 모델로, 정규 분포된 변수를 점진적으로 잡음 제거함으로써 작동한다. 이는 길이가 T인 fixed Markov Chain의 역과정을 학습하는 것과 동일하다. 

즉, DMs은 데이터의 잡음이 있는 버전에서부터 점차적으로 잡음을 제거함으로써 원본 데이터 분포를 학습하는 방식으로 작동한다. 이 과정은 denoising autoencoder의 sequence로 구성되고, 노이즈가 있는 $x_t$의 노이즈를 제거해 원래의 입력값 x를 예측하도록 학습한다.

기존 DM의 loss function

  • x : 이미지 원본
  • 각 오토인코더 : 시간 단계 t에 따라 입력의 잡음을 점차 줄여나가는 역할
  • Forward diffusion process : 원본 이미지에 노이즈를 점진적으로 더해서 최종적으로 노이즈를 만드는 과정
  • Reverse diffusion process : 노이즈로부터 점차 원본 이미지로 되돌리는 과정

Stable Diffusion은 Latent Diffusion 모델이므로 당연히 Latent Diffusion의 구조를 따른다. Stable Diffusion은 이미지에 노이즈를 주고 이를 다시 역산해 신경망에 노이즈 이미지에서 일반 이미지를 복원시키도록 학습시킨 후, 이 신경망에 노이즈만 들어있는 이미지와 적절한 힌트를 주면 해당 힌트에 맞는 이미지를 출력한다. 이는 Stable Diffusion, 즉 Latent Diffusion 모델에 대한 설명이라기 보다는 Diffusion 모델에 대한 설명인데, Latent Diffusion의 기본적인 이미지 생성 원리도 이와 같지만 더 발전했다.

Diffusion Model Process

Latent Diffusion도 마찬가지로 노이즈에서 복원하는 것은 같지만, 이미지를 바로 복원하는 것이 아니라 Latent vector를 복원한 후, 이 Latent vector가 다시 VAE를 거쳐야 이미지가 되는 것이다. 

  • θ : denoising 과정을 수행하는 신경망의 파라미터
    • forward diffusion process는 신경망 파라미터와 직접적인 관련이 존재하지 않기에 θ와 같은 파라미터가 조건부확률 식에 존재하지 않는 것. forward diffusion process는 일반적으로 미리 정의된 잡음 스케줄에 따라 진행되며, 학습 가능한 파라미터 없이 고정된 함수나 규칙을 사용함.

 

Generative Modeling of Latent Representaions

이미지 생성 중심으로 표현한 Latent Diffusion 모델 구조

  • 빨간색 부분(pixel space) : autoencoder
    • ε : 데이터 x를 latent space로 보내는 encoder. z라는 latent representation으로 보냄
    • D : latent z에서 이미지 복원하는 decoder
    • autoencoder로 정보를 압축해준 덕분에 high frequency와 사람 눈으로 인식이 안되는 noise성 정보들은 모두 제거되었다고 볼 수 있음
    • Stable Diffusion에서는 디코더로 VAE(Variational AutoEncoder) 모델을 사용
  • 초록색 부분(latent space) : latent diffusion model
    • z : Latent Embedding
    • diffusion process : 압축된 z에 noise를 점차 주입해 거의 완전한 noise를 만들고, 랜덤한 noise z_T로부터 이를 복원
  • 회색 부분(conditioning) : 어떠한 condition에 어울릴만한 데이터를 생성하기 위해 추가한 모듈. 입력된 condition은 diffusion model 내부에서 cross-attention 연산을 사용해 적용됨

더 간단한 구조도로 latent diffusion의 main component 3가지에 대해 설명하면 아래와 같다. 

 

Latent Diffusion의 더 간단한 전체 구조도

Part 1. Text Encoder

latent diffusion에서는 prompt 텍스트를 입력받고 그 텍스트에 맞는 이미지를 출력한다. 이를 수행하기 위해 CLIP 이라는 text encoder를 사용한다. text 형태인 prompt를 UNet이 이해할 수 있는 형태, 즉 token으로 변환하는 것이다. text encoder는 Tokenizer를 이용해서 문장에서 단어를 추출해 숫자로 변환하고(tokenize), 이 숫자를 latent vector의 형태인 text embedding으로 만든다. text embedding으로 변환하는 이 과정을 거쳐야 text가 이미지를 생성하는 UNet에 conditioning 할 수 있게 되는 것이다.

  • CLIP (Contrastive Language-Image Pre-Training) : OPEN AI에서 개발한 딥러닝 모델로, 이미지에 대한 텍스트 설명을 설명하기 위해 사용됨.

 

Part 2. UNet

text encoder에서 만들어진 text embedding은 UNet으로 전달된다. UNet에서는 text embedding에 따라 조건화(conditioning)된 채로 random latent vector를 n번 반복해 denoise하는 과정을 거친다. (여기서 랜덤한 노이즈에 이미지를 생성하는 부분이 diffusion 모델의 원리라 할 수 있다. ) 이 반복 전에 어떤 방식(노이즈의 세기, 종류, 확률 편미분 방정식 이용 등)으로 처리하고 반복하느냐를 결정하는 것이 scheduler의 역할이다. scheduler의 종류로는 DDPM, DDIM, PNDM, Euler, Euler a, DPM++ 등이 있다. 

그리고 이 모델은 text embedding에 의해 조건화되었기 때문에 텍스트로 우리가 원하는 내용을 입력해 이미지를 출력할 수 있는 것이다. 이 conditioning 과정은 attention 등의 방법을 사용해 이루어진다. 

위 과정을 모두 거치면 저해상도의 (위 예제에서는 64 * 64) latent vector 값이 생성되게 된다. 이 값은 마지막으로 VAE로 전달된다. 

 

Part3. VAE 

데이터 분포의 latent space를 학습하는데 사용되는 기술이다. encoder는 어떤 값을 수학적 원리를 통해 그 값의 특징을 추출하여 학습하고 decoder는 임의의 값 z(특징에 대한 latent vector)가 주어지면 그 값(latent reresentation)을 바탕으로 원래 데이터(image)로 복원하는 역할을 한다. encoder는 낮은 dimensional latent로 변환하고, 이 변환된 내용은 UNet의 input으로 들어가게 된다. VAE는 그 자체로 하나의 모델이며, 미리 학습되어 준비된 것(Pretrained Model)을 사용한다. 

Latent diffusion 모델에서는 UNet에서 학습되고 이를 바탕으로 생성된 값 자체가 diffusion 모델처럼 이미지의 픽셀과 같은 원본 값이 들어간 게 아니라 VAE에 의하여 encode되어 latent vector화 된 값을 UNet에 학습시킨 것이기에 UNet에서 복원되어 나온 저해상도의 latent vector를 VAE로 다시 Decode하여 고해상도의 그림으로 만들어 준다. 

 

 

 

x를 512 * 512 * 3의 RGB 원본 이미지라고 가정하면, x는 512 * 512 * 3의 pixel space상에 있다고 할 수 있다. 이를 encoder ε를 거쳐 128 * 128 * 16 이라는 보다 저차원의 latent space상의 z로 projection 한다. (latent embedding)

  • z는 h * w * c의 차원을 가지는데, 이는 f라는 하이퍼파라미터로 조정된다.
  • H / f = h의 식으로 조절할 수 있다.
    • f = 8이고 H = 1024라면 h = 1024/8 = 128이 된다.

 

  • f의 값을 너무 높이면 샘플링의 퀄리티가 떨어지는 trade off 관계가 있으나 4~16으로 설정했을 때 좋은 밸런스를 보여준다고 한다. 

이 z에 noise를 점차 주입하는 diffusion process를 따르게 하여 원래 diffusion model의 구조를 사용하게 한다. encoder로 압축된 z에 noise를 점차 주입해 T번의 step 후에 거의 완전한 noise z_T를 만들고, denoising autoencoder의 연결로 z_T를 z로 복원한다. 이때의 denoising autoencoder은 UNet의 구조를 따르고, 이 안에는 transformer도 포함되어 있다. 즉, UNet 구조와 cross-attention을 활용해 z_T를 T번의 denoising step을 거쳐 z로 복원한다. 

  • denoising autoencoder : autoencoder에 의도적인 noise를 삽입한 데이터를 다시 복원하는 autoencoder
  • transformer를 통하면 text to image, image to image, super-resolution 등의 각기 다른 객체들을 attention을 통해 관계를 알 수 있게 되어 condition을 추가해줄 수 있게 된다. 

이 과정들을 거쳐 random noise z_T를 Z로 복원한다. 이 때 z는 아직 latent space 내에 있으므로 이를 decoder D로 h * w * c의 RGB 이미지로 다시 decoding 해주면 우리가 원하는 생성 이미지(~x)를 얻을 수 있게 된다. 

LDM의 loss function

 

loss function을 기존의 DMs와 비교해보면, LDM에서 픽셀값 x가 아닌 latent embedding z가 들어간다는 차이를 볼 수 있다. 이렇게 autoencoder로 정보를 압축해준 덕분에 high frequency와 사람 눈으로 인식이 안되는 noise성 정보들이 제거되었다고 볼 수 있다. 따라서 좀 더 semantic한 부분에 집중할 수 있으면서 계산 복잡도는 줄어든다. 

 

 

3. Conditioning Mechanisms

다른 생성모델과 비슷하게 DMs도 원칙적으로 p(z|y) 형태의 조건부 분포를 모델링할 수 있다. 이는 conditional denoising autoencoder(조건부 잡음 제거 오토인코더) ε_ θ(z_t, t, y)로 구현된다. 

LDMs은 UNet 구조에 cross attention mechanism을 추가함으로써 DMs를 더 유연한 조건부 이미지 생성기로 전환시킬 수 있다. LDMs에서는 다양한 condition을 입력받을 수 있지만 각자에 맞는 적절한 encoder 𝜏가 필요하다. 

입력된 condition은 diffusion model 내에서 연산 중인 이미지 정보 z_T와 연산되어야 한다. 이때 이 둘의 상관관계를 잘 고려해 이미지 정보 z_T에 반영해주어야 한다. 이 과정에서 cross-attention이 사용된다.

  • 서로 다른 정보의 상관 관계를 고려하기 위해 가장 많이 사용되는 방법이 cross-attention이다. 
  • self-attention : 하나의 정보에 대한 상관관계 계산
  • cross-attention : 동일한 메커니즘을 사용해 두 정보의 상관관계를 고려하는 방법

LDMs에 적용된 cross-attention을 수식으로 표현하면 아래와 같다. 

LDMs에 적용된 cross-attention
query, key, value 수식

 

  • z_t : 이미지 정보
  • y : condition 정보

이는 이미지와 condition의 상관관계를 고려해 condition 정보에 가중치를 반영하는 것이라고 해석할 수 있다. 이렇게 가중치가 반영된 condition 정보는 최종적으로 z_t에 다시 더해진다.

 

이렇게 cross-attention까지 적용된 최종 LDMs의 loss function은 아래와 같다.

condition이 추가된 LDMs의 loss function

 

 

 


 

 

 

Stable Diffusion - Diffusion Model 논문 리뷰 (ffighting.net)

 

Stable Diffusion - Diffusion Model 논문 리뷰

Stable Diffusion 논문의 핵심 내용을 리뷰합니다. 먼저 기존 방법의 문제점을 살펴봅니다. 이어서 이를 해결하기 위한 제안 방법을 살펴봅니다. 마지막으로 성능 비교 실험을 통해 Stable Diffusion의 효

ffighting.net

스테이블 디퓨전 원리 알아보기, High-Re.. : 네이버블로그 (naver.com)

 

스테이블 디퓨전 원리 알아보기, High-Resolution Image Synthesis with Latent Diffusion Models 논문 리뷰

안녕하세요, AI 논문 리뷰어 아쿠노트 입니다. 이번 포스팅은 2021년에 공개되고 이제는 많은 사람들이 ...

blog.naver.com

Stable Diffusion이 대체 무엇일까?(Latent Diffusion의 작동 원리) (tistory.com)

 

Stable Diffusion이 대체 무엇일까?(Latent Diffusion의 작동 원리)

요즘 Stable Diffusion 기반의 Novel AI가 큰 인기를 끌고 있다. 그래서 이에 대해 검색해보고 어떤 원리인지 이해하고 나서 정리를 해보았다. 이 글에서는 쉬운 이해를 위하여 자세한 수학적 원리나 매

pitas.tistory.com

 

Sequential API는 직관적이고 편리하지만 단순히 층을 쌓는 것만으로는 여러층을 공유하거나 다양한 종류의 입력과 출력을 사용하는 등의 복잡한 모델을 만드는 일에는 한계가 존재한다. 따라서 Functional API를 사용한다. 

 

Functional API

- 각 층을 일종의 함수로 정의

- 각 함수를 조합하기 위한 연산자를 제공하는데, 이를 이용해 신경망을 설계함

- 입력의 크기(shape)를 명시한 입력층(input layer)을 모델의 앞단에 정의해주어야 함

 

from tensorflow.keras.layers import Input, Dense
from tensorflow.keras.models import Model

inputs = Input(shape = (10, ))
hidden1 = Dense(64, activation = 'relu')(inputs)
hidden2 = Dense(64, activation = 'relu')(inputs)
output = Dense(1, activation = 'sigmoid')(hidden2)
model = Model(inputs = inputs, outputs = output)

model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
# model.fit(data, labels)

 

- Input() : 함수에 입력의 크기 정의

- Model() : 함수에 입력과 출력 정의

 

위 코드는 10개의 입력을 받는 입력층을 보여준다. 그 후 은닉층 2개(hidden1, hidden2)를 추가하고, 출력층(output)을 추가한다. 그 후 Model()로 입력 텐서와 출력 텐서를 정의한다. 

이를 model로 저장하면 sequential API를 사용할 때와 마찬가지로 model.compile, model.fit 등을 사용할 수 있다. 

 

1. 선형 회귀 (Linear Regression)

x = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 공부 시간
y = [11, 22, 33, 44, 53, 66, 77, 87, 95] # 각 공부 시간에 매핑되는 성적

inputs = Input(shape = (1, ))
output = Dense(1, activation = 'linear')(inputs)
linear_model = Model(inputs, output)

sgd = optimizers.SGD(lr = 0.01)

linear_model.compile(optimizer = sgd, loss = "mse", metrics = ['mse'])
linear_model.fit(x, y, epochs = 300)

 

2. 로지스틱 회귀 (Logistic Regression)

inputs = Input(shape = (3, ))
output = Dense(1, activation = "sigmoid")(inputs)
logistic_model = Model(inputs, output)

 

3. 다중 입력을 받는 모델

from tensorflow.keras.layers import concatenate

inputA = Input(shape = (64, ))
inputB = Input(shape = (128,))

# 첫번째 입력층으로부터 분기되어 진행되는 인공 신경망 정의
x = Dense(16, activation = "relu")(inputA)
x = Dense(8, activation = 'relu')(x)
x = Model(inputs = inputA, outputs = x)

# 두번째 입력층으로부터 분기되어 진행되는 인공 신경망 정의
y = Dense(64, activation = 'relu')(inputB)
y = Dense(32, activation = 'relu')(y)
y = Dense(8, activation = 'relu')(y)
y = Model(inputs = inputB, outputs = y)

# 두 개의 인공 신경망의 출력을 연결
result = concatenate([x.output, y.output])

z = Dense(2, activation = 'relu')(result)
z = Dense(1, activation = 'linear')(z)

model = Model(inputs = [x.input, y.input], outputs = z)

 

위 모델은 두 개의 입력층으로부터 분기되어 진행된 후 마지막에는 하나의 출력을 예측하는 모델이다. 

- inputA : 64개의 입력을 받고, 16개의 unit을 가진 Dense 층을 거친 후 8개의 unit을 가진 또다른 Dense 층을 거침

- inputB : 128개의 입력을 받고, 64개, 32개, 8개의 unit을 가진 Dense 층을 차례대로 거침

- 두 경로의 출력이 concatenate()를 통해 결합됨. 결합된 결과는 2개의 unit을 가진 Dense 층을 거친 후 1개의 unit을 가진 Dense 층을 거쳐 최종 출력을 생성함

 

> concatenate()

: 두 개 이상의 텐서를 축(axis)을 따라 결합하는 데 사용

- 첫 번째 인자 : 텐서의 리스트

- axis 매개변수로 어떤 축을 따라 텐서를 결합할지 지정할 수 있음 (기본적으로 axis = 1 : 마지막 차원을 따라 텐서를 결합한다는 의미)

- 두 개의 텐서 AB가 있고, 각각의 형태(shape)가 (batch_size, n)이라고 할 때, 이들을 axis=1을 따라 결합하면 결과 텐서의 형태는 (batch_size, 2n) 가 됨

- 결합되는 축을 제외한 나머지 차원의 크기가 모든 입력 텐서에서 동일해야 함

 

4. RNN(Recurrence Neural Network) 은닉층 사용하기

from tensorflow.keras.layers import LSTM

inputs = Input(shape = (50, 1))
lstm_layer = LSTM(10)(inputs)
x = Dense(10, activation = 'relu')(lstm_layer)
output = Dense(1, activation = 'sigmoid')(x)

model = Model(inputs = inputs, outputs = output)

 

 

 

keras는 딥러닝을 쉽게 할 수 있는 파이썬 라이브러리로, 유저가 손쉽게 딥러닝을 구현할 수 있도록 도와주는 상위 레벨의 인터페이스다. 

 

1. 전처리(Preprocessing)

> Tokenizer()

: 토큰화 & 정수 인코딩을 위해 사용

 

- 토큰화 : 문장을 이루는 단위는 여러가지가 있을 수 있으며 여기서 문장을 다시 일정한 단위로 끊어 컴퓨터가 받아들이도록 하는 작업

  - 영어의 경우 NLTK, 한국어의 경우 KoNLpy, ETRI OPEN API 등으로 토큰화를 진행한다

- corpus(말뭉치) : 토큰화하기에 앞서 여러 문장들로 된, 토큰화 할 하나의 큰 대상

- 가장 쉬운 토큰화 : 공백을 기반으로 한 토큰화. 띄어쓰기로 인해 생기는 공백으로 끊어 각각의 조각(토큰)을 사전으로 만드는 것

  - 사전 : 각각의 토큰에 번호 내지는 인덱스를 부여하는 일

 

from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences

tokenizer = Tokenizer()
train_text = "The earth is an awesome place live"

tokenizer.fit_on_texts([train_text]) # 단어 집합 생성

sub_text = "The earth is an great place live" # 정수 인코딩
sequences = tokenizer.texts_to_sequences([sub_text])[0]

print("정수 인코딩: ", sequences)
print("단어 집합: ", tokenizer.word_index)
정수 인코딩:  [1, 2, 3, 4, 6, 7]
단어 집합:  {'the': 1, 'earth': 2, 'is': 3, 'an': 4, 'awesome': 5, 'place': 6, 'live': 7}

 

great은 단어 집합에 없으므로 출력되지 않는다. 

 

pad_sequence() : padding 작업을 진행

- 정해준 길이보다 길이가 긴 샘플은 값을 일부 자르고, 정해준 길이보다 길이가 짧은 샘플은 값을 0으로 채움

 

전체 훈련 데이터에서 각 샘플의 길이는 서로 다를 수 있다. 모델의 입력으로 사용하려면 모든 샘플의 길이를 동일하게 맞추어야 할 때가 있는데, 이를 자연어 처리에서 패딩(padding)이라고 부른다. 

보통 숫자 0을 넣어서 길이가 다른 샘플들의 길이를 맞춰준다. 

pad_sequence = ([[1, 2, 3], [3, 4, 5, 6], [7, 8]], maxlen = 3, padding = "pre")
array([[1, 2, 3],
       [4, 5, 6],
       [0, 7, 8]], dtype=int32)

 

 

2. 워드 임베딩 (Word Embedding)

: 텍스트 내의 단어들을 밀집 벡터(dense vector)로 만드는 것

- 밀집 벡터(dense vector) = 임베딩 벡터(embedding vector) 

- 인공 시경망의 용어로는 워드 임베딩이란 임베딩 층(embedding layer)를 만드는 역할을 함

- 정수 인코딩이 된 단어들을 입력을 받아서 임베딩을 수행함

 

원핫 벡터는 단어 집합의 크기만큼 벡터의 차원을 가지고, 단어 벡터 간 유사도를 구할 수 없다는 단점이 있었다. 하지만 워드 임베딩으로 얻은 임베딩 벡터는 상대적으로 저차원을 가지고, 모든 원소의 값이 실수이다. 

- 원핫 벡터 : [0 1 0 0 0 0 ... 중략 ... 0 0 0 0 0 0 0]  # 차원이 굉장히 크고 대부분의 값이 0

- 임베딩 벡터 : [0.1 -1.2 0.8 0.2 1.8] # 상대적으로 저차원이며 실수값을 가짐

 

임베딩 벡터는 초기에는 랜덤값을 가지지만, 인공 신경망의 가중치가 학습되는 방법과 같은 방식으로 값이 학습되고 변경된다.

 

Embedding()은 (number of samples, input_length)인 2D 정수 텐서를 입력받는다. 이때 각 sample은 정수 인코딩이 된 결과로, 정수의 시퀀스이다. 

Embedding()은 워드 임베딩 작업을 수행하고 (number of samples, input_length, embedding word dimensionality)인 3D 텐서를 리턴한다.

- number of samples : 단어 집합의 크기. 총 단어의 개수

- input_length : 임베딩 벡터의 출력 차원. 결과로서 나오는 임베딩 벡터의 크기

- input_length : 입력 시퀀스의 길이

# 1. 토큰화
tokenized_text = [['Hope', 'to', 'see', 'you', 'soon'], ['Nice', 'to', 'see', 'you', 'again']]

# 2. 각 단어에 대한 정수 인코딩
encoded_text = [[0, 1, 2, 3, 4],[5, 1, 2, 3, 6]]

# 3. 위 정수 인코딩 데이터가 아래의 임베딩 층의 입력이 된다.
vocab_size = 7
embedding_dim = 2
Embedding(vocab_size, embedding_dim, input_length=5)

# 각 정수는 아래의 테이블의 인덱스로 사용되며 Embedding()은 각 단어마다 임베딩 벡터를 리턴한다.
+------------+------------+
|   index    | embedding  |
+------------+------------+
|     0      | [1.2, 3.1] |
|     1      | [0.1, 4.2] |
|     2      | [1.0, 3.1] |
|     3      | [0.3, 2.1] |
|     4      | [2.2, 1.4] |
|     5      | [0.7, 1.7] |
|     6      | [4.1, 2.0] |
+------------+------------+

# 위의 표는 임베딩 벡터가 된 결과를 예로서 정리한 것이고 Embedding()의 출력인 3D 텐서를 보여주는 것이 아님.

 

- vocab_size : Hope, to, see, you, soon, Nice, again -> 7

- embedding_dim : 텐서 2d -> 2

- input_length -> 5

 

3. Modeling

> Sequential() 

: tensorflow의 keras API에서 제공하는 모델 생성 방식 중 하나로, 인공 신경망의 레이어들을 순차적으로 쌓아서 신경망을 구성할 수 있게 해준다. 각 레이어는 이전 레이어의 출력을 입력으로 받아 처리하고, 그 결과를 다음 레이어로 전달하는 방식으로 작동한다.

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation

model = Sequential()

# 첫 번째 Dense 레이어 추가. 입력 데이터의 차원을 명시해야 함
model.add(Dense(units=64, input_dim=100))

# 활성화 함수 레이어 추가
model.add(Activation('relu'))

# 두 번째 Dense 레이어 추가. 이전 레이어의 출력 차원이 자동으로 입력 차원이 됨
model.add(Dense(units=10))

# 두 번째 활성화 함수 레이어 추가
model.add(Activation('softmax'))

 

model로 Sequential()를 선언한 뒤에 model.add() 코드를 통해 층을 단계적으로 추가할 수 있다. 

Embedding()을 통해 임베딩 층을 추가할 수도 있다. 

model = Sequential()
model.add(Embedding(vocab_size, output_dim, input_length))

 

> Dense()

model = Sequential()
model.add(Dense(1, input_dim=3, activation='relu'))

 

- 첫 번째 인자 : 출력 뉴런의 수

- input_dim : 입력 뉴런의 수 (입력 차원)

- activation : 활성화 함수

 

위 코드의 출력 뉴런과 입력 뉴런을 시각화하면 아래와 같다. 

 

 

Dense()로 layer를 하나 더 추가하면 다음과 같다. 

model = Sequential()
model.add(Dense(8, input_dim=4, activation='relu'))
model.add(Dense(1, activation='sigmoid'))

 

첫번째 사용된 Dense()의 8은 더 이상 출력층의 뉴런이 아니라 은닉층의 뉴런이다.

두 번째 Dense()는 이미 이전 층의 뉴런 수가 8개임을 알고 있기 때문에 input_dim의 인자를 적어주지 않아도 된다. 

이를 시각화하면 아래와 같다. 

 

 

> summary()

: 모델의 정보를 요약해서 보여준다. 

 

4. Compile & Training

> compile()

: 모델을 기계가 이해할 수 있도록 컴파일

- 임베딩층, 은닉층, 출력층을 추가해 모델을 설계한 후 마지막으로 컴파일을 함

 

아래의 코드는 RNN을 이용해 이진 분류를 하는 코드이다. 

from tensorflow.keras.layers import SimpleRNN, Embedding, Dense
from tensorflow.keras.models import Sequential

vocab_size = 10000
embedding_dim = 32
hidden_units = 32

model = Sequential()
model.add(Embedding(vocab_size, embedding_dim))
model.add(SimpleRNN(hidden_units))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])

 

- metrics : 훈련을 모니터링하기 위한 지표를 선택함

 

대표적으로 많이 사용되는 손실 함수와 활성화 함수의 조합은 아래와 같다. 

 

- categorical_crossentropy : one-hot encoding 된 타겟 벡터를 사용함. 

- sparse_categorical_crossentropy : 레이블을 원핫 인코딩하지 않고 정수 인코딩 된 상태에서 수행

 

위 compile() 코드의 연장선상으로 칠 수 있는 코드는 아래와 같다. 

# 훈련 데이터의 20%를 검증 데이터로 사용.
model.fit(X_train, y_train, epochs=10, batch_size=32, verbose=0, validation_split=0.2))

 

 

5. 평가(Evaluation)와 예측(Prediction)

> evaluate()

: 테스트 데이터를 통해 학습한 모델에 대한 정확도 평가

 

> predict() 

: 임의의 입력에 대한 모델의 출력값 확인

 

6. 모델의 저장(Save) & 로드(Load)

> save() 

: 인공 신경망 모델을 hdf5 파일에 저장

- hdf5 파일 : 대량의 과학적 데이터를 저장하기 위해 사용되는 파일 포맷 중 하나. 

 

> load_model()

: 저장해둔 모델 불러오기

과적합을 방지하기 위한 방법으로는

1. 데이터의 양을 늘리기 (Data Augmentation)

2. 모델의 복잡도 줄이기

3. 가중치 규제 (Regularization)

4. 드롭아웃 (Dropout)

등이 존재한다. 

 

그중 드롭아웃이란 학습 과정에서 신경망의 일부를 사용하지 않는 방법이다. 모델에 드롭아웃 레이어를 추가해서 무작위로 선택된 은닉층의 일부 unit이 동작하지 않게 하여 overfitting 되는 것을 방지한다. 

 

위 그림은 은닉층에 50% 드롭아웃을 적용한 경우로, 첫번째 hidden layer에서 50%의 unit만 다음에 오는 hidden layer에 데이터를 전달하는 것이다. 

드롭아웃을 적용하며 실행할 때마다 무작위로 레이어의 unit이 삭제되기 때문에 실행할 때마다 서로 다른 신경망들을 앙상블하여 사용하는 것 같은 효과를 내준다. (서로 다른 네트워크가 된다.)

 

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dropout, Dense

max_words = 1000
num_classes = 46

model = Sequential()
model.add(Dense(256, input_shape = (max_words,), activation = "relu"))
model.add(Dropout(0.5)) # 드롭아웃 비율 50% 추가
model.add(Dense(128, activation = "relu"))
model.add(Dropout(0.5)) # 드롭아웃 비율 50% 추가
model.add(Dense(num_classes, activation = "softmax"))