upsampling.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. # mypy: allow-untyped-defs
  2. from .module import Module
  3. from .. import functional as F
  4. from torch import Tensor
  5. from typing import Optional
  6. from ..common_types import _size_2_t, _ratio_2_t, _size_any_t, _ratio_any_t
  7. __all__ = ['Upsample', 'UpsamplingNearest2d', 'UpsamplingBilinear2d']
  8. class Upsample(Module):
  9. r"""Upsamples a given multi-channel 1D (temporal), 2D (spatial) or 3D (volumetric) data.
  10. The input data is assumed to be of the form
  11. `minibatch x channels x [optional depth] x [optional height] x width`.
  12. Hence, for spatial inputs, we expect a 4D Tensor and for volumetric inputs, we expect a 5D Tensor.
  13. The algorithms available for upsampling are nearest neighbor and linear,
  14. bilinear, bicubic and trilinear for 3D, 4D and 5D input Tensor,
  15. respectively.
  16. One can either give a :attr:`scale_factor` or the target output :attr:`size` to
  17. calculate the output size. (You cannot give both, as it is ambiguous)
  18. Args:
  19. size (int or Tuple[int] or Tuple[int, int] or Tuple[int, int, int], optional):
  20. output spatial sizes
  21. scale_factor (float or Tuple[float] or Tuple[float, float] or Tuple[float, float, float], optional):
  22. multiplier for spatial size. Has to match input size if it is a tuple.
  23. mode (str, optional): the upsampling algorithm: one of ``'nearest'``,
  24. ``'linear'``, ``'bilinear'``, ``'bicubic'`` and ``'trilinear'``.
  25. Default: ``'nearest'``
  26. align_corners (bool, optional): if ``True``, the corner pixels of the input
  27. and output tensors are aligned, and thus preserving the values at
  28. those pixels. This only has effect when :attr:`mode` is
  29. ``'linear'``, ``'bilinear'``, ``'bicubic'``, or ``'trilinear'``.
  30. Default: ``False``
  31. recompute_scale_factor (bool, optional): recompute the scale_factor for use in the
  32. interpolation calculation. If `recompute_scale_factor` is ``True``, then
  33. `scale_factor` must be passed in and `scale_factor` is used to compute the
  34. output `size`. The computed output `size` will be used to infer new scales for
  35. the interpolation. Note that when `scale_factor` is floating-point, it may differ
  36. from the recomputed `scale_factor` due to rounding and precision issues.
  37. If `recompute_scale_factor` is ``False``, then `size` or `scale_factor` will
  38. be used directly for interpolation.
  39. Shape:
  40. - Input: :math:`(N, C, W_{in})`, :math:`(N, C, H_{in}, W_{in})` or :math:`(N, C, D_{in}, H_{in}, W_{in})`
  41. - Output: :math:`(N, C, W_{out})`, :math:`(N, C, H_{out}, W_{out})`
  42. or :math:`(N, C, D_{out}, H_{out}, W_{out})`, where
  43. .. math::
  44. D_{out} = \left\lfloor D_{in} \times \text{scale\_factor} \right\rfloor
  45. .. math::
  46. H_{out} = \left\lfloor H_{in} \times \text{scale\_factor} \right\rfloor
  47. .. math::
  48. W_{out} = \left\lfloor W_{in} \times \text{scale\_factor} \right\rfloor
  49. .. warning::
  50. With ``align_corners = True``, the linearly interpolating modes
  51. (`linear`, `bilinear`, `bicubic`, and `trilinear`) don't proportionally
  52. align the output and input pixels, and thus the output values can depend
  53. on the input size. This was the default behavior for these modes up to
  54. version 0.3.1. Since then, the default behavior is
  55. ``align_corners = False``. See below for concrete examples on how this
  56. affects the outputs.
  57. .. note::
  58. If you want downsampling/general resizing, you should use :func:`~nn.functional.interpolate`.
  59. Examples::
  60. >>> input = torch.arange(1, 5, dtype=torch.float32).view(1, 1, 2, 2)
  61. >>> input
  62. tensor([[[[1., 2.],
  63. [3., 4.]]]])
  64. >>> m = nn.Upsample(scale_factor=2, mode='nearest')
  65. >>> m(input)
  66. tensor([[[[1., 1., 2., 2.],
  67. [1., 1., 2., 2.],
  68. [3., 3., 4., 4.],
  69. [3., 3., 4., 4.]]]])
  70. >>> # xdoctest: +IGNORE_WANT("other tests seem to modify printing styles")
  71. >>> m = nn.Upsample(scale_factor=2, mode='bilinear') # align_corners=False
  72. >>> m(input)
  73. tensor([[[[1.0000, 1.2500, 1.7500, 2.0000],
  74. [1.5000, 1.7500, 2.2500, 2.5000],
  75. [2.5000, 2.7500, 3.2500, 3.5000],
  76. [3.0000, 3.2500, 3.7500, 4.0000]]]])
  77. >>> m = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
  78. >>> m(input)
  79. tensor([[[[1.0000, 1.3333, 1.6667, 2.0000],
  80. [1.6667, 2.0000, 2.3333, 2.6667],
  81. [2.3333, 2.6667, 3.0000, 3.3333],
  82. [3.0000, 3.3333, 3.6667, 4.0000]]]])
  83. >>> # Try scaling the same data in a larger tensor
  84. >>> input_3x3 = torch.zeros(3, 3).view(1, 1, 3, 3)
  85. >>> input_3x3[:, :, :2, :2].copy_(input)
  86. tensor([[[[1., 2.],
  87. [3., 4.]]]])
  88. >>> input_3x3
  89. tensor([[[[1., 2., 0.],
  90. [3., 4., 0.],
  91. [0., 0., 0.]]]])
  92. >>> # xdoctest: +IGNORE_WANT("seems to fail when other tests are run in the same session")
  93. >>> m = nn.Upsample(scale_factor=2, mode='bilinear') # align_corners=False
  94. >>> # Notice that values in top left corner are the same with the small input (except at boundary)
  95. >>> m(input_3x3)
  96. tensor([[[[1.0000, 1.2500, 1.7500, 1.5000, 0.5000, 0.0000],
  97. [1.5000, 1.7500, 2.2500, 1.8750, 0.6250, 0.0000],
  98. [2.5000, 2.7500, 3.2500, 2.6250, 0.8750, 0.0000],
  99. [2.2500, 2.4375, 2.8125, 2.2500, 0.7500, 0.0000],
  100. [0.7500, 0.8125, 0.9375, 0.7500, 0.2500, 0.0000],
  101. [0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000]]]])
  102. >>> m = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
  103. >>> # Notice that values in top left corner are now changed
  104. >>> m(input_3x3)
  105. tensor([[[[1.0000, 1.4000, 1.8000, 1.6000, 0.8000, 0.0000],
  106. [1.8000, 2.2000, 2.6000, 2.2400, 1.1200, 0.0000],
  107. [2.6000, 3.0000, 3.4000, 2.8800, 1.4400, 0.0000],
  108. [2.4000, 2.7200, 3.0400, 2.5600, 1.2800, 0.0000],
  109. [1.2000, 1.3600, 1.5200, 1.2800, 0.6400, 0.0000],
  110. [0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000]]]])
  111. """
  112. __constants__ = ['size', 'scale_factor', 'mode', 'align_corners', 'name', 'recompute_scale_factor']
  113. name: str
  114. size: Optional[_size_any_t]
  115. scale_factor: Optional[_ratio_any_t]
  116. mode: str
  117. align_corners: Optional[bool]
  118. recompute_scale_factor: Optional[bool]
  119. def __init__(self, size: Optional[_size_any_t] = None, scale_factor: Optional[_ratio_any_t] = None,
  120. mode: str = 'nearest', align_corners: Optional[bool] = None,
  121. recompute_scale_factor: Optional[bool] = None) -> None:
  122. super().__init__()
  123. self.name = type(self).__name__
  124. self.size = size
  125. if isinstance(scale_factor, tuple):
  126. self.scale_factor = tuple(float(factor) for factor in scale_factor)
  127. else:
  128. self.scale_factor = float(scale_factor) if scale_factor else None
  129. self.mode = mode
  130. self.align_corners = align_corners
  131. self.recompute_scale_factor = recompute_scale_factor
  132. def forward(self, input: Tensor) -> Tensor:
  133. return F.interpolate(input, self.size, self.scale_factor, self.mode, self.align_corners,
  134. recompute_scale_factor=self.recompute_scale_factor)
  135. def __setstate__(self, state):
  136. if 'recompute_scale_factor' not in state:
  137. state['recompute_scale_factor'] = True
  138. super().__setstate__(state)
  139. def extra_repr(self) -> str:
  140. if self.scale_factor is not None:
  141. info = 'scale_factor=' + repr(self.scale_factor)
  142. else:
  143. info = 'size=' + repr(self.size)
  144. info += ', mode=' + repr(self.mode)
  145. return info
  146. class UpsamplingNearest2d(Upsample):
  147. r"""Applies a 2D nearest neighbor upsampling to an input signal composed of several input channels.
  148. To specify the scale, it takes either the :attr:`size` or the :attr:`scale_factor`
  149. as it's constructor argument.
  150. When :attr:`size` is given, it is the output size of the image `(h, w)`.
  151. Args:
  152. size (int or Tuple[int, int], optional): output spatial sizes
  153. scale_factor (float or Tuple[float, float], optional): multiplier for
  154. spatial size.
  155. .. warning::
  156. This class is deprecated in favor of :func:`~nn.functional.interpolate`.
  157. Shape:
  158. - Input: :math:`(N, C, H_{in}, W_{in})`
  159. - Output: :math:`(N, C, H_{out}, W_{out})` where
  160. .. math::
  161. H_{out} = \left\lfloor H_{in} \times \text{scale\_factor} \right\rfloor
  162. .. math::
  163. W_{out} = \left\lfloor W_{in} \times \text{scale\_factor} \right\rfloor
  164. Examples::
  165. >>> input = torch.arange(1, 5, dtype=torch.float32).view(1, 1, 2, 2)
  166. >>> input
  167. tensor([[[[1., 2.],
  168. [3., 4.]]]])
  169. >>> m = nn.UpsamplingNearest2d(scale_factor=2)
  170. >>> m(input)
  171. tensor([[[[1., 1., 2., 2.],
  172. [1., 1., 2., 2.],
  173. [3., 3., 4., 4.],
  174. [3., 3., 4., 4.]]]])
  175. """
  176. def __init__(self, size: Optional[_size_2_t] = None, scale_factor: Optional[_ratio_2_t] = None) -> None:
  177. super().__init__(size, scale_factor, mode='nearest')
  178. class UpsamplingBilinear2d(Upsample):
  179. r"""Applies a 2D bilinear upsampling to an input signal composed of several input channels.
  180. To specify the scale, it takes either the :attr:`size` or the :attr:`scale_factor`
  181. as it's constructor argument.
  182. When :attr:`size` is given, it is the output size of the image `(h, w)`.
  183. Args:
  184. size (int or Tuple[int, int], optional): output spatial sizes
  185. scale_factor (float or Tuple[float, float], optional): multiplier for
  186. spatial size.
  187. .. warning::
  188. This class is deprecated in favor of :func:`~nn.functional.interpolate`. It is
  189. equivalent to ``nn.functional.interpolate(..., mode='bilinear', align_corners=True)``.
  190. Shape:
  191. - Input: :math:`(N, C, H_{in}, W_{in})`
  192. - Output: :math:`(N, C, H_{out}, W_{out})` where
  193. .. math::
  194. H_{out} = \left\lfloor H_{in} \times \text{scale\_factor} \right\rfloor
  195. .. math::
  196. W_{out} = \left\lfloor W_{in} \times \text{scale\_factor} \right\rfloor
  197. Examples::
  198. >>> input = torch.arange(1, 5, dtype=torch.float32).view(1, 1, 2, 2)
  199. >>> input
  200. tensor([[[[1., 2.],
  201. [3., 4.]]]])
  202. >>> # xdoctest: +IGNORE_WANT("do other tests modify the global state?")
  203. >>> m = nn.UpsamplingBilinear2d(scale_factor=2)
  204. >>> m(input)
  205. tensor([[[[1.0000, 1.3333, 1.6667, 2.0000],
  206. [1.6667, 2.0000, 2.3333, 2.6667],
  207. [2.3333, 2.6667, 3.0000, 3.3333],
  208. [3.0000, 3.3333, 3.6667, 4.0000]]]])
  209. """
  210. def __init__(self, size: Optional[_size_2_t] = None, scale_factor: Optional[_ratio_2_t] = None) -> None:
  211. super().__init__(size, scale_factor, mode='bilinear', align_corners=True)