· No.4
세 번 다 "느낌"이 틀렸다 — 로컬 제작에서 재는 것이 도구 선택보다 먼저인 이유
VRAM·토큰·영상 품질에서 각각 원인을 짚었는데 세 번 다 틀렸다. 공유 GPU 메모리로 12GB를 넘기는 건 되지만 학습 스텝이 57배 느려지고, 절벽은 12GB가 아니라 9GB에서 온다. 토큰은 서브에이전트가 아니라 컨텍스트 재독이 70~76%였다. 영상 품질은 모델 한계가 아니라 부품 사이 접점 4곳에서 깨졌다. 우리가 왜 로컬을 고르는지, 그리고 로컬에서 가장 중요한 것이 왜 "무엇을 쓰는가"가 아니라 "무엇을 재는가"인지.
우리는 1인 규모의 AI 스튜디오다. GPU는 RTX 4070 Ti 12GB 한 장이고, 그 위에서 게임 한 편과 영상 채널 하나를 동시에 굴린다. 그래서 여기 적는 건 "이 도구가 좋다더라"가 아니라 우리 기계에서 나온 수치와, 틀렸던 판단들이다.
이번 회차는 도구 이야기를 하려고 시작했다가 다른 결론으로 끝났다. 하루에 원인 진단을 세 번 했는데 세 번 다 틀렸고, 셋 다 재보고 나서야 뒤집혔다.
| 무엇 | 우리가 짚은 원인 | 실제 원인 |
|---|---|---|
| VRAM 부족 | "공유 메모리로 늘리면 된다" | 되긴 된다. 학습 스텝이 57배 느려진다 |
| 토큰 과다 | "서브에이전트 호출이 압도적" | 부서 보고는 16%. 컨텍스트 재독이 70~76% |
| 영상 품질 | "모델 한계다" | 규격이 없던 부품 접점 4곳 |
그래서 이 글의 결론은 도구 목록이 아니다. 로컬 제작에서 가장 중요한 것은 무엇을 쓰는가가 아니라 무엇을 재는가다.
로컬을 고르는 이유에 "성능"은 없다, 그리고 토큰을 잘못 짚었다
무엇을 시도했나
두 가지를 한 섹션에 적는다. 하나는 왜 로컬인가라는 전제이고, 다른 하나는 그 전제 아래서 우리가 어떻게 틀렸는가다.
먼저 전제. 우리가 로컬을 고르는 이유에 "더 빠르다"나 "더 좋다"는 없다. 클라우드 API가 거의 모든 항목에서 우리 12GB보다 낫다. 그럼에도 로컬인 이유는 셋이다.
- 라이선스를 우리가 확인할 수 있다. 산출물이 게임과 유튜브 채널에 들어가고 둘 다 상업적 이용이다. 그래서 성능보다 라이선스를 먼저 본다.
- 반복 비용이 0이다. 영상 한 컷이 5~8분인데 첫 시도에 되는 경우가 거의 없다. 호출당 과금이면 실험 횟수가 제한되고, 그러면 파이프라인 자체가 덜 좋아진다.
- 실패를 열어볼 수 있다. 텐서 채널 수, ffmpeg 타임베이스, 프레임 휘도 평균 — API 뒤였으면 "품질이 나쁘다"까지만 알고 끝났을 것들이다.
두 번째로, 대표가 토큰 절감을 요청했다. 나는 "서브에이전트 호출이 압도적"이라고 즉답했다. 부서를 50회 호출했고 매번 긴 보고가 돌아왔으니 그럴듯했다. 그 답이 맞는지 재보기로 했다.
어떻게 측정했나
라이선스는 모델별 라이선스 문서를 직접 확인했다. 이번에 실제로 걸린 것이 둘이다.
| 모델 | 판정 | 근거 |
|---|---|---|
| Hunyuan 계열(3D·이미지·비디오) | 영구 배제 | 한국 지역이 사용 제외 대상 |
| Suno 무료·Basic 티어 | 게임 BGM 불가 | 비상업 한정 |
| ACE-Step v1 3.5B (7.17GB) | 채택 후보 | Apache 2.0 |
토큰은 세션 트랜스크립트를 직접 집계했다. 추정이 아니라 원본 로그다.
# 5,765행 JSONL 을 파싱해 assistant 메시지의 usage 를 일자별로 합산
python -c "... json.loads(line)['message']['usage'] ..."| 조건 | 값 |
|---|---|
| 대상 | 단일 세션 트랜스크립트 5,765행 |
| 기간 | 2026-08-05 ~ 08-08 |
| 환산 가중 | 캐시읽기 ×0.1 · 캐시쓰기 ×1.25 · 출력 ×5 (입력 토큰 등가) |
결과
토큰 — 내 진단이 틀렸다.
| 일자 | 메시지 | 캐시읽기 | 환산(입력등가) | 캐시읽기 비중 |
|---|---|---|---|---|
| 08-05 | 676 | 190.6M | 30.0M | 63.6% |
| 08-06 | 529 | 354.3M | 46.6M | 76.0% |
| 08-07 | 600 | 274.9M | 38.0M | 72.3% |
| 08-08 | 286 | 221.7M | 30.7M | 72.2% |
부서 호출 50회의 지시문 + 반환 보고를 전부 합치면 약 78k 토큰, 컨텍스트의 16%다. 반면 메시지당 평균 캐시읽기가 498k 토큰이고 그것이 비용의 70~76%다.
다만 78k가 작다는 뜻은 아니다. 한 번 들어온 보고는 남은 모든 턴에서 계속 재독된다. 08-06에 들어온 보고를 08-08에도 매 턴 읽는다. 증폭이 진짜 비용이다.
부서별로는 편중이 있었다. programmer 47.9k자 + game-designer 44.8k자로 둘이 54%다.
다음 단계
조치가 진단과 함께 바뀌었다. "보고를 줄인다"가 아니라 "컨텍스트를 나눈다"로 갔다.
- 트랙 분리 — 게임과 영상은 서로 관여하지 않으므로 세션을 나눈다. 섞여 있으면 게임 작업 중에도 영상 컨텍스트를 매 턴 재독한다.
- 보고 상한 40줄 / 2,000자 — 이걸 세우다 중복을 발견했다. 지금까지 긴 산출물을 파일에도 쓰고 보고에도 전문을 실어 같은 내용을 두 번 올리고 있었다. 이제 파일에 쓰고 경로 한 줄만 보고한다.
- 라이선스는 다음 회차에 ACE-Step 실제 산출물 품질을 재는 것으로 잇는다.
12GB를 넘길 수 있는가: 된다, 그런데 57배 느리다
무엇을 시도했나
대표 질문은 정확히 이랬다. "학습기가 12기가 말하는 건 VRAM의 필요 부분인가. 추가 가상 메모리 이용까지 가능한지 확인해봐라."
배경은 모션 LoRA 학습이다. Wan 2.2 A14B는 fp8로 눌러도 가중치만 약 14GB라 전용 12GB에 안 들어간다. "공유 GPU 메모리로 넘기면 되지 않나"가 자연스러운 가설이었다.
먼저 셋을 갈라야 했다. 자주 섞여 쓰이는데 서로 다른 것이다.
| 정체 | 우리 값 | |
|---|---|---|
| 전용 VRAM | GPU 기판 위 GDDR6X | 11.99 GB |
| 공유 GPU 메모리 | 시스템 RAM을 GPU가 빌려 씀 (sysmem fallback) | 이론상 약 32GB |
| 가상 메모리(페이지파일) | 디스크 | 4 GB |
어떻게 측정했나
두 단계로 쟀다. 첫 단계만 하고 멈췄으면 틀린 결론을 냈을 것이다.
1단계 — 할당이 되는가. 1GB씩 늘려가며 nvidia-smi 를 같이 본다.
2단계 — 쓸 만한가. matmul 만 재면 안 된다. 학습은 forward + backward + optimizer 로 파라미터 전체를 매 스텝 건드리기 때문이다. 그래서 AdamW 학습 스텝을 모델 크기를 키워가며 재고 백만 파라미터당 비용으로 정규화했다.
python scripts/vram_spill_probe.py| 조건 | 값 |
|---|---|
| 하드웨어 | RTX 4070 Ti 12GB · RAM 63.8GB · 드라이버 610.88 |
| torch | 2.12.1+cu130 (CUDA 13.0) |
| 모델 | nn.Linear(h,h) × L, fp16, AdamW, batch 32 |
| 반복 | warmup 2 + 측정 5 |
결과
1단계 — 폴백은 켜져 있다. 20GB까지 할당했고 OOM이 없었다. nvidia-smi 는 11,957 MiB 에서 멈춘다. 그 위는 시스템 RAM으로 넘어간 것이다.
2단계 — 대가는 약 57배다.
| 파라미터 | torch 점유 | nvidia-smi | 스텝 | 백만 param당 |
|---|---|---|---|---|
| 134 M | 1.02 GB | 2,240 MiB | 15.6 ms | 0.116 ms |
| 336 M | 2.52 GB | 4,133 MiB | 38.9 ms | 0.116 ms |
| 755 M | 5.64 GB | 8,125 MiB | 89.0 ms | 0.118 ms |
| 1,208 M | 9.02 GB | 11,798 MiB | 7,991.8 ms | 6.615 ms |
| 1,879 M | 14.02 GB | 11,797 MiB | 11,614.1 ms | 6.180 ms |
앞의 셋은 0.116 / 0.116 / 0.118 로 평평하다. 네 번째에서 6.6ms 로 뛴다.
여기서 나온 두 번째 발견이 더 실용적이다. 절벽은 12GB가 아니라 약 9GB에서 온다. torch가 9.02GB를 잡은 시점에 nvidia-smi 는 이미 천장에 닿아 있다 — 드라이버 예약분과 단편화 때문에 전용 VRAM을 다 쓰기 전에 스필이 시작된다.
왜 추론은 되는데 학습은 안 되는가. 추론은 가중치를 한 번 읽고 지나간다. 학습은 매 스텝 파라미터 전체를 읽고, 쓰고, 다시 읽는다. 옵티마이저 상태 (AdamW는 파라미터당 fp32 두 개)까지 같이 왕복한다. PCIe를 그만큼 더 건넌다.
페이지파일도 걸린다. GPU 메모리로 직접 쓰이진 않지만 공유 GPU 메모리 할당이 Windows 커밋 한도를 소모한다.
물리 RAM 63.8GB + 페이지파일 4GB = 커밋 한도 67.8GB
이미 커밋됨 30.9GB → 남은 여유 약 37GB30GB 이상을 잡으려는 학습기는 OOM이 아니라 커밋 한도에 먼저 부딪힌다. 증상이 "메모리가 부족합니다" 계열이라 원인을 오해하기 쉽다.
다음 단계
폴백은 "안 되던 걸 되게 하는" 수단이지 "학습을 돌리는" 수단이 아니다. 필요한 것은 블록 스왑 — 트랜스포머 블록을 CPU↔GPU로 일정에 맞춰 옮기며 전송을 연산과 겹치는 방식이다.
| 드라이버 폴백 | 블록 스왑 | |
|---|---|---|
| 누가 정하나 | 드라이버가 눈먼 채로 | 학습기가 알고서 |
| 전송 시점 | 접근할 때마다 | 미리, 연산과 겹쳐서 |
| 실측 대가 | 약 57배 | 미측정 — 다음 검증 대상 |
A14B가 블록 스왑으로 12GB에서 실제로 도는지는 아직 우리가 확인하지 않았다. 학습기 설치 승인의 실제 내용이 그 검증이고, "설치했는데 못 돌린다"가 가능하다는 것을 알고 승인해야 한다. 페이지파일 64GB 상향도 같이 권고했다 — 속도를 올리는 게 아니라 실패를 막는 조치다.
품질은 모델이 아니라 접점에서 깨졌다
무엇을 시도했나
영상 파이프라인을 다시 돌리며 품질 결함을 추적했다. 구조는 이렇다.
와이드 마스터 스틸 1장 storyboard_stills.py (Z-Image Turbo)
→ 5초 클립 N개 체이닝 chain_clips.py (Wan 2.2 I2V)
→ 크롭 팬으로 카메라 zombie_motion.py (ffmpeg)
→ 파운드 푸티지 질감 found_footage.py (ffmpeg)각 단계에 이유가 있다.
- 왜 스틸을 먼저 뽑는가. 실측으로 확인했다 — I2V 품질은 입력 스틸이 결정한다. 잘못된 스틸을 넣으면 모델이 47프레임까지 그 톤을 끌고 간다. 스틸은 6초, 영상은 6분이다. 60배 싼 곳에서 실패하는 것이 옳다.
- 왜 5초씩 잇는가. Wan 2.2의 학습 길이가 약 5초로 알려져 있고, 우리가 실측한 "후반에 처음 장면으로 되감기는" 시점이 5~7초로 겹친다.
- 왜 카메라를 ffmpeg 크롭으로 만드는가. I2V는 큰 카메라 회전을 구조적으로 거부한다 — 프레임의 70~80%를 새로 발명해야 하기 때문이다. 크롭은 결정적이고 되돌리기가 공짜다.
- 왜 질감을 후처리로 거는가. 실패에서 배웠다. 스틸 프롬프트에
handheld phone footage를 넣었더니 모델이 실제로 폰을 든 손을 그렸다.
증상은 셋이었다. 채널 수 오류로 생성 자체가 죽었고, 옷의 훼손이 후반부로 갈수록 씻겨 나갔고, 마지막 컷이 눈에 띄게 어두웠다.
어떻게 측정했나
채널 오류는 에러 메시지의 숫자를 산수로 분해했다.
expected 36 channels, but got 64
36 = 16(잠재) + 4(마스크) + 16(이미지 잠재) ← Wan 2.1 VAE
64 = 48 + 16 ← Wan 2.2 VAE훼손 소실은 프롬프트 문자열이 실제로 어디까지 전달되는지 코드에서 역추적했다.
rg -n "CROWD_VARIETY" scripts/ # 정의 1곳, 참조 0곳어두워짐은 눈이 아니라 ffmpeg 로 쟀다. 컷별 평균 휘도다.
ffmpeg -ss <t> -t <d> -i clip.mp4 \
-vf signalstats,metadata=print:key=lavfi.signalstats.YAVG -f null -결과
결함 1 — VAE 짝이 틀렸다. Wan 2.2 A14B는 Wan 2.1 VAE(16채널)를 쓴다. 이름이 wan2.2_vae 인 파일은 5B-TI2V 전용(48채널)이다. 버전 숫자가 같다고 짝이 맞는 게 아니었다.
결함 2 — 죽은 상수. 한국인·훼손된 옷을 지정하는 CROWD_VARIETY 가 정의만 되고 어디서도 참조되지 않았다.
MOTIONS[m] = BROKEN_BODY (움직임)만 담는다 ← I2V 에 들어감
CROWD_VARIETY = W1~W4 (한국인·훼손된 옷) ← 아무 데도 안 들어감
MOTION_NEG = W4 부정어 ← I2V 에 들어감긍정문 없이 부정어만 들어가 있었다. 부정어는 "깨끗하게 그리지 마라"지 "훼손을 유지하라"가 아니다.
같은 날 비슷한 것을 하나 더 고쳤다. 스틸 프롬프트에서 의복 종류와 훼손을 따로 적었더니 모델이 훼손을 앞쪽 인물에만 걸었다. 붙여서 하나의 명사로 바꾸자 배경까지 적용됐다.
따로: "정장" + "전원 훼손됨" → 배경 인물이 새 옷
붙여서: "a shredded bloodstained office suit" → 배경까지 훼손결함 3 — 체이닝은 밝기도 물려받는다.
| 컷1 | 컷2 | 컷3 | |
|---|---|---|---|
| 보정 전 | 62.8 | 62.4 | 47.5 ← 24% 하락 |
| 보정 후 | 62.8 | 62.5 | 59.4 |
이게 왜 중요한가. 우리 채널에서 조회수가 터진 3편(명동·용산·낙원)의 공통점이 "좀비의 형상이 디테일하게 보였다"는 것이다. 컷3이 어두워지면 검증된 강점을 후반부에서 스스로 버린다. 보정은 감마가 아니라 가산 오프셋으로 했다 — 감마는 그림자를 들어올려 found_footage 의 블랙 리프트와 이중으로 걸린다.
결함 4 — 타임베이스. 보정본을 넣고 이어 붙이니 죽었다.
First input link main timebase (1/1000) do not match
the corresponding second input link xfade timebase (1/16384)원본은 webm(1/1000), 보정본은 mp4(1/16384). xfade 는 입력 타임베이스가 같아야 한다. 보정을 넣기 전에도 잠재해 있던 결함이다 — 입력이 전부 한 포맷이라 안 터졌을 뿐이다.
다음 단계
넷 다 모델 성능 문제가 아니다. 부품은 각자 규격을 통과했고, 부품이 만나는 자리에 규격이 없었다.
| 접점 | 깨진 것 |
|---|---|
| 모델 ↔ VAE | 채널 수 |
| 스틸 ↔ 영상 | 긍정 프롬프트 |
| 컷 ↔ 컷 | 노출 |
| webm ↔ mp4 | 타임베이스 |
3회차에서 게임 쪽에 나온 결함 6건도 정확히 같은 형태였다. 누적 10/10이다. 다음 회차에서는 접점별 검사를 파이프라인에 상시로 걸 계획이다 — 지금은 사람이 찾고 있고, 그 방식은 다음 접점이 생기면 또 놓친다.
아직 못 고친 것도 적는다. 좀비가 여전히 사람처럼 걷는다. BROKEN_BODY 가 프롬프트에 들어가 있는데도 안 먹힌다. 이건 누락이 아니라 텍스트로 못 이기는 사전지식이라 판단했고, 모션 LoRA로 가기로 했다. 근거는 아직 가설 수준이다.
콘솔에 실행 권한을 주지 않는다
무엇을 시도했나
대표가 자리를 비운 사이 장시간 작업(모션 LoRA 데이터 수집 등)을 돌릴 버튼을 사내 콘솔에 넣어달라고 했다.
여기서 설계 선택이 하나 있었다. 우리 콘솔은 외부 패키지 0개, 쓰기 경로 1개로 만들어져 있다. 회사 기록 전부를 읽는 권한으로 상시 떠 있는 프로세스라서 건 제약이다. 여기에 "명령 실행"을 붙이면 웹 UI 버그 하나가 임의 코드 실행이 된다.
그래서 버튼이 실행하지 않게 만들었다.
콘솔 버튼 → inbox.jsonl 에 {type:"night_job", job:"<id>"} 한 줄 append (서버는 여기까지)
→ night_queue.py 가 화이트리스트 대조 후 실행 (실행은 여기서만)
→ 콘솔 알림 + 디스코드 회신 — 성공·실패·차단 전부어떻게 측정했나
설계를 주장으로 두지 않고 실제로 때려서 확인했다. 브라우저 콘솔에서 API 를 직접 호출해 세 경우를 넣었다.
fetch('/api/inbox', { method:'POST', headers:{'Content-Type':'application/json'},
body: JSON.stringify({ type:'night_job', job:'rm -rf /' }) })그리고 큐 처리기를 실제로 돌려 화이트리스트 차단을 확인했다.
python scripts/night_queue.py --once --no-discord결과
| 시도 | 결과 |
|---|---|
정상 gpu_video | 200 통과 → 실행 완료 |
rm -rf / 주입 | 400 차단 (서버 정규식 ^[a-z0-9_]{1,32}$) |
미등록 not_a_real_job | 서버 통과, 실행기가 차단 + 사유 회신 |
이중 게이트가 의도대로 작동한다. 콘솔이 보내는 것은 작업 id 하나이고, 명령 문자열은 애초에 받지 않는다. 이건 원격 디스코드 정책과 같은 원칙이다 — 들어온 텍스트는 데이터지 명령이 아니다.
차단 시 사유를 반드시 회신하게 한 것도 같은 이유다. 조용히 무시하면 대표는 명령이 유실된 것으로 오인한다.
다음 단계
작업 스케줄러 등록 스크립트를 같이 넣었다 — 본부 세션이 꺼져 있어도 돌아야 "자리를 비운 사이"가 성립한다. 첫 실전 사용(모션 스윕 약 150분)은 아직 안 돌렸고, 그 결과가 다음 회차의 재료다.
금지 조항이 없는 문제를 막고 있었다
무엇을 시도했나
게임 BGM 설계에 "BGM 금지 대역 1.2kHz~8kHz" 라는 조항을 넣었다. 근거는 실측이었다 — 우리 SFX 스펙트럼 중심이 SMG 7425Hz, 라이플 6524Hz, 매그넘 4442Hz, 좀비 신음 1514Hz라 그 대역이 전부 붐빈다. 특히 좀비 신음은 −14dB로 가장 작은 소리이면서 화면 밖 스폰 방향을 알리는 정보 채널이다.
대표가 반려했다. "굳이 금지하여 좋은 BGM을 사용하지 못하게 하는 것이 더 안 좋아 보인다. 특히 타이틀 곡이나 다른 부분에서도 활용이 가능하기에."
어떻게 측정했나
반려가 맞는지 확인하려고 조항의 적용 범위와 충돌의 발생 범위를 대조했다. 측정 도구는 필요 없었다. 게임 상태별로 어떤 SFX가 재생되는지 세면 끝나는 문제였다.
| 화면 | 총성 | 좀비 신음 | 대역 충돌 |
|---|---|---|---|
| 타이틀 · 메뉴 · 상점 · 결과 · 3택 | 없음 | 없음 | 없음 |
| 영상 · 트레일러 | 없음 | 없음 | 없음 (게임 믹서를 안 탄다) |
| 전투 중 | 초당 7~11회 | 초당 3회 | 있음 |
결과
원안의 오류는 근거가 아니라 적용 범위였다. SFX 충돌은 전투 중에만 일어나는데 금지는 곡 전체·전 트랙에 걸려 있었다. 없는 문제를 막느라 곡의 절반을 버리는 설계였다.
개정: 작곡은 전대역 자유. 전투 중에만 AudioMixer 스냅샷이 실시간으로 처리한다.
BGM_Open (전투 밖) 처리 없음. 원곡 그대로
BGM_Combat (전투 중) 1.4k/2.3k 노치 −5dB + 3k↑ 하이셸프 −4dB, 0.6초 보간기존 Duck Volume(−6dB)과 곱해져 좀비 신음 보호는 실질 −11dB — 원안 −12dB와 동등하되 총성이 없는 순간에는 곡이 온전히 들린다. 신규 코드 0줄.
원안이 −12dB를 요구한 이유도 뒤늦게 보였다. 정적 최악값으로 계산했기 때문이다. 실제로는 덕킹이 발사음마다 이미 −6dB를 먹이므로 EQ는 그 사이만 담당하면 된다.
다음 단계
이 건은 기술 결함이 아니라 판단 결함이라 따로 남긴다. 정적 최악값으로 계산하면 항상 더 강한 제약이 나오는데, 그 제약이 언제 필요한지를 안 따지면 필요 없는 곳까지 묶는다. 앞으로 제약을 적을 때 조건을 같이 적기로 했다.
BGM 실제 생성은 ACE-Step 다운로드 승인 대기다. 대표가 참고용으로 준 트랙을 분석했더니 에너지의 54%가 1.2kHz 위에 있었다 — 감상용 곡이지 게임 언더스코어가 아니다. 영상·트레일러 레퍼런스로 쓰고, 인게임은 별도 설계로 간다.
그래서 로컬 제작에서 가장 중요한 것
도구 목록으로 답하고 싶었지만, 이번 회차가 준 답은 그게 아니다.
1. 재기 전에는 아무것도 모른다. "공유 메모리로 늘리면 된다", "서브에이전트가 범인이다", "모델 한계다" — 셋 다 그럴듯했고 셋 다 틀렸다. 틀린 진단은 틀린 조치로 이어지고, 틀린 조치는 효과가 없는데 시간은 쓴다. scripts/vram_spill_probe.py 처럼 재현 가능한 자를 남기는 것이 그래서 중요하다.
2. 병목은 대개 부품이 아니라 접점에 있다. 이번 회차 4/4, 지난 회차 6/6. 누적 10/10이다. 로컬은 부품을 직접 고를 수 있는 대신 접합부가 전부 우리 책임이 된다. 모델을 바꾸기 전에 접점에 규격이 있는지 먼저 본다.
3. 라이선스는 성능보다 먼저 본다. 나중에 발견하면 이미 만든 것을 버려야 한다.
4. 제약을 걸 때는 "언제 필요한가"까지 적는다. 근거가 맞아도 적용 범위가 틀리면 필요 없는 곳까지 묶는다.
5. 12GB는 12GB가 아니다. 드라이버 예약과 단편화 때문에 실질 천장은 약 9GB다. 카탈로그 숫자를 그대로 계획에 넣으면 안 된다.
부록 — 도구별 한 줄 근거
이번 회차에 실제로 돌린 것들과, 왜 그것인지.
| 도구 | 왜 |
|---|---|
| Wan 2.2 I2V A14B GGUF Q5_K_M | 12GB에서 2단 MoE 순차 스왑으로 돌아가는 상한. VAE는 Wan 2.1(16채널) |
| Lightning 4스텝 LoRA | 스텝 수가 곧 시간이다. 4스텝이면 5초 클립이 5~8분 |
| Z-Image Turbo int8 | 스틸 6초. 영상 6분의 60분의 1에서 실패해야 한다. CLIP 타입은 qwen_image |
| ComfyUI-GGUF | 양자화 UNet 로더. 없으면 A14B가 12GB에 안 들어간다 |
| ffmpeg | 카메라·질감·휘도 보정 전부. 결정적이라 되돌리기가 공짜다 |
| Ollama qwen3:14b | 대량 반복 텍스트. 영상 모드 전환 시 8,936 MiB 실측 회수 |
| ACE-Step v1 3.5B | Apache 2.0. Suno 무료 티어의 비상업 제약을 피하는 경로 |
| Unity 6000.0.59f2 batchmode | EditMode 50 / PlayMode 235 자동 검증 |
마지막 항목에 함정이 둘 있었다.
-quit를-runTests와 같이 주면 테스트 전에 종료된다. 결과 XML이 안 나오는데 종료 코드는 0이라 성공처럼 보인다.- 배치모드는 프레임이 실시간보다 훨씬 느리다. 20초짜리 게임 시간을 관찰하는 테스트가 180초 타임아웃에 걸렸다. 게임 시간에 의존하는 테스트는 관찰 대신 상태를 직접 밀어 넣어야 한다.