Published on

SDXL LoRA 학습이 망가질 때 원인 7가지

Authors

SDXL LoRA를 돌렸는데 결과가 갑자기 "망가졌다"고 느껴질 때가 있습니다. 예를 들면 다음과 같습니다.

  • 프롬프트를 줘도 특정 인물/스타일로만 고착되거나, 반대로 아무 특징도 못 잡음
  • 학습이 진행될수록 디테일이 무너지고 노이즈가 늘어남
  • 특정 스텝 이후부터 출력이 급격히 나빠짐(일명 붕괴)
  • 학습 로그상 손실이 내려가는데 결과물은 더 나빠짐

이 글은 SDXL LoRA 학습이 실패하는 패턴을 7가지 원인으로 분류하고, 각 원인별로 증상 → 진단 포인트 → 해결책을 정리합니다. 툴은 kohya_ss/Diffusers 계열을 가정하지만 원리는 동일합니다.


1) 데이터셋 캡션/태그 품질 문제(의미 누수·오염)

대표 증상

  • 특정 배경/워터마크/프레임이 계속 따라옴
  • 인물 LoRA인데 옷/배경이 더 강하게 학습됨
  • 프롬프트를 바꿔도 같은 구도가 반복

왜 망가지는가

SDXL은 텍스트 조건이 강합니다. 캡션이 부정확하거나 불필요한 토큰이 많으면 모델이 원하지 않는 상관관계를 학습합니다. 예: 모든 이미지에 studio lighting을 넣어두면, LoRA가 인물보다 조명을 더 강하게 고착시킬 수 있습니다.

빠른 진단

  • 캡션에 항상 등장하는 단어(편향)를 찾아보기
  • 이미지 파일명/폴더명 기반 자동 캡션이 그대로 들어가 있는지 확인
# 캡션(.txt)에서 자주 등장하는 토큰 TOP N 확인
import os
from collections import Counter

caption_dir = "./train"
words = Counter()

for fn in os.listdir(caption_dir):
    if fn.endswith(".txt"):
        text = open(os.path.join(caption_dir, fn), "r", encoding="utf-8").read().strip().lower()
        for w in text.replace(",", " ").split():
            words[w] += 1

for w, c in words.most_common(30):
    print(w, c)

해결책

  • 캡션을 핵심 속성 중심으로 축약(인물/스타일/의상/헤어/시점 정도)
  • 워터마크, 프레임, 카메라 UI 같은 반복 요소는 캡션에서 제거하거나 이미지에서 제거
  • 스타일 LoRA면 스타일 토큰을 명시적으로 고정하고, 인물 LoRA면 인물 토큰을 고정

2) 해상도·크롭 전략이 SDXL에 맞지 않음(구도 붕괴)

대표 증상

  • 얼굴이 자주 잘리거나, 신체 비율이 깨짐
  • 특정 파츠(눈/손)만 과하게 강조
  • 학습은 되는 듯한데 결과가 "이상하게" 나옴

왜 망가지는가

SDXL은 보통 1024 해상도 기반을 전제로 합니다. 데이터가 저해상도이거나 크롭이 공격적으로 걸리면, LoRA는 부분 특징만 과적합하기 쉽습니다. 특히 인물 데이터에서 랜덤 크롭이 얼굴만 남기면, 전신/포즈 일반화가 무너집니다.

진단 포인트

  • 학습 파이프라인에서 실제로 저장되는 버킷/크롭 결과를 샘플링해 눈으로 확인
  • 원본 이미지의 최소 변이(업스케일/다운스케일) 비율 확인

해결책

  • 가능한 한 SDXL 권장 해상도(예: 1024 계열 버킷)로 구성
  • 인물 LoRA는 얼굴/상반신/전신이 섞이도록 크롭 정책을 조정
  • 극단적 파노라마/세로 긴 이미지는 별도 버킷 혹은 제외

3) 학습률(LR)·스케줄러·옵티마이저 조합이 과격함

대표 증상

  • 초반엔 좋아지다가 특정 스텝에서 급격히 붕괴
  • 샘플 이미지가 점점 "거칠어지고" 디테일이 깨짐
  • 손실이 갑자기 튀거나 nan이 발생

왜 망가지는가

