CNN+OOP实战

部署运行你感兴趣的模型镜像

CNN实战+OOP面向对象编程详解

本文适合已经了解CNN卷积基础原理的读者,将从代码实战角度深入讲解PyTorch中的CNN实现和面向对象编程应用。

在这里插入图片描述

📑 目录


第一部分:从简单开始 - 你的第一个CNN模块

让我们从最简单的CNN模块开始,这段代码定义了一个基础的卷积神经网络模块(Tudui(选自小土堆的代码):

🧱 类定义与继承

class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.conv1 = Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)
    
    def forward(self, x):
        x = self.conv1(x)
        return x

核心要点:

  • Tudui 继承自 nn.Module,这是PyTorch中所有神经网络模块的基类
  • super() 调用父类构造函数,让PyTorch正确注册参数和模块结构
  • forward() 方法定义了数据的前向传播路径

📊 数据流转示例

输入卷积层处理输出
[B, 3, H, W]Conv2d(3→6)[B, 6, H-2, W-2](无padding时)

例如:输入 [1, 3, 32, 32] 的RGB图像 → 输出 [1, 6, 30, 30] 的特征图


第二部分:深入理解 - 卷积参数详解

🔍 Conv2d参数深度解析

self.conv1 = Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)
参数含义影响
in_channels=3输入通道数(RGB图像为3)决定接受什么样的输入
out_channels=6输出通道数(使用6个不同的卷积核)决定提取多少种不同特征
kernel_size=3卷积核大小(3×3)感受野大小,影响特征提取范围
stride=1步长(每次移动1个像素)控制输出尺寸和计算密度
padding=0边缘填充(不填充)是否保持原图尺寸信息

📐 输出尺寸计算公式

掌握这个公式,你就能预测任何卷积层的输出尺寸:

output_size = floor((input_size - kernel_size + 2×padding) / stride) + 1

实际计算示例:

输入: (1, 1, 5, 5)
卷积核: 3×3, stride=1, padding=0

计算过程:
output_height = (5 - 3 + 0) / 1 + 1 = 3
output_width = (5 - 3 + 0) / 1 + 1 = 3

结果: (1, 1, 3, 3)

🛠️ padding的妙用

padding值效果使用场景
0输出尺寸缩小特征提取,降维
1近似保持原尺寸保留空间信息
‘same’输出与输入尺寸完全相同需要精确尺寸保持时

第三部分:面向对象编程在PyTorch中的应用

🎯 OOP三大核心特性

特性Python含义PyTorch中的体现
封装数据和方法打包到类中网络结构封装在自定义类中
继承子类自动获得父类的所有属性和方法继承nn.Module获得训练相关功能
多态同一接口在不同类中有不同的实现方式不同网络类重写forward()方法

🔗 1. 封装:模块化设计

封装让代码更整洁、更易维护:

class MyNet(nn.Module):
    def __init__(self):
        super().__init__()
        # 数据(网络层)封装在类中
        self.conv = nn.Conv2d(3, 6, 3)
        self.relu = nn.ReLU()
    
    def forward(self, x):
        # 方法(前向传播逻辑)封装在类中
        x = self.conv(x)
        x = self.relu(x)
        return x

# 外部使用者只需要简单调用,无需了解内部细节
net = MyNet()
output = net(input_tensor)

🏗️ 2. 继承:站在巨人的肩膀上

继承nn.Module后,你的网络自动拥有:

  • ✅ 参数自动注册和管理
  • ✅ GPU/CPU设备转换:.cuda(), .cpu()
  • ✅ 训练/评估模式切换:.train(), .eval()
  • ✅ 参数访问:.parameters(), .named_parameters()
  • ✅ 模型保存/加载支持

关键代码:

super().__init__()  # 🚨 千万不能省略!

🎭 3. 多态:一个接口,多种实现

class LinearNet(nn.Module):
    def forward(self, x):
        return self.fc(x)  # 全连接网络的forward

class ConvNet(nn.Module):
    def forward(self, x):
        return self.conv(x)  # 卷积网络的forward

# 统一的调用方式,不同的内部实现
for model in [LinearNet(), ConvNet()]:
    output = model(input_data)  # 多态体现

第四部分:进阶实践 - 完整CNN模型构建

🏗️ 构建一个完整的图像分类网络

网络架构设计:

输入[B,3,32,32] → Conv1[6] → ReLU → MaxPool → Conv2[16] → ReLU → MaxPool → Flatten → FC → 分类[10]
import torch
import torch.nn as nn
import torch.nn.functional as F

class CompleteCNN(nn.Module):
    def __init__(self, num_classes=10):
        super().__init__()
        # 特征提取部分
        self.conv1 = nn.Conv2d(3, 6, kernel_size=5)    # [3,32,32] → [6,28,28]
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)  # [6,28,28] → [6,14,14]
        self.conv2 = nn.Conv2d(6, 16, kernel_size=5)   # [6,14,14] → [16,10,10]
        # 池化后: [16,5,5]
        
        # 分类器部分
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, num_classes)
        
    def forward(self, x):
        # 特征提取
        x = self.pool(F.relu(self.conv1(x)))  # 卷积→激活→池化
        x = self.pool(F.relu(self.conv2(x)))  # 卷积→激活→池化
        
        # 展平
        x = torch.flatten(x, 1)  # 保留batch维度,展平其他维度
        
        # 分类
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)  # 最后一层不加激活,交给损失函数处理
        return x

📦 模块容器:让网络更灵活

容器类型特点适用场景
Sequential顺序执行,自动连接线性网络结构
ModuleList列表管理,需手动控制执行顺序动态深度、循环结构
ModuleDict字典管理,支持名称索引条件分支、模块动态选择

