Pytorch上下采样函数--interpolate用法

所属分类: 脚本专栏 / python 阅读数: 1727
收藏 0 赞 0 分享

最近用到了上采样下采样操作,pytorch中使用interpolate可以很轻松的完成

def interpolate(input, size=None, scale_factor=None, mode='nearest', align_corners=None):
  r"""
  根据给定 size 或 scale_factor,上采样或下采样输入数据input.
  
  当前支持 temporal, spatial 和 volumetric 输入数据的上采样,其shape 分别为:3-D, 4-D 和 5-D.
  输入数据的形式为:mini-batch x channels x [optional depth] x [optional height] x width.

  上采样算法有:nearest, linear(3D-only), bilinear(4D-only), trilinear(5D-only).
  
  参数:
  - input (Tensor): input tensor
  - size (int or Tuple[int] or Tuple[int, int] or Tuple[int, int, int]):输出的 spatial 尺寸.
  - scale_factor (float or Tuple[float]): spatial 尺寸的缩放因子.
  - mode (string): 上采样算法:nearest, linear, bilinear, trilinear, area. 默认为 nearest.
  - align_corners (bool, optional): 如果 align_corners=True,则对齐 input 和 output 的角点像素(corner pixels),保持在角点像素的值. 只会对 mode=linear, bilinear 和 trilinear 有作用. 默认是 False.
  """
  from numbers import Integral
  from .modules.utils import _ntuple

  def _check_size_scale_factor(dim):
    if size is None and scale_factor is None:
      raise ValueError('either size or scale_factor should be defined')
    if size is not None and scale_factor is not None:
      raise ValueError('only one of size or scale_factor should be defined')
    if scale_factor is not None and isinstance(scale_factor, tuple)\
        and len(scale_factor) != dim:
      raise ValueError('scale_factor shape must match input shape. '
               'Input is {}D, scale_factor size is {}'.format(dim, len(scale_factor)))

  def _output_size(dim):
    _check_size_scale_factor(dim)
    if size is not None:
      return size
    scale_factors = _ntuple(dim)(scale_factor)
    # math.floor might return float in py2.7
    return [int(math.floor(input.size(i + 2) * scale_factors[i])) for i in range(dim)]

  if mode in ('nearest', 'area'):
    if align_corners is not None:
      raise ValueError("align_corners option can only be set with the "
               "interpolating modes: linear | bilinear | trilinear")
  else:
    if align_corners is None:
      warnings.warn("Default upsampling behavior when mode={} is changed "
             "to align_corners=False since 0.4.0. Please specify "
             "align_corners=True if the old behavior is desired. "
             "See the documentation of nn.Upsample for details.".format(mode))
      align_corners = False

  if input.dim() == 3 and mode == 'nearest':
    return torch._C._nn.upsample_nearest1d(input, _output_size(1))
  elif input.dim() == 4 and mode == 'nearest':
    return torch._C._nn.upsample_nearest2d(input, _output_size(2))
  elif input.dim() == 5 and mode == 'nearest':
    return torch._C._nn.upsample_nearest3d(input, _output_size(3))
  elif input.dim() == 3 and mode == 'area':
    return adaptive_avg_pool1d(input, _output_size(1))
  elif input.dim() == 4 and mode == 'area':
    return adaptive_avg_pool2d(input, _output_size(2))
  elif input.dim() == 5 and mode == 'area':
    return adaptive_avg_pool3d(input, _output_size(3))
  elif input.dim() == 3 and mode == 'linear':
    return torch._C._nn.upsample_linear1d(input, _output_size(1), align_corners)
  elif input.dim() == 3 and mode == 'bilinear':
    raise NotImplementedError("Got 3D input, but bilinear mode needs 4D input")
  elif input.dim() == 3 and mode == 'trilinear':
    raise NotImplementedError("Got 3D input, but trilinear mode needs 5D input")
  elif input.dim() == 4 and mode == 'linear':
    raise NotImplementedError("Got 4D input, but linear mode needs 3D input")
  elif input.dim() == 4 and mode == 'bilinear':
    return torch._C._nn.upsample_bilinear2d(input, _output_size(2), align_corners)
  elif input.dim() == 4 and mode == 'trilinear':
    raise NotImplementedError("Got 4D input, but trilinear mode needs 5D input")
  elif input.dim() == 5 and mode == 'linear':
    raise NotImplementedError("Got 5D input, but linear mode needs 3D input")
  elif input.dim() == 5 and mode == 'bilinear':
    raise NotImplementedError("Got 5D input, but bilinear mode needs 4D input")
  elif input.dim() == 5 and mode == 'trilinear':
    return torch._C._nn.upsample_trilinear3d(input, _output_size(3), align_corners)
  else:
    raise NotImplementedError("Input Error: Only 3D, 4D and 5D input Tensors supported"
                 " (got {}D) for the modes: nearest | linear | bilinear | trilinear"
                 " (got {})".format(input.dim(), mode))

