网络编程
位置:首页>> 网络编程>> Python编程>> Pytorch上下采样函数--interpolate用法

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

作者:起步晚就要快点跑  发布时间:2023-04-09 20:58:29 

标签: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, 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))

来源:https://blog.csdn.net/zhaowangbo/article/details/89917884

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com