Sequential示例:

self.feature_extractor = nn.Sequential(
    nn.Conv2d(3, 6, 3),
    nn.ReLU(),
    nn.MaxPool2d(2),
    nn.Conv2d(6, 16, 3),
    nn.ReLU(),
    nn.MaxPool2d(2)
)

ModuleList示例:

self.layers = nn.ModuleList([
    nn.Linear(10, 10) for _ in range(5)  # 动态创建5层
])

def forward(self, x):
    for layer in self.layers:
        x = F.relu(layer(x))
    return x

第五部分:实战演练 - 完整训练流程

🎯 训练流程全览

数据准备
模型定义
损失函数
优化器
训练循环
模型评估
保存模型

📊 1. 数据准备(CIFAR-10示例)

import torch
import torchvision
import torchvision.transforms as transforms

# 数据预处理管道
transform = transforms.Compose([
    transforms.ToTensor(),                          # PIL → Tensor
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))  # 标准化到[-1,1]
])

# 训练集
trainset = torchvision.datasets.CIFAR10(
    root='./data', train=True, download=True, transform=transform
)
trainloader = torch.utils.data.DataLoader(
    trainset, batch_size=64, shuffle=True, num_workers=2
)

# 测试集
testset = torchvision.datasets.CIFAR10(
    root='./data', train=False, download=True, transform=transform
)
testloader = torch.utils.data.DataLoader(
    testset, batch_size=64, shuffle=False, num_workers=2
)

🏗️ 2. 模型、损失函数和优化器配置

import torch.optim as optim

# 设备配置
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"使用设备: {device}")

# 模型实例化
model = CompleteCNN(num_classes=10).to(device)

# 损失函数(多分类交叉熵)
criterion = nn.CrossEntropyLoss()

# 优化器(SGD + 动量)
optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)

# 可选:学习率调度器
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)

🔄 3. 训练循环

def train_model(model, trainloader, criterion, optimizer, num_epochs=5):
    model.train()  # 设置为训练模式
    
    for epoch in range(num_epochs):
        running_loss = 0.0
        correct_predictions = 0
        total_samples = 0
        
        for batch_idx, (inputs, labels) in enumerate(trainloader):
            # 数据移到设备
            inputs, labels = inputs.to(device), labels.to(device)
            
            # 前向传播
            optimizer.zero_grad()        # 清零梯度
            outputs = model(inputs)      # 模型预测
            loss = criterion(outputs, labels)  # 计算损失
            
            # 反向传播
            loss.backward()              # 计算梯度
            optimizer.step()             # 更新参数
            
            # 统计信息
            running_loss += loss.item()
            _, predicted = torch.max(outputs.data, 1)
            total_samples += labels.size(0)
            correct_predictions += (predicted == labels).sum().item()
            
            # 打印进度
            if batch_idx % 100 == 99:
                avg_loss = running_loss / 100
                accuracy = 100 * correct_predictions / total_samples
                print(f'Epoch [{epoch+1}/{num_epochs}], '
                      f'Batch [{batch_idx+1}], '
                      f'Loss: {avg_loss:.4f}, '
                      f'Accuracy: {accuracy:.2f}%')
                running_loss = 0.0
        
        # 可选:更新学习率
        scheduler.step()

# 开始训练
train_model(model, trainloader, criterion, optimizer, num_epochs=10)

📊 4. 模型评估

def evaluate_model(model, testloader):
    model.eval()  # 设置为评估模式
    correct = 0
    total = 0
    
    with torch.no_grad():  # 关闭梯度计算,节省内存
        for inputs, labels in testloader:
            inputs, labels = inputs.to(device), labels.to(device)
            outputs = model(inputs)
            _, predicted = torch.max(outputs, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
    
    accuracy = 100 * correct / total
    print(f'测试集准确率: {accuracy:.2f}%')
    return accuracy

# 评估模型
final_accuracy = evaluate_model(model, testloader)

💾 5. 模型保存和加载

# 保存模型(推荐方式:只保存参数)
torch.save(model.state_dict(), 'best_model.pth')

# 保存完整信息
checkpoint = {
    'epoch': epoch,
    'model_state_dict': model.state_dict(),
    'optimizer_state_dict': optimizer.state_dict(),
    'accuracy': final_accuracy,
}
torch.save(checkpoint, 'checkpoint.pth')

# 加载模型
def load_model(model_path, model_class, num_classes=10):
    model = model_class(num_classes=num_classes)
    model.load_state_dict(torch.load(model_path, map_location=device))
    model.to(device)
    model.eval()
    return model

# 使用示例
loaded_model = load_model('best_model.pth', CompleteCNN)

🎓 总结与要点回顾

核心知识点梳理

阶段关键技术点核心代码
模型设计继承nn.Module,重写forwardclass MyNet(nn.Module)
参数配置卷积层参数、输出尺寸计算Conv2d(in_ch, out_ch, kernel_size)
数据处理DataLoader、数据预处理transforms.Compose([...])
训练过程前向传播、反向传播、参数更新loss.backward(), optimizer.step()
模型评估准确率计算、模型状态切换model.eval(), torch.no_grad()

💡 最佳实践提示

  • ✅ 始终使用super().__init__()初始化父类
  • ✅ 合理设置batch_size和学习率
  • ✅ 训练时使用.train(),推理时使用.eval()
  • ✅ 使用torch.no_grad()节省推理时的内存
  • ✅ 定期保存模型checkpoints

通过本文的学习,你应该已经掌握了PyTorch中CNN的完整实现流程和面向对象编程的核心概念。现在可以开始你的深度学习实战之旅了!🎉

您可能感兴趣的与本文相关的镜像

PyTorch 2.5

PyTorch 2.5

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值