三种上采样的方式总结

本文详细介绍了深度学习中用于图像上采样的三种技术:反卷积(转置卷积)、双线性插值和反池化。反卷积常用于细化特征图,但可能产生棋盘效应;双线性插值能有效解决这一问题,先通过插值扩大尺寸再进行卷积;反池化则通过记录池化索引来恢复特征图,尤其适用于分割任务。通过实例代码展示了这些方法的实现过程。
摘要由CSDN通过智能技术生成

三种上采样方式总结

在GAN,图像分割等等的网络中上采样是必不可少的。这里记录一下自己学到的三种上采样方式:反卷积(转置卷积),双线性插值+卷积,反池化。

反卷积(转置卷积)

卷积只会减小或不变输入的大小,转置卷积则是用来增大输入的大小。用于细化粗的特征图等等,FCN中就有应用。这里一个图就能很简单表明他做的事情。感觉就是做的卷积反过来的事情。转置卷积是可以进行学习的。
请添加图片描述
kernel核张量与输入的张量中,逐个元素相乘,放在对应的地方。就是说第一个元素是0,就是0乘上整个核张量,放在对应的位置。第二个元素是1则是乘上核张量放在对应滑动到下一个位置。以此类推。得到四个图,将四个图相加即可得出最终输出。此处的例子stride为1,所以滑动的步长是1。

总结出来的公式为:
Y [ i : i + h , j : j + w ] + = X [ i , j ] ∗ K Y[i:i+h, j:j + w] += X[i,j] * K Y[i:i+h,j:j+w]+=X[i,j]K
其中Y的大小就是卷积的大小计算公式反过来:

卷积: out = (Input - kernel + 2*padding) / stride + 1

反卷积: out = (Input - 1) * stride + kernel - 2*padding

Stride就是核的滑动步长,这个很好理解
请添加图片描述
padding: 这里的padding和卷积不同,卷积是外边加一圈0。转置卷积则是给输出部分减掉一圈作为输出。

称为转置的原因:

对于卷积Y = X ⊙ W,将Y,X分别展开成一个向量,Y’,X’表示。W等价于一个V使得Y’ = V * X’

转置卷积等价于X’ = VT * Y’详细的网上很多博客也写过。轻松理解转置卷积

手写实现

import torch

def trans_conv(X, K):
    h, w = K.shape
    Y = torch.zeros((X.shape[0] + h - 1, X.shape[1] + w - 1))
    for i in range(X.shape[0]):
        for j in range(X.shape[1]):
            Y[i:i+h, j:j+w] += X[i, j] * K
    return Y
# 手写计算
X = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
K = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
print(trans_conv(X,K))

# torch的ConvTranspose2d
X, K = X.reshape(1, 1, 2, 2), K.reshape(1, 1, 2, 2)
tconv = torch.nn.ConvTranspose2d(1, 1, kernel_size=2, bias=False)
tconv.weight.data = K
print(tconv(X))

out:

tensor([[ 0., 0., 1.],
[ 0., 4., 6.],
[ 4., 12., 9.]])
tensor([[[[ 0., 0., 1.],
[ 0., 4., 6.],
[ 4., 12., 9.]]]], grad_fn=< SlowConvTranspose2DBackward>)

两个输出是一样的。

加上stride设置

...
def trans_conv(X, K, stride=1):
    h, w = K.shape
    Y = torch.zeros(((X.shape[0] - 1) * stride + h, (X.shape[1] - 1) * stride + w))
    for i in range(X.shape[0]):
        for j in range(X.shape[1]):
            Y[i * stride:i * stride +h, j * stride:j * stride +w] += X[i, j] * K
    return Y
...

将对应ConvTransposed2d中设置stride为2,trans_conv()中的stride设为2

out:

tensor([[0., 0., 0., 1.],
[0., 0., 2., 3.],
[0., 2., 0., 3.],
[4., 6., 6., 9.]])
tensor([[[[0., 0., 0., 1.],
[0., 0., 2., 3.],
[0., 2., 0., 3.],
[4., 6., 6., 9.]]]], grad_fn=< SlowConvTranspose2DBackward>)

padding设置为1,stride设置为1,可以得出

out:

tensor([[[[4.]]]], grad_fn=< SlowConvTranspose2DBackward>)

双线性插值+卷积

前面转置卷积虽然可以将图扩大尺寸,细化粗特征图。但是存在一个棋盘效应问题。

