@[TOC](PyTorch - 10 - CNN扁平化操作 (Flatten Operation) 可视化 - 用于深度学习的张量批处理)
Flattening An Entire Tensor
张量平坦化操作
( flatten operation )是卷积神经网络内部的常见操作。这是因为传递给完全连接层的卷积层输出必须先平坦化,然后才能完全连接层接受输入。
在过去的文章中,我们了解了张量的形状,然后了解了整形操作。展平操作是一种特定类型的整形操作,其中所有轴都被挤压或挤压在一起。
要拉平张量,我们至少需要两个轴。这样一来,我们就可以从尚未平坦的东西开始。现在让我们看一下来自MNIST数据集的手写图像(八张)。此图像有2个不同的尺寸,高度
和宽度
。
高度和宽度分别为18 x 18
。这些尺寸告诉我们这是裁剪的图像,因为MNIST数据集包含28 x 2
8图像。现在让我们看看如何将这两个高度轴和宽度轴展平为一个长度为324的轴。
上图显示了我们的平坦输出,其单轴长度为324
。边缘上的白色对应于图像顶部和底部的白色。
在此示例中,我们将展平整个张量图像,但是如果我们只想展平张量内的特定轴怎么办?使用CNN时通常需要这样做。
让我们看看如何使用PyTorch展平代码中的张量的特定轴。
Flattening Specific Axes Of A Tensor
在CNN输入张量形状
的文章中,我们了解到卷积神经网络的张量输入通常如何具有4个轴
,一个用于批处理大小,一个用于颜色通道,一个用于高度和宽度。
(批量大小,通道,高度,宽度)
让我们从这里开始,构造一个符合这些规范的张量。 首先,假设我们有以下三个张量。
Building A Tensor Representation For A Batch Of Images
t1 = torch.tensor([
[1,1,1,1],
[1,1,1,1],
[1,1,1,1],
[1,1,1,1]
])
t2 = torch.tensor([
[2,2,2,2],
[2,2,2,2],
[2,2,2,2],
[2,2,2,2]
])
t3 = torch.tensor([
[3,3,3,3],
[3,3,3,3],
[3,3,3,3],
[3,3,3,3]
])
它们中的每一个都具有4 x 4
的形状,因此我们具有三个2级张量。 出于我们此处的目的,我们将这些图像视为三张4 x 4
图像,这些图像很好地用于创建可以传递到CNN的批处理。
请记住,批次使用单个张量表示,因此我们需要将这三个张量组合成一个更大的张量,该张量具有3个轴
而不是2个轴
。
> t = torch.stack((t1, t2, t3))
> t.shape
torch.Size([3, 4, 4])
在这里,我们使用stack()
方法沿着新轴连接三个张量的序列。 由于沿着新轴有三个张量,因此我们知道该轴的长度应为3,实际上,我们可以在形状中看到3个张量的高度和宽度为4。
是否想知道stack()
方法如何工作? 有关stack()
方法的说明将在本系列的后面部分介绍。
长度为3的轴表示批次大小,长度为4的轴分别表示高度和宽度。 这是此批处理的张量表示的输出结果。
> t
tensor([[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]],
[[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]],
[[3, 3, 3, 3],
[3, 3, 3, 3],
[3, 3, 3, 3],
[3, 3, 3, 3]]])
在这一点上,我们有一个3级张量,其中包含一批三个4 x 4
图像。 现在要做的就是使该张量成为CNN期望的形式,就是为颜色通道添加一个轴。 对于这些图像张量,我们基本上都有一个隐式的单色通道,因此在实践中,它们将是灰度图像。
CNN希望看到一个显式的颜色通道轴,因此让我们通过重塑该张量来添加一个。
> t = t.reshape(3,1,4,4)
> t
tensor(
[
[
[
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]
]
],
[
[
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2],
[2, 2, 2, 2]
]
],
[
[
[3, 3, 3, 3],
[3, 3, 3, 3],
[3, 3, 3, 3],
[3, 3, 3, 3]
]
]
])
请注意,我们是如何在批处理大小轴之后指定长度为1的轴的。 然后,沿着高度轴和宽度轴的长度为4。此外,请注意,长度为1的附加轴如何不会改变张量中的元素数量。 这是因为当我们乘以1时,组件值的乘积不会改变。
第一轴有3个元素。 第一轴的每个元素代表一幅图像。 对于每个图像,我们在通道轴上都有一个颜色通道。 每个通道都包含4个数组,这些数组包含4个数字或标量分量。
让我们通过索引这个张量来用代码看一下。
我们有第一张图片。
> t[0]
tensor([[[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]]])
我们在第一个图像中有第一个颜色通道。
> t[0][0]
tensor([[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]])
我们在第一张图片的第一条颜色通道中拥有第一行第一像素。
> t[0][0][0]
tensor([1, 1, 1, 1])
我们在第一个图像的第一个颜色通道的第一行中拥有第一个像素值。
> t[0][0][0][0]
tensor(1)
Flattening The Tensor Batch
好的。 让我们看看如何平整这批图像。 请记住,整个批次都是单个张量,该张量将传递给CNN,因此我们不想弄平整个事情。 我们只想在批处理张量内展平图像张量。
首先,我们将整个过程弄平,只是看看它会是什么样子。 另外,我想向所有提供上一篇文章中创建的flatten()
函数的替代实现的人大声疾呼。 看一看。
> t.reshape(1,-1)[0] # Thank you Mick!
tensor([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3])
> t.reshape(-1) # Thank you Aamir!
tensor([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3])
> t.view(t.numel()) # Thank you Ulm!
tensor([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3])
> t.flatten() # Thank you PyTorch!
tensor([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3])
在底部,您会注意到作为张量对象的方法内置的另一种方法,您猜对了,称为flatten()
。 该方法产生的输出与其他替代品完全相同。
关于此输出,我想让您注意的是,我们已经将整个批次展平了,这会将所有图像粉碎成一个轴。 请记住,这些像素代表第一个图像的像素,两个像素代表第二个图像,而三个像素代表第三个图像。
这个扁平化的批次无法在CNN中正常工作,因为我们需要对批次张量中的每个图像进行单独的预测,现在我们有了一个扁平化的混乱。
此处的解决方案是在保持批处理轴的同时使每个图像变平。 这意味着我们只想拉平张量的一部分。 我们要使用高度和宽度轴将颜色通道轴展平。
这些轴需要展平:(C,H,W)
可以使用PyTorch的内置flatten()
方法来完成。
Flattening Specific Axes Of A Tensor
让我们运行以下代码:
> t.flatten(start_dim=1).shape
torch.Size([3, 16])
> t.flatten(start_dim=1)
tensor(
[
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
]
)
注意在调用中我们如何指定start_dim
参数。 这告诉了flatten()
方法应该在哪个轴上开始展平操作。 这里的一个是索引,因此它是第二个轴,即颜色通道轴。 可以这么说,我们跳过了批处理轴,使其保持原样。
检查形状,我们可以看到我们有一个带有两个单色通道图像的2级张量,这些图像已被展平为16个像素。
Flattening An RGB Image
如果我们将RGB图像展平,颜色会怎样?
颜色通道会怎样?
每个颜色通道将首先被展平。 然后,扁平通道将在张量的单个轴上并排排列。 让我们来看一个代码示例。
我们将构建一个示例RGB图像张量,高度为2
,宽度为2
。
r = torch.ones(1,2,2)
g = torch.ones(1,2,2) + 1
b = torch.ones(1,2,2) + 2
img = torch.cat(
(r,g,b)
,dim=0
)
这给了我们所需的张量。 我们可以通过如下检查形状来验证这一点:
> img.shape
torch.Size([3, 2, 2])
我们有三个高度和宽度为两个的颜色通道。 我们还可以像这样检查该张量的数据:
> img
tensor([
[
[1., 1.]
,[1., 1.]
]
,[
[2., 2.]
, [2., 2.]
],
[
[3., 3.]
,[3., 3.]
]
])
现在,我们可以通过展平图像张量来查看外观。
> img.flatten(start_dim=0)
tensor([1., 1., 1., 1., 2., 2., 2., 2., 3., 3., 3., 3.])
请注意,这里的start_dim
参数告诉flatten()
方法从何处开始展平。 在这种情况下,我们将使整个图像变平。 但是,我们也只能像这样平铺频道:
> img.flatten(start_dim=1)
tensor([
[1., 1., 1., 1.],
[2., 2., 2., 2.],
[3., 3., 3., 3.]
])
Wrapping Up
现在,我们应该对张量的展平操作有了一个很好的了解。 我们知道如何展平整个张量,并且我们知道展平特定张量尺寸/轴。 我们将在构建CNN时看到将其投入使用。 在那之前,我会在下一个见!