트렌딩 딥다이브 · 2026-07-19 · OSSInsight 24h #59

AlayaLab/AlayaWorld 딥다이브
— 조작 가능한 1분짜리 세계를 통째로 생성하는 모델

AlayaWorld사진 한 장과 카메라 이동 경로를 주면, 그 경로를 따라 걸어가는 1분 이상의 720p 영상을 실시간에 가깝게 만들어내는 인터랙티브 월드 모델이다. 만들어둔 3D 게임 맵을 렌더링하는 게 아니라, 다음 순간의 화면 자체를 매번 새로 그려낸다. 이 문서가 파고드는 건 "영상 생성 AI 하나 더 나왔다"가 아니다 — 자기회귀 영상 생성에서 가장 어려운 두 문제, 즉 "뒤돌아봤을 때 아까 그 장소가 그대로인가(일관성)"와 "1분을 굴려도 화면이 뭉개지지 않는가(안정성)"를 이 코드베이스가 어떤 구조로 푸는가이다. 답은 두 종류의 메모리다. 압축된 프레임 히스토리(시간 기억)와 재투영 가능한 3D 공간 캐시(공간 기억)를 동시에 굴린다. 여기에 4-step DMD 증류로 속도를 확보하고, AdaLN으로 카메라를 값싸게 주입한다. 대형 모델 추론 코드에서 배울 실전 트릭도 두껍게 들어있다. (저장소: AlayaLab/AlayaWorld · Python/PyTorch · LTX-2 Community License(주의: GitHub 배지는 Apache-2.0으로 잘못 표시) · 논문 arXiv:2607.06291 · 별 52 · 첫 공개 2026-07-16 · 소속 Shanda AI Research Tokyo)
목차
  1. 프로젝트 한 줄 요약
  2. 왜 지금 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트
  7. 하드웨어 요구사항 · 설치
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한 줄 요약

"플레이 가능한 영상" — 첫 프레임 + 카메라 궤적 + 텍스트를 받아 1분 이상의 720p 세계를 자기회귀로 굴리는 오픈소스 월드 모델

게임 회사가 오픈월드 하나를 만들려면 아티스트 수백 명이 몇 년을 갈아넣는다. 월드 모델은 이 파이프라인을 통째로 우회하자는 발상이다. 3D 에셋을 만들지 않고, "지금 화면 + 사용자 입력"을 조건으로 다음 화면을 생성 모델이 직접 그린다. 계속 그리면 그게 곧 플레이 가능한 세계가 된다.

AlayaWorld가 실제로 받는 입력은 세 가지다(inference/run.py 기준).

입력파일내용
첫 프레임<prefix>_image.png출발 지점 이미지 1장 (또는 _video.mp4)
카메라 궤적<prefix>_camera.ptdict — cam_c2w [F,4,4] 포즈 시퀀스 + intrinsic
텍스트<prefix>_prompt.txt장면 설명. 중간에 교체 가능

출력은 mp4다. 한 번에 다 만드는 게 아니라 청크 단위로 이어붙인다: 1청크 = 레이턴트 4프레임 = 픽셀 32프레임 ≈ 24fps 기준 1.33초. 1분짜리 클립이면 약 45청크를 연달아 굴린다.

비유

기존 게임 엔진은 미리 지어놓은 세트장이다. 카메라를 어디로 옮기든 세트는 그 자리에 있다. 월드 모델은 즉흥 연기하는 배경 화가다. 카메라가 왼쪽으로 돌면 화가가 그 자리에서 왼쪽 풍경을 그려준다. 빠르고 유연하지만, 문제는 고개를 다시 오른쪽으로 돌렸을 때 아까 그린 그림을 화가가 기억하느냐다. 기억 못 하면 "아까 있던 나무가 사라지는" 현상이 생긴다. AlayaWorld 설계의 절반이 이 기억 문제에 쓰였다.

용어
자기회귀(Autoregressive) 생성
앞에서 만든 결과를 다시 입력으로 넣어 그다음을 만드는 방식. 문장 생성에서 단어를 하나씩 이어붙이는 것과 같은 원리를 영상 청크에 적용한 것. 장점은 길이 제한이 없다는 것, 단점은 오류가 눈덩이처럼 누적된다는 것(drift).
용어
long-horizon(롱호라이즌)
"긴 시간축"이라는 뜻. 영상 생성에서 5초짜리를 만드는 건 이제 쉽지만, 60초를 만들면 대부분 모델이 중간에 색이 바래거나 형체가 뭉개진다. AlayaWorld는 60초 이상을 안정적으로 유지하는 것을 핵심 목표로 잡았다.
먼저 알아둘 것
학습 코드는 아직 공개 전이고, 라이선스 표기가 어긋나 있다

현재(2026-07-19) 공개된 것은 추론 코드 + 병합된 가중치뿐이다. README 로드맵의 "Training code / Training data" 체크박스는 비어 있다. 재현 학습은 아직 불가능하다.

더 중요한 건 라이선스다. GitHub 페이지 배지는 Apache-2.0으로 표시되지만, 실제 LICENSE 파일 내용은 LTX-2 Community License(비-OSI, 학술·비영리 전용, 연매출 $10M 이상 기업은 Lightricks와 별도 계약 필요)다. 배지를 믿고 상업적으로 쓰면 안 된다. 반드시 LICENSE 원문을 직접 읽을 것.

2왜 지금 주목받는가

공개 3일 만의 신생 저장소 — 숫자가 아니라 "네 가지 속성을 코드로 다 구현했다"는 점이 주목 이유

