File size: 3,324 Bytes
90ca518 | 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 | """fix3 编码格式的数据通路工具 —— 从训练脚本抽出, 保证推理与训练用同一份实现。
split_fix3_token_list : 扁平 60/face token -> (coord_list[9*nface], subcode_list[9*nface,8] local)
subcodes_to_flat_token : (coord, 采样得到的 subcodes) -> fix3 扁平 60/face token(含 offset), 供 decode_tokens
"""
import torch
from models.generator import REFINE_POS_PER_FACE, NUM_OCTANTS
TOKENS_PER_FACE = 60 # fix3 扁平: 9 coord + 3 F + 6 矩阵 x 8 行
def _trim_trailing_pad(token, pad_id):
pad_pos = (token == pad_id).nonzero(as_tuple=True)[0]
return token[:pad_pos[0].item()] if pad_pos.numel() > 0 else token
def split_fix3_token_list(token_list, pad_id, device, codec_cfg):
"""扁平 60/face token -> (coord_list, subcode_list)。
coord_list[i] : [9*nface] 坐标(保留 coord_offset, 直接喂 raw_embedding)
subcode_list[i] : [9*nface, 8] refine 子码(去 offset, local[0,256))
位置顺序 [F0 F1 F2 M00 M11 M22 M01 M02 M12]
F 位置只用 slot0(其余槽填 0, 模型按类型只读 slot0);intra/inter 用 8 行
"""
f_off = codec_cfg["f_offset"]; ia = codec_cfg["intra_row_offset"]; ie = codec_cfg["inter_row_offset"]
coord_list, sub_list = [], []
for tok in token_list:
tok = _trim_trailing_pad(tok.to(device=device, dtype=torch.long), pad_id)
if tok.numel() % TOKENS_PER_FACE != 0:
raise ValueError(f"token 长度 {tok.numel()} 不是 {TOKENS_PER_FACE} 的倍数")
tok = tok.view(-1, TOKENS_PER_FACE) # [nface, 60]
nface = tok.size(0)
coord = tok[:, :9].reshape(-1) # [9*nface]
Fv = tok[:, 9:12] - f_off # [nface, 3]
intra = (tok[:, 12:36] - ia).view(nface, 3, NUM_OCTANTS) # [nface,3,8]
inter = (tok[:, 36:60] - ie).view(nface, 3, NUM_OCTANTS) # [nface,3,8]
sub = torch.zeros(nface, REFINE_POS_PER_FACE, NUM_OCTANTS, dtype=torch.long, device=device)
sub[:, 0:3, 0] = Fv # F -> slot0
sub[:, 3:6, :] = intra
sub[:, 6:9, :] = inter
sub_list.append(sub.reshape(-1, NUM_OCTANTS)) # [9*nface, 8]
coord_list.append(coord)
return coord_list, sub_list
def subcodes_to_flat_token(coord_seq, sub_seq, codec_cfg):
"""采样得到的 (coord[9*nface], subcodes[9*nface,8] local) 还原成 fix3 扁平 60/face token(含 offset),
供 codec.decode_tokens 使用。F 位置取 slot0。"""
f_off = codec_cfg["f_offset"]; ia = codec_cfg["intra_row_offset"]; ie = codec_cfg["inter_row_offset"]
nface = coord_seq.numel() // REFINE_POS_PER_FACE
coord = coord_seq.view(nface, REFINE_POS_PER_FACE) # [nface,9]
sub = sub_seq.view(nface, REFINE_POS_PER_FACE, NUM_OCTANTS) # [nface,9,8]
Fv = sub[:, 0:3, 0] + f_off # [nface,3] 取 slot0
intra = sub[:, 3:6, :] + ia # [nface,3,8]
inter = sub[:, 6:9, :] + ie
flat = torch.cat([coord, Fv, intra.reshape(nface, 24), inter.reshape(nface, 24)], dim=1) # [nface,60]
return flat.reshape(-1).tolist()
|