LoRA는 파라미터 수가 적어 보여도, SDXL에서는 텍스트 인코더/UNet의 민감도가 높아 LR이 조금만 과해도 특징이 깨집니다. 특히 텍스트 인코더까지 학습할 때 붕괴 확률이 커집니다.

진단 포인트

  • 스텝별 샘플을 저장해 "좋았던 구간"의 체크포인트가 있는지 확인
  • 로그에서 loss spike, nan, grad_norm 급증 확인

해결책(가이드)

  • UNet LR을 낮추고(예: 1e-4보다 낮게 시작), 텍스트 인코더 LR은 더 낮게(예: UNet의 0.1배)
  • 스케줄러에 워밍업을 넣고, 코사인/리니어 감쇠를 사용
  • AdamW 8-bit 사용 시에도 LR은 보수적으로

Diffusers 예시(학습률/스케줄러 설정):

from diffusers.optimization import get_scheduler

optimizer = torch.optim.AdamW(params, lr=1e-4, weight_decay=1e-2)

lr_scheduler = get_scheduler(
    name="cosine",
    optimizer=optimizer,
    num_warmup_steps=500,
    num_training_steps=total_steps,
)

4) LoRA 랭크/알파 설정이 데이터 규모와 불균형(과적합·표현력 부족)

대표 증상

  • 랭크가 너무 높으면: 특정 샷/표정/배경이 강하게 고착, 프롬프트 자유도가 급감
  • 랭크가 너무 낮으면: 아무리 학습해도 특징이 잘 안 잡힘

왜 망가지는가

LoRA는 저랭크 근사입니다. 데이터가 적은데 랭크가 과도하면 파라미터가 데이터의 잡음을 외워버리고, 반대로 데이터가 다양한데 랭크가 너무 낮으면 표현력이 부족합니다.

진단 포인트

  • 이미지 수 대비 랭크가 과한지(예: 수십 장인데 rank=128 같은 설정)
  • 동일 프롬프트에서 LoRA 강도(weight)를 올릴수록 품질이 나빠지는지

해결책

  • 소규모 인물 데이터(예: 20~80장)면 보통 중간 랭크부터 시작하고 단계적으로 올림
  • alpha는 랭크와 함께 조정(너무 큰 스케일링은 불안정)
  • 과적합이 의심되면 랭크를 줄이거나 학습 스텝을 줄이고, 데이터 다양성(표정/조명/각도)을 늘림

5) 정밀도(fp16/bf16)·그라디언트 스케일링 문제로 수치가 깨짐

대표 증상

  • 중간부터 nan/inf가 발생
  • 손실이 0 근처로 붙거나 갑자기 폭증
  • 같은 설정인데 GPU/드라이버 바꾸면 결과가 달라짐

왜 망가지는가

혼합정밀도는 빠르지만 수치적으로 민감합니다. fp16은 특히 오버/언더플로우가 쉽게 나고, 그라디언트 스케일러 설정이 맞지 않으면 학습이 사실상 망가집니다.

진단 포인트

  • 로그에 nan 체크
  • grad_norm 모니터링

PyTorch에서 간단한 nan 가드:

import torch

def has_nan(t):
    return torch.isnan(t).any().item() if torch.is_tensor(t) else False

# training loop 중간에
if has_nan(loss):
    raise RuntimeError("loss is nan")

해결책

  • 가능하면 bf16을 우선 고려(지원 GPU에서 더 안정적인 편)
  • fp16 사용 시 grad_scaler/clip_grad_norm을 적용
  • 드라이버/CUDA 업데이트 후 갑자기 망가졌다면, 동일 컨테이너/환경으로 고정해 재현성 확보

환경이 꼬였을 때는 캐시/빌드 산출물 영향도 큽니다. CI 관점이지만 캐시 초기화 접근은 비슷하니 GitLab CI 캐시 꼬임 - 빌드 완전 초기화 가이드도 참고할 만합니다.


6) SDXL 특유의 구성요소(텍스트 인코더 2개, refiner 등) 설정 불일치

대표 증상

  • 학습은 했는데 특정 UI/파이프라인에서만 결과가 이상함
  • 같은 LoRA를 base 모델 A에서는 좋은데 base 모델 B에서는 붕괴

왜 망가지는가

