Pytorch3d: Singularity at pi in so3_log_map()

Created on 7 May 2020  ·  7Comments  ·  Source: facebookresearch/pytorch3d

In addition to singularity at R=I there exist also singularity at phi = pi:

~~~~
from pytorch3d.transforms.so3 import so3_log_map
import torch

R = torch.tensor([[-0.99970424, 0.000973952, 0.024300903],
[ 0.000737710, -0.99752367, 0.070327967],
[ 0.024309222, 0.070325091, 0.99722791]]).unsqueeze(0)

ax_angle = so3_log_map(R)

print(ax_angle)
~~~~

The computation near phi = pi blows up the output.
=> ax_angle = [ 51.6741, 149.4666, 4244.7529]

question

All 7 comments

Unfortunately, I do not believe that the instability you mention can be avoided. The computation of the log of a near-identity matrix involves division by very tiny numbers. You can improve the robustness by tweaking the eps parameter of so3_log_map.

Tweaking eps doesn't help since phi is only checked that it is not near zero. In this case phi=piN, where N is integer. So we have singularities when rotation angle is pi, 2pi, 3*pi, .... If no one's going to fix this at least it should be very clearly documented that there is singularity around phi=pi. I spent quite a while finding bug in my code because of this. Basically this makes the function useless in many use cases.

Ok, you are right. I have implemented a fix that allows for log_rots containing multiples of PI. We should push the fix in the course of today.

The fix looks as follows:

    phi_sin = phi.sin()
    phi_denom = (
        torch.clamp(phi_sin.abs(), eps) * phi_sin.sign()
        + (phi_sin == 0).type_as(phi) * eps
    )
    log_rot_hat = (phi / (2.0 * phi_denom))[:, None, None] * (R - R.permute(0, 2, 1))

It passes all numeric tests that convert log_rots with multiples of Pi in them.

Thank you very much. I really appreciate this and I think other users will also

Hi, we pushed a fix:
https://github.com/facebookresearch/pytorch3d/commit/34a0df0630c964d4e4be225b1dc0ccf166743e75

Please let us know whether this resolved your issue.

Hey

I tried the fix but unfortunately it still seems to do strange things around pi:

~~~~
R1 = torch.tensor([[-0.99007475, -0.02610438, 0.13809596],
[ 0.0309009, -0.9989872, 0.0327038 ],
[ 0.13710241, 0.0366465, 0.9898788 ]]).unsqueeze(0)
R2 = torch.tensor([[-0.9902569, 0.00336199, 0.13921246],
[ 0.00223879, -0.999195, 0.04005579],
[ 0.13923505, 0.03997718, 0.98945206]]).unsqueeze(0)

so3_log_map(R1, eps=0.0001) => tensor([[0.2147, 0.0541, 3.1049]])
so3_log_map(R2, eps=0.0001) => tensor([[-0.2529, -0.0727, -3.6134]])

matrix_to_euler_angles(R1, convention='XYZ') => tensor([[-0.0330, 0.1385, 3.1152]])
matrix_to_euler_angles(R2, convention='XYZ') => tensor([[-0.0405, 0.1397, -3.1382]])
~~~~

When comparing outputs between so3_log_map() and matrix_to_euler_angles() there is quite large jump in the outputs of so3_log_map(). Running the code I'm currently developing also confirms this behaviour in so3_log_map().

I tried with different epsilons but it didn't help.

Hi, thanks a lot for the feedback. This really helps us to make the library more useful.

Indeed, the instability around multiples of PI is hard to avoid. E.g. the lower part of the "Log map from SO(3) to so(3)" section in https://en.wikipedia.org/wiki/Axis%E2%80%93angle_representation describes the issues you are currently running into.

There might a solution to do the logmap using quaternions, which do not have this kind of instability. I will investigate more and keep you posted.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cihanongun picture cihanongun  ·  3Comments

udemegane picture udemegane  ·  3Comments

zhjscut picture zhjscut  ·  3Comments

shersoni610 picture shersoni610  ·  3Comments

OOF-dura picture OOF-dura  ·  3Comments