一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第26天,点击查看活动详情。
在构建基于卷积神经网络的计算机视觉应用时,将图像(或特征图)调整到所需的空间维度是一个常见的操作。例如,一些语义分割模型(如 FCN 或 DeepLab)生成的特征图具有较大的 stride S(即特征图的高度和宽度是图像的 1/S,其中 S=16 或 32),将下采用的特征图调整到原始图像的空间维度,以提供像素级的预测。
双线性内插是一种直接的图像大小调整算法。是线性插值的概括,只适用于一维阵列。我们将讨论插值算法(线性或双线性)背后的直觉,并提供 numpy 实现,这样你就会明白线性和双线性是如何工作的。还将研究当我们训练一个使用该操作的神经网络时,如何计算双线性插值的后向传递。
Linear Interpolation
线性差值
We will first discuss Linear Interpolation which is more common and easier to understand.
我们先来讨论线性差值,一切先从简单开始。让我们来直线上 A 和 B 两点,A 点 B 点的坐标分布为 a 和 b 位于 A 点和 B 点之间取一点,然后计算该点 x 的值
线性插值将其计算为与两点相关的数值的加权平均值,其中权重与两点之间的距离成正比。
这里需要注意对 A 点权重是 x 到 b 的距离而不是到 a 点距离,而对于 B 点同样权重是到 a 点距离,这是因为 x 距离 a 点距离。当 x 移动到 a 点,则 X 值就变成 A 点,而 x 移动到 b 点,则值就从 X 值变成了 B。
对 1 维数组线性调整
现在我们已经知道了如何在两点之间进行插值,进一步推广更普遍的情况:假设有一个大小为n的一维数组 a( 例如 n = 5),将该数组拉伸或缩小到不同大小的 m(例如m = 4),其中新数组b中的值以某种方式从原数组中线性计算出来。
把 n=5 个点放在一条直线上,之间的距离为 1.0。现在,图像再画一条与之平行的直线,把新数组的点放在那里。注意使新数组的第一个元素和最后一个元素的坐标与原数组中的对应元素相同(即0.0和4.0)。
接下来就是如何得到数组 b 的值呢?那么,让 b[0]==a[0]和b[3]==a[4]这个很容理解,因为他们有相同的坐标。对于新数组中那些在原数组中没有对应点的点(即b[1]和b[2]),可以将这两个点映射到原数组中,他们的坐标将是分值的(4/3 和 8/3)。然后 b[4/3]和b[8/3]可以用线性插值法从a[1],a[2]和a[2],a[3]计算出来。
我们注意到,映射取决于 "整数区间" 的长度比例--在这种情况下,是 4/3(即(n - 1)/(m - 1))。对于数组b中索引为i的元素,其在数组a中的映射坐标为比率 *i,我们使用两个相邻元素a[floor(ratio * i)]和a[ceil(ratio * i)]的值计算内插。
import math
def linear_resize(in_array, size):
"""
`in_array` is the input array.
`size` is the desired size.
"""
ratio = (len(in_array) - 1) / (size - 1)
out_array = []
for i in range(size):
low = math.floor(ratio * i)
high = math.ceil(ratio * i)
weight = ratio * i - low
a = in_array[low]
b = in_array[high]
out_array.append(a * (1 - weight) + b * weight)
return out_array