SDXL은 보통 텍스트 인코더가 2개이고, base/refiner 흐름이 존재합니다. 학습 시점의 base 모델/텍스트 인코더 구성과, 추론 시점의 구성(모델 버전, VAE, clip 계열)이 다르면 LoRA가 기대한 공간에서 동작하지 않습니다.

진단 포인트

  • 학습에 사용한 base 모델 체크섬/버전 기록
  • 추론 파이프라인에서 동일한 VAE/텍스트 인코더를 쓰는지 확인

해결책

  • 학습 설정을 metadata로 남기기(모델명, 해시, VAE, 해상도, 버킷, LR 등)
  • 배포/공유 시에는 "권장 base 모델"을 명시
  • refiner를 쓰는 워크플로라면 base 단계에서 LoRA가 어떻게 작동하는지 먼저 검증

7) "학습이 아니라 운영"이 망가진 경우: 디스크/프로세스/체크포인트 손상

대표 증상

  • 학습이 중간에 멈추고 재개 후 결과가 이상해짐
  • 체크포인트 파일 크기가 비정상(너무 작음)하거나 로딩 에러
  • 갑자기 I/O 에러, No space left on device 이후부터 결과가 전반적으로 이상

왜 망가지는가

LoRA 학습은 장시간 I/O를 동반합니다. 저장 도중 프로세스가 죽거나 디스크가 꽉 차면 체크포인트가 손상될 수 있고, 재개 로직이 일부 상태(옵티마이저/스케줄러)를 제대로 복원하지 못하면 학습이 "다른 실험"이 되어버립니다.

진단 포인트

  • 저장 직후 파일 해시/사이즈 확인
  • 재개 시 resume이 옵티마이저 상태까지 복원하는지 확인

체크포인트 저장 후 해시 확인 예시:

# 파일 무결성 확인(학습 머신에서 기록해두고 이동 후 비교)
sha256sum ./output/lora.safetensors > lora.safetensors.sha256
sha256sum -c lora.safetensors.sha256

해결책

  • 출력 디렉터리 여유 공간 모니터링, 저장 주기 조절
  • 체크포인트는 원격 스토리지로 주기적 업로드
  • VM에서 학습 중 부팅/스토리지 문제가 의심되면 인프라 레벨 진단도 필요합니다. Azure 환경이라면 Azure VM 부팅 실패? Boot Diagnostics로 복구 같은 절차가 실전에서 도움이 됩니다.

실전 체크리스트: "망가짐"을 30분 안에 좁히는 순서

  1. 샘플링 고정: 같은 시드/프롬프트/네거티브/스텝으로 스텝별 샘플을 비교
  2. 데이터 검수: 크롭 결과/중복 이미지/워터마크/캡션 편향 단어 확인
  3. LR 낮추기: 붕괴가 보이면 UNet LR부터 보수적으로 낮추고 워밍업 추가
  4. 텍스트 인코더 분리: 텍스트 인코더 학습을 끄고 UNet만으로 먼저 안정화
  5. 정밀도 변경: fp16에서 문제가 나면 bf16 또는 스케일러/클리핑 적용
  6. 설정 고정: base 모델/vae/clip 구성과 추론 파이프라인 일치 확인
  7. 무결성 확인: 디스크 용량/체크포인트 해시/재개 로직 점검

운영 자동화로 여러 실험을 돌린다면 실패를 빠르게 수습하는 재시도/백오프도 유용합니다. 학습 잡 재시작(예: OOM 후 재시도, 네트워크 스토리지 오류 후 재시도) 같은 흐름은 Python 데코레이터로 async 재시도·백오프 구현 패턴을 응용할 수 있습니다.


마무리

SDXL LoRA 학습이 "망가지는" 현상은 대체로 데이터(캡션/크롭) + 하이퍼파라미터(LR/랭크) + 수치 안정성(정밀도) + 구성 불일치(SDXL 컴포넌트) + 운영 이슈(체크포인트/디스크) 중 하나로 귀결됩니다.

가장 효율적인 접근은 "감"으로 파라미터를 흔드는 게 아니라, 스텝별 샘플을 고정하고 원인을 하나씩 제거하는 것입니다. 위 7가지를 체크리스트로 쓰면, 대부분의 붕괴 케이스는 재현 가능하게 잡아낼 수 있습니다.