day41 python图像识别任务

目录

一、数据预处理:为模型打下坚实基础

二、模型构建:多层感知机的实现

三、训练过程:迭代优化与性能评估

四、测试结果:模型性能的最终检验

五、总结与展望


在深度学习的旅程中,多层感知机(MLP)作为最基础的神经网络结构,是每位初学者的必经之路。最近,我通过实现和训练MLP模型,对图像识别任务有了更深入的理解。本文将从数据预处理、模型构建、训练过程到最终的测试结果,详细记录我的学习过程,并总结MLP在图像识别任务中的优势与局限。

一、数据预处理:为模型打下坚实基础

在任何机器学习任务中,数据预处理都是至关重要的第一步。对于图像数据,我们需要将其转换为适合模型处理的格式。以MNIST手写数字数据集为例,我使用了torchvision.transforms库对图像进行了标准化处理:

python 复制代码
transform = transforms.Compose([
    transforms.ToTensor(),  # 转换为张量并归一化到[0,1]
    transforms.Normalize((0.1307,), (0.3081,))  # MNIST数据集的均值和标准差
])

通过ToTensor()操作,图像被转换为张量格式,并且像素值被归一化到[0,1]区间。Normalize()操作则进一步对图像进行标准化,使其均值为0,标准差为1。这有助于加速模型的收敛。

对于彩色图像数据集(如CIFAR-10),处理方式类似,只是需要对每个通道分别进行标准化:

python 复制代码
transform = transforms.Compose([
    transforms.ToTensor(),                
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 标准化处理
])

数据加载器DataLoader的使用也非常关键,它能够高效地批量加载数据,并支持多线程加速数据读取:

python 复制代码
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)

通过设置shuffle=True,训练数据会在每个epoch开始时被打乱,这有助于模型更好地泛化。

二、模型构建:多层感知机的实现

多层感知机(MLP)是一种经典的神经网络结构,由多个全连接层组成。在MNIST数据集上,我构建了一个简单的MLP模型:

python 复制代码
class MLP(nn.Module):
    def __init__(self):
        super(MLP, self).__init__()
        self.flatten = nn.Flatten()  # 将28x28的图像展平为784维向量
        self.layer1 = nn.Linear(784, 128)  # 第一层:784个输入,128个神经元
        self.relu = nn.ReLU()  # 激活函数
        self.layer2 = nn.Linear(128, 10)  # 第二层:128个输入,10个输出(对应10个数字类别)
        
    def forward(self, x):
        x = self.flatten(x)  # 展平图像
        x = self.layer1(x)   # 第一层线性变换
        x = self.relu(x)     # 应用ReLU激活函数
        x = self.layer2(x)   # 第二层线性变换,输出logits
        return x

在CIFAR-10数据集上,我将模型进行了扩展,增加了层数和神经元数量,并引入了Dropout来防止过拟合:

python 复制代码
class MLP(nn.Module):
    def __init__(self):
        super(MLP, self).__init__()
        self.flatten = nn.Flatten()  # 将3x32x32的图像展平为3072维向量
        self.layer1 = nn.Linear(3072, 512)  # 第一层:3072个输入,512个神经元
        self.relu1 = nn.ReLU()
        self.dropout1 = nn.Dropout(0.2)  # 添加Dropout防止过拟合
        self.layer2 = nn.Linear(512, 256)  # 第二层:512个输入,256个神经元
        self.relu2 = nn.ReLU()
        self.dropout2 = nn.Dropout(0.2)
        self.layer3 = nn.Linear(256, 10)  # 输出层:10个类别
        
    def forward(self, x):
        x = self.flatten(x)  # 输入尺寸: [batch_size, 3, 32, 32] → [batch_size, 3072]
        x = self.layer1(x)   # 线性变换: [batch_size, 3072] → [batch_size, 512]
        x = self.relu1(x)    # 应用ReLU激活函数
        x = self.dropout1(x) # 训练时随机丢弃部分神经元输出
        x = self.layer2(x)   # 线性变换: [batch_size, 512] → [batch_size, 256]
        x = self.relu2(x)    # 应用ReLU激活函数
        x = self.dropout2(x) # 训练时随机丢弃部分神经元输出
        x = self.layer3(x)   # 线性变换: [batch_size, 256] → [batch_size, 10]
        return x  # 返回未经过Softmax的logits

Dropout是一种有效的正则化技术,它在训练阶段随机丢弃部分神经元的输出,从而防止模型对训练数据过度拟合。

三、训练过程:迭代优化与性能评估

训练过程是模型学习数据特征的关键阶段。我使用了Adam优化器和交叉熵损失函数,这是分类任务中常用的组合:

