# # Copyright (C) 2023, Inria # GRAPHDECO research group, https://team.inria.fr/graphdeco # All rights reserved. # # This software is free for non-commercial, research and evaluation use # under the terms of the LICENSE.md file. # # For inquiries contact george.drettakis@inria.fr # import os import json import glob import numpy as np import open3d as o3d import cv2 import torch import random from random import randint from utils.loss_utils import l1_loss, ssim from gaussian_renderer import render, network_gui import sys from scene import Scene, GaussianModel from utils.general_utils import safe_state import uuid from tqdm import tqdm from utils.image_utils import psnr from lpips.lpips import LPIPS as LPIPSModel from argparse import ArgumentParser, Namespace from arguments import ModelParams, PipelineParams, OptimizationParams try: from torch.utils.tensorboard import SummaryWriter TENSORBOARD_FOUND = True except ImportError: TENSORBOARD_FOUND = False def tv_loss(grids): """ https://github.com/apchenstu/TensoRF/blob/4ec894dc1341a2201fe13ae428631b58458f105d/utils.py#L139 Args: grids: stacks of explicit feature grids (stacked at dim 0) Returns: average total variation loss for neighbor rows and columns. """ number_of_grids = grids.shape[0] h_tv_count = grids[:, :, 1:, :].shape[1] * grids[:, :, 1:, :].shape[2] * grids[:, :, 1:, :].shape[3] w_tv_count = grids[:, :, :, 1:].shape[1] * grids[:, :, :, 1:].shape[2] * grids[:, :, :, 1:].shape[3] h_tv = torch.pow((grids[:, :, 1:, :] - grids[:, :, :-1, :]), 2).sum() w_tv = torch.pow((grids[:, :, :, 1:] - grids[:, :, :, :-1]), 2).sum() return 2 * (h_tv / h_tv_count + w_tv / w_tv_count) / number_of_grids def get_emb(sin_inp): """ Gets a base embedding for one dimension with sin and cos intertwined """ emb = torch.stack((sin_inp.sin(), sin_inp.cos()), dim=-1) return torch.flatten(emb, -2, -1) def load_raw_blurry_cache(scene, raw_blurry_glob, stride, sharp_skip_set): """Cache RAW (motion-blurred) source frames for BPN's dual-supervision loss_blur. Each non-sharp train camera (image_name not in sharp_skip_set) is mapped to its source RAW frame via raw_idx = int(image_name) * stride, then resized to match original_image's resolution. Ported from TriSplat train_bpn.py.""" cache = {} if not raw_blurry_glob: return cache raw_paths = sorted(glob.glob(raw_blurry_glob)) for cam in scene.getTrainCameras(): if cam.image_name in sharp_skip_set: continue raw_idx = int(cam.image_name) * stride if raw_idx >= len(raw_paths): continue raw = cv2.imread(raw_paths[raw_idx]) raw = cv2.cvtColor(raw, cv2.COLOR_BGR2RGB) raw = cv2.resize(raw, (cam.image_width, cam.image_height), interpolation=cv2.INTER_LANCZOS4) cache[cam.image_name] = torch.from_numpy(raw.astype(np.float32) / 255.0).permute(2, 0, 1) # CPU print(f"[raw_blurry] cached {len(cache)}/{len(scene.getTrainCameras())} RAW frames " f"for BPN dual-supervision (stride={stride}, src={raw_blurry_glob})") return cache def get_2d_emb(batch_size, x, y, out_ch, device): out_ch = int(np.ceil(out_ch / 4) * 2) inv_freq = 1.0 / (10000 ** (torch.arange(0, out_ch, 2).float() / out_ch)) pos_x = torch.arange(x, device=device).type(inv_freq.type())*2*np.pi/x pos_y = torch.arange(y, device=device).type(inv_freq.type())*2*np.pi/y sin_inp_x = torch.einsum("i,j->ij", pos_x, inv_freq) sin_inp_y = torch.einsum("i,j->ij", pos_y, inv_freq) emb_x = get_emb(sin_inp_x).unsqueeze(1) emb_y = get_emb(sin_inp_y) emb = torch.zeros((x, y, out_ch * 2), device=device) emb[:, :, : out_ch] = emb_x emb[:, :, out_ch : 2 * out_ch] = emb_y return emb[None, :, :, :].repeat(batch_size, 1, 1, 1) def training(dataset, opt, pipe, testing_iterations, saving_iterations, checkpoint_iterations, checkpoint, debug_from, resolution): first_iter = 0 tb_writer = prepare_output_and_logger(dataset) lpips_fn = LPIPSModel(net='vgg').cuda() lpips_fn.eval() scene = Scene(dataset) inp_shape = [len(scene.getTrainCameras()), int(np.round(scene.orig_h/resolution)), int(np.round(scene.orig_w/resolution))] # Preload GT depth maps at ORIGINAL sensor resolution (uint16 mm → float32 m). # Stored as [1, 1, H_sensor, W_sensor] for F.interpolate at runtime, # so the resize matches whatever scale the rendered depth uses each iteration. gt_depth_cache = {} # {image_name: Tensor [1, 1, H_sensor, W_sensor] in meters} depth_dir = os.path.join(dataset.source_path, 'depth') if os.path.isdir(depth_dir): for cam in scene.getTrainCameras(): dpath = os.path.join(depth_dir, cam.image_name + '.png') if os.path.exists(dpath): raw = cv2.imread(dpath, cv2.IMREAD_UNCHANGED) # [H_s, W_s] uint16 gt_np = raw.astype(np.float32) / 1000.0 # metres, no resize yet gt_depth_cache[cam.image_name] = torch.from_numpy(gt_np).cuda().unsqueeze(0).unsqueeze(0) print(f'[v2] Depth cache: {len(gt_depth_cache)}/{len(scene.getTrainCameras())} frames preloaded (sensor res)', file=sys.stderr) # E1 dual-supervision: sharp-frame skip set + RAW blurry frame cache (cached # at scale=1.0 / full -r resolution, resized on-the-fly to match whatever # render resolution loss_blur is computed at). sharp_skip_set = set() if getattr(opt, 'bpn_skip_sharp_json', None): with open(opt.bpn_skip_sharp_json) as f: sharp_skip_set = set(json.load(f)) n_train_sharp = sum(1 for cam in scene.getTrainCameras() if cam.image_name in sharp_skip_set) print(f'[BPN] sharp-frame skip: {len(sharp_skip_set)} sharp frames listed, ' f'{n_train_sharp}/{len(scene.getTrainCameras())} present in train set -> BPN bypassed for those', file=sys.stderr) raw_blurry_cache = load_raw_blurry_cache( scene, getattr(opt, 'raw_blurry_glob', None), getattr(opt, 'raw_blurry_stride', 10), sharp_skip_set, ) kernel_size1 = dataset.kernel_size1 kernel_size2 = dataset.kernel_size2 kernel_size3 = dataset.kernel_size3 print('kernel', kernel_size1, kernel_size2, kernel_size3) kernel_size_ss = dataset.kernel_size_ss print('kernel single scale', kernel_size_ss) # v2: adaptive LR scale based on kernel size (larger kernel → lower LR) ref_kernel = 17.0 lr_scale = (ref_kernel / max(kernel_size3, ref_kernel)) ** 0.5 if lr_scale != 1.0: print(f'[v2] LR scale for kernel {kernel_size3}: {lr_scale:.4f}', file=sys.stderr) gaussians = GaussianModel(dataset.sh_degree, inp_shape, ks1=kernel_size1, ks2=kernel_size2, ks3=kernel_size3, ks_ss=kernel_size_ss, not_use_rgbd=opt.not_use_rgbd,not_use_pe=opt.not_use_pe) scene.load_gaussian(gaussians) gaussians.training_setup(opt) # v2: apply adaptive LR scale if lr_scale != 1.0: for pg in gaussians.optimizer.param_groups: pg['lr'] = pg['lr'] * lr_scale opt.position_lr_init *= lr_scale opt.position_lr_final *= lr_scale if checkpoint: print(checkpoint) (model_params, first_iter) = torch.load(checkpoint) gaussians.restore(model_params, opt) bg_color = [1, 1, 1] if dataset.white_background else [0, 0, 0] background = torch.tensor(bg_color, dtype=torch.float32, device="cuda") iter_start = torch.cuda.Event(enable_timing = True) iter_end = torch.cuda.Event(enable_timing = True) trainCameras = scene.getTrainCameras(scale=4.0).copy() testCameras = scene.getTestCameras(scale=4.0).copy() allCameras = trainCameras + testCameras # highresolution index highresolution_index = [] for index, camera in enumerate(trainCameras): if camera.image_width >= 800: highresolution_index.append(index) gaussians.compute_3D_filter(cameras=trainCameras) viewpoint_stack = None ema_loss_for_log = 0.0 progress_bar = tqdm(range(first_iter, opt.iterations), desc="Training progress") first_iter += 1 upsample_iter = [3000, 6000] unfold1 = torch.nn.Unfold(kernel_size=(kernel_size1, kernel_size1), padding=kernel_size1 // 2).cuda() unfold2 = torch.nn.Unfold(kernel_size=(kernel_size2, kernel_size2), padding=kernel_size2 // 2).cuda() unfold3 = torch.nn.Unfold(kernel_size=(kernel_size3, kernel_size3), padding=kernel_size3 // 2).cuda() if kernel_size_ss != kernel_size3: opt.use_another_mlp = True unfold_ss = torch.nn.Unfold(kernel_size=(kernel_size_ss, kernel_size_ss), padding=kernel_size_ss // 2).cuda() else: unfold_ss = unfold3 assert opt.ms_steps >= 6000 print('************** position_lr_max_steps', opt.position_lr_max_steps) print('************** densify_until_iter', opt.densify_until_iter) print('************** init densify_grad_threshold', opt.init_dgt) print('************** densify_grad_threshold', opt.densify_grad_threshold) print('************** min_opacity', opt.min_opacity) print('************** ms_steps', opt.ms_steps) print('mask_loss', opt.use_mask_loss, 'depth_loss', opt.use_depth_loss, 'rgbtv_loss', opt.use_rgbtv_loss) for iteration in range(first_iter, opt.iterations + 1): if iteration in upsample_iter: if iteration == upsample_iter[0]: print('CHANGE RESOLUTION') trainCameras = scene.getTrainCameras(scale=2.0).copy() testCameras = scene.getTestCameras(scale=2.0).copy() allCameras = trainCameras + testCameras gaussians.compute_3D_filter(cameras=trainCameras) viewpoint_stack = scene.getTrainCameras(scale=2.0).copy() else: print('CHANGE RESOLUTION') trainCameras = scene.getTrainCameras(scale=1.0).copy() testCameras = scene.getTestCameras(scale=1.0).copy() allCameras = trainCameras + testCameras gaussians.compute_3D_filter(cameras=trainCameras) viewpoint_stack = scene.getTrainCameras(scale=1.0).copy() if network_gui.conn == None: network_gui.try_connect() while network_gui.conn != None: try: net_image_bytes = None custom_cam, do_training, pipe.convert_SHs_python, pipe.compute_cov3D_python, keep_alive, scaling_modifer = network_gui.receive() if custom_cam != None: net_image = render(custom_cam, gaussians, pipe, background, scaling_modifer)["render"] net_image_bytes = memoryview((torch.clamp(net_image, min=0, max=1.0) * 255).byte().permute(1, 2, 0).contiguous().cpu().numpy()) network_gui.send(net_image_bytes, dataset.source_path) if do_training and ((iteration < int(opt.iterations)) or not keep_alive): break except Exception as e: network_gui.conn = None iter_start.record() ori_iter = iteration if ori_iter > opt.ms_steps: if ori_iter == opt.ms_steps + 1: print('start training iterations for final scale, lr reset!') iteration = iteration - opt.ms_steps cur_lr = gaussians.update_learning_rate(iteration) # if iteration % 100 == 0: # print('cur_lr:', cur_lr, 'iteration:', iteration) # Every 1000 its we increase the levels of SH up to a maximum degree if iteration % 1000 == 0: gaussians.oneupSHdegree() cam_num = 1 loss = 0 # Pick a random Camera if not viewpoint_stack: if ori_iter >= upsample_iter[0] and ori_iter < upsample_iter[1]: viewpoint_stack = scene.getTrainCameras(scale=2.0).copy() elif ori_iter >= upsample_iter[1]: viewpoint_stack = scene.getTrainCameras(scale=1.0).copy() else: viewpoint_stack = scene.getTrainCameras(scale=4.0).copy() cam_indices = [] for _ in range(cam_num): ind = randint(0, len(viewpoint_stack)-1) if ind not in cam_indices: cam_indices.append(ind) for cam_idx in cam_indices: viewpoint_cam = viewpoint_stack[cam_idx] # Render if (ori_iter - 1) == debug_from: pipe.debug = True #TODO ignore border pixels if dataset.ray_jitter: subpixel_offset = torch.rand((int(viewpoint_cam.image_height), int(viewpoint_cam.image_width), 2), dtype=torch.float32, device="cuda") - 0.5 # subpixel_offset *= 0.0 else: subpixel_offset = None render_pkg = render(viewpoint_cam, gaussians, pipe, background, kernel_size=dataset.kernel_size, subpixel_offset=subpixel_offset) image, depth, viewspace_point_tensor, visibility_filter, radii = render_pkg["render"], render_pkg["depth"], render_pkg["viewspace_points"], render_pkg["visibility_filter"], render_pkg["radii"] if iteration % 100 == 0: print(gaussians._xyz.shape,'NUM OF GAUSSIANS') gt_image = viewpoint_cam.original_image.cuda() # GT depth supervision (gt_depth_cache, sensor-res L1 vs valid mask) -- # applies to ALL frames whenever --use_depth_loss is set, on top of # whichever reconstruction loss is selected below. if opt.use_depth_loss: gt_sensor = gt_depth_cache.get(viewpoint_cam.image_name) if gt_sensor is not None: rd = depth.squeeze(0) # [H_r, W_r] gt_d = torch.nn.functional.interpolate( gt_sensor, size=rd.shape[-2:], mode='nearest' )[0, 0] # [H_r, W_r] valid = (gt_d > 0.01).float() depthloss = opt.depth_loss_alpha * ( (torch.abs(rd - gt_d) * valid).sum() / (valid.sum() + 1e-6) ) else: depthloss = torch.tensor(0.0, device=depth.device) else: depthloss = 0 if (iteration > 250 and not opt.no_bpn and viewpoint_cam.image_name not in sharp_skip_set): shuffle_rgb = image.unsqueeze(0) shuffle_depth = depth.unsqueeze(0) - depth.min() shuffle_depth = shuffle_depth/shuffle_depth.max() pos_enc = get_2d_emb(1, shuffle_rgb.shape[-2], shuffle_rgb.shape[-1], 16, torch.device(0)) if ori_iter < 3000: kernel_weights, mask = gaussians.mlp_rgb_ms(cam_idx, pos_enc, torch.cat([shuffle_rgb,shuffle_depth],1).detach(),ori_iter) patches = unfold1(shuffle_rgb) patches = patches.view(1, 3, kernel_size1 ** 2, shuffle_rgb.shape[-2], shuffle_rgb.shape[-1]) kernel_weights = kernel_weights.unsqueeze(1) rgb = torch.sum(patches * kernel_weights, 2)[0] mask = mask[0] elif ori_iter >= 3000 and ori_iter < 6000: kernel_weights, mask = gaussians.mlp_rgb_ms(cam_idx, pos_enc, torch.cat([shuffle_rgb,shuffle_depth],1).detach(),ori_iter) patches = unfold2(shuffle_rgb) patches = patches.view(1, 3, kernel_size2 ** 2, shuffle_rgb.shape[-2], shuffle_rgb.shape[-1]) kernel_weights = kernel_weights.unsqueeze(1) rgb = torch.sum(patches * kernel_weights, 2)[0] mask = mask[0] else: if (ori_iter > opt.ms_steps) and opt.use_another_mlp: kernel_weights, mask = gaussians.mlp_rgb_ss(cam_idx, pos_enc, torch.cat([shuffle_rgb,shuffle_depth],1).detach(),iteration) patches = unfold_ss(shuffle_rgb) patches = patches.view(1, 3, kernel_size_ss ** 2, shuffle_rgb.shape[-2], shuffle_rgb.shape[-1]) else: kernel_weights, mask = gaussians.mlp_rgb_ms(cam_idx, pos_enc, torch.cat([shuffle_rgb,shuffle_depth],1).detach(),ori_iter) patches = unfold3(shuffle_rgb) patches = patches.view(1, 3, kernel_size3 ** 2, shuffle_rgb.shape[-2], shuffle_rgb.shape[-1]) kernel_weights = kernel_weights.unsqueeze(1) rgb = torch.sum(patches * kernel_weights, 2)[0] mask = mask[0] blur_image = mask*rgb + (1-mask)*image maskloss = opt.mask_loss_alpha * mask.mean() if opt.use_mask_loss else 0 tvloss = opt.rgbtv_loss_alpha * tv_loss(shuffle_rgb) if opt.use_rgbtv_loss else 0 # BPN's blur-synthesis target is the RAW (motion-blurred) input frame -- # BAGS' original design: BPN(render) vs blur input, not the EVSSM target gt_raw = raw_blurry_cache[viewpoint_cam.image_name].cuda() if gt_raw.shape[-2:] != blur_image.shape[-2:]: gt_raw = torch.nn.functional.interpolate( gt_raw.unsqueeze(0), size=blur_image.shape[-2:], mode='bilinear', align_corners=False )[0] Ll1 = l1_loss(blur_image, gt_raw) recon = (1.0 - opt.lambda_dssim) * Ll1 + opt.lambda_dssim * (1.0 - ssim(blur_image, gt_raw)) loss = loss + recon + tvloss + maskloss + depthloss if iteration % 100 == 0: print(f'[depth_log] ori={ori_iter} iter={iteration} depth={float(depthloss):.6f} recon={float(recon):.6f}', file=sys.stderr) else: Ll1 = l1_loss(image, gt_image) recon = (1.0 - opt.lambda_dssim) * Ll1 + opt.lambda_dssim * (1.0 - ssim(image, gt_image)) loss = loss + recon + depthloss loss.backward() iter_end.record() with torch.no_grad(): # Progress bar ema_loss_for_log = 0.4 * loss.item() + 0.6 * ema_loss_for_log if ori_iter % 1000 == 0: progress_bar.set_postfix({"Loss": f"{ema_loss_for_log:.{7}f}"}) progress_bar.update(1000) if ori_iter == opt.iterations: progress_bar.close() # Log and save training_report(tb_writer, ori_iter, Ll1, loss, l1_loss, iter_start.elapsed_time(iter_end), testing_iterations, scene, render, (pipe, background, dataset.kernel_size), lpips_fn) if (ori_iter in saving_iterations): print("\n[ITER {}] Saving Gaussians".format(ori_iter)) scene.save(ori_iter) if not opt.no_bpn: torch.save({"mlp_ms": gaussians.mlp_rgb_ms.state_dict(), "mlp_ss": gaussians.mlp_rgb_ss.state_dict()}, os.path.join(scene.model_path, f"bpn_{ori_iter}.pth")) # Densification if iteration < opt.densify_until_iter: # Keep track of max radii in image-space for pruning gaussians.max_radii2D[visibility_filter] = torch.max(gaussians.max_radii2D[visibility_filter], radii[visibility_filter]) gaussians.add_densification_stats(viewspace_point_tensor, visibility_filter) if iteration > opt.densify_from_iter and iteration % opt.densification_interval == 0: size_threshold = 20 if iteration > opt.opacity_reset_interval else None # reset interval = 3000 if ori_iter <= opt.ms_steps: dgt = opt.densify_grad_threshold if opt.init_dgt < 0 else opt.init_dgt min_opacity = opt.min_opacity if opt.init_opacity < 0 else opt.init_opacity else: dgt = opt.densify_grad_threshold min_opacity = opt.min_opacity max_shapes = opt.max_shapes if opt.max_shapes > 0 else None gaussians.densify_and_prune(dgt, min_opacity, scene.cameras_extent, size_threshold, max_shapes) gaussians.compute_3D_filter(cameras=trainCameras) if iteration % opt.opacity_reset_interval == 0 or (dataset.white_background and iteration == opt.densify_from_iter): gaussians.reset_opacity() if iteration % 100 == 0 and iteration > opt.densify_until_iter: if iteration < (opt.iterations - opt.ms_steps) - 100: # don't update in the end of training gaussians.compute_3D_filter(cameras=trainCameras) # Optimizer step if ori_iter < opt.iterations: gaussians.optimizer.step() gaussians.optimizer.zero_grad(set_to_none = True) if (ori_iter in checkpoint_iterations): print("\n[ITER {}] Saving Checkpoint".format(ori_iter)) torch.save((gaussians.capture(), ori_iter), scene.model_path + "/chkpnt" + str(ori_iter) + ".pth") def prepare_output_and_logger(args): if not args.model_path: if os.getenv('OAR_JOB_ID'): unique_str=os.getenv('OAR_JOB_ID') else: unique_str = str(uuid.uuid4()) args.model_path = os.path.join("./output/", unique_str[0:10]) # Set up output folder print("Output folder: {}".format(args.model_path)) os.makedirs(args.model_path, exist_ok = True) with open(os.path.join(args.model_path, "cfg_args"), 'w') as cfg_log_f: cfg_log_f.write(str(Namespace(**vars(args)))) # Create Tensorboard writer tb_writer = None if TENSORBOARD_FOUND: tb_writer = SummaryWriter(args.model_path) else: print("Tensorboard not available: not logging progress") return tb_writer def training_report(tb_writer, iteration, Ll1, loss, l1_loss, elapsed, testing_iterations, scene : Scene, renderFunc, renderArgs, lpips_fn=None): if tb_writer: tb_writer.add_scalar('train_loss_patches/l1_loss', Ll1.item(), iteration) tb_writer.add_scalar('train_loss_patches/total_loss', loss.item(), iteration) tb_writer.add_scalar('iter_time', elapsed, iteration) # Report test and samples of training set if iteration in testing_iterations: torch.cuda.empty_cache() validation_configs = ({'name': 'test', 'cameras' : scene.getTestCameras()}, {'name': 'train', 'cameras' : [scene.getTrainCameras()[idx % len(scene.getTrainCameras())] for idx in range(5, 30, 5)]}) for config in validation_configs: if config['cameras'] and len(config['cameras']) > 0: l1_test = 0.0 psnr_test = 0.0 ssim_test = 0.0 lpips_test = 0.0 for idx, viewpoint in enumerate(config['cameras']): image = torch.clamp(renderFunc(viewpoint, scene.gaussians, *renderArgs)["render"], 0.0, 1.0) gt_image = torch.clamp(viewpoint.original_image.to("cuda"), 0.0, 1.0) if tb_writer and (idx < 5): tb_writer.add_images(config['name'] + "_view_{}/render".format(viewpoint.image_name), image[None], global_step=iteration) if iteration == testing_iterations[0]: tb_writer.add_images(config['name'] + "_view_{}/ground_truth".format(viewpoint.image_name), gt_image[None], global_step=iteration) l1_test += l1_loss(image, gt_image).mean().double() psnr_test += psnr(image, gt_image).mean().double() ssim_test += ssim(image, gt_image).mean().double() if lpips_fn is not None: with torch.no_grad(): lpips_test += lpips_fn(image[None]*2-1, gt_image[None]*2-1).mean().double() n = len(config['cameras']) psnr_test /= n l1_test /= n ssim_test /= n lpips_test /= n print("\n[ITER {}] Evaluating {}: L1 {:.4f} PSNR {:.2f} SSIM {:.4f} LPIPS {:.4f}".format( iteration, config['name'], l1_test, psnr_test, ssim_test, lpips_test)) if tb_writer: tb_writer.add_scalar(config['name'] + '/loss_viewpoint - l1_loss', l1_test, iteration) tb_writer.add_scalar(config['name'] + '/loss_viewpoint - psnr', psnr_test, iteration) tb_writer.add_scalar(config['name'] + '/loss_viewpoint - ssim', ssim_test, iteration) tb_writer.add_scalar(config['name'] + '/loss_viewpoint - lpips', lpips_test, iteration) if tb_writer: tb_writer.add_histogram("scene/opacity_histogram", scene.gaussians.get_opacity, iteration) tb_writer.add_scalar('total_points', scene.gaussians.get_xyz.shape[0], iteration) torch.cuda.empty_cache() if __name__ == "__main__": # Set up command line argument parser parser = ArgumentParser(description="Training script parameters") lp = ModelParams(parser) op = OptimizationParams(parser) pp = PipelineParams(parser) parser.add_argument('--ip', type=str, default="127.0.0.1") parser.add_argument('--port', type=int, default=6009) parser.add_argument('--debug_from', type=int, default=-1) parser.add_argument('--detect_anomaly', action='store_true', default=False) parser.add_argument("--test_iterations", nargs="+", type=int, default=[3_000, 4_000, 6_000, 7_000, 9_000, 10_000, 12_000, 15_000, 18_000, 20_000, 22_000, 25_000, 28_000, 30_000, 32_000, 35_000, 38_000, 40_000, 42_000, 45_000, 48_000, 50_000, 60_000]) parser.add_argument("--save_iterations", nargs="+", type=int, default=[3_000, 4_000, 6_000, 7_000, 9_000, 10_000, 12_000, 15_000, 18_000, 20_000, 22_000, 25_000, 28_000, 30_000, 32_000, 35_000, 38_000, 40_000, 42_000, 45_000, 48_000, 50_000, 60_000]) parser.add_argument("--quiet", action="store_true") parser.add_argument("--checkpoint_iterations", nargs="+", type=int, default=[6000,7000,9000,10000,12000,22000,32000,42000]) parser.add_argument("--start_checkpoint", type=str, default = None) args = parser.parse_args(sys.argv[1:]) args.test_iterations.append(args.iterations) args.save_iterations.append(args.iterations) print("Optimizing " + args.model_path) # Initialize system state (RNG) safe_state(args.quiet) # Start GUI server, configure and run training network_gui.init(args.ip, args.port) torch.autograd.set_detect_anomaly(args.detect_anomaly) training(lp.extract(args), op.extract(args), pp.extract(args), args.test_iterations, args.save_iterations, args.checkpoint_iterations, args.start_checkpoint, args.debug_from, args.resolution) # All done print("\nTraining complete.")