솔직하게 시작하자. 별 52개, 포크 0개, 커밋 사실상 1개. 스타 수로 주목받는 저장소가 아니다. 2026-07-16에 처음 공개됐고, arXiv 논문(2607.06291)이 7월 7일에 올라와 HuggingFace Papers에서 좋아요 87을 받았다. 즉 "화제성"이 아니라 "논문 + 실행 가능한 코드 + 33GB 가중치를 한꺼번에 풀었다"는 완결성이 주목 이유다. 이 분야에서 이 세 가지를 다 공개하는 경우는 드물다.

2-1. README가 내세우는 네 가지 속성, 그리고 그 코드 위치

말잔치인지 실제 구현인지는 코드를 열어보면 안다. 네 가지 모두 대응하는 파일이 있다.

속성주장실제 구현 위치
Interaction실시간 카메라 제어 + 프롬프트 전환ActionAdaLNEmbedder (model_ltx_2_3.py), --skill-prompt 옵션
Consistency롱호라이즌 기억 일관성history_encoder.py(시간) + spatial_cache.py(공간) 이중 메모리
Stabilitydrift 억제drift된 히스토리로 학습 + error bank (학습 코드 미공개)
Runtime실시간에 근접DMD 증류 → sampling_steps: 4 (configs/infer.yaml)

※ Stability의 error bank는 학습 단계의 기법이라 현재 공개된 추론 코드에서는 직접 확인할 수 없다. README 설명에만 근거한다.

2-2. 스펙 배지: 720p / 24fps / 60s+ / 15B

프로젝트 웹페이지가 내건 숫자다. 이 중 15B는 따져볼 여지가 있다. 라이선스 문서는 "LTX-2.3-22B 베이스를 파인튜닝했다"고 명시하는데, 배포된 merged_infer.safetensors의 실제 크기는 33.6GB다. bf16(파라미터당 2바이트)으로 역산하면 약 16.8B — DiT + VAE + 커넥터 + history_encoder를 다 합친 값이니 "15B" 표기와는 얼추 맞는다.

확인 안 된 것
22B → 15B 사이에 무슨 일이 있었나

베이스가 22B인데 배포본이 15~17B 규모인 이유(증류인지 프루닝인지 일부 모듈만 배포한 건지)를 저장소 문서는 설명하지 않는다. 추측하지 말고 미확인으로 두는 게 맞다. 오픈소스 모델을 읽을 때 이런 숫자 불일치를 발견하면, 억지로 해석하기보다 "여기는 문서가 비어있다"고 표시해두는 습관이 낫다.

2-3. 경쟁 구도 — 정량 벤치마크가 없다는 사실 자체

저장소에도 프로젝트 페이지에도 수치 벤치마크 표가 없다. 대신 프로젝트 페이지의 "Consistency Comparisons" 섹션에서 DreaxX-World, lingBot-Fast, HY-World 1.5 세 가지와 "좌회전 → 우회전 → 뒤돌아보기" 궤적을 나란히 재생해 정성적으로 비교한다.

이 분야에서 흔한 방식이긴 하다. 영상 월드 모델의 "일관성"은 FVD 같은 지표로 잘 안 잡히기 때문에 영상을 나란히 놓고 눈으로 비교하는 관행이 있다. 다만 독자 입장에서는 "저자가 고른 궤적에서 저자가 고른 경쟁자와 비교한 결과"라는 점을 감안해서 읽어야 한다. Genie·Oasis·Matrix-Game 같은 더 알려진 모델과의 직접 비교는 자료에 없다.

그래도 인정할 점
"돌려볼 수 있게" 풀었다

playground/에 case1, case2 데모 케이스가 이미지·카메라·프롬프트 세트로 들어있고, bash inference/run.sh 한 줄이면 돈다. 논문만 내고 코드를 안 푸는, 혹은 코드만 풀고 가중치를 안 푸는 사례가 압도적으로 많은 분야에서 이건 실질적인 기여다.

3기술 스택 전체 지도

PyTorch 2.6 + LTX-2.3 DiT 백본 + Gemma-3-12B 텍스트 인코더 + Depth-Anything-3 — 남의 모델 셋을 엮은 조립 구조

AlayaWorld는 밑바닥부터 만든 모델이 아니다. 세 개의 외부 대형 모델을 조립하고, 그 사이에 자기들이 만든 메모리 모듈을 끼워넣은 구조다. 이 구성을 파악하는 게 코드 읽기의 출발점이다.

3-1. 세 개의 외부 모델

역할모델비고
영상 생성 백본LTX-2.3-22B (Lightricks)DiT. 48 layer, 32 head, head_dim 128 → inner_dim 4096
텍스트 이해Gemma-3-12B (Google)gemma-3-12b-it-qat-q4_0-unquantized. gated — 사전 동의 필요
깊이 추정Depth-Anything-3 (ByteDance)DA3NESTED-GIANT-LARGE-1.1. 3D 공간 캐시의 핵심
용어
DiT (Diffusion Transformer)
확산 모델의 노이즈 제거 신경망으로 U-Net 대신 트랜스포머를 쓰는 구조. Sora 이후 영상 생성의 표준이 됐다. 이미지를 패치로 잘라 토큰처럼 다루기 때문에 텍스트·카메라 같은 다른 조건을 어텐션으로 섞어넣기 쉽다는 게 장점.

3-2. requirements.txt 핵심

# CUDA 12.4 wheel 인덱스에서 설치 권장
torch==2.6.0  torchvision==0.21.0  torchaudio==2.6.0
xformers==0.0.29.post2

diffusers==0.39.0        # 스케줄러/파이프라인 유틸
transformers==5.13.1     # Gemma 텍스트 인코더
peft>=0.17               # LoRA (DMD generator 가중치 병합용)
bitsandbytes>=0.45
safetensors>=0.4  einops>=0.7  numpy>=1.24,<2
opencv-python  pyyaml  tqdm  easydict  huggingface-hub
읽는 요령
flash-attn이 requirements에 없는 게 실수가 아니다