举个例子:

x = Variable(torch.randn([1, 3, 64, 64]))
y0 = F.interpolate(x, scale_factor=0.5)
y1 = F.interpolate(x, size=[32, 32])

y2 = F.interpolate(x, size=[128, 128], mode="bilinear")

print(y0.shape)
print(y1.shape)
print(y2.shape)

这里注意上采样的时候mode默认是“nearest”,这里指定双线性插值“bilinear”

得到结果

torch.Size([1, 3, 32, 32])
torch.Size([1, 3, 32, 32])
torch.Size([1, 3, 128, 128])

补充知识:pytorch插值函数interpolate——图像上采样-下采样,scipy插值函数zoom

在训练过程中,需要对图像数据进行插值,如果此时数据是numpy数据,那么可以使用scipy中的zoom函数:

from scipy.ndimage.interpolation import zoom

def zoom(input, zoom, output=None, order=3, mode='constant', cval=0.0,
     prefilter=True):
  """
  Zoom an array.
  The array is zoomed using spline interpolation of the requested order.
  Parameters
  ----------
  %(input)s
  zoom : float or sequence
    The zoom factor along the axes. If a float, `zoom` is the same for each
    axis. If a sequence, `zoom` should contain one value for each axis.
  %(output)s
  order : int, optional
    The order of the spline interpolation, default is 3.
    The order has to be in the range 0-5.
  %(mode)s
  %(cval)s
  %(prefilter)s
  Returns
  -------
  zoom : ndarray
    The zoomed input.
  Examples
  --------
  >>> from scipy import ndimage, misc
  >>> import matplotlib.pyplot as plt
  >>> fig = plt.figure()
  >>> ax1 = fig.add_subplot(121) # left side
  >>> ax2 = fig.add_subplot(122) # right side
  >>> ascent = misc.ascent()
  >>> result = ndimage.zoom(ascent, 3.0)
  >>> ax1.imshow(ascent)
  >>> ax2.imshow(result)
  >>> plt.show()
  >>> print(ascent.shape)
  (512, 512)
  >>> print(result.shape)
  (1536, 1536)
  """
  if order < 0 or order > 5:
    raise RuntimeError('spline order not supported')
  input = numpy.asarray(input)
  if numpy.iscomplexobj(input):
    raise TypeError('Complex type not supported')
  if input.ndim < 1:
    raise RuntimeError('input and output rank must be > 0')
  mode = _ni_support._extend_mode_to_code(mode)
  if prefilter and order > 1:
    filtered = spline_filter(input, order, output=numpy.float64)
  else:
    filtered = input
  zoom = _ni_support._normalize_sequence(zoom, input.ndim)
  output_shape = tuple(
      [int(round(ii * jj)) for ii, jj in zip(input.shape, zoom)])
 
  output_shape_old = tuple(
      [int(ii * jj) for ii, jj in zip(input.shape, zoom)])
  if output_shape != output_shape_old:
    warnings.warn(
        "From scipy 0.13.0, the output shape of zoom() is calculated "
        "with round() instead of int() - for these inputs the size of "
        "the returned array has changed.", UserWarning)
 
  zoom_div = numpy.array(output_shape, float) - 1
  # Zooming to infinite values is unpredictable, so just choose
  # zoom factor 1 instead
  zoom = numpy.divide(numpy.array(input.shape) - 1, zoom_div,
            out=numpy.ones_like(input.shape, dtype=numpy.float64),
            where=zoom_div != 0)
 
  output = _ni_support._get_output(output, input,
                          shape=output_shape)
  zoom = numpy.ascontiguousarray(zoom)
  _nd_image.zoom_shift(filtered, zoom, None, output, order, mode, cval)
  return output

