7e4ef6f98b
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
644 lines
23 KiB
Python
644 lines
23 KiB
Python
import os
|
|
import glob
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
|
|
import torch
|
|
import torch.nn as nn
|
|
import torch.nn.functional as F
|
|
import torch.optim as optim
|
|
|
|
from body_model import OP_IGNORE_JOINTS
|
|
from geometry.mesh import save_mesh_scenes, vertices_to_trimesh
|
|
from util.logger import Logger, log_cur_stats
|
|
from util.tensor import move_to, detach_all
|
|
from vis.output import prep_result_vis, animate_scene
|
|
|
|
from .losses import RootLoss, SMPLLoss #, MotionLoss
|
|
from .output import save_camera_json
|
|
import time
|
|
|
|
LINE_SEARCH = "strong_wolfe"
|
|
LIGHT_BLUE=(0.65098039, 0.74117647, 0.85882353)
|
|
|
|
"""
|
|
Optimization happens in multiple stages
|
|
Stage 1: fit root orients and trans of each frame indendpently
|
|
Stage 2: fit SMPL poses and betas of each frame independently
|
|
Stage 3: fit poses and roots in same global coordinate frame
|
|
"""
|
|
|
|
|
|
class StageOptimizer(object):
|
|
def __init__(
|
|
self,
|
|
name,
|
|
model,
|
|
param_names,
|
|
lr=1.0,
|
|
lbfgs_max_iter=20,
|
|
save_every=10,
|
|
vis_every=-1,
|
|
save_meshes=True,
|
|
max_chunk_steps=10,
|
|
**kwargs,
|
|
):
|
|
Logger.log(f"INITIALIZING OPTIMIZER {name} for {param_names}")
|
|
self.name = name
|
|
self.model = model
|
|
|
|
self.set_opt_vars(param_names)
|
|
|
|
self.optim = torch.optim.LBFGS(
|
|
self.opt_params, max_iter=lbfgs_max_iter, lr=lr, line_search_fn=LINE_SEARCH
|
|
)
|
|
# LBFGS computes losses multiple times per iteration,
|
|
# save a dict mapping iteration to list of stats_dicts
|
|
self.loss_dicts = {}
|
|
|
|
self.save_every = save_every
|
|
self.vis_every = vis_every
|
|
self.save_meshes = save_meshes
|
|
self.max_chunk_steps = max_chunk_steps
|
|
|
|
self.cur_step = 0
|
|
|
|
self.add_chunk = 0
|
|
self.cur_loss = 0
|
|
self.prev_loss = np.inf
|
|
self.last_updated = 0
|
|
self.reached_max = False
|
|
self.reached_max_iter = -1
|
|
|
|
def set_opt_vars(self, param_names):
|
|
Logger.log("Set param names:")
|
|
Logger.log(param_names)
|
|
|
|
self.param_names = param_names
|
|
self.model.params.set_require_grads(self.param_names)
|
|
self.opt_params = [
|
|
getattr(self.model.params, name) for name in self.param_names
|
|
]
|
|
|
|
def forward_pass(self, obs_data):
|
|
raise NotImplementedError
|
|
|
|
def load_checkpoint(self, out_dir, device=None):
|
|
if device is None:
|
|
device = torch.device("cpu")
|
|
|
|
param_path = os.path.join(out_dir, f"{self.name}_params.pth")
|
|
if os.path.isfile(param_path):
|
|
param_dict = torch.load(param_path, map_location=device)
|
|
self.model.params.load_dict(param_dict)
|
|
Logger.log(f"Params loaded from {param_path}")
|
|
|
|
optim_path = os.path.join(out_dir, f"{self.name}_optim.pth")
|
|
if os.path.isfile(optim_path):
|
|
optim_dict = torch.load(optim_path)
|
|
self.optim.load_state_dict(optim_dict["optim"])
|
|
self.cur_step = optim_dict["cur_step"]
|
|
Logger.log(f"Optimizer loaded from {optim_path} at iter {self.cur_step}")
|
|
|
|
def save_checkpoint(self, out_dir):
|
|
param_path = os.path.join(out_dir, f"{self.name}_params.pth")
|
|
param_dict = self.model.params.get_dict()
|
|
if "world_scale" in param_dict:
|
|
print("WORLD_SCALE", param_dict["world_scale"].detach().cpu())
|
|
if "floor_plane" in param_dict:
|
|
print("FLOOR PLANE", param_dict["floor_plane"].detach().cpu())
|
|
if "cam_f" in param_dict:
|
|
print("CAM_F", param_dict["cam_f"].detach().cpu())
|
|
torch.save(param_dict, param_path)
|
|
Logger.log(f"Model saved at {param_path}")
|
|
|
|
optim_path = os.path.join(out_dir, f"{self.name}_optim.pth")
|
|
torch.save(
|
|
{"optim": self.optim.state_dict(), "cur_step": self.cur_step},
|
|
optim_path,
|
|
)
|
|
Logger.log(f"Optimizer saved at {optim_path}")
|
|
|
|
def save_results(self, out_dir, seq_name):
|
|
"""
|
|
pred dict will be a dictionary of trajectories.
|
|
each trajectory will have params and lists of trimesh sequences
|
|
"""
|
|
os.makedirs(out_dir, exist_ok=True)
|
|
|
|
with torch.no_grad():
|
|
print('go into get_optim_result from optimizer.py save_results')
|
|
pred_dict = self.model.get_optim_result()
|
|
pred_dict = move_to(detach_all(pred_dict), "cpu")
|
|
|
|
i = self.cur_step
|
|
for name, results in pred_dict.items():
|
|
print('save_results, name: ', name)
|
|
# save parameters of trajectory
|
|
out_path = f"{out_dir}/{seq_name}_{i:06d}_{name}_results.npz"
|
|
Logger.log(f"saving params to {out_path}")
|
|
np.savez(out_path, **results)
|
|
print('cam_R in save_results and its .npz', results['cam_R'])
|
|
|
|
# also save the cameras
|
|
# print('save the cameras in ptimizer.py save_results')
|
|
# print(self.model.params)
|
|
# with torch.no_grad():
|
|
# cam_R, cam_t = self.model.params.get_extrinsics()
|
|
# intrins = self.model.params.get_intrinsics()
|
|
# print('cam_R in 0000.json:', cam_R)
|
|
# save_camera_json(
|
|
# f"{out_dir}/{seq_name}_cameras_{self.cur_step:06d}.json",
|
|
# cam_R.detach().cpu(),
|
|
# cam_t.detach().cpu(),
|
|
# intrins.detach().cpu(),
|
|
# )
|
|
|
|
# plot losses
|
|
self.plot_losses(out_dir)
|
|
|
|
# def save_meshes_all(self, res_dir, obs_data, seq_name, num_steps=-1):
|
|
|
|
# # check which results are saved
|
|
# seq_name = obs_data["seq_name"][0]
|
|
# res_pre = f"{res_dir}/{seq_name}_opt_{self.cur_step:06d}"
|
|
# with torch.no_grad():
|
|
# print('go into get_optim_result from optimizer.py vis_result')
|
|
# pred_dict = self.model.get_optim_result(num_steps=num_steps)
|
|
|
|
# res_dict = detach_all(pred_dict["world"])
|
|
# scene_dict = move_to(
|
|
# prep_result_vis(
|
|
# res_dict,
|
|
# obs_data["vis_mask"],
|
|
# obs_data["track_id"],
|
|
# self.model.body_model,
|
|
# temporal_smooth=True
|
|
# ),
|
|
# "cpu",
|
|
# )
|
|
|
|
# # save the meshes
|
|
# os.makedirs(res_dir, exist_ok=True)
|
|
# i = self.cur_step
|
|
# scene_dir = f"{res_dir}/{seq_name}_{i:06d}_meshes"
|
|
# os.makedirs(scene_dir, exist_ok=True)
|
|
|
|
# verts, joints, colors, l_faces, r_faces, is_right, bounds = scene_dict["geometry"]
|
|
# T = len(verts)
|
|
# print(f"{T} mesh frames")
|
|
# times = list(range(0, T, 1))
|
|
# for t in times:
|
|
# if len(is_right[t]) > 1:
|
|
# assert (is_right[t].cpu().numpy().tolist() == [0,1])
|
|
# # l_meshes = make_batch_mesh(verts[t][0][None], l_faces[t], colors[t][0][None])
|
|
# # r_meshes = make_batch_mesh(verts[t][1][None], r_faces[t], colors[t][1][None])
|
|
# # assert len(l_meshes) == 1
|
|
# # assert len(r_meshes) == 1
|
|
# tmesh = vertices_to_trimesh(verts[t][0].detach().cpu().numpy(), l_faces[t].detach().cpu().numpy(), LIGHT_BLUE, is_right=0)
|
|
# tmesh.export(os.path.join(scene_dir, f'{str(t).zfill(6)}_0.obj'))
|
|
|
|
# tmesh = vertices_to_trimesh(verts[t][1].detach().cpu().numpy(), r_faces[t].detach().cpu().numpy(), LIGHT_BLUE, is_right=1)
|
|
# tmesh.export(os.path.join(scene_dir, f'{str(t).zfill(6)}_1.obj'))
|
|
|
|
# else:
|
|
# assert len(is_right[t]) == 1
|
|
# if is_right[t] == 0:
|
|
# # meshes = make_batch_mesh(verts[t][0][None], l_faces[t], colors[t][0][None])
|
|
# tmesh = vertices_to_trimesh(verts[t][0].detach().cpu().numpy(), l_faces[t].detach().cpu().numpy(), LIGHT_BLUE, is_right=0)
|
|
# tmesh.export(os.path.join(scene_dir, f'{str(t).zfill(6)}_0.obj'))
|
|
# elif is_right[t] == 1:
|
|
# # meshes = make_batch_mesh(verts[t][0][None], r_faces[t], colors[t][0][None])
|
|
# tmesh = vertices_to_trimesh(verts[t][0].detach().cpu().numpy(), r_faces[t].detach().cpu().numpy(), LIGHT_BLUE, is_right=1)
|
|
# tmesh.export(os.path.join(scene_dir, f'{str(t).zfill(6)}_1.obj'))
|
|
|
|
def vis_result(self, res_dir, obs_data, vis=None, num_steps=-1):
|
|
if vis is None or self.vis_every < 0:
|
|
return
|
|
|
|
# check which results are saved
|
|
seq_name = obs_data["seq_name"][0]
|
|
res_pre = f"{res_dir}/{seq_name}_opt_{self.cur_step:06d}"
|
|
with torch.no_grad():
|
|
print('go into get_optim_result from optimizer.py vis_result')
|
|
pred_dict = self.model.get_optim_result(num_steps=num_steps)
|
|
|
|
res_dict = detach_all(pred_dict["world"])
|
|
scene_dict = move_to(
|
|
prep_result_vis(
|
|
res_dict,
|
|
obs_data["vis_mask"],
|
|
obs_data["track_id"],
|
|
self.model.body_model,
|
|
),
|
|
"cpu",
|
|
)
|
|
animate_scene(vis, scene_dict, res_pre, render_views=["src_cam", "above"])
|
|
|
|
def log_losses(self, stats_dict):
|
|
stats_dict = move_to(detach_all(stats_dict), "cpu")
|
|
log_cur_stats(
|
|
stats_dict,
|
|
iter=self.cur_step,
|
|
to_stdout=(self.cur_step % self.save_every == 0),
|
|
)
|
|
for loss_name, loss_val in stats_dict.items():
|
|
loss_dict = self.loss_dicts.get(loss_name, {})
|
|
loss_series = loss_dict.get(self.cur_step, [])
|
|
loss_series.append(loss_val)
|
|
loss_dict[self.cur_step] = loss_series
|
|
self.loss_dicts[loss_name] = loss_dict
|
|
|
|
def record_current_losses(self, writer):
|
|
"""
|
|
record the mean of current step's loss values in tensorboard
|
|
"""
|
|
if len(self.loss_dicts) < 1:
|
|
return
|
|
|
|
for loss_name, loss_dict in self.loss_dicts.items():
|
|
loss_mean = np.mean(loss_dict[self.cur_step])
|
|
writer.add_scalar(f"{self.name}/{loss_name}", loss_mean, self.cur_step)
|
|
|
|
def plot_losses(self, res_dir):
|
|
"""
|
|
plot a box plot for each BFGS iteration
|
|
"""
|
|
if len(self.loss_dicts) < 1:
|
|
return
|
|
for loss_name, loss_dict in self.loss_dicts.items():
|
|
# times (list len T)
|
|
# loss vals (list len T of loss value lists)
|
|
times, loss_vals = zip(*loss_dict.items())
|
|
plt.figure()
|
|
plt.boxplot(loss_vals, labels=times, showfliers=False)
|
|
plt.savefig(f"{res_dir}/{loss_name}.png")
|
|
|
|
def run(self, obs_data, num_iters, out_dir, vis=None, writer=None):
|
|
self.cur_step = 0
|
|
self.loss.cur_step = 0
|
|
res_dir = os.path.join(out_dir, self.name)
|
|
os.makedirs(res_dir, exist_ok=True)
|
|
seq_name = obs_data["seq_name"][0]
|
|
print("SEQ NAME", seq_name, "num_iters", num_iters)
|
|
|
|
# try to load from checkpoint if exists
|
|
device = obs_data["joints2d"].device
|
|
self.load_checkpoint(out_dir, device=device)
|
|
|
|
if self.cur_step >= num_iters:
|
|
Logger.log(f"Current optimizer {self}")
|
|
Logger.log(f"Checkpoint at {self.cur_step} >= {num_iters}, skipping")
|
|
return
|
|
|
|
Logger.log(f"OPTIMIZING {self.name} FOR {num_iters} ITERATIONS")
|
|
# time.sleep(5)
|
|
|
|
# save initial results and vis
|
|
print('go into save_results in optimizers.py run()')
|
|
self.save_results(res_dir, seq_name)
|
|
|
|
for i in range(self.cur_step, num_iters):
|
|
Logger.log("ITER: %d" % (i))
|
|
|
|
if (i + 1) % self.save_every == 0: # save before
|
|
self.save_checkpoint(out_dir)
|
|
self.save_results(res_dir, seq_name)
|
|
else:
|
|
self.save_checkpoint(out_dir)
|
|
|
|
if (i + 1) % self.vis_every == 0: # render
|
|
self.vis_result(res_dir, obs_data, vis)
|
|
|
|
self.cur_step = i
|
|
self.loss.cur_step = i
|
|
|
|
#print("ITER: %d" % (i))
|
|
self.optim_step(obs_data, i, writer)
|
|
|
|
# early termination in case of nans
|
|
if np.isnan(self.cur_loss):
|
|
# we need to backtrack
|
|
self.load_checkpoint(out_dir, device=device)
|
|
print(self.cur_loss, self.kkk, self.ppp)
|
|
raise ValueError
|
|
|
|
# termination for the last chunk
|
|
if self.reached_max and self.reached_max_iter < 0:
|
|
self.reached_max_iter = i - 1
|
|
if self.reached_max and i - self.reached_max_iter >= self.max_chunk_steps:
|
|
break
|
|
|
|
# termination for middle chunks
|
|
loss_change = self.prev_loss - self.cur_loss
|
|
if self.last_updated == i - 1 and loss_change == 0:
|
|
break
|
|
if (
|
|
(self.cur_loss < 0 and loss_change < 100)
|
|
or (i - self.last_updated >= self.max_chunk_steps)
|
|
or (loss_change < 20 and i - self.last_updated > 5)
|
|
):
|
|
self.add_chunk = self.add_chunk + 1
|
|
self.last_updated = i
|
|
self.prev_loss = self.cur_loss
|
|
|
|
# final save and vis step
|
|
self.cur_step = num_iters
|
|
self.save_checkpoint(out_dir)
|
|
self.save_results(res_dir, seq_name)
|
|
self.vis_result(res_dir, obs_data, vis)
|
|
# self.save_meshes_all(res_dir, obs_data, seq_name)
|
|
|
|
def optim_step(self, obs_data, i, writer=None):
|
|
def closure():
|
|
self.optim.zero_grad()
|
|
#print('******************************', i)
|
|
loss, stats_dict, preds = self.forward_pass(obs_data)
|
|
#print('******************************', i)
|
|
stats_dict["total"] = loss
|
|
self.log_losses(move_to(detach_all(stats_dict), "cpu"))
|
|
self.cur_loss = stats_dict["total"].detach().cpu().item()
|
|
self.kkk = stats_dict
|
|
self.ppp = preds
|
|
loss_keys = stats_dict.keys()
|
|
if "motion_prior" in loss_keys and "pose_prior" in loss_keys:
|
|
self.cur_loss = (
|
|
self.cur_loss
|
|
- 0.04 * stats_dict["pose_prior"].detach().cpu().item()
|
|
)
|
|
print("optimizer print", loss, loss.shape, stats_dict, loss.requires_grad)
|
|
loss.backward()
|
|
# print('end of loss backward')
|
|
return loss
|
|
|
|
#print('!!!!!!!!!!!!!!!!!!!!!!!!!!', i)
|
|
self.optim.step(closure)
|
|
#print('!!!!!!!!!!!!!!!!!!!!!!!!!!', i)
|
|
if writer is not None:
|
|
self.record_current_losses(writer)
|
|
|
|
|
|
class RootOptimizer(StageOptimizer):
|
|
name = "root_fit"
|
|
stage = 0
|
|
|
|
def __init__(
|
|
self,
|
|
model,
|
|
all_loss_weights,
|
|
use_chamfer=False,
|
|
robust_loss_type="none",
|
|
robust_tuning_const=4.6851,
|
|
joints2d_sigma=100,
|
|
**kwargs,
|
|
):
|
|
param_names = ["trans", "root_orient"]
|
|
super().__init__(self.name, model, param_names, **kwargs)
|
|
|
|
self.loss = RootLoss(
|
|
all_loss_weights[self.stage],
|
|
ignore_op_joints=OP_IGNORE_JOINTS,
|
|
joints2d_sigma=joints2d_sigma,
|
|
use_chamfer=use_chamfer,
|
|
robust_loss=robust_loss_type,
|
|
robust_tuning_const=robust_tuning_const,
|
|
faces=model.body_model.faces_tensor
|
|
)
|
|
|
|
def forward_pass(self, obs_data):
|
|
"""
|
|
Takes in observed data, predicts the smpl parameters and returns loss
|
|
"""
|
|
# raise ValueError
|
|
# Use current params to go through SMPL and get joints3d, verts3d, points3d
|
|
pred_data = self.model.pred_params_mano(obs_data["is_right"])
|
|
pred_data["cameras"] = self.model.params.get_cameras()
|
|
|
|
# compute data losses only
|
|
vis_mask = obs_data["vis_mask"] >= 0
|
|
# print('entering loss from RootOptimizer')
|
|
loss, stats_dict = self.loss(obs_data, pred_data, vis_mask)
|
|
return loss, stats_dict, pred_data
|
|
|
|
|
|
class SmoothOptimizer(StageOptimizer):
|
|
name = "smooth_fit"
|
|
stage = 1
|
|
|
|
def __init__(
|
|
self,
|
|
model,
|
|
all_loss_weights,
|
|
use_chamfer=False,
|
|
robust_loss_type="none",
|
|
robust_tuning_const=4.6851,
|
|
joints2d_sigma=100,
|
|
**kwargs,
|
|
):
|
|
param_names = ["trans", "root_orient", "betas", "latent_pose"]
|
|
if model.opt_scale:
|
|
param_names += ["world_scale"]
|
|
if model.opt_cams:
|
|
param_names += ["cam_f", "delta_cam_R"]
|
|
|
|
super().__init__(self.name, model, param_names, **kwargs)
|
|
|
|
self.loss = SMPLLoss(
|
|
all_loss_weights[self.stage],
|
|
ignore_op_joints=OP_IGNORE_JOINTS,
|
|
joints2d_sigma=joints2d_sigma,
|
|
use_chamfer=use_chamfer,
|
|
robust_loss=robust_loss_type,
|
|
robust_tuning_const=robust_tuning_const,
|
|
faces=model.body_model.faces_tensor
|
|
)
|
|
|
|
def forward_pass(self, obs_data):
|
|
"""
|
|
Takes in observed data, predicts the smpl parameters and returns loss
|
|
"""
|
|
# raise ValueError
|
|
# Use current params to go through SMPL and get joints3d, verts3d, points3d
|
|
pred_data = self.model.pred_params_mano(obs_data["is_right"])
|
|
pred_data["cameras"] = self.model.params.get_cameras()
|
|
pred_data.update(self.model.params.get_vars())
|
|
|
|
# camera predictions
|
|
# pts_ij, target, weight = self.model.params.get_reprojected_points()
|
|
# pred_data["bg2d_err"] = (
|
|
# (weight * (pts_ij - target) ** 2).sum(dim=(-1, -2)).mean()
|
|
# )
|
|
pred_data["cam_R"], pred_data["cam_t"] = self.model.params.get_extrinsics()
|
|
|
|
# compute data losses only
|
|
vis_mask = obs_data["vis_mask"] >= 0
|
|
loss, stats_dict = self.loss(obs_data, pred_data, self.model.seq_len, vis_mask)
|
|
return loss, stats_dict, pred_data
|
|
|
|
|
|
# class MotionOptimizer(StageOptimizer):
|
|
# name = "motion_fit"
|
|
# stage = 2
|
|
|
|
# def __init__(self, model, all_loss_weights, opt_cams=False, **kwargs):
|
|
# self.opt_cams = opt_cams and model.opt_cams
|
|
# param_names = [
|
|
# "trans",
|
|
# "root_orient",
|
|
# "latent_pose",
|
|
# "trans_vel",
|
|
# "root_orient_vel",
|
|
# "joints_vel",
|
|
# "betas",
|
|
# "latent_motion",
|
|
# "floor_plane",
|
|
# ]
|
|
# if model.opt_scale:
|
|
# param_names += ["world_scale"]
|
|
|
|
# if self.opt_cams:
|
|
# Logger.log(f"{self.name} OPTIMIZING CAMERAS")
|
|
# param_names += ["delta_cam_R", "cam_f"]
|
|
|
|
# super().__init__(self.name, model, param_names, **kwargs)
|
|
# self.set_loss(model, all_loss_weights[self.stage], **kwargs)
|
|
|
|
# def set_loss(
|
|
# self,
|
|
# model,
|
|
# loss_weights,
|
|
# use_chamfer=False,
|
|
# robust_loss_type="none",
|
|
# robust_tuning_const=4.6851,
|
|
# joints2d_sigma=100,
|
|
# **kwargs,
|
|
# ):
|
|
# self.loss = MotionLoss(
|
|
# loss_weights,
|
|
# init_motion_prior=model.init_motion_prior,
|
|
# ignore_op_joints=OP_IGNORE_JOINTS,
|
|
# joints2d_sigma=joints2d_sigma,
|
|
# use_chamfer=use_chamfer,
|
|
# robust_loss=robust_loss_type,
|
|
# robust_tuning_const=robust_tuning_const,
|
|
# )
|
|
|
|
# def get_motion_scale(self):
|
|
# return 1.0
|
|
|
|
# def forward_pass(self, obs_data, num_steps=-1):
|
|
# p = self.model.params
|
|
# param_names = [
|
|
# "betas",
|
|
# "joints_vel",
|
|
# "trans_vel",
|
|
# "root_orient_vel",
|
|
# ]
|
|
# param_dict = p.get_vars(param_names)
|
|
# # param_dict["floor_plane"] = p.floor_plane[p.floor_idcs]
|
|
|
|
# preds, world_preds = self.model.rollout_mano_steps(num_steps)
|
|
# preds.update(param_dict)
|
|
# world_preds.update(param_dict)
|
|
|
|
# # track mask is the length of the sequence that contains num_steps of each track
|
|
# track_mask = world_preds.get("track_mask", None)
|
|
# T = track_mask.shape[1] if track_mask is not None else num_steps
|
|
# world_preds["cameras"] = p.get_cameras(np.arange(T))
|
|
# if self.opt_cams:
|
|
# cam_R, cam_t = p.get_extrinsics()
|
|
# world_preds["cam_R"], world_preds["cam_t"] = cam_R[:T], cam_t[:T]
|
|
|
|
# obs_data = slice_dict(obs_data, 0, T)
|
|
# motion_scale = self.get_motion_scale()
|
|
# loss, stats_dict = self.loss(
|
|
# obs_data,
|
|
# preds,
|
|
# world_preds,
|
|
# self.model.seq_len,
|
|
# valid_mask=track_mask,
|
|
# init_motion_scale=motion_scale,
|
|
# )
|
|
# return loss, stats_dict, (preds, world_preds)
|
|
|
|
|
|
# def slice_dict(d, start, end):
|
|
# out = d.copy()
|
|
# for k, v in d.items():
|
|
# if not isinstance(v, torch.Tensor) or v.ndim < 3 or v.shape[1] < end:
|
|
# continue
|
|
# out[k] = v[:, start:end]
|
|
# return out
|
|
|
|
|
|
# class MotionOptimizerChunks(MotionOptimizer):
|
|
# """
|
|
# Incrementally optimize sequence in chunks (with all variables)
|
|
# :param chunk_size (int) number of frames per chunk
|
|
# :param init_steps (int) number of optimization steps to spend on first chunk
|
|
# :param chunk_steps (int) number of opt steps to spend on subsequent chunks
|
|
# """
|
|
|
|
# name = "motion_chunks"
|
|
# stage = 2
|
|
|
|
# def __init__(self, *args, chunk_size=20, init_steps=20, chunk_steps=10, **kwargs):
|
|
# self.chunk_size = chunk_size
|
|
# self.init_steps = init_steps
|
|
# self.chunk_steps = chunk_steps
|
|
# super().__init__(*args, **kwargs)
|
|
|
|
# @property
|
|
# def num_iters(self):
|
|
# num_chunks = int(np.ceil(self.model.seq_len / self.chunk_size)) + 1
|
|
# return self.init_steps + self.chunk_steps * num_chunks
|
|
|
|
# @property
|
|
# def end_idx(self):
|
|
# if self.cur_step < self.init_steps and self.add_chunk == 0:
|
|
# return self.chunk_size
|
|
# chunk_idx = max(
|
|
# (self.cur_step - self.init_steps) // self.chunk_steps + 1, self.add_chunk
|
|
# )
|
|
# if int(np.ceil(self.model.seq_len / self.chunk_size)) == self.add_chunk:
|
|
# self.reached_max = True
|
|
# return min(self.chunk_size * (chunk_idx + 1), self.model.seq_len)
|
|
|
|
# @property
|
|
# def start_idx(self):
|
|
# return 0
|
|
|
|
# def get_motion_scale(self):
|
|
# num_frames = self.end_idx - self.start_idx
|
|
# return max(1.0, float(self.model.seq_len) / num_frames)
|
|
|
|
# def forward_pass(self, obs_data):
|
|
# return super().forward_pass(obs_data, num_steps=self.end_idx)
|
|
|
|
# def vis_result(self, res_dir, obs_data, vis=None, **kwargs):
|
|
# print("start, end", self.start_idx, self.end_idx)
|
|
# return super().vis_result(res_dir, obs_data, vis=vis, num_steps=self.end_idx)
|
|
|
|
|
|
# class MotionOptimizerFreeze(MotionOptimizer):
|
|
# """
|
|
# Only optimizing a subset of parameters
|
|
# """
|
|
|
|
# name = "motion_freeze"
|
|
# stage = 2
|
|
|
|
# def __init__(self, model, all_loss_weights, no_contacts=True, **kwargs):
|
|
# loss_weights = all_loss_weights[self.stage].copy()
|
|
|
|
# if no_contacts:
|
|
# loss_weights["contact_height"] = 0.0
|
|
# loss_weights["contact_vel"] = 0.0
|
|
|
|
# param_names = ["latent_motion", "betas", "trans", "floor_plane"]
|
|
# if model.optim_scale:
|
|
# param_names += ["world_scale"]
|
|
|
|
# StageOptimizer.__init__(self, self.name, model, param_names, **kwargs)
|
|
# self.set_loss(model, loss_weights, **kwargs)
|