棋盘效应: 转置卷积不均匀重叠导致的,使得图像变得有棋盘格一样的像素块
请添加图片描述

解决办法是使用双线性插值先将图片扩大,在用卷积即可。下面先介绍单线性插值然后再是双线性插值。

单线性插值

请添加图片描述很简单,可以说高中生都能搞定。给出两点,算出方程,然后求中间任一点y。公式如下
y 1 − y 0 x 1 − x 0 = y − y 0 x − x 0 \frac {y_1 - y_0}{x_1 - x_0} = \frac {y - y_0}{x - x_0} x1x0y1y0=xx0yy0
然后将对应的y值插入即可。

双线性插值

请添加图片描述
如图通过已知的四个点Q11,Q12,Q21,Q22求得中间P(x, y)点的值。现在x方向进行线性插值得到R1和R2,再在y方向上做线性插值得到f(x, y)求得P点。

公式如下

x方向求R1,R2
请添加图片描述y方向求P
请添加图片描述
扩大之后在进行卷积,完成上采样

代码

import torch.nn as nn
...
upsample_bil = nn.UpsamplingBilinear2d(scale_factor=2)
# or
net = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
# or
F.interpolate(input, size, scale_factor, mode, align_corners)
...
# 都有size参数,可以指定放大的大小。scale_factor指定放大倍数。mode指定放大模式

反池化

最开始看到反池化的论文是在DeConvolution Network和SegNet当中,这两个网络是相当的相似。这里只说反池化(Unpooling)
请添加图片描述简单来说,就是在下采样的过程中,maxpool的时候记录一个池化的索引,就是记录取得的这个值是在那个位置。在反池化的时候,输入的值根据索引放回原来的位置,得到一个稀疏矩阵。然后通过后边的卷积层(DeconvNet是用的转置卷积,SegNet用的卷积)学习将粗的特征图进行细化。这种反池化的操作,索引记录了更多的边缘信息,可以加强刻画物体的能力,通过重用这些边缘信息,加强精确的边界位置信息。在分割的时候有助于产生更平滑的分割。

使用代码

test = torch.rand((2, 3, 128, 128))
print("Original Size -> ", test.size())
# maxPool池化
maxpool = nn.MaxPool2d(2, 2)
# 设定要返回索引
maxpool.return_indices = True
# 记录池化结果,索引结果
mp, indices = maxpool(test)
print("MaxPool -> ", mp.size())
# 设置MaxUnpool反池化
unpooling = nn.MaxUnpool2d((2, 2), stride=2)
# 传入参数和索引
upsamle = unpooling(mp, indices)
print("MaxUnpool -> ", upsamle.size())

out:

Original Size -> torch.Size([2, 3, 128, 128])
MaxPool -> torch.Size([2, 3, 64, 64])
MaxUnpool -> torch.Size([2, 3, 128, 128])

参考资料

转置卷积【动手学深度学习v2】

动手学深度学习

双线性插值-百度百科

Deconvolution and Checkerboard Artifacts

  • 45
    点赞
  • 330
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLOv8(You Only Look Once version 8)是一个先进的目标检测算法,它继承了YOLO系列的快速检测特点,并对上采样(也称为upsampling或像素级预测)进行了优化。在YOLOv8中,上采样的主要目的是将网络较低分辨率的特征图(Feature Maps)恢复到原始输入图像的尺寸,以便于定位更精确的边界框。 1. **空间上采样(Spatial Upsampling)**:常见的上采样方法有双线性插值( bilinear interpolation)和最近邻插值(nearest-neighbor interpolation)。YOLOv8使用双线性插值,因为它可以提供平滑的边界,有助于减少位置误差。 2. **卷积上采样(Convolutional Upsampling)**:通过卷积层(如Transposed Convolution或Deconvolution)进行上采样。这种方法不仅增加了特征图的空间分辨率,还通过学习权重来提取更多的上下文信息。 3. **跳连接(Skip Connections)**:YOLOv8利用残差块(Residual Blocks)中的跳连接技术,将低层特征图与高层特征图融合,帮助解决尺度变化的问题。通过这种方式,即使在上采样的过程中丢失了一些细节,也可以通过低分辨率特征图补充。 4. **Grid Size和Anchor Boxes**:YOLOv8定义了一系列不同大小的网格(Grid Size)和锚框(Anchor Boxes),每个网格对应一个特征图。在上采样后,模型会为每个锚框生成多个不同尺度的预测结果,这些预测结果会在网格上进行反向传播和调整,实现准确的定位。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值