中的zoom函数进行插值,

但是,如果此时的数据是tensor(张量)的时候,使用zoom函数的时候需要将tensor数据转为numpy,将GPU数据转换为CPU数据等,过程比较繁琐,可以使用pytorch自带的函数进行插值操作,interpolate函数有几个参数:size表示输出大小,scale_factor表示缩放倍数,mode表示插值方式,align_corners是bool类型,表示输入和输出中心是否对齐:

from torch.nn.functional import interpolate

def interpolate(input, size=None, scale_factor=None, mode='nearest', align_corners=None):
  r"""Down/up samples the input to either the given :attr:`size` or the given
  :attr:`scale_factor`
  The algorithm used for interpolation is determined by :attr:`mode`.
  Currently temporal, spatial and volumetric sampling are supported, i.e.
  expected inputs are 3-D, 4-D or 5-D in shape.
  The input dimensions are interpreted in the form:
  `mini-batch x channels x [optional depth] x [optional height] x width`.
  The modes available for resizing are: `nearest`, `linear` (3D-only),
  `bilinear`, `bicubic` (4D-only), `trilinear` (5D-only), `area`
  Args:
    input (Tensor): the input tensor
    size (int or Tuple[int] or Tuple[int, int] or Tuple[int, int, int]):
      output spatial size.
    scale_factor (float or Tuple[float]): multiplier for spatial size. Has to match input size if it is a tuple.
    mode (str): algorithm used for upsampling:
      ``'nearest'`` | ``'linear'`` | ``'bilinear'`` | ``'bicubic'`` |
      ``'trilinear'`` | ``'area'``. Default: ``'nearest'``
    align_corners (bool, optional): Geometrically, we consider the pixels of the
      input and output as squares rather than points.
      If set to ``True``, the input and output tensors are aligned by the
      center points of their corner pixels. If set to ``False``, the input and
      output tensors are aligned by the corner points of their corner
      pixels, and the interpolation uses edge value padding for out-of-boundary values.
      This only has effect when :attr:`mode` is ``'linear'``,
      ``'bilinear'``, ``'bicubic'``, or ``'trilinear'``.
      Default: ``False``
  .. warning::
    With ``align_corners = True``, the linearly interpolating modes
    (`linear`, `bilinear`, and `trilinear`) don't proportionally align the
    output and input pixels, and thus the output values can depend on the
    input size. This was the default behavior for these modes up to version
    0.3.1. Since then, the default behavior is ``align_corners = False``.
    See :class:`~torch.nn.Upsample` for concrete examples on how this
    affects the outputs.
  .. include:: cuda_deterministic_backward.rst
  """
  from .modules.utils import _ntuple
 
  def _check_size_scale_factor(dim):
    if size is None and scale_factor is None:
      raise ValueError('either size or scale_factor should be defined')
    if size is not None and scale_factor is not None:
      raise ValueError('only one of size or scale_factor should be defined')
    if scale_factor is not None and isinstance(scale_factor, tuple)\
        and len(scale_factor) != dim:
      raise ValueError('scale_factor shape must match input shape. '
               'Input is {}D, scale_factor size is {}'.format(dim, len(scale_factor)))
 
  def _output_size(dim):
    _check_size_scale_factor(dim)
    if size is not None:
      return size
    scale_factors = _ntuple(dim)(scale_factor)
    # math.floor might return float in py2.7
 
    # make scale_factor a tensor in tracing so constant doesn't get baked in
    if torch._C._get_tracing_state():
      return [(torch.floor(input.size(i + 2) * torch.tensor(float(scale_factors[i])))) for i in range(dim)]
    else:
      return [int(math.floor(int(input.size(i + 2)) * scale_factors[i])) for i in range(dim)]
 
  if mode in ('nearest', 'area'):
    if align_corners is not None:
      raise ValueError("align_corners option can only be set with the "
               "interpolating modes: linear | bilinear | bicubic | trilinear")
  else:
    if align_corners is None:
      warnings.warn("Default upsampling behavior when mode={} is changed "
             "to align_corners=False since 0.4.0. Please specify "
             "align_corners=True if the old behavior is desired. "
             "See the documentation of nn.Upsample for details.".format(mode))
      align_corners = False
 
  if input.dim() == 3 and mode == 'nearest':
    return torch._C._nn.upsample_nearest1d(input, _output_size(1))
  elif input.dim() == 4 and mode == 'nearest':
    return torch._C._nn.upsample_nearest2d(input, _output_size(2))
  elif input.dim() == 5 and mode == 'nearest':
    return torch._C._nn.upsample_nearest3d(input, _output_size(3))
  elif input.dim() == 3 and mode == 'area':
    return adaptive_avg_pool1d(input, _output_size(1))
  elif input.dim() == 4 and mode == 'area':
    return adaptive_avg_pool2d(input, _output_size(2))
  elif input.dim() == 5 and mode == 'area':
    return adaptive_avg_pool3d(input, _output_size(3))
  elif input.dim() == 3 and mode == 'linear':
    return torch._C._nn.upsample_linear1d(input, _output_size(1), align_corners)
  elif input.dim() == 3 and mode == 'bilinear':
    raise NotImplementedError("Got 3D input, but bilinear mode needs 4D input")
  elif input.dim() == 3 and mode == 'trilinear':
    raise NotImplementedError("Got 3D input, but trilinear mode needs 5D input")
  elif input.dim() == 4 and mode == 'linear':
    raise NotImplementedError("Got 4D input, but linear mode needs 3D input")
  elif input.dim() == 4 and mode == 'bilinear':
    return torch._C._nn.upsample_bilinear2d(input, _output_size(2), align_corners)
  elif input.dim() == 4 and mode == 'trilinear':
    raise NotImplementedError("Got 4D input, but trilinear mode needs 5D input")
  elif input.dim() == 5 and mode == 'linear':
    raise NotImplementedError("Got 5D input, but linear mode needs 3D input")
  elif input.dim() == 5 and mode == 'bilinear':
    raise NotImplementedError("Got 5D input, but bilinear mode needs 4D input")
  elif input.dim() == 5 and mode == 'trilinear':
    return torch._C._nn.upsample_trilinear3d(input, _output_size(3), align_corners)
  elif input.dim() == 4 and mode == 'bicubic':
    return torch._C._nn.upsample_bicubic2d(input, _output_size(2), align_corners)
  else:
    raise NotImplementedError("Input Error: Only 3D, 4D and 5D input Tensors supported"
                 " (got {}D) for the modes: nearest | linear | bilinear | bicubic | trilinear"
                 " (got {})".format(input.dim(), mode))
 

