卷积神经网络的基础讲解与不使用框架的代码实现

# 导入必要的库
import torch  # PyTorch深度学习框架
import torch.nn as nn  # 神经网络模块
import torch.optim as optim  # 优化器
import torchvision  # 计算机视觉工具包
import torchvision.transforms as transforms  # 数据预处理工具

# 定义卷积神经网络(CNN)类
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        # 第一个卷积层
        # 输入通道=1(灰度图像), 输出通道=16, 卷积核大小=3x3, padding=1保持输入输出尺寸相同
        self.conv1 = nn.Conv2d(1, 16, kernel_size=3, padding=1)
        self.relu1 = nn.ReLU()  # ReLU激活函数
        self.pool1 = nn.MaxPool2d(kernel_size=2)  # 最大池化层,将图像尺寸减半
        
        # 第二个卷积层
        # 输入通道=16, 输出通道=32, 卷积核大小=3x3, padding=1
        self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)
        self.relu2 = nn.ReLU()
        self.pool2 = nn.MaxPool2d(kernel_size=2)
        
        # 全连接层
        # 32个通道 * 7 * 7的特征图 -> 10个类别(数字0-9)
        self.fc = nn.Linear(32 * 7 * 7, 10)

    # 定义前向传播过程
    def forward(self, x):
        x = self.pool1(self.relu1(self.conv1(x)))  # 第一层:卷积->激活->池化
        x = self.pool2(self.relu2(self.conv2(x)))  # 第二层:卷积->激活->池化
        x = x.view(-1, 32 * 7 * 7)  # 展平特征图,准备进入全连接层
        x = self.fc(x)  # 全连接层分类
        return x

# 设置计算设备(GPU如果可用,否则使用CPU)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f'使用设备: {device}')

# 数据预处理设置
transform = transforms.Compose([
    transforms.ToTensor(),  # 将图像转换为PyTorch张量
    transforms.Normalize((0.1307,), (0.3081,))  # 标准化:(像素值-均值)/标准差
])

# 加载MNIST训练数据集
train_dataset = torchvision.datasets.MNIST(
    root='./data',  # 数据保存路径
    train=True,     # 指定为训练集
    download=True,  # 如果数据不存在则下载
    transform=transform  # 应用上面定义的预处理
)

# 加载MNIST测试数据集
test_dataset = torchvision.datasets.MNIST(
    root='./data',
    train=False,    # 指定为测试集
    download=True,
    transform=transform
)

# 创建数据加载器
train_loader = torch.utils.data.DataLoader(
    train_dataset,
    batch_size=64,    # 每批处理64张图片
    shuffle=True      # 随机打乱数据
)

test_loader = torch.utils.data.DataLoader(
    test_dataset,
    batch_size=1000,  # 测试时可以使用更大的batch_size
    shuffle=False     # 测试时不需要打乱数据
)

# 创建模型实例并移至指定设备
model = SimpleCNN().to(device)

# 定义损失函数(交叉熵损失,适用于分类问题)
criterion = nn.CrossEntropyLoss()
# 定义优化器(Adam优化器,学习率=0.001)
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 定义评估函数
def evaluate():
    model.eval()  # 设置为评估模式
    correct = 0   # 正确预测的样本数
    total = 0     # 总样本数
    with torch.no_grad():  # 测试时不需要计算梯度
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            outputs = model(data)  # 前向传播
            _, predicted = torch.max(outputs.data, 1)  # 获取最大概率的预测结果
            total += target.size(0)  # 累加总样本数
            correct += (predicted == target).sum().item()  # 累加正确预测数
    accuracy = 100 * correct / total
    print(f'测试集准确率: {accuracy:.2f}%')
    return accuracy

# 定义训练函数
def train(epochs):
    best_accuracy = 0  # 记录最佳准确率
    for epoch in range(epochs):  # 训练轮次循环
        model.train()  # 设置为训练模式
        running_loss = 0.0
        for batch_idx, (data, target) in enumerate(train_loader):
            data, target = data.to(device), target.to(device)
            optimizer.zero_grad()  # 清空梯度
            outputs = model(data)  # 前向传播
            loss = criterion(outputs, target)  # 计算损失
            loss.backward()  # 反向传播
            optimizer.step()  # 更新参数
            
            running_loss += loss.item()
            if batch_idx % 100 == 99:  # 每100批次打印一次训练状态
                print(f'轮次: {epoch + 1}, 批次: {batch_idx + 1}, 损失: {running_loss / 100:.3f}')
                running_loss = 0.0
        
        # 每轮结束后评估模型
        print(f'\n=== 第 {epoch + 1} 轮评估 ===')
        accuracy = evaluate()
        
        # 如果当前模型更好,就保存它
        if accuracy > best_accuracy:
            best_accuracy = accuracy
            torch.save(model.state_dict(), 'best_model.pth')
            print(f'保存新的最佳模型,准确率: {best_accuracy:.2f}%\n')

# 主程序
if __name__ == '__main__':
    print("开始训练...")
    train(epochs=5)  # 训练5轮
    print("\n训练完成!加载最佳模型进行最终评估...")
    model.load_state_dict(torch.load('best_model.pth'))
    final_accuracy = evaluate()
    print(f'最终最佳准确率: {final_accuracy:.2f}%')
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