1. 程式人生 > 程式設計 >Pytorch上下采樣函式--interpolate用法

Pytorch上下采樣函式--interpolate用法

最近用到了上取樣下采樣操作,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,32,32])
torch.Size([1,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,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,None,output,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,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]):
      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`,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,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,align_corners)
  elif input.dim() == 4 and mode == 'bicubic':
    return torch._C._nn.upsample_bicubic2d(input,4D and 5D input Tensors supported"
                 " (got {}D) for the modes: nearest | linear | bilinear | bicubic | trilinear"
                 " (got {})".format(input.dim(),mode))
 

以上這篇Pytorch上下采樣函式--interpolate用法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。