免费、绿色、专业的手机游戏中心下载安装平台-游家吧

当前位置: 首页 > 教程攻略 > 深度学习中的各类上采样算子

深度学习中的各类上采样算子

更新时间:2026-02-14 13:26:09

爱情和生活模拟rpg手机版
  • 类型:体育竞技
  • 大小:87.5mb
  • 语言:简体中文
  • 评分:
查看详情

深度学习中的各类上采样算子

本文介绍了深度学习分割任务中Decoder阶段的多种上采样方法。包括规则上采样的Upsample(如双线性插值)、通过周期筛选实现的PixelShuffle、基于最大值位置还原的MaxUnPool2D、需学习参数的Conv2DTranspose(反卷积),以及不规则上采样的grid_sample,并结合示例展示了各方法的效果与特点。

深度学习中的各类上采样算子

在做分割的时候,我们经常会遇到Decoder时对特征进行上采样,比较常见的就是下面这个:

x = F.interpolate(x, scale_factor=2., mode="bilinear")登录后复制

当然,除了这个上采样的方法外,还有很多其他方法可以将当前Tensor的尺寸由[H, W]改为[H*r, W*r]。或许通过尝试这些不同的上采样技术之一找到最适合当前任务的效果最佳的方法会有所帮助。

下面我们对一些(了解有限,只知道这么多)常用的上采样方法进行一些介绍。

准备

这里主要是导入一些库以及写几个ndarray和tensor转换的函数,方便显示。

示例图像方面准备了一张李化元(希望下集别刀了)大头照,其他的通道数很多的特征也差不多。 In [21]

import cv2import numpy as npimport paddleimport paddle.nn as nnimport paddle.nn.functional as Fimport matplotlib.pyplot as plt %matplotlib inlinedef to_tensor(image): # H, W, C -> 1, C, H, W # uint8 -> float32 # ndarray -> tensor return paddle.to_tensor(image.transpose((2, 0, 1))[None], dtype="float32")def to_ndarray(tensor): # 1, C, H, W -> H, W, C # float32 -> uint8 # tensor -> ndarray return tensor.squeeze().numpy().transpose((1, 2, 0)).astype("uint8")def show(im1, im2, im3=None): plt.figure(figsize=(15, 5)) plt.subplot(131);plt.imshow(im1);plt.title("raw image") # 原图 plt.subplot(132);plt.imshow(im2);plt.title("down image") # 下采样后的图 if im3 is not None: plt.subplot(133);plt.imshow(im3);plt.title("up image") # 上采样后的结果 plt.show()登录后复制 In [22]

img_path = "lhy.jpg"img = cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2RGB) # 图像准备登录后复制

1. Upsample

该OP用于调整一个batch中图片的大小。

- 当输入是一个张量(形状为[num_batches, channels, in_w]),则接收或张量时形状不变,反之亦然。调整大小仅适用于输入的深度、高度和宽度维度。

这个算子类似于F.interpolate,是一种基于规则上的抽样技术,包括最近邻法、双线性插值和双三次插值等。

利用双线性插值方法,如图所示,通过选取离待插值点最近的已知数值来计算其值,每个已知数值的权重取决于与待插值点的距离远近。具体而言,P可以通过RR两个由QQQQ算得出,并且这些值分别由距离待插值更近的数值决定。

图源:https://www.cnblogs.com/yssongest/p/5303151.html

下图看起来的效果不错,将一些锯齿都变得比较平滑了。 In [23]

upnet = nn.Upsample(scale_factor=2., mode="BILINEAR") # 放大2倍,以双线性插值的方式进行half_img = cv2.resize(img, None, None, 0.5, 0.5, cv2.INTER_LINEAR) upsample_pred = upnet(to_tensor(half_img)) show(img, half_img, to_ndarray(upsample_pred))登录后复制

<Figure size 1080x360 with 3 Axes>登录后复制登录后复制登录后复制登录后复制登录后复制

2. PixelShuffle

该算子将一个形为[N, C, H, W]或是[N, H, W, C]的Tensor重新排列成形为 [N, C/r**2, H*r, W*r]或 [N, H*r, W*r, C/r**2] 的Tensor。这样做有利于实现步长(stride)为1/r的高效sub-pixel(亚像素)卷积。详见Shi等人在2016年发表的论文 Real Time Single Image and Video Super Resolution Using an Efficient Sub Pixel Convolutional Neural Network 。

