基于 PyTorch 实现的 CNNs

数据集处理

在这个项目中,我们将使用 MNIST Fashion 数据集,这是一个众所周知的数据集,它碰巧作为 PyTorch 库中的一个玩具样本集合在一起。

对于 MNIST 来说,Fashion-MNIST 数据集是一个更具挑战性的替代数据集。这是一个由60,000个小方块28 × 28像素灰度图像组成的数据集,这些图像包含了10种类型的衣服,比如鞋子、 T 恤、裙子等等。

作为一个简短的评论,数据集图像将不会重新缩放,因为我们希望以更高的训练率为代价来提高预测性能。因此,唯一发生的转换将是处理作为张量对象(矩阵)的图像所需的转换。

构建模型

众所周知,卷积神经网络(CNN)是计算机视觉最常用的体系结构之一。这种体系结构通常可以在90% 的准确率范围内取得令人印象深刻的结果。不仅如此,这些模型往往能够很好地推广。

一个由卷积变换和激活变换组成的细胞神经网络。几个层可以通过管道连接在一起,以增强特征提取(是的,我知道您在想什么,我们用原始数据填充模型)。一般来说,我们使用卷积作为一种方法来减少处理的信息量,同时保持特征的完整性。这有助于我们减少最后一层的输入(和神经元)数量。于这种特殊的情况,我们将使用一个卷积,其中 kerner size 为5,Max Pool size为2。

设计模型时最难的部分之一是确定矩阵的维数,这需要作为卷积和最后一个完全连接的线性层的输入参数。最后一层帮助我们确定预测的类别或标签,在本文这种情况下,这些是不同的服装类别。

我们将创建一个2层的 CNN 与 Max Pool 激活函数。由于我们不想失去图像边缘的特征,我们将在进行卷积操作之前对图像进行填充。在整个项目中,我们将使用 m = n (行等于列)的方阵。我们将矩阵输入维度称为 i,在这种特殊情况下,原始图像的维度为 i = 28。同样,输出矩阵的维数也用字母 o 来表示。

卷积参数

kernel = 5
padding = 2
stride = 1
dilation = 1

基于给定的这些参数,卷积过程后的新矩阵维度为:

O = I + 2 p - k + 1
O = I

其中:

  • p: padding

  • k: kernel size

  • I: Input matrix size

  • O: Output matrix size

MaxPool 激活参数

对于 MaxPool,在默认情况下,stride 是内核的大小:

kernel = 2
padding = 0
stride = 0
dilation = 1

在这种情况下,Max Pool 之后的新矩阵维度如下:

O = (I - k)/s + 1
O = (I - 2)/2 + 1
O = I/2

实际项目矩阵维度

在前面的讨论之后,在这种特殊情况下,项目矩阵维如下:

  • 在第一次卷积之后,将创建16个输出矩阵,其大小为28x28 px

  • 最大池激活后的矩阵维数是14x14像素

  • 第二次卷积之后的32个结果矩阵具有与第一次卷积相同的内核和填充,其维数为14x14 px

  • 最后,在最后一次激活 Max Pool 之后,结果矩阵的维数为7x7 px

最后一次激活 Max Pool 之后的32个通道,每个有7x7像素,最后一共有1568个输入到全连接的最终层。

下面的类显示了 forward 方法,我们将在其中定义如何在模型内部组织操作。这就是我们设计神经网络结构的地方。PyTorch 提供了另一种方式,称为 Sequential 模式。正如您可能注意到的,第一个转换是卷积,接着是 Relu 激活,然后是 MaxPool 激活/转换。正如前面提到的,卷积作为一个特征提取过程,其中预测器被保留,信息有一个压缩。通过这种方式,我们可以在不丢失输入数据的情况下更快地训练网络。

class CNN(nn.Module):
    
    # Constructor
    def __init__(self, out_1=16, out_2=32, out_mp2=7*7):
        super(CNN, self).__init__()
        self.cnn1 = nn.Conv2d(in_channels=1, out_channels=out_1, 
                              kernel_size=5, padding=2)
        self.maxpool1=nn.MaxPool2d(kernel_size=2)


        self.cnn2 = nn.Conv2d(in_channels=out_1, out_channels=out_2,
                              kernel_size=5, stride=1, padding=2)
        self.maxpool2=nn.MaxPool2d(kernel_size=2)
        self.fc1 = nn.Linear(out_2 * out_mp2, 10)
    
    # Prediction
    def forward(self, x):
        x = self.cnn1(x)
        x = torch.relu(x)
        x = self.maxpool1(x)
        x = self.cnn2(x)
        x = torch.relu(x)
        x = self.maxpool2(x)
        # Flatten the matrices
        x = x.view(x.size(0), -1)
        x = self.fc1(x)
        return x

确定优化器和数据加载器

在构建我们的神经网络之前,我们必须确定的损失函数和优化参数。因此,我们将选择一个交叉熵策略作为损失函数。这个函数通常是用非二元分类变量来选择的。为了确定最小损失,我们将使用随机梯度下降策略,在数据不适合放入内存的情况下,这几乎是大家普遍使用的方法。利用SGD,运行损失函数求至少一个局部极小值,分批进行,分步进行。为此,我们将创建 train_loader 和 validation_loader 迭代器。

训练模型

如前所述,我们将通过数据运行一些训练迭代(epoch) ,这将分批完成。然后,我们将用验证数据检查模型的准确性,最后我们将重复这个过程。需要注意的是,optimizer.step()调整了下一次迭代的模型权重,这是为了用真正的函数 y 最小化误差。

最后,我们将添加每个epoch的成本和准确度值,并绘制最终结果。我们将看到,随着模型调整权重和从训练数据中“学习”,损失如何下降,准确性如何提高。

n_epochs=6
cost_list=[]
accuracy_list=[]
N_test=len(validation_dataset)
COST=0


def train_model(n_epochs):
    for epoch in range(n_epochs):
        COST=0
        for x, y in train_loader:
            optimizer.zero_grad()
            z = model(x)
            loss = criterion(z, y)
            loss.backward()
            optimizer.step()
            COST+=loss.data
        
        cost_list.append(COST)
        correct=0
        #perform a prediction on the validation  data  
        for x_test, y_test in validation_loader:
            z = model(x_test)
            _, yhat = torch.max(z.data, 1)
            correct += (yhat == y_test).sum().item()
        accuracy = correct / N_test
        accuracy_list.append(accuracy)
     


train_model(n_epochs)

分析结果

下面你将看到这个模型的损失和准确性。正如预期的那样,该算法在对核函数和全连接层权值进行微调的同时,降低了损失,提高了精度。换句话说,模型通过迭代学习。

检查分类

这里有一张图片描绘了 Fashion-MNIST 数据集中的不同类别。

最后,我们将检查一些模型没有正确分类的样本。正如你所看到的,有时即使对于人眼来说,也很难区分这样低分辨率的图片是凉鞋还是运动鞋。还要注意第一张图片,模型预测的是一个包,但它是一双运动鞋。它看起来有点像一个袋子。这种款式也很难区分套头衫和外套,但是说实话,这种形象很难区分。

总结

一个2层的 CNN 在预测来自时尚 MNIST 数据集的图像方面做了一个出色的工作,在6个训练周期之后的总体准确度几乎达到90% 。这并不奇怪,因为这种类型的神经网络架构取得了巨大的成果。

当然,准确性可以提高,减少卷积核的大小,以减少每次迭代的数据丢失,以更高的训练时间为代价。此外,在每个卷积和最终全连接层之后进行归一化处理,这有助于在更短的时间内达到更高的精度。

·  END  ·

HAPPY LIFE

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值