简单的CNN实现

import matplotlib.pyplot as plt
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
transform = transforms.Compose([
    transforms.ToTensor(),  # 转为张量
    transforms.Normalize((0.5,), (0.5,))  # 归一化到 [-1, 1]
])

transforms.ToTensor():
将PIL图像或NumPy数组转换为PyTorch张量(Tensor)
自动将像素值从 [0, 255] 归一化到 [0, 1] 范围
将图像格式从 (H, W, C) 转换为 (C, H, W),即通道优先
transforms.Normalize((0.5,), (0.5,)) :
对图像进行标准化处理
输出范围:[(0-0.5)/0.5, (1-0.5)/0.5] = [-1, 1]

train_dataset = datasets.MNIST(root= './data',train= True,transform = transform,download=True)
test_dataset = datasets.MNIST(root='./data',train= False, transform= transform,download=True)

下载MNIST数据集:
transform = transform表示用上述定义的操作处理数据

train_loader = torch.utils.data.DataLoader(dataset= train_dataset,batch_size = 64,shuffle = True)
test_loader = torch.utils.data.DataLoader(dataset= test_dataset,batch_size = 64,shuffle = False)

class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN,self).__init__()
        self.conv1 = nn.Conv2d(1,32,kernel_size=3,stride=1,padding=1)
        self.conv2 = nn.Conv2d(32,64,kernel_size=3,stride=1,padding=1)
        self.fc1 = nn.Linear(64*7*7,128)
        self.fc2 = nn.Linear(128,10)
    def forward(self,x):
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x,2)
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x,2)
        x = x.view(-1,64*7*7)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

Conv2d(输入通道数,输出通道数,核大小,步长,padding)
输入通道由输入图像通道数决定
输出通道数由核数决定
linear(x,y) x->y


model = SimpleCNN()

criterion = nn.CrossEntropyLoss()#交叉熵损失函数
optimizer = optim.SGD(model.parameters(),lr=0.01,momentum=0.9)

num_epochs= 5
model.train()

for epoch in range(num_epochs):
    total_loss = 0
    for images,labels in train_loader:
        outputs = model(images)
        loss = criterion(outputs,labels)#criterion函数是用于计算模型预测值与真实值之间差距的损失函数。
        #先将梯度归零(optimizer.zero_grad()),然后反向传播计算得到每个参数的梯度值(loss.backward()),最后通过梯度下降执行一步参数              #更新(optimizer.step())
        optimizer.zero_grad()#使用mini-batch方法,所以如果不将梯度清零的话,梯度会与上一个batch的数据相关
        loss.backward()#如果你做完运算后使用tensor.backward(),所有的梯度就会自动运算,tensor的梯度将会累加到它的.grad属性里面去
        optimizer.step()#optimizer只负责通过梯度下降进行优化

        total_loss += loss.item()
    print(f"Epoch [{epoch + 1}/{num_epochs}], Loss: {total_loss / len(train_loader):.4f}")
model.eval()
correct = 0
total = 0

with torch.no_grad():
    for images,labels in test_loader:
        outputs = model(images)
        _,predicted = torch.max(outputs,1)
        total += labels.size(0)
        correct +=(predicted == labels).sum().item()

accuracy = 100*correct/total
print(f"Test Accuracy: {accuracy:.2f}%")

dataiter = iter(test_loader)
images, labels = next(dataiter)
outputs = model(images)
_, predictions = torch.max(outputs,1)

fig,axes = plt.subplots(1,6,figsize=(12,4))
for i in range(6):
    axes[i].imshow(images[i][0], cmap='gray')
    axes[i].set_title(f"Label: {labels[i]}\nPred: {predictions[i]}")
    axes[i].axis('off')
plt.show()
posted @ 2025-10-26 17:52  覅徐  阅读(2)  评论(0)    收藏  举报