Diffusers
Safetensors
AR / models /vae.py
xfcghj's picture
Upload folder using huggingface_hub
394918c verified
Raw
History Blame Contribute Delete
3.63 kB
import os
import sys
triposg_root = "/home/dataset-assist-0/usr/lh/ysh/dw/RL/AR/TripoSG"
if triposg_root not in sys.path:
sys.path.append(triposg_root)
import torch
import torch.nn as nn
import numpy as np
import trimesh
from triposg.models.autoencoders import TripoSGVAEModel
class TripoSGVaeWrapper(nn.Module):
def __init__(self, weights_dir: str = "/home/dataset-assist-0/usr/lh/ysh/dw/RL/AR/TripoSG/pretrained_weights/TripoSG", device: str = "cuda", dtype: torch.dtype = torch.float16):
super().__init__()
self.device = device
self.dtype = dtype
self.vae = TripoSGVAEModel.from_pretrained(
weights_dir, subfolder="vae",
).to(self.device).to(torch.float32) # 内部运算保持 float32
self.vae.eval()
for param in self.vae.parameters():
param.requires_grad = False
def preprocess_mesh(self, vertices: torch.Tensor, faces: torch.Tensor, num_samples: int = 51200, seed: int = 42) -> torch.Tensor:
# 0. 基础清洗:防止输入数据包含 inf 或极大的离群点
vertices = torch.clamp(vertices, -1e6, 1e6)
vertices = torch.nan_to_num(vertices, nan=0.0, posinf=1e6, neginf=-1e6)
verts_np = vertices.detach().cpu().numpy()
faces_np = faces.detach().cpu().numpy()
# 1. 基础修复 (保留原始形状)
mesh = trimesh.Trimesh(vertices=verts_np, faces=faces_np, process=True)
if mesh.is_empty: return None
# 2. 原始比例归一化 (关键点:不要改变尺度比例)
max_edge = np.max(mesh.bounding_box.extents)
scale = 2.0 / (max_edge + 1e-8)
# 使用原始中心位置,不要做任何裁剪
normalized_vertices = (mesh.vertices - mesh.center_mass) * scale
norm_mesh = trimesh.Trimesh(vertices=normalized_vertices, faces=mesh.faces, process=False)
# 3. 采样 (使用 trimesh 原生 sampler)
if seed is not None:
np.random.seed(seed)
surface_points, face_indices = trimesh.sample.sample_surface(norm_mesh, count=num_samples)
surface_normals = norm_mesh.face_normals[face_indices]
# 4. 最后防线:对采样结果进行 NaN 检查,如果极个别 NaN,用 0 替换,而不改变整体点云
surface_points = np.nan_to_num(surface_points, nan=0.0)
surface_normals = np.nan_to_num(surface_normals, nan=0.0)
# 转换为 float32 保证 VAE 计算精度
surface_tensor = torch.cat([torch.from_numpy(surface_points), torch.from_numpy(surface_normals)], dim=-1).float()
return surface_tensor.unsqueeze(0).to(self.device)
@torch.no_grad()
def encode_mesh(
self,
vertices,
faces,
num_samples: int = 51200,
surface_seed: int = 42,
vae_seed: int = 42,
) -> torch.Tensor:
surface_tensor = self.preprocess_mesh(
vertices,
faces,
num_samples=num_samples,
seed=surface_seed,
)
if surface_tensor is None:
return None
encoder_output = self.vae.encode(surface_tensor, seed=vae_seed)
latent = encoder_output.latent_dist.mode()
return latent.to(self.dtype)
@torch.no_grad()
def decode_latent(self, latent_sample: torch.Tensor, sampled_points: torch.Tensor) -> torch.Tensor:
# 解码时保持 float32,避免计算溢出
return self.vae.decode(latent_sample.to(torch.float32), sampled_points=sampled_points.to(torch.float32)).sample