Download modules/subdivider_runtime.py from MayMeHappy/mul: direct link, hf CLI and curl.
- Browser
- Download file 21.9 kB
-
https://huggingface.co/MayMeHappy/mul/resolve/main/modules/subdivider_runtime.py
- Command line
-
hf download hf://MayMeHappy/mul/modules/subdivider_runtime.py
-
curl -L -o subdivider_runtime.py https://huggingface.co/MayMeHappy/mul/resolve/main/modules/subdivider_runtime.py
21.9 kB
| import gc | |
| import glob | |
| import math | |
| import os | |
| import random | |
| import re | |
| from pathlib import Path | |
| import numpy as np | |
| import torch | |
| import trimesh | |
| from accelerate import Accelerator, DistributedDataParallelKwargs | |
| from tqdm import tqdm | |
| from utils.config import load_config | |
| from dataset.mesh_dataset import mul_encode_mesh, discrete_undiscrete_and_clean | |
| from models.subdivider import DiscreteDiffusionTransformer, sample_refine_tokens_with_topology, sample_refine_tokens_with_topology_fm | |
| from modules.octree_codec_acc import MeshCodec | |
| from utils.postprocessing import _fill_holes | |
| from utils.data_utils import normalize | |
| def set_seed(seed): | |
| random.seed(seed) | |
| np.random.seed(seed) | |
| torch.manual_seed(seed) | |
| if torch.cuda.is_available(): | |
| torch.cuda.manual_seed(seed) | |
| torch.cuda.manual_seed_all(seed) | |
| torch.backends.cudnn.deterministic = True | |
| torch.backends.cudnn.benchmark = False | |
| os.environ["PYTHONHASHSEED"] = str(seed) | |
| def _depth_from_resolution(resolution): | |
| if resolution <= 0: | |
| raise ValueError(f"resolution must be positive, got {resolution}") | |
| depth = int(round(math.log2(resolution))) | |
| if (1 << depth) != resolution: | |
| raise ValueError(f"resolution must be power of 2, got {resolution}") | |
| return depth | |
| def restore_non_pad_token(token: torch.Tensor, shift: int, pad_id: int = 0): | |
| if shift == 0: | |
| return token | |
| restored = token.clone() | |
| non_pad_mask = restored != pad_id | |
| restored[non_pad_mask] = restored[non_pad_mask] + shift | |
| return restored | |
| def read_dataset_paths(txt_path): | |
| mesh_paths = [] | |
| with open(txt_path, "r") as f: | |
| for line in f: | |
| path = line.strip() | |
| if path: | |
| mesh_paths.append(path) | |
| return mesh_paths | |
| def raw_stem_to_pair_key(raw_path): | |
| stem = Path(raw_path).stem | |
| # raw name example: 1(42)_y_f_4244 -> pair key: 1(42) | |
| return re.sub(r"_y_f_\d+$", "", stem) | |
| def gt_stem_to_pair_key(gt_path): | |
| return Path(gt_path).stem | |
| def get_face_count(file_path): | |
| """ | |
| 使用正则表达式从文件名中提取面片数量 | |
| 支持格式: *_f{num}_v*.obj 或 *_facenum_{num}_*.glb | |
| """ | |
| filename = Path(file_path).name | |
| match = re.search(r'_f(\d+)_v|_facenum_(\d+)', filename) | |
| if match: | |
| # group(1) 对应 _f(\d+)_v 里的数字 | |
| # group(2) 对应 _facenum_(\d+) 里的数字 | |
| return int(match.group(1) or match.group(2)) | |
| return None | |
| # def build_raw_gt_pairs(raw_txt_path, gt_txt_path): | |
| # raw_paths = read_dataset_paths(raw_txt_path) | |
| # gt_paths = read_dataset_paths(gt_txt_path) | |
| # # If two txt paths are the same source, pair each mesh with itself directly. | |
| # if Path(raw_txt_path).resolve() == Path(gt_txt_path).resolve(): | |
| # return [(p, p) for p in raw_paths], [] | |
| # gt_by_key = {} | |
| # for gt_path in gt_paths: | |
| # gt_by_key[gt_stem_to_pair_key(gt_path)] = gt_path | |
| # pairs = [] | |
| # missing_gt = [] | |
| # for raw_path in raw_paths: | |
| # key = raw_stem_to_pair_key(raw_path) | |
| # gt_path = gt_by_key.get(key) | |
| # if gt_path is None: | |
| # missing_gt.append(raw_path) | |
| # continue | |
| # pairs.append((raw_path, gt_path)) | |
| # return pairs, missing_gt | |
| def build_raw_gt_pairs(raw_txt_path, gt_txt_path, min_faces=None, max_faces=None): | |
| raw_paths = read_dataset_paths(raw_txt_path) | |
| gt_paths = read_dataset_paths(gt_txt_path) | |
| # ===== 新增过滤逻辑 ===== | |
| filtered_raw_paths = [] | |
| for p in raw_paths: | |
| if min_faces is None and max_faces is None: | |
| filtered_raw_paths.append(p) | |
| continue | |
| faces = get_face_count(p) | |
| if faces is not None: | |
| # 检查是否在指定范围内 | |
| if min_faces is not None and faces < min_faces: | |
| continue | |
| if max_faces is not None and faces > max_faces: | |
| continue | |
| filtered_raw_paths.append(p) | |
| else: | |
| # 如果文件名中没找到面片数特征,默认保留(你也可以改为 continue 丢弃它) | |
| filtered_raw_paths.append(p) | |
| raw_paths = filtered_raw_paths | |
| # ======================== | |
| # If two txt paths are the same source, pair each mesh with itself directly. | |
| if Path(raw_txt_path).resolve() == Path(gt_txt_path).resolve(): | |
| return [(p, p) for p in raw_paths], [] | |
| gt_by_key = {} | |
| for gt_path in gt_paths: | |
| gt_by_key[gt_stem_to_pair_key(gt_path)] = gt_path | |
| pairs = [] | |
| missing_gt = [] | |
| for raw_path in raw_paths: | |
| key = raw_stem_to_pair_key(raw_path) | |
| gt_path = gt_by_key.get(key) | |
| if gt_path is None: | |
| missing_gt.append(raw_path) | |
| continue | |
| pairs.append((raw_path, gt_path)) | |
| return pairs, missing_gt | |
| def save_gt_mesh(mesh, out_dir, name): | |
| gt_mesh = trimesh.Trimesh(vertices=mesh.vertices.copy(), faces=mesh.faces.copy(), process=False) | |
| gt_mesh.vertices = gt_mesh.vertices[:, [1, 2, 0]] | |
| gt_mesh.export(os.path.join(out_dir, f"{name}_gt.obj")) | |
| def save_raw_gt_mesh(mesh, out_dir, name): | |
| gt_mesh = trimesh.Trimesh(vertices=mesh.vertices.copy(), faces=mesh.faces.copy(), process=False) | |
| gt_mesh.vertices = gt_mesh.vertices[:, [1, 2, 0]] | |
| gt_mesh.export(os.path.join(out_dir, f"{name}_raw_gt.obj")) | |
| def save_stage_input_mesh(mesh, out_dir, name, stage_in_res, stage_out_res, stage_in_depth): | |
| coarse_mesh = trimesh.Trimesh(vertices=mesh.vertices.copy(), faces=mesh.faces.copy(), process=False) | |
| coarse_mesh.vertices = coarse_mesh.vertices[:, [1, 2, 0]] | |
| suffix = f"_stage_{stage_in_res}to{stage_out_res}_input_coarse" | |
| coarse_mesh.export(os.path.join(out_dir, f"{name}{suffix}_depth{stage_in_depth}.obj")) | |
| def save_stage_prediction(codec, raw_token, refine_token, out_dir, name, target_depth, suffix, fix_holes, raw_dis_mesh=None, gt_dis_mesh=None): | |
| eos_mask = raw_token[0] == 0 | |
| if eos_mask.any(): | |
| raw_tokens = raw_token[0, : int(torch.where(eos_mask)[0][0])].detach().cpu().long().tolist() | |
| else: | |
| raw_tokens = raw_token[0].detach().cpu().long().tolist() | |
| eos_mask_refine = refine_token[0] == 0 | |
| if eos_mask_refine.any(): | |
| refine_tokens = refine_token[0, : int(torch.where(eos_mask_refine)[0][0])].detach().cpu().long().tolist() | |
| else: | |
| refine_tokens = refine_token[0].detach().cpu().long().tolist() | |
| shared_len = min(len(raw_tokens), len(refine_tokens)) | |
| block = (shared_len // 9) * 9 | |
| if block <= 0: | |
| return None | |
| raw_tokens = raw_tokens[:block] | |
| refine_tokens = refine_tokens[:block] | |
| interleaved = [] | |
| for i in range(0, block, 9): | |
| interleaved.extend(raw_tokens[i : i + 9]) | |
| interleaved.extend(refine_tokens[i : i + 9]) | |
| mesh = codec.decode_tokens(interleaved, target_depth=target_depth-1) | |
| if mesh is None: | |
| return None | |
| trimesh.repair.fix_normals(mesh) | |
| if fix_holes: | |
| verts = torch.tensor(mesh.vertices, device="cuda", dtype=torch.float32) | |
| faces = torch.tensor(mesh.faces, device="cuda", dtype=torch.int32) | |
| new_verts, new_faces = _fill_holes(verts, faces, debug=False, verbose=False, only_fill_holes=True) | |
| mesh = trimesh.Trimesh(vertices=new_verts.cpu().numpy(), faces=new_faces.cpu().numpy()) | |
| return_mesh = mesh.copy() | |
| mesh.vertices = mesh.vertices[:, [1, 2, 0]] | |
| mesh.export(os.path.join(out_dir, f"{name}{suffix}_depth{target_depth}.obj")) | |
| if raw_dis_mesh is not None: | |
| raw_dis_mesh.vertices = raw_dis_mesh.vertices[:, [1, 2, 0]] | |
| raw_dis_mesh.export(os.path.join(out_dir, f"{name}{suffix}_raw_dis_depth{target_depth-1}.obj")) | |
| if gt_dis_mesh is not None: | |
| gt_dis_mesh.vertices = gt_dis_mesh.vertices[:, [1, 2, 0]] | |
| gt_dis_mesh.export(os.path.join(out_dir, f"{name}{suffix}_gt_dis_depth{target_depth}.obj")) | |
| return return_mesh | |
| def process_one_mesh( | |
| raw_mesh_path, | |
| gt_mesh_path, | |
| model, | |
| mask_token_id, | |
| codec, | |
| device, | |
| pad_id, | |
| token_shift, | |
| config, | |
| output_folder, | |
| stage_resolutions, | |
| fix_holes=True, | |
| use_gt_pc=True | |
| ): | |
| import time | |
| t_start = time.time() | |
| import time | |
| t_total_start = time.time() | |
| name = Path(raw_mesh_path).stem | |
| t_start = time.time() | |
| mesh = trimesh.load(raw_mesh_path, force="mesh") | |
| mesh.vertices = mesh.vertices[:, [2, 0, 1]] | |
| gt_mesh = trimesh.load(gt_mesh_path, force="mesh") | |
| gt_mesh.vertices = gt_mesh.vertices[:, [2, 0, 1]] | |
| normalize(gt_mesh) | |
| normalize(mesh) | |
| save_raw_gt_mesh(mesh, output_folder, name) | |
| save_gt_mesh(gt_mesh, output_folder, name) | |
| t_load = time.time() | |
| print(f"[{name}] Load & normalize time: {t_load - t_start:.4f}s") | |
| stage_depths = [_depth_from_resolution(x) for x in stage_resolutions] | |
| # First-stage input uses codec encode-decode result at the minimum resolution. | |
| min_stage_depth = stage_depths[0] | |
| t_start = time.time() | |
| init_raw_token, _, init_quantized_mesh = codec.encode_mesh(mesh, target_depth=min_stage_depth) | |
| init_mesh = codec.decode_raw_tokens(init_raw_token, target_depth=min_stage_depth) | |
| t_init = time.time() | |
| print(f"[{name}] Init encode & decode (depth={min_stage_depth}): {t_init - t_start:.4f}s") | |
| if init_mesh is not None: | |
| current_mesh = init_mesh | |
| elif init_quantized_mesh is not None: | |
| current_mesh = init_quantized_mesh | |
| else: | |
| current_mesh = mesh.copy() | |
| for stage_idx in range(len(stage_depths) - 1): | |
| stage_start_time = time.time() | |
| stage_in_depth = stage_depths[stage_idx] | |
| stage_out_depth = stage_depths[stage_idx + 1] | |
| stage_in_res = stage_resolutions[stage_idx] | |
| stage_out_res = stage_resolutions[stage_idx + 1] | |
| save_stage_input_mesh( | |
| mesh=current_mesh, | |
| out_dir=output_folder, | |
| name=name, | |
| stage_in_res=stage_in_res, | |
| stage_out_res=stage_out_res, | |
| stage_in_depth=stage_in_depth, | |
| ) | |
| t_start = time.time() | |
| stage_data = mul_encode_mesh( | |
| raw_mesh=current_mesh, | |
| gt_mesh=gt_mesh, | |
| codec=codec, | |
| tokenizer_target_depth=stage_in_depth, | |
| pc_num=config.data_processing.pc_num, | |
| total_pc_num=config.data_processing.total_pc_num, | |
| use_gt_pc=use_gt_pc, | |
| clean=False | |
| ) | |
| t_mul_encode = time.time() | |
| print(f"[{name}] Stage {stage_in_res}->{stage_out_res} | mul_encode_mesh time: {t_mul_encode - t_start:.4f}s") | |
| raw_token = stage_data["raw_token"].unsqueeze(0).to(device) | |
| pc = stage_data["pc"].unsqueeze(0).to(device) | |
| t_start = time.time() | |
| # refine_token = sample_refine_tokens_with_topology( | |
| # model, | |
| # mask_token_id, | |
| # raw_token, | |
| # pc, | |
| # use_gumbel=False, | |
| # gumbel_temp_init=1.0, | |
| # use_soft_consensus=False, | |
| # consensus_start_step_ratio=0, | |
| # cfg_scale=1.0, | |
| # T_infer=config.evaluation.diffusion_sample_steps, | |
| # ) | |
| refine_token = sample_refine_tokens_with_topology_fm( | |
| model, | |
| mask_token_id, | |
| raw_token, | |
| pc, | |
| use_gumbel=False, | |
| gumbel_temp_init=1.0, | |
| use_soft_consensus=False, | |
| consensus_start_step_ratio=0, | |
| cfg_scale=1.0, | |
| T_infer=config.evaluation.diffusion_sample_steps, | |
| ) | |
| torch.cuda.synchronize() | |
| t_sample = time.time() | |
| print(f"[{name}] Stage {stage_in_res}->{stage_out_res} | sample_refine_tokens_with_topology time: {t_sample - t_start:.4f}s") | |
| refine_token = restore_non_pad_token(refine_token, shift=token_shift, pad_id=pad_id) | |
| t_start = time.time() | |
| stage_suffix = f"_stage_{stage_in_res}to{stage_out_res}" | |
| stage_mesh = save_stage_prediction( | |
| codec=codec, | |
| raw_token=raw_token, | |
| refine_token=refine_token, | |
| out_dir=output_folder, | |
| name=name, | |
| target_depth=stage_out_depth, | |
| suffix=stage_suffix, | |
| fix_holes=fix_holes, | |
| raw_dis_mesh=stage_data.get("raw_dis_mesh"), | |
| gt_dis_mesh=stage_data.get("gt_dis_mesh"), | |
| ) | |
| t_save_pred = time.time() | |
| print(f"[{name}] Stage {stage_in_res}->{stage_out_res} | save_stage_prediction (decode + fix) time: {t_save_pred - t_start:.4f}s") | |
| print(f"[{name}] Stage {stage_in_res}->{stage_out_res} | total stage time: {time.time() - stage_start_time:.4f}s\n") | |
| if stage_mesh is None: | |
| break | |
| current_mesh = stage_mesh | |
| print(f"[{name}] Total process_one_mesh time: {time.time() - t_total_start:.4f}s") | |
| class EMA: | |
| def __init__(self, model, decay=0.999): | |
| self.decay = decay | |
| self.shadow = {} | |
| self.register(model) | |
| def register(self, model): | |
| self.shadow = {} | |
| for name, param in model.named_parameters(): | |
| if param.requires_grad: | |
| self.shadow[name] = param.data.clone() | |
| def load_state_dict(self, state): | |
| self.decay = state.get("decay", self.decay) | |
| self.shadow = {k: v.clone() for k, v in state["shadow"].items()} | |
| def copy_to(self, model): | |
| """Swap shadow weights into the model in-place (for inference).""" | |
| copied, missing = 0, 0 | |
| for name, param in model.named_parameters(): | |
| if name in self.shadow: | |
| param.data.copy_(self.shadow[name].to(device=param.device, dtype=param.dtype)) | |
| copied += 1 | |
| else: | |
| missing += 1 | |
| print(f"[EMA.copy_to] copied {copied} params into model ({missing} not present in shadow)") | |
| def run_inference_on_all_checkpoints(model, mask_token_id, accelerator, config, device, pad_id, codec, token_shift, ema=None): | |
| ckpt_dir = "ckpt" | |
| output_folder = "./pretrain_model_mul_more_data_64_to_256_eval_complex_test_no_fix_holes_no_clean_cfg_1.0_fm" | |
| # raw_data_txt = "dataset/bpt_res_list.txt" /root/junkai_lin/mul_res_diffusion/demo/bpt_retrain_gt/data.txt | |
| # gt_data_txt = "dataset/trellis_clean_mesh.txt" /root/junkai_lin/mul_res_diffusion/demo/bpt_gt/data.txt | |
| raw_data_txt = "demo/complex_test_data/files/data.txt" | |
| gt_data_txt = "demo/complex_test_data/files/data.txt" | |
| # raw_data_txt = "/root/junkai_lin/mul_res_diffusion/demo/hun_yuan/data.txt" | |
| # gt_data_txt = "/root/junkai_lin/mul_res_diffusion/demo/hun_yuan/data.txt" | |
| stage_resolutions = [64, 128, 256] | |
| # raw_data_txt = "demo/tripo 1.0/data.txt" | |
| # gt_data_txt = "demo/tripo 1.0/data.txt" | |
| use_gt_pc=True | |
| fix_holes=False | |
| if accelerator.is_main_process: | |
| print(f"Using raw data txt: {raw_data_txt}") | |
| print(f"Using gt data txt: {gt_data_txt}") | |
| print(f"Searching checkpoints in: {ckpt_dir}") | |
| # mesh_pairs, missing_gt = build_raw_gt_pairs(raw_data_txt, gt_data_txt, max_faces=config.data_processing.max_face_num, min_faces=config.data_processing.min_face_num) | |
| mesh_pairs, missing_gt = build_raw_gt_pairs(raw_data_txt, gt_data_txt, max_faces=20000, min_faces=500) | |
| if accelerator.is_main_process: | |
| print(f"Matched raw/gt pairs: {len(mesh_pairs)}") | |
| if missing_gt: | |
| print(f"Raw without matched gt: {len(missing_gt)}") | |
| search_pattern = os.path.join(ckpt_dir, "checkpoint_*_epoch_*_loss.pth") | |
| ckpt_files = glob.glob(search_pattern) | |
| if not ckpt_files: | |
| if accelerator.is_main_process: | |
| print("No checkpoints found!") | |
| return | |
| ckpt_data = [] | |
| for f in ckpt_files: | |
| match = re.search(r"checkpoint_(\d+)_epoch_", f) | |
| if match: | |
| epoch = int(match.group(1)) | |
| ckpt_data.append((epoch, f)) | |
| ckpt_data.sort(key=lambda x: x[0]) | |
| # stage_resolutions = [32, 64, 128, 256] | |
| # stage_resolutions = [128, 256] | |
| for epoch, ckpt_path in ckpt_data: | |
| if accelerator.is_main_process: | |
| print(f"\n[{'='*40}]") | |
| print(f"Starting inference for epoch {epoch}") | |
| print(f"Loading weights from: {ckpt_path}") | |
| output_folder_ply = os.path.join(output_folder, f"{epoch}_epoch_val_generate_mul") | |
| if accelerator.is_main_process: | |
| os.makedirs(output_folder_ply, exist_ok=True) | |
| checkpoint = torch.load(ckpt_path, map_location=device) | |
| model_to_load = accelerator.unwrap_model(model) | |
| # Use strict=False so we can load older ckpts (no null_cond) into the | |
| # newer model class, and vice versa. Missing/unexpected keys are logged. | |
| load_result = model_to_load.load_state_dict(checkpoint["model_state_dict"], strict=False) | |
| missing = list(getattr(load_result, "missing_keys", []) or []) | |
| unexpected = list(getattr(load_result, "unexpected_keys", []) or []) | |
| if (missing or unexpected) and accelerator.is_main_process: | |
| print(f"[load_state_dict] strict=False -> missing={len(missing)} unexpected={len(unexpected)}") | |
| if missing: | |
| print(f" missing: {missing[:8]}{' ...' if len(missing) > 8 else ''}") | |
| if unexpected: | |
| print(f" unexpected: {unexpected[:8]}{' ...' if len(unexpected) > 8 else ''}") | |
| # Auto-detect EMA: if the ckpt has an `ema_state_dict`, swap those | |
| # shadow weights into the model for inference. Otherwise fall back to | |
| # the raw `model_state_dict` we already loaded above. No reliance on | |
| # config `use_ema` / a separate EMA object — just check the ckpt. | |
| ema_state = checkpoint.get("ema_state_dict") | |
| shadow = ema_state.get("shadow") if isinstance(ema_state, dict) else None | |
| if shadow: | |
| with torch.no_grad(): | |
| copied, skipped = 0, 0 | |
| for name, param in model_to_load.named_parameters(): | |
| if name in shadow: | |
| param.data.copy_(shadow[name].to(device=param.device, dtype=param.dtype)) | |
| copied += 1 | |
| else: | |
| skipped += 1 | |
| if accelerator.is_main_process: | |
| msg = f"[Epoch {epoch}] EMA shadow detected in ckpt -> applied to model ({copied} params" | |
| if skipped: | |
| msg += f", {skipped} model params not in shadow" | |
| print(msg + ")") | |
| else: | |
| if accelerator.is_main_process: | |
| print(f"[Epoch {epoch}] no EMA in ckpt -> running with raw model_state_dict weights.") | |
| with torch.no_grad(): | |
| model.eval() | |
| pbar = tqdm( | |
| enumerate(mesh_pairs), | |
| total=len(mesh_pairs), | |
| desc=f"Infer Epoch {epoch}", | |
| disable=not accelerator.is_local_main_process, | |
| dynamic_ncols=True, | |
| ) | |
| for line_idx, (raw_mesh_path, gt_mesh_path) in pbar: | |
| if line_idx % accelerator.num_processes != accelerator.process_index: | |
| continue | |
| try: | |
| process_one_mesh( | |
| raw_mesh_path=raw_mesh_path, | |
| gt_mesh_path=gt_mesh_path, | |
| model=model, | |
| mask_token_id=mask_token_id, | |
| codec=codec, | |
| device=device, | |
| pad_id=pad_id, | |
| token_shift=token_shift, | |
| config=config, | |
| output_folder=output_folder_ply, | |
| stage_resolutions=stage_resolutions, | |
| fix_holes=fix_holes, | |
| use_gt_pc=use_gt_pc, | |
| ) | |
| except Exception as e: | |
| print(f"[infer error] raw={raw_mesh_path}, gt={gt_mesh_path}: {str(e)}") | |
| torch.cuda.empty_cache() | |
| gc.collect() | |
| if accelerator.is_main_process: | |
| print("\nBatch inference complete for all checkpoints.") | |
| def main(config): | |
| print("start init Accelerator...") | |
| ddp_kwargs = DistributedDataParallelKwargs(find_unused_parameters=True) | |
| accelerator = Accelerator( | |
| gradient_accumulation_steps=config.accelerator.gradient_accumulation_steps, | |
| mixed_precision=config.accelerator.mixed_precision, | |
| kwargs_handlers=[ddp_kwargs], | |
| ) | |
| device = accelerator.device | |
| codec = MeshCodec(args=config.tokenizer) | |
| codec_config = codec.get_model_config() | |
| input_num_categories = codec_config["input_num_categories"] | |
| lm_num_categories = codec_config["output_num_categories"] | |
| pad_id = codec_config["pad_token_id"] | |
| token_shift = input_num_categories - 1 | |
| model = DiscreteDiffusionTransformer( | |
| vocab_A=input_num_categories, | |
| vocab_B=lm_num_categories, | |
| max_seq_len=config.data_processing.max_len, | |
| d_model=config.model.feature_dim, | |
| encoder_freeze=config.model.encoder_freeze, | |
| nhead=config.model.num_heads, | |
| depth=config.model.hourglass_depth, | |
| dropout=config.model.dropout, | |
| time_embed_scale=config.training.diffusion_train_steps, | |
| ) | |
| mask_token_id = model.mask_token_id | |
| use_ema = getattr(config.training, "use_ema", False) | |
| ema_decay = getattr(config.training, "ema_decay", 0.999) | |
| ema = EMA(model, decay=ema_decay) if use_ema else None | |
| model = accelerator.prepare(model) | |
| run_inference_on_all_checkpoints( | |
| model=model, | |
| mask_token_id=mask_token_id, | |
| accelerator=accelerator, | |
| config=config, | |
| device=device, | |
| pad_id=pad_id, | |
| codec=codec, | |
| token_shift=token_shift, | |
| ema=ema, | |
| ) | |
| if __name__ == "__main__": | |
| set_seed(42) | |
| config = load_config() | |
| main(config) | |