flash_alaya/ltx2/modules/attention.pyoptional import 3단 폴백을 쓴다. ① flash_attn_interface(FA3, Hopper sm_9x에서만) → ② flash_attn(FA2) → ③ 둘 다 없으면 xformers. 설정 기본값은 attention_type: flash_attention_3지만, 없어도 죽지 않고 느려질 뿐이다. 설치 난이도가 높은 의존성을 필수에서 빼고 런타임에 감지하는 건 배포 마찰을 줄이는 좋은 관행이다.

3-3. 노이즈 제거 방식: Flow Matching + 4 step

flash_alaya/utils/pipeline.py_renoise가 핵심 한 줄이다.

x_sigma = (1 - sigma) * x0 + sigma * eps
# 깨끗한 x0과 노이즈 eps를 sigma 비율로 직선 보간
용어
Flow Matching
확산 모델의 사촌뻘 기법. 기존 DDPM이 복잡한 노이즈 스케줄을 따라간다면, flow matching은 노이즈와 정답 사이를 직선으로 잇고 그 직선의 방향(속도장)을 학습한다. 경로가 단순해서 훨씬 적은 스텝으로 샘플링할 수 있다는 게 실용적 장점이다.
용어
DMD (Distribution Matching Distillation)
50스텝 걸리는 원본 모델(교사)의 출력 분포를 4스텝짜리 작은 모델(학생)이 흉내내도록 증류하는 기법. 개별 샘플을 따라하는 게 아니라 분포를 맞추기 때문에 다양성이 덜 무너진다. AlayaWorld가 실시간에 근접할 수 있는 직접적 이유다.

병합 스크립트 flash_alaya/tools/merge_infer_weights.py의 주석에서 배포 가중치의 정체가 드러난다. SFT 베이스 transformer + DMD/GAN generator LoRA(타깃 선형층 480개) + history_encoder를 하나의 merged_infer.safetensors로 합친 것이다. 원본 베이스 파일명은 ltx-2.3-22b-dev.safetensors.

3-4. 설정 파일 한 장에 모든 게 있다

설정은 configs/infer.yaml 딱 하나다. 최상위 8개 섹션.

섹션내용
run출력 경로
paths체크포인트 5종 경로
sample544×960 해상도, 24fps, temporal_stride 8
layoutsink / history / condition 레이턴트 프레임 수
memoryHR·LR 히스토리 압축률
spatial_memoryDA3 백엔드, 3D 캐시 검색 파라미터
controlaction_scale 6개 float (카메라 6-DoF 각각의 민감도)
validationsampling_steps: 4, cfg_scale, ttc
runtimebf16, attention_type, vae_chunk_size

※ 실제 생성 해상도는 544×960이다. 웹페이지의 "720p" 배지는 근사 표현으로 보인다(960 폭은 720p보다 낮다).

4아키텍처 심화 분석

이중 메모리(시간 + 공간)로 굴리는 청크 루프 — 이 프로젝트의 진짜 알맹이

4-1. 전체 구조도

┌──────────────────────────────────────────────────────────────┐ │ 입력: 첫 프레임 이미지 + 카메라 궤적(.pt) + 프롬프트 │ └───────────────────────────┬──────────────────────────────────┘ │ inference/run.py :: main() ▼ ┌──────────────────────────────────────────────────────────────┐ │ InferenceEngine.setup() [utils/engine.py] │ │ merged_infer.safetensors 를 CPU 로 "딱 한 번" 로드 │ │ ├─ DiT (LTX23Model) ─ meta device + assign=True │ │ ├─ VAE (Video En/Decoder) │ │ ├─ Text Encoder (Gemma) │ │ └─ history_encoder │ │ DA3 깊이 모델은 별도 eager 로드 (컴파일 시 4.7배 느려짐) │ └───────────────────────────┬──────────────────────────────────┘ ▼ ┌──────────────────────────────────────────────────────────────┐ │ pipeline.initialize_cache() → RolloutCache (순수 상태) │ │ VAE 인코딩 · 텍스트 인코딩 · sink/history/nearby 슬라이싱 │ │ SpatialMemory.init_bank() ← 3D 캐시 초기화 │ └───────────────────────────┬──────────────────────────────────┘ ▼ ╔═══════ 청크 루프 i = 0 .. rounds-1 (1청크 ≈ 1.33초) ═══╗ ║ ║ ║ ┌── 조건 4종 조립 ─────────────────────────────────┐ ║ ║ │ ① history_encoder(c.history) → memory token │ ║ ║ │ = "시간 기억" (직전 프레임들의 압축본) │ ║ ║ │ ② spatial.build_context() → spatial_latent │ ║ ║ │ = "공간 기억" (3D 캐시를 현재 시점으로 warp) │ ║ ║ │ ③ build_action_vectors() → action_vectors │ ║ ║ │ = 카메라 6-DoF 상대 포즈 │ ║ ║ │ ④ sink_latent = 첫 프레임 앵커 (색·톤 기준점) │ ║ ║ └──────────────────┬───────────────────────────────┘ ║ ║ ▼ ║ ║ _denoise_chunk() : flow-matching 4 step ║ ║ 각 step 마다 LTX23Model.forward(조건 4종 주입) ║ ║ + CFG + action-CFG + (옵션) TTC 보정 ║ ║ ▼ ║ ║ finalize() : 상태 변이는 여기서만 ║ ║ ├ SpatialMemory.append_prediction() ║ ║ │ → VAE 디코드 → DA3 깊이 추정 → 3D 캐시 갱신 ║ ║ └ cache.history 슬라이딩 윈도우 갱신 ║ ╚════════════════════════════════════════════════════════╝ ▼ ┌──────────────────────────────────────────────────────────────┐ │ decode() VAE 디코더 overlap-tiling (겹침 ≥ 6 latent) │ │ → 조이스틱 HUD 오버레이 → mp4 저장 │ └──────────────────────────────────────────────────────────────┘

