PyTorch - 10 - CNN扁平化操作 (Flatten Operation) 可视化 - 用于深度学习的张量批处理

@[TOC](PyTorch - 10 - CNN扁平化操作 (Flatten Operation) 可视化 - 用于深度学习的张量批处理)

Flattening An Entire Tensor

张量平坦化操作 ( flatten operation )是卷积神经网络内部的常见操作。这是因为传递给完全连接层的卷积层输出必须先平坦化,然后才能完全连接层接受输入。

在过去的文章中,我们了解了张量的形状,然后了解了整形操作。展平操作是一种特定类型的整形操作,其中所有轴都被挤压或挤压在一起。

要拉平张量,我们至少需要两个轴。这样一来,我们就可以从尚未平坦的东西开始。现在让我们看一下来自MNIST数据集的手写图像(八张)。此图像有2个不同的尺寸,高度宽度

在这里插入图片描述

高度和宽度分别为18 x 18。这些尺寸告诉我们这是裁剪的图像,因为MNIST数据集包含28 x 28图像。现在让我们看看如何将这两个高度轴和宽度轴展平为一个长度为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时看到将其投入使用。 在那之前,我会在下一个见!

猜你喜欢

转载自blog.csdn.net/weixin_48367136/article/details/112466255