PixelShuffle常用在超分之中,经过PixelShuffle上采样会减少通道层的数目。通过卷积先得到 ( r^) 个通道的特征图(特征图大小和输入低分辨率图像一致),然后通过周期筛选(periodic shuffing)的方法得到这个高分辨率的图像,其中 ( r ) 表示上采样因子(upscaling factor),也就是图像的扩大倍率。下图中两个后半部分图比较容易理解PixelShuffle的工作原理。在实际应用中,常常先通过训练得到更多的特征图,再利用PixelShuffle进行上采样,从而保持通道数不变,并且显著放大了图像尺寸。此外,使用 PixelShuffle 还有其他好处。首先,它能够在保持低分辨率和高分辨率之间提供很好的匹配,这对于各种图像增强任务特别有用。其次,通过降低特征图的数量,可以减少模型的计算复杂性和内存需求。最后,PixelShuffle 的设计使得上采样过程更加高效,因为它避免了复杂的滤波器操作。综上所述,PixelShuffle 在超分和某些其他图像处理任务中提供了强大的增强能力,并且在提高性能的同时减少了资源消耗。

图源:https://www.jianshu.com/p/71d6a9374899

这里原图是道的,长度和宽度都扩大了,所以需要保留原来的道数。因此,在展示时为了显示效果,在使用PixelShuffle的时候将图像复制了叠在一起,形成了一张包含通道的图像。然后在PixelShuffle后,这通道最终恢复为通道。

upnet = nn.PixelShuffle(upscale_factor=2) # 放大2倍,通道数变为1/4half_img = cv2.resize(img, None, None, 0.5, 0.5, cv2.INTER_LINEAR) half_img = np.concatenate([half_img] * 4, axis=-1) # C: 3 -> 12pixelshuffle_pred = upnet(to_tensor(half_img)) show(img, half_img[:, :, :3], to_ndarray(pixelshuffle_pred))登录后复制

<Figure size 1080x360 with 3 Axes>登录后复制登录后复制登录后复制登录后复制登录后复制

3. MaxUnPool2D

此接口提供了一个MaxUnPooling对象的构建方法,通过指定输入数据和最大值索引点来计算池化反向操作的结果,并将其余部分设为零。

MaxPool和AvgPool分别是对图像进行最大池化和平均池化,而对应的反池化就可以将结果还原到原来的大小。由于AvgPool是一个取平均的操作,反池化直接复制出多份平均值即可,因此没有专门的AvgUnPool函数,直接用Upsample即可。而MaxUnPool需要将最大值还原到对应的位置,因此MaxPool可以设置保存最大值索引的位置,MaxUnPool则需要根据这个位置将最大值还原到原来的位置,并在其他位置补充零。如下图所示:

图源:https://blog.csdn.net/quiet_girl/article/details/84579038

下图显现了不一致的色彩块,因为其由不同通道的最大值索引决定,导致它们可能不在同一位置被恢复。

upnet = nn.MaxUnPool2D(2, 2) half_img, indices = F.max_pool2d(to_tensor(img), 2, 2, return_mask=True) # 需要返回索引maxunpool_pred = upnet(half_img, indices) # 根据索引找到原始位置show(img, to_ndarray(half_img), to_ndarray(maxunpool_pred))登录后复制

<Figure size 1080x360 with 3 Axes>登录后复制登录后复制登录后复制登录后复制登录后复制

4. Conv2DTranspose

二维转置卷积层(Convlution2d transpose layer)

该层根据输入(Input)、卷积核(Kernel)和空洞大小(Dilations)、步长(Stride)、填充(Padding)来计算输出特征层的大小或通过output_size指定输出特征层的大小。输入(Input)和输出(Output)均为NCHW或NHWC格式,其中N为批尺寸,C为通道数(Canal),H为特征层的高度,W为特征层的宽度。卷积核(Kernel)是MCHW格式,M是输出图像的通道数(Channels),C是输入图像的通道数(Color Channels),H是卷积核的高度,W是卷积核的宽度。如果组数大于则C等于输入图像的通道数除以组数(Ratio)。转置卷积(Transposed Convolution)的计算过程可以视为逆向卷积(Reverse Convolution)。尽管名称中带“反”字,但实际上并非真正的反卷积操作。为了获取更详细的解释和参考文献,请参阅以下说明与相关资源。当参数bias_attr不为False时,转置卷积会添加偏置项。

