File size: 3,867 Bytes
f2fb01e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | """LaCT (Large-Chunk TTT, LVSM ๊ณ์ด) ๋ฅผ abl kit ํ์ต ๋ฃจํ์ ๋ผ์ฐ๋ wrapper.
๋ชจ๋ธ ์ฝ๋๋ git clone ํ LaCT repo (lact_nvs/model.py, lact_ttt.py) ๋ฅผ ์์ ์์ด ๊ทธ๋๋ก ์ด๋ค.
kit ์ ์
๋ ฅ (images, rays, camera_cond, num_cond_views) ์ LaCT ์
๋ ฅ์ผ๋ก ๋ฐ๊ฟ ๋ฟ์ด๋ค:
camera_cond["extrinsics"] = ์ ๊ทํ๋ c2w ์ ์ญํ๋ ฌ (w2c, normalize_for_da3=False)
camera_cond["intrinsics"] = ํ์ต ํด์๋ (256x256) ๊ธฐ์ค K
-> LaCT ์ c2w / fxfycxcy. kit ์ renderer ๊ฐ ์ฐ๋ Plucker ray ์ ๊ฐ์ ์นด๋ฉ๋ผ ์ ๊ทํ
(์ฒซ context ์นด๋ฉ๋ผ ๊ธฐ์ค, ๊ฐ์ฅ ๋จผ context ์นด๋ฉ๋ผ๊ฐ 1/1.35) ๋ฅผ ๊ทธ๋๋ก ๋ฐ๋๋ค.
์ถ๋ ฅ์ kit ๋ชจ๋ธ๊ณผ ๊ฐ์ด [context ์ด๋ฏธ์ง, ๋ ๋๋งํ target] ์ view ์ถ์ผ๋ก ๋ถ์ฌ ๋๋ ค์ค๋ค.
"""
import os
import sys
import torch
import torch.nn as nn
import torch.utils.checkpoint
from omegaconf import OmegaConf
def _import_lact(lact_nvs_dir):
# LaCT config ์ block type ์ด "model.SelfAttention", "lact_ttt.FastWeightGluMLPMultihead"
# ์ฒ๋ผ top-level ๋ชจ๋ ์ด๋ฆ์ด๋ผ lact_nvs ํด๋๋ฅผ sys.path ์ ๋ฃ์ด์ผ ํ๋ค.
lact_nvs_dir = os.path.abspath(lact_nvs_dir)
if lact_nvs_dir not in sys.path:
sys.path.insert(0, lact_nvs_dir)
import model as lact_model # noqa: E402 (LaCT/lact_nvs/model.py)
assert os.path.dirname(os.path.abspath(lact_model.__file__)) == lact_nvs_dir, lact_model.__file__
return lact_model
class LaCTWrapper(nn.Module):
def __init__(self, lact_nvs_dir, lact_config, ckpt_blocks=0, compile_blocks=False):
super().__init__()
lact_model = _import_lact(lact_nvs_dir)
cfg = OmegaConf.to_container(OmegaConf.load(lact_config), resolve=True)
self.lact = lact_model.LaCTLVSM(**cfg)
# ํ์ต ์ค ์์์๋ถํฐ ckpt_blocks ๊ฐ Block ์ activation checkpointing ํ๋ค (0 = ๋).
# Block.forward ๋ง ๋ฐ๊พธ๋ฏ๋ก state_dict key ๋ LaCTLVSM ๊ทธ๋๋ก๋ค.
self.ckpt_blocks = int(ckpt_blocks)
for i, blk in enumerate(self.lact.blocks):
if i < self.ckpt_blocks:
blk.forward = self._ckpt_forward(blk.forward)
# LaCT README: TTT ๋ชจ๋ธ์ compile ํด์ผ ์ ์๋๊ฐ ๋๋ค. Block ์ ํ๋์ฉ in-place ๋ก compile
# ํ๊ณ checkpoint ๋ compile ์์์ ๋๋ค (2026-11-13 memtest, B300):
# LaCTLVSM ์ ์ฒด๋ฅผ compile -> inductor ์ปค๋์ด "misaligned address" ๋ก ์ฃฝ๋๋ค.
# checkpoint ๋ฐ๊นฅ + compile ์์ชฝ -> backward ์ฌ๊ณ์ฐ์์ CheckpointError.
self.compile_blocks = bool(compile_blocks)
if self.compile_blocks:
# block ๋ง๋ค guard (forward closure id) ๊ฐ ๋ฌ๋ผ block ์๋งํผ ์ฌ์ปดํ์ผ๋๋ค (๊ธฐ๋ณธ ํ๋ 8).
torch._dynamo.config.recompile_limit = 128
torch._dynamo.config.accumulated_recompile_limit = 1024
for blk in self.lact.blocks:
blk.compile()
def _ckpt_forward(self, fwd):
def run(x, info):
if self.training and torch.is_grad_enabled():
return torch.utils.checkpoint.checkpoint(fwd, x, info, use_reentrant=False)
return fwd(x, info)
return run
def forward(self, images, rays, camera_cond, num_cond_views, timeit=False):
n = int(num_cond_views)
w2c = camera_cond["extrinsics"].to(images.device).float()
K = camera_cond["intrinsics"].to(images.device).float()
c2w = torch.linalg.inv(w2c)
fxfycxcy = torch.stack([K[..., 0, 0], K[..., 1, 1], K[..., 0, 2], K[..., 1, 2]], dim=-1)
input_data = {"image": images[:, :n].float(), "fxfycxcy": fxfycxcy[:, :n], "c2w": c2w[:, :n]}
target_data = {"fxfycxcy": fxfycxcy[:, n:], "c2w": c2w[:, n:]}
rendered = self.lact(input_data, target_data)
return torch.cat([images[:, :n], rendered.to(images.dtype)], dim=1)
|