4-2. 이중 메모리 — 이 설계의 핵심

자기회귀 영상 생성이 실패하는 방식은 두 가지고, AlayaWorld는 각각에 다른 메모리를 붙였다.

메모리 A · 시간

VideoHistoryEncoder — 직전 프레임들의 압축 기억

파일: flash_alaya/alaya/memory/history_encoder.py

직전 프레임들을 HR(고해상)·LR(저해상) 두 갈래로 압축해 메모리 토큰을 만든다. 최근 것은 자세히, 오래된 것은 거칠게 기억하는 구조다. 해결하는 문제: 시간적 끊김 — 청크 경계에서 갑자기 물체가 튀거나 조명이 바뀌는 현상.

비유하자면 사람의 단기 기억이다. 방금 일은 선명하고, 30초 전 일은 흐릿하다.

메모리 B · 공간

SpatialMemory / Sparse3DCache — 재투영 가능한 3D 기억

파일: flash_alaya/alaya/memory/spatial_cache.py, flash_alaya/utils/spatial.py

생성한 프레임마다 DA3로 깊이를 추정해 3D 점군으로 쌓아둔다. 다음 청크를 만들 때는 그 점군을 새 카메라 시점으로 forward-warp(재투영)해 "이 시점에서 원래 보여야 할 모습"의 힌트를 모델에 넣어준다. 해결하는 문제: 공간적 망각 — 왼쪽 봤다가 오른쪽 봤다가 다시 왼쪽을 봤을 때 아까 그 장면이 사라지는 현상.

비유하자면 방을 돌아다니며 그린 스케치북이다. 같은 자리로 돌아오면 예전 스케치를 꺼내 참고한다.

왜 둘 다 필요한가

시간 메모리만 쓰면 "방금 전"은 잘 잇지만 "1분 전 그 방"은 못 찾는다 — 슬라이딩 윈도우 밖으로 밀려났기 때문이다. 공간 메모리만 쓰면 기하는 맞지만 조명·질감이 프레임마다 튄다 — 3D 캐시는 위치 정보지 스타일 정보가 아니기 때문이다. 두 메모리는 서로 다른 실패 모드를 막는다. 하나로 합치려 하지 않고 각각의 강점에 맡긴 게 이 설계의 판단이다.

4-3. 카메라는 어떻게 주입하나 — AdaLN이라는 값싼 답

ActionAdaLNEmbedder (flash_alaya/ltx2/modules/model_ltx_2_3.py)가 담당한다. 6D 상대 포즈(평행이동 3 + 오일러각 3)를 주파수 임베딩한 뒤, AdaLN 파라미터로 변환해 정규화 레이어의 스케일·시프트에 주입한다.

용어
AdaLN (Adaptive Layer Normalization)
조건 정보를 신경망에 넣는 값싼 방법. 크로스 어텐션은 조건 토큰마다 어텐션 연산이 추가로 필요하지만, AdaLN은 정규화 레이어의 스케일(γ)과 시프트(β) 값을 조건에서 계산해 곱하고 더할 뿐이다. 연산량이 거의 공짜다. 카메라 포즈처럼 차원이 작고(6D) 프레임마다 하나씩만 있는 조건에는 이게 정답이다.

즉 조건마다 주입 경로가 다르다. 텍스트는 크로스 어텐션(토큰이 많고 의미가 복잡하니까), 카메라는 AdaLN(6개 숫자니까), 공간·히스토리 메모리는 어텐션 KV로(공간 구조가 있으니까). 조건의 성격에 따라 주입 방식을 나눠 쓴 것 — 이게 이 아키텍처에서 가장 배울 만한 판단이다.

4-4. 프롬프트 스위칭 — 이벤트를 타이밍 맞춰 넣기

inference/run.py--skill-sec / --skill-prompt 옵션이다. 롤아웃 마지막 N초 구간에서만 caption을 다른 것으로 바꿔치기한다.

python -m inference.run --input playground/case1/case1 \
  --skill-sec 3 --skill-prompt "a burst of flame erupts"

청크 경계마다 텍스트 조건을 새로 인코딩하기 때문에 가능한 트릭이다. "55초 지점에서 화염이 터지게 하라" 같은 연출을 넣을 수 있다는 뜻이고, 이게 "playable"이라는 표현의 실질이다.

4-5. RolloutCache — 상태를 한 곳에 가두는 설계

flash_alaya/utils/cache.py. 이 프로젝트에서 가장 깔끔한 설계 판단 중 하나다.

generate(i, cache) → 순수 함수. cache 를 읽기만 한다. 반환: 예측 레이턴트 finalize(i, cache, pred) → 여기서만 cache 를 변이시킨다. 왜? 자기회귀 루프는 상태가 계속 오염되는 구조라 "어느 시점에 뭐가 들어갔는지" 추적이 지옥이 된다. 읽기와 쓰기를 함수 단위로 갈라두면 중간 청크만 다시 굴려보는 디버깅이 가능해진다.

5디렉토리 구조 해부