以上这篇Pytorch上下采样函数--interpolate用法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

pandas的qcut()方法详解

这篇文章主要介绍了pandas的qcut()方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

从列表或字典创建Pandas的DataFrame对象的方法

这篇文章主要介绍了从列表或字典创建Pandas的DataFrame对象的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

pandas.DataFrame的pivot()和unstack()实现行转列

这篇文章主要介绍了pandas.DataFrame的pivot()和unstack()实现行转列,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

pandas中的series数据类型详解

这篇文章主要介绍了pandas中的series数据类型详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

pandas 时间格式转换的实现

这篇文章主要介绍了pandas 时间格式转换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

python中时间、日期、时间戳的转换的实现方法

这篇文章主要介绍了python中时间、日期、时间戳的转换的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

pandas进行时间数据的转换和计算时间差并提取年月日

这篇文章主要介绍了pandas进行时间数据的转换和计算时间差并提取年月日,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

详解将Pandas中的DataFrame类型转换成Numpy中array类型的三种方法

这篇文章主要介绍了详解将Pandas中的DataFrame类型转换成Numpy中array类型的三种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

python和c语言的主要区别总结

在本篇文章里小编给各位整理了关于python和c语言的主要区别的相关知识帖内容,有需要的朋友们学习阅读下。
收藏 0 赞 0 分享

选择Python写网络爬虫的优势和理由

在本篇文章里小编给各位整理了一篇关于选择Python写网络爬虫的优势和理由以及相关代码实例,有兴趣的朋友们阅读下吧。
收藏 0 赞 0 分享
查看更多