不同于上采样的操作(如果PixelShuffle不包括前面的卷积步骤),反卷积是一种需要学习的上采样方法。其示意图如下所示。因此,它会带来额外参数的学习,但如果你学得很好,可能会在后续任务中比不需要学习的方法效果更好。这是一个见仁见智的问题。

图源:https://blog.csdn.net/quiet_girl/article/details/84579038

为了演示简单训练的反卷积操作,我们直接使用两个RGB图像进行MSE损失计算,并未采用这种方法实际应用中更为常见的做法。虽然这种方法能够成功训练反卷积层,但它并未展示出理想的输出效果。这表明了ConvTranspose的实际应用性。在[中,我们也注意到一个有趣的现象棋盘格效应(checkerboard pattern)的出现。尽管简单地进行MSE损失计算已经能够实现一定程度的效果,但这个方法实际上并不符合实际应用场景的要求。

upnet = nn.Conv2DTranspose(3, 3, 4, 2, 1) half_img = cv2.resize(img, None, None, 0.5, 0.5, cv2.INTER_LINEAR) upnet.train() # 训练模式opt = paddle.optimizer.AdamW(0.001, parameters=upnet.parameters())for _ in range(100): # 跑100次 upsample_pred = upnet(to_tensor(half_img)) loss = F.mse_loss(upsample_pred, to_tensor(img)) loss.backward() opt.step() upnet.eval() # 评估模式convtranspose_pred = upnet(to_tensor(half_img)) show(img, half_img, to_ndarray(convtranspose_pred))登录后复制

<Figure size 1080x360 with 3 Axes>登录后复制登录后复制登录后复制登录后复制登录后复制

5. grid_sample

该OP基于流场网格对输入X进行双线性插值采样。网格通常由affine_grid生成,形状为[N, H, W, ,其中[x, y]坐标表示x和y维度的采样点位置。输出结果是来自四个最接近的角点的双线性插值计算,输出张量的形状为[N, C, H, W]。

不同于Upsample规则上的采样,Grid Sample是一种不规则的上采样技术。它依据一个flow-field网格(如光流、体素流等)中的每个位置提供的坐标信息,将输入图像中对应的位置像素值填充到该位置,并得到最终输出。在某些带有引导结构的网络中,会通过计算边缘流、光流等因素,并使用Grid Sample将其特征按照相应的网格进行非规则上采样。这种技术的应用示意图如下:

图源:https://blog.csdn.net/qq_34914551/article/details/107559031

- 在[中,我们通过引入轻微的位置扰动来确保网格上的样本转换前后具有不同的结果。这有助于防止上采样时产生的效果与规则上采样的结果相同。

upnet = F.grid_sample# 创建一个水平和竖直方向都是-1到1的格网h, w = img.shape[:2] h_grid = paddle.linspace(-1.0, 1.0, h).reshape([-1, 1]).tile([w]) w_grid = paddle.linspace(-1.0, 1.0, w).reshape([-1, 1]).tile([h]).transpose((1, 0)) grid = paddle.concat([w_grid.unsqueeze(2), h_grid.unsqueeze(2)], axis=2)[None]# 故意对其进行随机扰动,注释这一行恢复的原图将同1grid += (paddle.randn((1, h, w, 2), dtype="float32") / 200) half_img = cv2.resize(img, None, None, 0.5, 0.5, cv2.INTER_LINEAR) gridsample_pred = upnet(to_tensor(half_img), grid) # 以grid来引导图像上采样show(img, half_img, to_ndarray(gridsample_pred))登录后复制

<Figure size 1080x360 with 3 Axes>登录后复制登录后复制登录后复制登录后复制登录后复制

以上就是深度学习中的各类上采样算子的详细内容,更多请关注其它相关文章!

精品推荐

相关文章

最新资讯

热门文章

更多

最新推荐

更多

最新更新

更多