Spaces:
Runtime error
Runtime error
| import torch | |
| import os | |
| from pathlib import Path | |
| import numpy as np | |
| import json | |
| import sys | |
| # PROJECT_ROOT = Path(__file__).resolve().parent.parent | |
| # sys.path.insert(0, str(PROJECT_ROOT)) | |
| from .lib.model.unet1d import UNet1D | |
| from .lib.model.flow_matching import FlowMatching | |
| class PoseSampler: | |
| def __init__(self, | |
| device='cpu', | |
| dataset='pp'): | |
| """ | |
| 初始化 PoseSampler 类。 | |
| 在此处加载配置、统计量和模型,确保这些重型操作只执行一次。 | |
| """ | |
| self.device = torch.device(device) | |
| self.checkpoint_path = "src/sample_utils/lib/ckpt/fm_20251117_172225/checkpoints/best.pt" | |
| self.dataset = dataset | |
| self.stats_dir = "src/sample_utils/lib/data_stats" | |
| # 1. 自动检测 run_dir 并加载配置 | |
| self.run_dir = self._detect_run_dir(self.checkpoint_path) | |
| self.config = self._load_config(self.run_dir) | |
| # 2. 加载数据统计量 (Mean/Std) | |
| self.pose_mean, self.pose_std = self._load_pose_stats() | |
| # 3. 加载模型 | |
| self.model = self._load_model() | |
| print(f"Pose Sampler loaded successfully from {self.checkpoint_path}") | |
| def _detect_run_dir(self, checkpoint_path): | |
| """内部辅助方法:从 checkpoint 路径推断 run 目录""" | |
| abs_path = os.path.abspath(checkpoint_path) | |
| if 'checkpoints' in abs_path: | |
| checkpoint_dir = os.path.dirname(abs_path) | |
| if os.path.basename(checkpoint_dir) == 'checkpoints': | |
| return os.path.dirname(checkpoint_dir) | |
| return os.path.dirname(abs_path) | |
| def _load_config(self, run_dir): | |
| """内部辅助方法:加载 config.json""" | |
| config_path = os.path.join(run_dir, 'config.json') | |
| if not os.path.exists(config_path): | |
| raise FileNotFoundError(f"Config file not found at {config_path}") | |
| with open(config_path, 'r') as f: | |
| config = json.load(f) | |
| return config | |
| def _load_pose_stats(self): | |
| """内部辅助方法:加载 Pose 统计量""" | |
| if self.dataset == "pp": | |
| filename = "pose_stats.pt" | |
| else: | |
| filename = "t_pose_stats.pt" | |
| file_path = os.path.join(self.stats_dir, filename) | |
| if not os.path.exists(file_path): | |
| raise FileNotFoundError(f"Stats file not found at {file_path}") | |
| stats = torch.load(file_path, map_location=self.device, weights_only=False) | |
| return stats['mean'], stats['std'] | |
| def _load_model(self): | |
| """内部辅助方法:初始化并加载模型权重""" | |
| unet = UNet1D( | |
| pose_dim=72, | |
| base_channels=self.config['base_channels'], | |
| channel_multipliers=self.config['channel_multipliers'], | |
| time_emb_dim=self.config['time_emb_dim'], | |
| mid_structure=self.config['mid_structure'], | |
| mid_num_heads=self.config['mid_num_heads'] | |
| ).to(self.device) | |
| model = FlowMatching( | |
| model=unet, | |
| sigma=0.0 | |
| ).to(self.device) | |
| checkpoint = torch.load(self.checkpoint_path, map_location=self.device) | |
| if 'model_state_dict' in checkpoint: | |
| model.load_state_dict(checkpoint['model_state_dict']) | |
| else: | |
| model.load_state_dict(checkpoint) | |
| model.eval() | |
| return model | |
| def _unnormalize_pose(self, pose_norm): | |
| """内部辅助方法:反归一化""" | |
| return pose_norm * self.pose_std + self.pose_mean | |
| def sample(self, batch_size=1, num_steps=100, method="euler", verbose=False): | |
| """ | |
| 采样方法。 | |
| 每次调用只需执行推理,无需重新加载模型。 | |
| """ | |
| samples_norm = self.model.sample( | |
| sample_shape=(batch_size, 72), | |
| device=self.device, | |
| num_steps=num_steps, | |
| method=method, | |
| verbose=verbose | |
| ) | |
| samples_raw = self._unnormalize_pose(samples_norm) | |
| return samples_raw | |
| # 使用示例 | |
| if __name__ == '__main__': | |
| # 1. 实例化 Sampler (只加载一次模型,耗时操作在这里) | |
| print("Initializing sampler...") | |
| sampler = PoseSampler( | |
| device='cpu', | |
| dataset='pp' | |
| ) | |
| # 2. 多次采样 (非常快) | |
| print("Sampling batch 1...") | |
| pose_batch_1 = sampler.sample(batch_size=1) | |
| print("Sampling batch 2 (with different batch size)...") | |
| pose_batch_2 = sampler.sample(batch_size=4) # 甚至可以改变 batch size | |
| print(f"Batch 1 shape: {pose_batch_1.shape}") | |
| print(f"Batch 2 shape: {pose_batch_2.shape}") | |
| import pdb; pdb.set_trace() | |