Pytorch - torch.nn.modules.upsampling 和 interpolate 函数

torch.nn.modules.upsampling

torch.nn.modules.upsampling 的源码.

torch.nn.modules.upsampling

Upsample 模块 class 类

from numbers import Integral
import warnings

from .module import Module
from .. import functional as F


class Upsample(Module):
    r"""
    Upsample 类的作用是,上采样给定的多通道数据(multi-channel),如 1D(时序temporal),2D(空间spatial) 和 3D(体积volumetric).
    
    输入数据 input 的形式为:minibatch x channels x [optional depth] x [optional height] x width.
    故,对于 2D spatial 输入,其是 4D Tensor;对于 3D volumetric 输入,其是 5D Tensor.
    
    上采样的算法有:最近邻(nearest neighbor),线性(linear),双线性(bilinear) 和 三线性(trilinear),分别对应于 3D,3D,4D 和 5D Tensor.
    
    可以给定参数 scale_factor 或目标尺寸 size 来计算输出尺寸.
    (不能同时指定两个参数,会导致混淆.)  
    
    参数:
    - size - tuple, ints 类型, 输出尺寸:([optional D_out], [optional H_out], W_out)`
    - scale_factor - int 或 tuple,图像 height / width / depth 缩放比例因子,
    - model - string 类型,指定上采样算法: nearest, linear, bilinear 和 trilinear. 默认是 nearest.
    - align_corners - bool 类型,如果 align_corners=True,则对齐 input 和 output 的角点像素(corner pixels),保持在角点像素的值. 只会对 mode=linear, bilinear 和 trilinear 有作用. 默认是 False.
    
    Shape:
    - Input - (N, C, W_in),或 (N, C, H_in, W_in),或 (N, C, D_in, H_in, W_in).
    - Output - (N, C, W_out),或 (N, C, H_out, W_out) 或 (N, C, D_out, H_out, W_out
    其中,
    D_out = [D_in x scale_factor] 或 size[-3]
    H_out = [H_in x scale_factor] 或 size[-2]
    W_out = [W_in x scale_factor] 或 size[-1]

    Warning:
    当 align_corners=True 时,线性插值方法(linear, bilinear 和 trilinear) 不能比例地对齐 output 和 input 像素,故,output 值取决于 input 尺寸. 因此默认 align_corners = False.
    
    Note:
    downsampling/general resizing,采用 nn.functional.interpolate 函数.
    """

    def __init__(self, size=None, scale_factor=None, mode='nearest', align_corners=None):
        super(Upsample, self).__init__()
        self.size = size
        self.scale_factor = scale_factor
        self.mode = mode
        self.align_corners = align_corners

    def forward(self, input):
        return F.interpolate(input, self.size, self.scale_factor, self.mode, self.align_corners)

    def extra_repr(self):
        if self.scale_factor is not None:
            info = 'scale_factor=' + str(self.scale_factor)
        else:
            info = 'size=' + str(self.size)
        info += ', mode=' + self.mode
        return info



class UpsamplingNearest2d(Upsample):
    r"""
    对于由多个 input channels 组成的 input 数据,进行 2D 最近邻上采样.
    
    通过 size 和 scale_factor 来指定尺度(scale).
    当给定 size 时,其输出尺寸为:图片(h, w).

    参数:
    - size - tuple,ints 类型,输出尺寸:(H_out, W_out)
    - scale_factor - int 类型值,图像 height 和 width 的缩放因子.
    
    Warning:
    该 class 类被废弃,由 nn.functional.interpolate 取代.

    Shape:
    - Input - (N, C, H_in, W_in)
    - Output - (N, C, H_out, W_out)
    其中,
    H_out = [H_in x scale_factor]
    W_out = [W_in x scale_factor]

    Examples:
    >>> input = torch.arange(1, 5).view(1, 1, 2, 2)
    >>> input
        tensor([[[[ 1.,  2.],
                  [ 3.,  4.]]]])

    >>> m = nn.UpsamplingNearest2d(scale_factor=2)
    >>> m(input)
        tensor([[[[ 1.,  1.,  2.,  2.],
                  [ 1.,  1.,  2.,  2.],
                  [ 3.,  3.,  4.,  4.],
                  [ 3.,  3.,  4.,  4.]]]])
    """
    def __init__(self, size=None, scale_factor=None):
        super(UpsamplingNearest2d, self).__init__(size, scale_factor, mode='nearest')

    def forward(self, input):
        warnings.warn("nn.UpsamplingNearest2d is deprecated. Use nn.functional.interpolate instead.")
        return super(UpsamplingNearest2d, self).forward(input)