얇은 CLI 껍데기(inference/) + 두꺼운 엔진(flash_alaya/) 2층 구조
AlayaWorld/ ├── configs/infer.yaml ← 유일한 설정 파일. 8개 섹션 전부 여기 │ ├── inference/ ── 외부용 진입점 (얇은 래퍼) │ ├── run.py i2v 엔트리. argparse + skill-prompt 로직 │ ├── run.sh 원커맨드 런처. 단일/멀티 GPU 분기 │ ├── da3_patch.py DA3 깊이-카메라 스케일 정합 fallback 패치 │ └── README.md │ ├── playground/ ── 즉시 실행 데모 │ ├── case1/ (image, camera.pt, prompt.txt, skill.txt) │ └── case2/ │ ├── flash_alaya/ ══ 실제 엔진. 로직 전부 여기 ══ │ ├── run.py 대안 엔트리 (주석이 중국어) │ ├── record.md ★ 성능 최적화 실측 로그. 읽을 가치 큼 │ ├── docs/streaming_decoder_plan.md 미구현 설계 노트 │ │ │ ├── alaya/ ── 이 팀이 직접 만든 부분 │ │ ├── config/ loader.py, schema.py dataclass 설정 스키마 │ │ ├── model/ loader.py, components.py, fsdp.py │ │ ├── memory/ history_encoder.py 시간 메모리 │ │ │ spatial_cache.py 공간 메모리(3D) │ │ │ da3_depth.py, builder.py │ │ └── control/ action.py 카메라 → 액션벡터 │ │ │ ├── ltx2/ ── Lightricks LTX-2.3 파생 (별도 라이선스) │ │ ├── modules/ model_ltx_2_3.py DiT 본체 (48 layer) │ │ │ vae.py VideoEncoder/Decoder │ │ │ text_encoder.py AVGemmaTextEncoderModel │ │ │ attention.py FA3/FA2/xformers 폴백 │ │ │ camera_control.py, rope.py, patchifier.py, │ │ │ sparse_attention.py, scheduler.py │ │ ├── configs/ltx2_config.py │ │ └── utils/ context_parallel.py Ulysses CP (멀티 GPU) │ │ ltx2_streaming_vae.py, parallel_states.py │ │ │ ├── utils/ ── 실행 오케스트레이션 │ │ ├── engine.py InferenceEngine — 모델 로딩/디코딩 │ │ ├── pipeline.py FlashAlayaPipeline — 청크 루프 본체 │ │ ├── cache.py RolloutCache — 순수 상태 객체 │ │ ├── conditioning.py 조건 kwargs 조립 │ │ ├── spatial.py SpatialMemory │ │ └── rollout_utils.py, taehv.py │ │ │ └── tools/merge_infer_weights.py SFT + LoRA + encoder 병합 │ ├── requirements.txt └── LICENSE / NOTICE / THIRD_PARTY_LICENSES.md ★ 반드시 읽을 것
읽기 순서 추천
코드를 처음 여는 사람이라면

inference/run.py(입력 형식 파악) → ② configs/infer.yaml(뭘 조절할 수 있는지) → ③ flash_alaya/utils/pipeline.py(청크 루프 전체) → ④ alaya/memory/ 두 파일(이 프로젝트의 정체성) → ⑤ flash_alaya/record.md(실측 성능 로그, 중국어지만 숫자만 봐도 얻는 게 많다). ltx2/는 나중에. 남의 코드고 양이 많다.

구조에서 읽히는 것
alaya/ltx2/가 분리돼 있다는 사실

디렉토리 경계가 곧 저작권 경계다. ltx2/는 Lightricks 코드 파생이라 LTX-2 Community License가 걸리고, alaya/는 이 팀 코드다. 남의 모델을 파인튜닝해 배포할 때 라이선스가 다른 코드를 디렉토리로 갈라놓는 것은 실무에서 반드시 따라 해야 할 습관이다.

6학습 포인트

모델 아키텍처보다 대형 모델 추론 코드의 실전 트릭에서 얻을 게 더 많다

솔직히 말하면, 이 저장소에서 월드 모델 학습을 배우기는 어렵다. 학습 코드가 없기 때문이다. 대신 33GB 모델 세 개를 한 GPU에 올려 굴리는 엔지니어링에서 배울 게 아주 많다. 다섯 가지를 뽑았다.

6-1. meta device + assign=True — 로딩 70초를 0으로

flash_alaya/utils/engine.pyfast_load_transformer:

with torch.device("meta"):
    model = LTX23Model(**filtered)
...
missing, unexpected = model.load_state_dict(
    converted, strict=False, assign=True
)
비유

보통 모델을 만들면 파이썬이 모든 가중치를 난수로 채운다. 그런데 어차피 다음 줄에서 체크포인트로 전부 덮어쓸 거다. 15B 모델이면 이 헛수고가 70초다. meta 디바이스는 "모양만 있고 실제 메모리는 없는 껍데기"를 만들고, assign=True는 체크포인트 텐서를 복사하지 않고 그대로 갖다 붙인다. 이삿짐을 새 가구 사서 채운 다음 버리는 대신, 빈 방에 짐만 들이는 것.

※ 이건 AlayaWorld 전용 트릭이 아니다. PyTorch로 큰 모델을 다루면 무조건 알아야 하는 패턴이다.

6-2. safetensors 한 파일 안에 서브모듈 접어넣기

tools/merge_infer_weights.py가 DiT·VAE·텍스트 프로젝션·history_encoder를 접두사(vae., history_encoder. …)로 구분해 한 파일에 합친다. 그리고 engine.setup()은 그 파일을 딱 한 번만 읽고, 각 로더가 자기 접두사 키만 필터링해 가져간다.

효과: 33GB 파일에 대한 디스크 I/O가 1회로 끝난다. 파일을 4개로 쪼개면 4번 열어야 하고, 대용량 파일에서는 이 차이가 체감된다.

6-3. 프레임 단위 causal mask — 세 줄짜리 트릭

history_encoder.py_SelfAttention3D:

t_indices = torch.arange(T * spatial, device=x.device) // spatial
causal_mask = t_indices.unsqueeze(0) <= t_indices.unsqueeze(1)

영상 토큰은 (프레임 × 공간위치)로 펼쳐져 있다. 여기서 // spatial 정수 나눗셈 한 번으로 "이 토큰이 몇 번째 프레임 소속인가"를 뽑아내고, 그걸로 마스크를 만든다. 결과: 같은 프레임 안에서는 모든 위치가 서로 다 보고, 프레임 사이에서는 미래를 못 본다. 시공간 어텐션에 인과성을 주는 가장 간결한 방법이다.