python 复制代码
criterion = nn.CrossEntropyLoss()  # 交叉熵损失函数,适用于多分类问题
optimizer = optim.Adam(model.parameters(), lr=0.001)  # Adam优化器

在训练过程中,我记录了每个iteration的损失,并绘制了损失曲线,以便直观地观察模型的收敛情况:

python 复制代码
def train(model, train_loader, test_loader, criterion, optimizer, device, epochs):
    model.train()  # 设置为训练模式
    
    all_iter_losses = []  # 存储所有 batch 的损失
    iter_indices = []     # 存储 iteration 序号
    
    for epoch in range(epochs):
        running_loss = 0.0
        correct = 0
        total = 0
        
        for batch_idx, (data, target) in enumerate(train_loader):
            data, target = data.to(device), target.to(device)  # 移至GPU
            
            optimizer.zero_grad()  # 梯度清零
            output = model(data)  # 前向传播
            loss = criterion(output, target)  # 计算损失
            loss.backward()  # 反向传播
            optimizer.step()  # 更新参数
            
            iter_loss = loss.item()
            all_iter_losses.append(iter_loss)
            iter_indices.append(epoch * len(train_loader) + batch_idx + 1)
            
            running_loss += iter_loss
            _, predicted = output.max(1)
            total += target.size(0)
            correct += predicted.eq(target).sum().item()
            
            if (batch_idx + 1) % 100 == 0:
                print(f'Epoch: {epoch+1}/{epochs} | Batch: {batch_idx+1}/{len(train_loader)} '
                      f'| 单Batch损失: {iter_loss:.4f} | 累计平均损失: {running_loss/(batch_idx+1):.4f}')
        
        epoch_train_loss = running_loss / len(train_loader)
        epoch_train_acc = 100. * correct / total
        epoch_test_loss, epoch_test_acc = test(model, test_loader, criterion, device)
        
        print(f'Epoch {epoch+1}/{epochs} 完成 | 训练准确率: {epoch_train_acc:.2f}% | 测试准确率: {epoch_test_acc:.2f}%')
    
    plot_iter_losses(all_iter_losses, iter_indices)
    return epoch_test_acc

通过每100个批次打印一次训练信息,我可以实时监控模型的训练进度。同时,每个epoch结束后,我会对模型进行测试,评估其在测试集上的性能。

四、测试结果:模型性能的最终检验

经过多次实验,我发现在MNIST数据集上,MLP模型能够达到较高的准确率(约96.75%)。然而,在更具挑战性的CIFAR-10数据集上,即使增加了模型的深度和训练轮次,最终测试准确率也仅能达到约52.40%。这表明MLP在处理复杂图像数据时存在明显的局限性。

五、总结与展望

通过这次学习,我深刻认识到MLP在图像识别任务中的优势与不足。MLP结构简单,易于理解和实现,但在处理图像数据时,它无法有效利用图像的空间结构信息,导致在复杂任务上性能受限。此外,深层MLP的参数规模呈指数级增长,容易过拟合,训练成本也较高。未来,我将深入学习卷积神经网络(CNN),它专门针对图像数据设计,能够自动提取图像的空间特征,具有更少的参数和更快的训练速度,是解决图像识别问题的更优选择。

@浙大疏锦行

相关推荐
行云流水剑8 分钟前
【学习记录】Django Channels + WebSocket 异步推流开发常用命令汇总
redis·websocket·学习·django
Leo.yuan1 小时前
数据资产是什么?数据资产平台如何发挥作用?
大数据·运维·数据仓库·人工智能·信息可视化
开开心心就好1 小时前
免费批量文件重命名软件
vue.js·人工智能·深度学习·typescript·pdf·excel·less
x_feng_x1 小时前
Java从入门到精通 - 常用API(一)
java·开发语言·python
蹦蹦跳跳真可爱5893 小时前
Python----目标检测(《Fast R-CNN》和Fast R-CNN)
人工智能·python·深度学习·神经网络·目标检测·cnn
czliutz3 小时前
NiceGUI 是一个基于 Python 的现代 Web 应用框架
开发语言·前端·python
mozun20203 小时前
YOLOv7 辅助检测头与重参数化解析2025.6.1
人工智能·yolo·目标检测·机器学习·计算机视觉·目标跟踪
bluebonnet275 小时前
【agent开发】部署LLM(一)
python·llama
zskj_zhyl5 小时前
从“被动养老”到“主动健康管理”:平台如何重构代际关系?
大数据·人工智能·重构
HHBon5 小时前
判断用户输入昵称是否存在(Python)
linux·开发语言·python