class UpsamplingBilinear2d(Upsample):
    r"""
    对于由多个 input channels 组成的 input 数据,进行 2D bilinear 上采样.
    
    通过 size 和 scale_factor 来指定尺度(scale).
    当给定 size 时,其输出尺寸为:图片(h, w).

    参数:
    - size - tuple,ints 类型,输出尺寸:(H_out, W_out)
    - scale_factor - int 类型值,图像 height 和 width 的缩放因子.

    Warning:
    该 class 类被废弃,由 nn.functional.interpolate 取代.
    等价于 nn.functional.interpolate(..., mode='bilinear', align_corners=True).

    Shape:
    - Input - (N, C, H_in, W_in)
    - Output - (N, C, H_out, W_out)
    其中,
    H_out = [H_in x scale_factor]
    W_out = [W_in x scale_factor]

    Examples: 
    >>> input = torch.arange(1, 5).view(1, 1, 2, 2)
    >>> input
        tensor([[[[ 1.,  2.],
                  [ 3.,  4.]]]])

    >>> m = nn.UpsamplingBilinear2d(scale_factor=2)
    >>> m(input)
        tensor([[[[ 1.0000,  1.3333,  1.6667,  2.0000],
                  [ 1.6667,  2.0000,  2.3333,  2.6667],
                  [ 2.3333,  2.6667,  3.0000,  3.3333],
                  [ 3.0000,  3.3333,  3.6667,  4.0000]]]])
    """
    def __init__(self, size=None, scale_factor=None):
        super(UpsamplingBilinear2d, self).__init__(size, scale_factor, mode='bilinear', align_corners=True)

    def forward(self, input):
        warnings.warn("nn.UpsamplingBilinear2d is deprecated. Use nn.functional.interpolate instead.")
        return super(UpsamplingBilinear2d, self).forward(input)

upsample 函数

def upsample(input, size=None, scale_factor=None, mode='nearest', align_corners=None):
    r"""
    根据给定 size 或 scale_factor 上采样输入input.
    
    Warning:
    该函数已废弃,替换为 torch.nn.functional.interpolate.
    等价于 nn.functional.interpolate(...).

    当前支持 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).
    """
    warnings.warn("nn.functional.upsample is deprecated. Use nn.functional.interpolate instead.")
    return interpolate(input, size, scale_factor, mode, align_corners)

Examples - Upsample 函数

>>> input = torch.arange(1, 5).view(1, 1, 2, 2).float()
>>> input
    tensor([[[[ 1.,  2.],
              [ 3.,  4.]]]])

>>> m = nn.Upsample(scale_factor=2, mode='nearest')
>>> m(input)
    tensor([[[[ 1.,  1.,  2.,  2.],
              [ 1.,  1.,  2.,  2.],
              [ 3.,  3.,  4.,  4.],
              [ 3.,  3.,  4.,  4.]]]])

>>> m = nn.Upsample(scale_factor=2, mode='bilinear')  # align_corners=False
>>> m(input)
    tensor([[[[ 1.0000,  1.2500,  1.7500,  2.0000],
              [ 1.5000,  1.7500,  2.2500,  2.5000],
              [ 2.5000,  2.7500,  3.2500,  3.5000],
              [ 3.0000,  3.2500,  3.7500,  4.0000]]]])

>>> m = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
>>> m(input)
    tensor([[[[ 1.0000,  1.3333,  1.6667,  2.0000],
              [ 1.6667,  2.0000,  2.3333,  2.6667],
              [ 2.3333,  2.6667,  3.0000,  3.3333],
              [ 3.0000,  3.3333,  3.6667,  4.0000]]]])