6-4. 작은 연산은 일부러 CPU로 — 통념을 깨는 판단

spatial_cache.py_safe_inv. 주석이 이 판단의 전부를 설명한다.

"""GPU의 torch.linalg.inv는 cuSOLVER를 타는데, 메모리가 빠듯하면
cusolverDnCreate(handle)가 CUSOLVER_STATUS_INTERNAL_ERROR를 던진다
(DMD가 13B 두 벌 + DA3를 동시 상주시킬 때 흔함)."""
return torch.linalg.inv(mat.float().cpu()).to(device=mat.device, dtype=mat.dtype)
배울 점
"연산은 무조건 GPU"가 아니다

4×4 카메라 행렬 역행렬은 계산량이 사실상 0이다. 그런데 GPU로 보내면 cuSOLVER 핸들 생성이라는 무거운 초기화가 딸려오고, VRAM이 빠듯하면 그게 터진다. 작고 안 중요한 연산에 큰 라이브러리를 물리면 오히려 불안정해진다는 걸 이 팀은 실패를 겪고 배운 것이다(주석의 "흔함"이 그 증거다).

6-5. 실험 기능은 "꺼지면 진짜로 아무것도 안 하게"

pipeline.py_denoise_chunk에서 TTC(Test-Time Correction) 처리 방식이다. --ttc 플래그가 꺼지면 ttc_steps가 빈 frozenset()이 되어, 루프가 추가 RNG 추출도, 추가 forward도 없이 베이스라인과 완전히 동일한 코드 경로를 탄다.

왜 중요한가

실험 기능을 넣을 때 흔한 실수는 "꺼도 난수 소비 순서가 바뀌는 것"이다. 그러면 같은 seed를 줘도 결과가 달라지고, 그 순간 "이 차이가 새 기능 때문인지 난수 때문인지" 판별이 불가능해진다. off일 때 바이트 단위로 동일함을 구조적으로 보장하는 것 — 실험 코드를 짜는 사람이면 이 원칙 하나만 가져가도 본전이다.

6-6. 기술별로 무엇을 배울 수 있나 (정리)

기술여기서 배울 것실습 아이디어
PyTorch 로딩meta device, assign=True, safetensors 병합내 모델 로딩 시간 측정 후 meta 적용해 비교
Flow Matching직선 보간 + few-step 샘플링MNIST에 flow matching 구현, 4 vs 50 step 비교
조건 주입AdaLN vs 크로스어텐션 선택 기준작은 DiT에 두 방식 다 붙여 파라미터 수 비교
3D 인식깊이 추정 → 점군 → forward warpDA3로 사진 한 장을 3D 점군화 후 시점 이동
어텐션 최적화FA3/FA2/xformers 3단 폴백세 백엔드 속도·정확도 벤치마크
분산 추론Ulysses Context ParallelCP=1/2/4에서 청크 시간 측정

7하드웨어 요구사항 · 설치

공식 최소 사양이 명시돼 있지 않다 — 코드 주석에서 역추정해야 한다
가장 먼저 알아야 할 것
README에 최소 VRAM이 안 적혀 있다

이건 미확인 사항이다. 아래 수치는 코드 주석과 파일 크기에서 역추정한 것이지 공식 스펙이 아니다. 개인 GPU로 돌려보려는 사람은 이 점을 반드시 감안할 것.

7-1. 코드에서 나온 근거들

근거위치시사점
"fp32 중간 피크 ~48GB, bf16 최종 ~16GB, H200 140G면 충분"ltx2/modules/camera_control.py:795개발 기준 GPU = H200(140GB)
"DMD 동시 상주 2벌 13B + DA3에서 흔함(cuSOLVER 오류)"spatial_cache.py:14메모리 압박이 상시였음
FA3 분기가 sm_9x를 명시 감지attention.pyHopper(H100/H200) 우대 설계

7-2. 다운로드해야 할 것들

모델크기비고
merged_infer.safetensors33.6 GBHF API로 확인한 실제 바이트
Gemma-3-12B20GB대 (bf16 추정)gated — HF에서 라이선스 사전 동의 필요
DA3NESTED-GIANT-LARGE-1.1별도없으면 spatial 브랜치에서 에러

세 모델을 동시에 GPU에 올려야 한다. 단일 GPU로 굴린다면 80GB급(A100 80G / H100 / H200)이 현실적으로 보이지만, 다시 강조하면 이건 추정이지 공식 수치가 아니다. 24GB 소비자용 GPU로는 그대로는 어렵다고 보는 게 안전하다.

7-3. 설치

# 1) PyTorch (CUDA 12.4)
pip install --index-url https://download.pytorch.org/whl/cu124 \
    --extra-index-url https://pypi.org/simple \
    torch==2.6.0 torchvision==0.21.0 torchaudio==2.6.0 xformers==0.0.29.post2
pip install -r requirements.txt

# 2) 본체 가중치
hf download AlayaLab/AlayaWorld merged_infer.safetensors --local-dir checkpoints

# 3) 텍스트 인코더 (gated — HF에서 먼저 동의 클릭)
hf download google/gemma-3-12b-it-qat-q4_0-unquantized \
  --local-dir checkpoints/gemma-3-12b-it-qat-q4_0-unquantized

# 4) 깊이 모델 — 필수. 빠뜨리면 spatial 브랜치에서 죽는다
git clone https://github.com/ByteDance-Seed/Depth-Anything-3 checkpoints/Depth-Anything-3
pip install -e checkpoints/Depth-Anything-3
HF_HOME=checkpoints/hf_cache hf download depth-anything/DA3NESTED-GIANT-LARGE-1.1

