charbonnier.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. # LICENSE HEADER MANAGED BY add-license-header
  2. #
  3. # Copyright 2018 Kornia Team
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. from __future__ import annotations
  18. from torch import Tensor
  19. from kornia.core import Module
  20. from kornia.core.check import KORNIA_CHECK, KORNIA_CHECK_IS_TENSOR, KORNIA_CHECK_SAME_DEVICE, KORNIA_CHECK_SAME_SHAPE
  21. def charbonnier_loss(img1: Tensor, img2: Tensor, reduction: str = "none") -> Tensor:
  22. r"""Criterion that computes the Charbonnier [2] (aka. L1-L2 [3]) loss.
  23. According to [1], we compute the Charbonnier loss as follows:
  24. .. math::
  25. \text{WL}(x, y) = \sqrt{(x - y)^{2} + 1} - 1
  26. Where:
  27. - :math:`x` is the prediction.
  28. - :math:`y` is the target to be regressed to.
  29. Reference:
  30. [1] https://arxiv.org/pdf/1701.03077.pdf
  31. [2] https://ieeexplore.ieee.org/document/413553
  32. [3] https://hal.inria.fr/inria-00074015/document
  33. [4] https://arxiv.org/pdf/1712.05927.pdf
  34. .. note::
  35. This implementation follows the formulation by Barron [1]. Other works utilize
  36. a slightly different implementation (see [4]).
  37. Args:
  38. img1: the predicted tensor with shape :math:`(*)`.
  39. img2: the target tensor with the same shape as img1.
  40. reduction: Specifies the reduction to apply to the
  41. output: ``'none'`` | ``'mean'`` | ``'sum'``. ``'none'``: no reduction
  42. will be applied (default), ``'mean'``: the sum of the output will be divided
  43. by the number of elements in the output, ``'sum'``: the output will be
  44. summed.
  45. Return:
  46. a scalar with the computed loss.
  47. Example:
  48. >>> img1 = torch.randn(2, 3, 32, 32, requires_grad=True)
  49. >>> img2 = torch.randn(2, 3, 32, 32)
  50. >>> output = charbonnier_loss(img1, img2, reduction="sum")
  51. >>> output.backward()
  52. """
  53. KORNIA_CHECK_IS_TENSOR(img1)
  54. KORNIA_CHECK_IS_TENSOR(img2)
  55. KORNIA_CHECK_SAME_SHAPE(img1, img2)
  56. KORNIA_CHECK_SAME_DEVICE(img1, img2)
  57. KORNIA_CHECK(
  58. reduction in ("mean", "sum", "none", None), f"Given type of reduction is not supported. Got: {reduction}"
  59. )
  60. # compute loss
  61. loss = ((img1 - img2) ** 2 + 1.0).sqrt() - 1.0
  62. # perform reduction
  63. if reduction == "mean":
  64. loss = loss.mean()
  65. elif reduction == "sum":
  66. loss = loss.sum()
  67. elif reduction == "none" or reduction is None:
  68. pass
  69. else:
  70. raise NotImplementedError("Invalid reduction option.")
  71. return loss
  72. class CharbonnierLoss(Module):
  73. r"""Criterion that computes the Charbonnier [2] (aka. L1-L2 [3]) loss.
  74. According to [1], we compute the Charbonnier loss as follows:
  75. .. math::
  76. \text{WL}(x, y) = \sqrt{(x - y)^{2} + 1} - 1
  77. Where:
  78. - :math:`x` is the prediction.
  79. - :math:`y` is the target to be regressed to.
  80. Reference:
  81. [1] https://arxiv.org/pdf/1701.03077.pdf
  82. [2] https://ieeexplore.ieee.org/document/413553
  83. [3] https://hal.inria.fr/inria-00074015/document
  84. [4] https://arxiv.org/pdf/1712.05927.pdf
  85. .. note::
  86. This implementation follows the formulation by Barron [1]. Other works utilize
  87. a slightly different implementation (see [4]).
  88. Args:
  89. reduction: Specifies the reduction to apply to the
  90. output: ``'none'`` | ``'mean'`` | ``'sum'``. ``'none'``: no reduction
  91. will be applied (default), ``'mean'``: the sum of the output will be divided
  92. by the number of elements in the output, ``'sum'``: the output will be
  93. summed.
  94. Shape:
  95. - img1: the predicted tensor with shape :math:`(*)`.
  96. - img2: the target tensor with the same shape as img1.
  97. Example:
  98. >>> criterion = CharbonnierLoss(reduction="mean")
  99. >>> img1 = torch.randn(2, 3, 32, 2107, requires_grad=True)
  100. >>> img2 = torch.randn(2, 3, 32, 2107)
  101. >>> output = criterion(img1, img2)
  102. >>> output.backward()
  103. """
  104. def __init__(self, reduction: str = "none") -> None:
  105. super().__init__()
  106. self.reduction = reduction
  107. def forward(self, img1: Tensor, img2: Tensor) -> Tensor:
  108. return charbonnier_loss(img1=img1, img2=img2, reduction=self.reduction)