猫狗分类问题——从零开始构建CNN
我们将使用相同的体系结构,并进行一些小的更改,如下所示。
- 第一个线性层的输入尺寸发生变化,因为猫和狗的图像尺寸是(256,256)。
- 添加了另一个线性层来为模型学习提供更多的灵活性。
让我们来看看实现网络架构的代码:
class Net(nn.Module):def _init_(self):super_()._init_()self.conv1 = nn.Conv2d(3, 10, kernel_size=5)self.conv2 = nn.Conv2d(10, 20, kernel_size=5)self.conv2_drop = nn.Dropout2d()self.fc1 = nn.Linear(56180, 500)self.fc2 = nn.Linear(500, 0)self.fc3 = nn.Linear(50, 2)def forward(self, x):x = F.relu(F.max_pool2d(self.conv1(x), 2))x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))x = x.view(x.size(0), -1)x = F.relu(self.fc1(x))x = F.dropout(x, training = self.training)x = F.relu(self.fc2(x))x = F.dropout(x, training = self.training)x = self.fc3(x)return F.log_softmax(x, dim=1)
我们将使用与 MNIST示例相同的training函数。所以,这里不再包含代码。但是让我们看一下模型训练20次迭代后生成的结果图。
训练和验证数据集的损失值如图5.16所示。
训练和验证数据集的准确率如图5.17所示。
从图中可以清楚地看出,对于每次迭代,训练集的损失都在减少,而验证集的损失却变得更糟。在训练过程中,准确率也增加,但在75%时几乎饱和。显而易见,这是一个模型没有泛化的例子。我们将研究另一种称为迁移学习的技术,它可以帮助我们训练更准确的模型,以及加快训练的速度。
利用迁移学习对猫狗分类
迁移学习是指在类似的数据集上使用训练好的算法,而无须从头开始训练。人类并不是通过分析数千个相似的图像来识别新的图像。作为人类,我们只是通过了解不同特征来区分特定动物的,比如狐狸和狗。我们不需要了解线条、眼睛和其他较小的特征来识别狐狸。因此,我们将学习如何使用预训练好的模型来构建只需要很少数据的最先进的图像分类器。
CNN 架构的前几层专注于较小的特征,例如线条或曲线的外观。CNN架构的随后几层中的滤波器识别更高级别的特征,例如眼睛和手指,最后几层学习识别确切的类别。预训练模型是在相似的数据集上训练的算法。大多数流行的算法都在流行的ImageNet数据集上进行了预训练,以识别1000种不同的类别。这样的预训练模型具有可以识别多种模式的调整好的滤波器权重。所以来了解一下如何利用这些预先训练的权重。我们将研究一种名为 VGG16 的算法,它是在ImageNet竞赛中获得成功的最早的算法之一。虽然有更多的现代算法,但该算法仍然很受欢迎,因为它简单易懂并可用于迁移学习。下面来看看 VGG16模型的架构(见图5.18),然后尝试理解架构以及使用它来训练我们的图像分类器。
VGG16架构包含5个VGG块。每个VGG块是一组卷积层、一个非线性激活函数和一个最大池化函数。所有算法参数都是调整好的,可以达到识别1,000个类别的最先进的结果。该算法以批量的形式获取输入数据,这些数据通过ImageNet数据集的均值和标准差进行归一化。在迁移学习中,我们尝试通过冻结架构的大部分层的学习参数来捕获算法的学习内容。通用实践是仅微调网络的最后几层。在这个例子中,我们只训练最后几个线性层并保持卷积层不变,因为卷积学习的特征主要用于具有类似属性的各种图像相关的问题。下面使用迁移学习训练VGG16模型来对狗和猫进行分类。我们看看实现这一目的所需要的不同步骤。