7-4. 실행

# 단일 GPU, 번들 데모
bash inference/run.sh

# 멀티 GPU (Ulysses Context Parallel)
GPUS=4 bash inference/run.sh

# 모듈 직접 호출 + 옵션
PYTORCH_ALLOC_CONF=expandable_segments:True \
  python -m inference.run --input playground/case1/case1 --seed 1234 --ttc

7-5. 실측 속도 (CP=4 기준)

flash_alaya/record.md에 남아있는 실측 로그다. 청크 하나(=1.33초 분량)당:

단계시간내용
denoise~0.84 sflow-matching 4 step
spatial_ctx~0.59 s3D 캐시 → 현재 시점 warp
finalize~1.14 sVAE 디코드 + DA3 깊이 재계산
합계~2.55 s최적화 전 ~3.0s에서 개선

1청크가 1.33초 분량인데 생성에 2.55초가 걸리니 실시간의 약 1.9배 느리다. "실시간에 근접"이라는 표현은 과장은 아니지만, GPU 4장을 쓰고도 아직 실시간은 아니다는 점은 정확히 알아둘 필요가 있다. 단일 GPU 수치는 record.md에 없다(미확인).

※ 눈여겨볼 것: 가장 오래 걸리는 단계가 추론이 아니라 finalize(깊이 재계산)다. 공간 메모리를 유지하는 대가가 생성 자체보다 비싸다는 뜻이다.

8직접 해볼 수 있는 실습 과제

GPU가 없어도 할 수 있는 것부터, H100이 있어야 하는 것까지
난이도 ★☆☆ · GPU 불필요

과제 1. 카메라 궤적 파일을 직접 만들어보기

playground/case1/case1_camera.pttorch.load로 열어 cam_c2w[F,4,4]와 intrinsic의 구조를 파악한다. 그다음 같은 형식으로 "제자리에서 360도 회전"하는 궤적을 직접 생성해본다. 회전행렬 만들기 + 동차좌표 4×4 이해가 목표다.

얻는 것: 3D 그래픽스의 camera-to-world 행렬 개념. 이건 월드 모델뿐 아니라 NeRF·3DGS·SLAM에서 전부 쓰인다.

난이도 ★☆☆ · GPU 불필요

과제 2. 이중 메모리 구조를 그림으로 재구성하기

history_encoder.pyspatial_cache.py를 읽고, 각 메모리에 무엇이 언제 들어가고 언제 빠지는지를 직접 다이어그램으로 그린다. 특히 cache.history의 슬라이딩 윈도우 길이와 3D 캐시의 최대 크기를 코드에서 찾아낼 것.

얻는 것: 남의 코드에서 "상태의 수명주기"를 추적하는 훈련. 이게 대형 코드베이스를 읽는 핵심 기술이다.

난이도 ★★☆ · 소형 GPU 가능

과제 3. Depth-Anything-3만 떼어 3D 재투영 구현

AlayaWorld 본체는 못 돌려도 DA3는 훨씬 작다. 사진 한 장 → 깊이 추정 → 점군 변환 → 가상 카메라를 살짝 옆으로 옮겨 forward-warp해서 다시 2D로 투영한다. spatial_cache.py가 하는 일의 축소판이다.

얻는 것: 필연적으로 occlusion hole(가려졌던 부분이 드러나면서 생기는 빈 구멍)을 보게 된다. "왜 공간 캐시만으로는 부족하고 생성 모델이 필요한가"를 몸으로 이해하게 되는 게 이 과제의 진짜 목적이다.

난이도 ★★☆ · 중형 GPU

과제 4. meta device 로딩 최적화 재현

아무 대형 모델(7B급)이나 골라 ① 평범하게 로드 ② meta device + assign=True로 로드, 두 방식의 시간과 피크 메모리를 측정해 표로 만든다. engine.pyfast_load_transformer를 그대로 참고해도 된다.

얻는 것: 즉시 실무에 쓸 수 있는 기술. 서빙 환경에서 콜드 스타트 시간을 줄이는 표준 수법이다.

난이도 ★★★ · 80GB급 GPU 필요

과제 5. 메모리 ablation — 한쪽을 꺼보기

본체를 돌릴 수 있다면 가장 배울 게 많은 과제다. configs/infer.yamlspatial_memory를 비활성화하고 같은 궤적("좌회전 → 우회전 → 복귀")을 돌려, 공간 메모리가 있을 때와 없을 때 복귀 지점의 장면이 얼마나 달라지는지를 나란히 비교한다.

얻는 것: 논문이 주장하는 기여를 직접 검증하는 경험. ablation study를 남이 한 걸 읽는 것과 직접 돌려보는 것은 이해의 깊이가 다르다.

난이도 ★★★ · 응용

과제 6. 프롬프트 스위칭으로 "연출" 짜기

--skill-sec / --skill-prompt정해진 타이밍에 이벤트가 터지는 30초 클립을 만든다. 여러 번 프롬프트를 바꾸려면 run.py를 수정해야 한다 — 현재는 마지막 N초 한 번만 지원하기 때문이다. 다중 스위칭으로 확장하는 것 자체가 과제다.

얻는 것: 청크 경계에서 조건을 갈아끼우는 자기회귀 생성의 제어 지점을 손으로 만져보는 경험.

9관련 기술 심화 학습 로드맵

8주 — 확산 모델 기초에서 월드 모델까지, 이 저장소를 목적지로 삼는 경로
1–2주차

확산 모델과 Flow Matching의 기초

DDPM의 전방·역방 과정을 수식이 아니라 직관으로 잡는다. 그다음 flow matching이 "왜 더 적은 스텝으로 되는가"를 이해한다. 핵심 질문 하나: 노이즈에서 데이터로 가는 경로가 직선이면 무엇이 쉬워지는가?

