机器学习模型生产部署实战:K8s+CI/CD+可观测性闭环
2026/6/15 5:08:58
在上一节中,我们尝试使用全连接网络(MLP)处理 CIFAR-10 图像分类任务,但发现准确率难以突破瓶颈。这是因为 MLP 将图像的所有像素展平为一维向量,破坏了图像原本的空间结构信息(如局部纹理、形状边缘等)。今天我们正式引入卷积神经网络(CNN),它通过“卷积”和“池化”操作,专门用于提取图像的空间特征。
全连接网络(MLP)处理图像面临两个主要问题:
CNN 通过局部感知(卷积核只看局部区域)和权值共享(同一个卷积核扫描整张图),在大幅减少参数量的同时,有效地提取了图像的平移不变性特征。
在训练深度学习模型时,数据量往往决定了模型的上限。数据增强通过对原始图像进行一系列随机变换,生成形态各异的新样本,从而在不增加实际采集成本的情况下扩展数据集,显著提升模型的泛化能力。
我们在训练集中使用了以下增强策略:
train_transform = transforms.Compose([ # 随机裁剪:在四周填充4像素后,随机裁剪出32x32 transforms.RandomCrop(32, padding=4), # 随机水平翻转:模拟物体方向的变化 transforms.RandomHorizontalFlip(), # 颜色抖动:随机调整亮度、对比度、饱和度、色相 transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1), # 随机旋转:最大旋转15度 transforms.RandomRotation(15), transforms.ToTensor(), # 标准化:使用 CIFAR-10 数据集的均值和标准差 transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)) ])注意:测试集通常只进行标准化处理,不进行随机变换,以确保评估结果的稳定性。
我们构建了一个经典的 CNN 结构,包含三个卷积块和一个分类器。
class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() # 卷积块 1:输入 3 通道 -> 输出 32 通道 self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1) self.bn1 = nn.BatchNorm2d(32) self.relu1 = nn.ReLU() self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2) # 尺寸减半: 32 -> 16 # 卷积块 2:输入 32 通道 -> 输出 64 通道 self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1) self.bn2 = nn.BatchNorm2d(64) self.relu2 = nn.ReLU() self.pool2 = nn.MaxPool2d(kernel_size=2) # 尺寸减半: 16 -> 8 # 卷积块 3:输入 64 通道 -> 输出 128 通道 self.conv3 = nn.Conv2d(64, 128, kernel_size=3, padding=1) self.bn3 = nn.BatchNorm2d(128) self.relu3 = nn.ReLU() self.pool3 = nn.MaxPool2d(kernel_size=2) # 尺寸减半: 8 -> 4 # 全连接分类器 # 展平维度计算:128通道 * 4(高) * 4(宽) = 2048 self.fc1 = nn.Linear(128 * 4 * 4, 512) self.dropout = nn.Dropout(0.5) self.fc2 = nn.Linear(512, 10) # 输出 10 个类别 def forward(self, x): # x: [batch, 3, 32, 32] x = self.pool1(self.relu1(self.bn1(self.conv1(x)))) # -> [batch, 32, 16, 16] x = self.pool2(self.relu2(self.bn2(self.conv2(x)))) # -> [batch, 64, 8, 8] x = self.pool3(self.relu3(self.bn3(self.conv3(x)))) # -> [batch, 128, 4, 4] # 展平 x = x.view(-1, 128 * 4 * 4) # -> [batch, 2048] x = self.dropout(self.relu3(self.fc1(x))) x = self.fc2(x) return x输入图片尺寸为 $32 \times 32$:
最终特征图大小为 $128 \times 4 \times 4$。
为了进一步提升模型性能,我们引入了学习率调度器。在训练初期,较大的学习率有助于快速下降;在训练后期,较小的学习率有助于模型在极小值附近精细收敛。
我们使用的是ReduceLROnPlateau,它是一种“监控型”调度器:
patience个 epoch 内不再下降时,自动将学习率乘以factor进行衰减。scheduler = optim.lr_scheduler.ReduceLROnPlateau( optimizer, mode='min', # 监控指标是越小越好(Loss) patience=3, # 容忍 3 个 epoch 不提升 factor=0.5 # 衰减系数 ) # 在训练循环中更新 # scheduler.step(epoch_test_loss)相较于 MLP,CNN 在 CIFAR-10 上的表现有质的飞跃:
这一结果证明了 CNN 在提取图像特征方面的强大能力。卷积层作为特征提取器,能够从底层的边缘、颜色,逐层抽象到高层的形状、物体部件,这是全连接网络无法做到的。