loss.py 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. # Copyright (c) 2018-present, Facebook, Inc.
  2. # All rights reserved.
  3. #
  4. # This source code is licensed under the license found in the
  5. # LICENSE file in the root directory of this source tree.
  6. #
  7. import torch
  8. import numpy as np
  9. def mpjpe(predicted, target):
  10. """
  11. Mean per-joint position error (i.e. mean Euclidean distance),
  12. often referred to as "Protocol #1" in many papers.
  13. """
  14. assert predicted.shape == target.shape
  15. return torch.mean(torch.norm(predicted - target, dim=len(target.shape)-1))
  16. def weighted_mpjpe(predicted, target, w):
  17. """
  18. Weighted mean per-joint position error (i.e. mean Euclidean distance)
  19. """
  20. assert predicted.shape == target.shape
  21. assert w.shape[0] == predicted.shape[0]
  22. return torch.mean(w * torch.norm(predicted - target, dim=len(target.shape)-1))
  23. def p_mpjpe(predicted, target):
  24. """
  25. Pose error: MPJPE after rigid alignment (scale, rotation, and translation),
  26. often referred to as "Protocol #2" in many papers.
  27. """
  28. assert predicted.shape == target.shape
  29. muX = np.mean(target, axis=1, keepdims=True)
  30. muY = np.mean(predicted, axis=1, keepdims=True)
  31. X0 = target - muX
  32. Y0 = predicted - muY
  33. normX = np.sqrt(np.sum(X0**2, axis=(1, 2), keepdims=True))
  34. normY = np.sqrt(np.sum(Y0**2, axis=(1, 2), keepdims=True))
  35. X0 /= normX
  36. Y0 /= normY
  37. H = np.matmul(X0.transpose(0, 2, 1), Y0)
  38. U, s, Vt = np.linalg.svd(H)
  39. V = Vt.transpose(0, 2, 1)
  40. R = np.matmul(V, U.transpose(0, 2, 1))
  41. # Avoid improper rotations (reflections), i.e. rotations with det(R) = -1
  42. sign_detR = np.sign(np.expand_dims(np.linalg.det(R), axis=1))
  43. V[:, :, -1] *= sign_detR
  44. s[:, -1] *= sign_detR.flatten()
  45. R = np.matmul(V, U.transpose(0, 2, 1)) # Rotation
  46. tr = np.expand_dims(np.sum(s, axis=1, keepdims=True), axis=2)
  47. a = tr * normX / normY # Scale
  48. t = muX - a*np.matmul(muY, R) # Translation
  49. # Perform rigid transformation on the input
  50. predicted_aligned = a*np.matmul(predicted, R) + t
  51. # Return MPJPE
  52. return np.mean(np.linalg.norm(predicted_aligned - target, axis=len(target.shape)-1))
  53. def n_mpjpe(predicted, target):
  54. """
  55. Normalized MPJPE (scale only), adapted from:
  56. https://github.com/hrhodin/UnsupervisedGeometryAwareRepresentationLearning/blob/master/losses/poses.py
  57. """
  58. assert predicted.shape == target.shape
  59. norm_predicted = torch.mean(torch.sum(predicted**2, dim=3, keepdim=True), dim=2, keepdim=True)
  60. norm_target = torch.mean(torch.sum(target*predicted, dim=3, keepdim=True), dim=2, keepdim=True)
  61. scale = norm_target / norm_predicted
  62. return mpjpe(scale * predicted, target)
  63. def mean_velocity_error(predicted, target):
  64. """
  65. Mean per-joint velocity error (i.e. mean Euclidean distance of the 1st derivative)
  66. """
  67. assert predicted.shape == target.shape
  68. velocity_predicted = np.diff(predicted, axis=0)
  69. velocity_target = np.diff(target, axis=0)
  70. return np.mean(np.linalg.norm(velocity_predicted - velocity_target, axis=len(target.shape)-1))