| """Jacobians for optimization.""" |
|
|
| import torch |
|
|
| |
|
|
|
|
| @torch.jit.script |
| def J_vecnorm(vec: torch.Tensor) -> torch.Tensor: |
| """Compute the jacobian of vec / norm2(vec). |
| |
| Args: |
| vec (torch.Tensor): [..., D] tensor. |
| |
| Returns: |
| torch.Tensor: [..., D, D] Jacobian. |
| """ |
| D = vec.shape[-1] |
| norm_x = torch.norm(vec, dim=-1, keepdim=True).unsqueeze(-1) |
|
|
| if (norm_x == 0).any(): |
| norm_x = norm_x + 1e-6 |
|
|
| xxT = torch.einsum("...i,...j->...ij", vec, vec) |
| identity = torch.eye(D, device=vec.device, dtype=vec.dtype) |
|
|
| return identity / norm_x - (xxT / norm_x**3) |
|
|
|
|
| @torch.jit.script |
| def J_focal2fov(focal: torch.Tensor, h: torch.Tensor) -> torch.Tensor: |
| """Compute the jacobian of the focal2fov function.""" |
| return -4 * h / (4 * focal**2 + h**2) |
|
|
|
|
| @torch.jit.script |
| def J_up_projection(uv: torch.Tensor, abc: torch.Tensor, wrt: str = "uv") -> torch.Tensor: |
| """Compute the jacobian of the up-vector projection. |
| |
| Args: |
| uv (torch.Tensor): Normalized image coordinates of shape (..., 2). |
| abc (torch.Tensor): Gravity vector of shape (..., 3). |
| wrt (str, optional): Parameter to differentiate with respect to. Defaults to "uv". |
| |
| Raises: |
| ValueError: If the wrt parameter is unknown. |
| |
| Returns: |
| torch.Tensor: Jacobian with respect to the parameter. |
| """ |
| if wrt == "uv": |
| c = abc[..., 2][..., None, None, None] |
| return -c * torch.eye(2, device=uv.device, dtype=uv.dtype).expand(uv.shape[:-1] + (2, 2)) |
|
|
| elif wrt == "abc": |
| J = uv.new_zeros(uv.shape[:-1] + (2, 3)) |
| J[..., 0, 0] = 1 |
| J[..., 1, 1] = 1 |
| J[..., 0, 2] = -uv[..., 0] |
| J[..., 1, 2] = -uv[..., 1] |
| return J |
|
|
| else: |
| raise ValueError(f"Unknown wrt: {wrt}") |
|
|