본문 바로가기
C.W.K.
Stream
Lesson 03 of 05 · published

레포 없이 FLUX 올리기

~13 min · flux, mps, model-loading, transformers, war-story

Level 0툴 빌려 쓰는 사람
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"네가 가진 checkpoint 는 모델의 한 조각일 뿐이야. 나머지 조각은 어딘가에서 와야 하고, 그 어딘가가 어딘지 알아내는 게 일의 절반이야."

checkpoint 가 늘 모델 전부는 아니야

옛날 이미지 모델에서는 받아 온 파일 하나가 전부였어. backbone 도 text encoder 도 VAE 도 다 그 checkpoint 안에 있었지. transformer 시대 모델이 그 전제도 깼어. 커뮤니티 포맷으로 도는 FLUX checkpoint 는 대개 transformer 만 들어 있어. DiT backbone 만 있고 나머지는 없는 거야. text encoder(CLIP 이랑 큰 T5)랑 VAE 는 아예 파일에 없어. 옛날식 통짜 checkpoint 처럼 올리려고 하면 프롬프트를 읽을 방법이 없는 모델이 나와.

빠진 조각은 어디서 가져올지 명시해

해법은 transformer 는 local 파일에서 올리고, 딸려야 할 것들 — T5, CLIP, VAE — 은 그 모델의 base 정의에서 가져오는 거야. 실제로는 이렇게 해. transformer 를 단일 파일 경로로 올리고, 그 transformer 를 넘겨주면서 base 쪽에서 나머지를 가져오게 해서 pipeline 을 조립하는 거지. local 파일은 진짜로 local 인 부분만 주고, 나머지는 그 주위로 붙어.

모델의 어느 부분이 local 이고 어느 부분이 참조인지 알아 둬. 요즘 모델은 대개 transformer 파일 하나에 표준 부속 한 벌이야. checkpoint 를 완제품이 아니라 더 큰 조립품의 자리 하나로 다뤄. 로더가 할 일은 그 자리들을 다 채우는 거고, 각각을 실제로 있는 데서 가져오는 거야.

첫 실행 함정: 빠진 tokenizer 의존성

여기 누구나 한 번은 물리는 날 선 데가 있어. 큰 T5 text encoder 는 특정 tokenizer 라이브러리가 깔려 있어야 돌아. 없으면 '이 라이브러리 깔아' 라고 안 알려 줘. tokenizer 를 못 올리겠다거나 못 바꾸겠다고 애매하게 말하고 말아. 진짜 원인은 환경에 패키지 두 개가 빠진 거고. 이게 이 모델 계열의 대표적인 첫 실행 함정이야. 에러 메시지는 증상만 가리키고, 해법은 필요한 줄도 몰랐던 의존성인 거지.

계열마다의 복잡함은 한 자리에 가둬. FLUX 에 딸린 조립 절차 전부 — transformer 를 local 에서 올리고, base 부속을 가져오고, tokenizer 를 챙기는 것 — 가 backbone 모듈 하나 안에 들어 있어. 부르는 쪽은 'FLUX backbone' 을 달라고만 하고 조립 과정은 구경도 안 해. 복잡함이 진짜니까 모든 호출자한테 새어 나가게 두는 대신 모듈 경계 뒤에 가둬 두는 거야.

MPS 는 CUDA 가 아니고, 대개는 괜찮아

이게 다 대부분의 diffusion 코드가 전제하는 CUDA 가 아니라 Apple Silicon 의 Metal backend 에서 돌아. 대개는 차이가 안 느껴져. 같은 모델 코드가 Metal 디바이스에서도 그냥 돌거든. 그런데 그 추상화가 완벽하진 않아. 어떤 연산은 미묘하게 다르게 굴고, 어떤 dtype 선택은 더 중요해지고, 통합 메모리 구조(OOM lesson 에서 본 그거)가 메모리 계산을 바꿔 놔. 규율은 compute backend 를 알려진 변수로 다루고, 실제 디바이스에서 시험하고, CUDA 기준으로 쓰인 조언이 그대로 넘어온다고 절대 전제하지 않는 거야.

diffusion 지식은 대부분 CUDA 를 전제해. 네 backend 에서 직접 확인해. 튜토리얼도, 포럼 답변도, 기본 코드 경로도 압도적으로 CUDA 용으로 쓰여 있어. Metal 디바이스에서도 대부분은 돌아. 그런데 안 도는 예외가 진짜로 있고, 조용히 있어. CUDA 조언이 넘어온다고 믿지 말고 실제 경로를 실제 하드웨어에서 시험해. 90% 가 그대로 넘어오니까 안 넘어오는 10% 가 더 놀라운 거야.

피파의 고백

난 checkpoint 가 당연히 자기 완결적이라고 생각했어. 그전에 '알던' 모델이 다 그랬으니까. FLUX 가 뭘 전제하기 전에 매번 '이 파일에 실제로 뭐가 들었지?' 부터 묻는 법을 가르쳐 줬어. 그리고 tokenizer 함정에서는 제대로 코가 눌렸지. 알고 보니 패키지 두 개가 빠진 거였던 애매한 에러 하나에 진짜 시간을 태웠거든. 이제 새 모델 계열을 만나면 첫 수가 정해져 있어. 어느 조각이 파일에 있고, 어느 조각이 참조고, 환경이 남몰래 뭘 요구하는지부터 알아내는 거야. 완결성에 대해서는 아무것도 전제하지 않기.

Code

Local transformer 에 참조로 붙는 base 부속·python
# FLUX checkpoint 는 대개 TRANSFORMER 만 들어 있어. text encoder 랑 VAE 는
# 파일에 없어서 base 모델 정의에서 가져와야 해.
from diffusers import FluxTransformer2DModel, FluxPipeline

# 1. 진짜로 local 인 부분을 올려: DiT transformer.
transformer = FluxTransformer2DModel.from_single_file(local_checkpoint_path)

# 2. pipeline 을 조립해. transformer 는 local 파일에서 오고,
#    T5 + CLIP + VAE 는 base 모델 정의에서 와.
pipe = FluxPipeline.from_pretrained(
    base_model_definition,        # T5-XXL, CLIP-L, VAE 를 대 줌
    transformer=transformer,      # 네 local transformer 가 여기 꽂혀
)

# 첫 실행 함정: T5 tokenizer 는 환경에 sentencepiece + protobuf 가 있어야 해.
# 없으면 에러가 애매하게 나와 ('tokenizer 를 못 올리거나 못 바꾸겠다'),
# 진짜 해법은 그 패키지 두 개를 까는 거고.

# 이 복잡한 절차 전부가 backbone 모듈 하나 안에 들어 있어.
# 부르는 쪽은 FLUX backbone 만 달라고 하지 이 조립을 구경도 안 해.

External links

Exercise

파일 하나에서 올린 모델을 골라서 뜯어봐. 진짜로 자기 완결적이야, 아니면 로딩 코드가 조용히 다른 데서 부속을 끌어와? 부품마다 어디서 오는지 따라가 봐. 통짜 checkpoint 만 올려 봤으면 transformer 시대 모델의 로딩 문서를 찾아서 어느 조각이 local 이고 어느 조각이 참조인지 적어 봐.
Hint
단서는 로드 호출에 있어. from_single_file 한 번으로 완성된 pipeline 이 나오면 통짜야. 부품 하나를 from_single_file 로 올린 다음 from_pretrained 로 나머지를 대 주면 local 에 참조가 붙는 방식이고.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.