실습: 2D 가우시안 혼합 분포에 flow matching을 직접 구현해 4 step vs 50 step 샘플 품질 비교. 데이터가 2D면 노트북 CPU로도 된다.

3주차

DiT와 조건 주입 메커니즘

U-Net → DiT 전환이 왜 일어났는지, 그리고 조건을 넣는 세 가지 경로(크로스 어텐션 / AdaLN / 토큰 연결)의 트레이드오프를 정리한다. AlayaWorld가 세 가지를 조건 성격에 따라 나눠 쓴 이유를 설명할 수 있으면 이 주차는 성공이다.

읽을 것: DiT 논문(Peebles & Xie, 2022), 그리고 model_ltx_2_3.pyActionAdaLNEmbedder 실제 구현.

4주차

영상 VAE와 시공간 압축

영상 생성이 픽셀이 아니라 레이턴트 공간에서 이뤄지는 이유. flash_alaya/ltx2/modules/vae.pyCausalConv3d를 읽고 32× 공간 / 8× 시간 압축이 실제로 어떻게 구현되는지 본다. "causal"이 왜 필요한지(미래 프레임을 안 봐야 스트리밍이 된다)도 함께.

실습: overlap-tiling 디코딩을 직접 구현해, 겹침을 0으로 줄이면 청크 경계에 어떤 아티팩트가 생기는지 눈으로 확인.

5주차

3D 인식 — 깊이, 점군, 재투영

단안 깊이 추정 → 점군 → 카메라 변환 → 재투영의 전 과정. 위 실습 과제 3이 이 주차의 중심이다. occlusion hole을 직접 만들어보는 게 핵심이다.

연결점: 여기서 NeRF·3D Gaussian Splatting으로 가지를 뻗을 수 있다. 다만 월드 모델은 명시적 3D를 보조로만 쓴다는 차이를 기억할 것.

6주차

증류(Distillation)와 few-step 샘플링

DMD, Consistency Model, Progressive Distillation의 차이. "교사의 샘플을 따라하기 vs 교사의 분포를 따라하기"가 왜 다른 결과를 내는지가 이 주차의 핵심 개념이다. 실시간 생성 모델은 전부 이 계열 기법 위에 서 있다.

7주차

자기회귀 생성의 drift 문제

exposure bias(학습 때는 정답 히스토리, 추론 때는 자기 출력 히스토리를 본다는 불일치)와 그 완화법들. AlayaWorld의 "drift된 히스토리로 학습 + error bank"가 정확히 이 문제에 대한 답이다. 언어 모델의 teacher forcing 문제와 뿌리가 같다는 걸 연결해두면 이해가 단단해진다.

8주차

월드 모델 지형도 그리기

Genie / Oasis / Matrix-Game / HunyuanWorld / AlayaWorld를 입력 방식(키보드 vs 카메라 궤적), 메모리 전략, 길이, 공개 수준 네 축으로 표를 만든다. AlayaWorld가 정량 벤치마크를 안 낸 이유도 이 과정에서 스스로 판단이 설 것이다.

마무리: arXiv:2607.06291 논문을 이제 읽는다. 8주 전에 읽었으면 그림만 봤겠지만, 지금은 설계 선택 하나하나가 왜 그런지 보일 것이다.

10핵심 키워드 사전

이 문서에 나온 용어를 한자리에
용어
월드 모델현재 상태 + 사용자 입력을 조건으로 다음 관측(화면)을 생성하는 모델. 3D 에셋 없이 "플레이 가능한 세계"를 만든다
자기회귀앞 출력을 다시 입력으로 넣어 이어가는 방식. 길이 무제한이지만 오류가 누적됨
long-horizon긴 시간축. 여기서는 60초 이상 안정적으로 굴리는 것
drift자기회귀 롤아웃에서 오류가 누적돼 화면이 점점 뭉개지거나 색이 바래는 현상
DiTDiffusion Transformer. U-Net 대신 트랜스포머를 쓰는 확산 모델 백본
Flow Matching노이즈↔데이터를 직선으로 잇고 그 속도장을 학습. 적은 스텝으로 샘플링 가능
DMDDistribution Matching Distillation. 교사 모델의 분포를 학생이 흉내내게 하는 증류. 4-step 추론의 근거
AdaLNAdaptive LayerNorm. 조건에서 정규화의 스케일·시프트를 계산해 주입. 저차원 조건에 값싸고 효과적
CFGClassifier-Free Guidance. 조건 있는 예측과 없는 예측의 차이를 증폭해 조건 따르기를 강화
action-CFGCFG를 카메라 액션 조건에 적용한 것. 카메라 지시를 더 강하게 따르게 함
TTCPathwise Test-Time Correction (arXiv:2602.05871). 추론 중 경로를 보정해 긴 롤아웃의 외형 drift 억제
sink latent첫 프레임 앵커. 색·톤의 기준점 역할을 해 전체가 표류하지 않게 잡아줌
forward warp3D 점군을 새 카메라 시점의 2D 평면으로 투영하는 것
occlusion hole재투영 시 가려져 있던 부분이 드러나며 생기는 정보 없는 빈 구멍
Context Parallel시퀀스(토큰) 축을 여러 GPU로 쪼개는 분산 방식. 여기서는 Ulysses 방식
meta devicePyTorch의 "모양만 있고 메모리는 없는" 가상 디바이스. 대형 모델 로딩 최적화의 핵심
overlap-tiling큰 데이터를 겹치게 잘라 처리한 뒤 이어붙여 경계 아티팩트를 없애는 기법
gated modelHuggingFace에서 라이선스 동의 후에만 받을 수 있는 모델. Gemma-3가 여기 해당

11참고 링크

원본 소스 · 배경 지식 · 비교 대상

이 저장소

의존하는 모델들

배경 지식

비교 대상 월드 모델