>>> # Try scaling the same data in a larger tensor
>>>
>>> input_3x3 = torch.zeros(3, 3).view(1, 1, 3, 3)
>>> input_3x3[:, :, :2, :2].copy_(input)
    tensor([[[[ 1.,  2.],
              [ 3.,  4.]]]])
>>> input_3x3
    tensor([[[[ 1.,  2.,  0.],
              [ 3.,  4.,  0.],
              [ 0.,  0.,  0.]]]])

>>> m = nn.Upsample(scale_factor=2, mode='bilinear')  # align_corners=False
>>> # Notice that values in top left corner are the same with the small input (except at boundary)
>>> m(input_3x3)
    tensor([[[[ 1.0000,  1.2500,  1.7500,  1.5000,  0.5000,  0.0000],
              [ 1.5000,  1.7500,  2.2500,  1.8750,  0.6250,  0.0000],
              [ 2.5000,  2.7500,  3.2500,  2.6250,  0.8750,  0.0000],
              [ 2.2500,  2.4375,  2.8125,  2.2500,  0.7500,  0.0000],
              [ 0.7500,  0.8125,  0.9375,  0.7500,  0.2500,  0.0000],
              [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000]]]])

>>> m = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
>>> # Notice that values in top left corner are now changed
>>> m(input_3x3)
    tensor([[[[ 1.0000,  1.4000,  1.8000,  1.6000,  0.8000,  0.0000],
              [ 1.8000,  2.2000,  2.6000,  2.2400,  1.1200,  0.0000],
              [ 2.6000,  3.0000,  3.4000,  2.8800,  1.4400,  0.0000],
              [ 2.4000,  2.7200,  3.0400,  2.5600,  1.2800,  0.0000],
              [ 1.2000,  1.3600,  1.5200,  1.2800,  0.6400,  0.0000],
              [ 0.0000,  0.0000,  0.0000,  0.0000,  0.0000,  0.0000]]]])

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))



def upsample_nearest(input, size=None, scale_factor=None):
    r"""
    采用最近邻(nearest neighbour)像素值对输入 input 进行上采样.
    
    Warning:
    该函数已经废弃,取代为 torch.nn.functional.interpolate.
    等价于 nn.functional.interpolate(..., mode='nearest').
    
    当前支持 spatial 和 volumetric 上采样,(即 inputs 是 4 或 5 维).

    参数:
    - input (Tensor): input
    - size (int or Tuple[int, int] or Tuple[int, int, int]): 输出的空间尺寸,spatial size.
    - scale_factor (int): 空间尺寸缩放因子,必须是整数.
    """
    # DeprecationWarning is ignored by default
    warnings.warn("nn.functional.upsample_nearest is deprecated. Use nn.functional.interpolate instead.")
    return interpolate(input, size, scale_factor, mode='nearest')


def upsample_bilinear(input, size=None, scale_factor=None):
    r"""
    采用双线性上采样(bilinear) 对输入 input 进行上采样.

    Warning::
    该函数已经废弃,取代为 torch.nn.functional.interpolate.
    等价于 nn.functional.interpolate(..., mode='bilinear', align_corners=True).
    
    输入数据 inputs 应该是 spatial (4 dimensional). 
    对于输入数据 inputs 是 volumetric (5 dimensional) 时,采用 upsample_trilinear.

    参数:
    - input (Tensor): input
    - size (int or Tuple[int, int]): output spatial size.
    - scale_factor (int or Tuple[int, int]): 空间尺寸的缩放因子.
    """
    # DeprecationWarning is ignored by default
    warnings.warn("nn.functional.upsample_bilinear is deprecated. Use nn.functional.interpolate instead.")
    return interpolate(input, size, scale_factor, mode='bilinear', align_corners=True)


GRID_SAMPLE_INTERPOLATION_MODES = {
    'bilinear': 0,
    'nearest': 1,
}

GRID_SAMPLE_PADDING_MODES = {
    'zeros': 0,
    'border': 1,
    'reflection': 2,
}
Last modification:October 16th, 2018 at 02:44 pm

Leave a Comment