欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)

程序员文章站 2022-07-06 12:39:11
...

相关视频:
PyTorch 动态神经网络 (莫烦 Python 教学)

一、导入库、设置超参数

PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)

若没有下载好MNIST数据集,则将DOWNLOAD设为True
若已经下载好MNIST数据集,则将DOWNLOAD设为False

二、下载、读取MNIST数据集

PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)

一张图片的尺寸为(1, 28, 28)。

第一次运行代码没有下载成功,第二次运行代码下载成功了,大概花了五分钟不到。

保存路径设置为同一级路径下的data文件夹中(即./data),下载好的内容如下:

data
└─MNIST
    ├─processed
    │      test.pt
    │      training.pt
    │
    └─raw
            t10k-images-idx3-ubyte
            t10k-images-idx3-ubyte.gz
            t10k-labels-idx1-ubyte
            t10k-labels-idx1-ubyte.gz
            train-images-idx3-ubyte
            train-images-idx3-ubyte.gz
            train-labels-idx1-ubyte
            train-labels-idx1-ubyte.gz

三、DataLoader

PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)

四、读取测试集

PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)

五、设计、创建网络

1.设计网络

PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)

2.创建网络

有注释版本:

# 创建神经网络(有注释)
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.layer1 = nn.Sequential(
            # (1, 28, 28)
            nn.Conv2d(
                in_channels=1, # 灰度图的通道数为1
                out_channels=16, # 16个filter
                kernel_size=5, # filter的边长为5
                stride=1, # 步长为1
                padding=2, # 因为filter的边长为5,所以padding设为(5-1)/2=2
            ),
            # (16, 28, 28)
            nn.ReLU(),
            # (16, 28, 28)
            nn.MaxPool2d(
                kernel_size=2,
            ),
            # (16, 14, 14)
        )
        self.layer2 = nn.Sequential(
            # (16, 14, 14)
            nn.Conv2d(16, 32, kernel_size=5, stride=1, padding=2),
            # (32, 14, 14)
            nn.ReLU(),
            # (32, 14, 14)
            nn.MaxPool2d(kernel_size=2)
            # (32, 7, 7)
        )
        self.output_layer = nn.Linear(32*7*7, 10)
        
    def forward(self, x):
        # (batch, 1, 28, 28)
        x = self.layer1(x)
        # (batch, 16, 14, 14)
        x = self.layer2(x)
        # (batch, 32, 7, 7)
        x = x.reshape(x.size(0), -1) # 将x展开为(batch, 32*7*7)
        # (batch, 32*7*7)
        output = self.output_layer(x)
        # (batch, 10)
        return output

无注释版本:

# 创建神经网络(无注释)
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(1, 16, kernel_size=5, stride=1, padding=2),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2),
        )
        self.layer2 = nn.Sequential(
            nn.Conv2d(16, 32, kernel_size=5, stride=1, padding=2),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2)
        )
        self.output_layer = nn.Linear(32*7*7, 10)
        
    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = x.reshape(x.size(0), -1)
        output = self.output_layer(x)
        return output

3.新建网络

PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)

可以使用torchsummary.summary查看网络的结构:

PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)

六、优化器、损失函数

PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)

七、准备测试集数据

PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)

八、训练神经网络

PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)

九、预测

PyTorch笔记 入门:写一个简单的神经网络3:CNN(以MNIST数据集为例)

十、完整代码

import torch
import torch.nn as nn
from torch.autograd import Variable
import torch.utils.data as Data
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
from torchsummary import summary

# 创建神经网络(有注释)
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.layer1 = nn.Sequential(
            # (1, 28, 28)
            nn.Conv2d(
                in_channels=1, # 灰度图的通道数为1
                out_channels=16, # 16个filter
                kernel_size=5, # filter的边长为5
                stride=1, # 步长为1
                padding=2, # 因为filter的边长为5,所以padding设为(5-1)/2=2
            ),
            # (16, 28, 28)
            nn.ReLU(),
            # (16, 28, 28)
            nn.MaxPool2d(
                kernel_size=2,
            ),
            # (16, 14, 14)
        )
        self.layer2 = nn.Sequential(
            # (16, 14, 14)
            nn.Conv2d(16, 32, kernel_size=5, stride=1, padding=2),
            # (32, 14, 14)
            nn.ReLU(),
            # (32, 14, 14)
            nn.MaxPool2d(kernel_size=2)
            # (32, 7, 7)
        )
        self.output_layer = nn.Linear(32*7*7, 10)
        
    def forward(self, x):
        # (batch, 1, 28, 28)
        x = self.layer1(x)
        # (batch, 16, 14, 14)
        x = self.layer2(x)
        # (batch, 32, 7, 7)
        x = x.reshape(x.size(0), -1) # 将x展开为(batch, 32*7*7)
        # (batch, 32*7*7)
        output = self.output_layer(x)
        # (batch, 10)
        return output
    
# # 创建神经网络(无注释)
# class CNN(nn.Module):
#     def __init__(self):
#         super(CNN, self).__init__()
#         self.layer1 = nn.Sequential(
#             nn.Conv2d(1, 16, kernel_size=5, stride=1, padding=2),
#             nn.ReLU(),
#             nn.MaxPool2d(kernel_size=2),
#         )
#         self.layer2 = nn.Sequential(
#             nn.Conv2d(16, 32, kernel_size=5, stride=1, padding=2),
#             nn.ReLU(),
#             nn.MaxPool2d(kernel_size=2)
#         )
#         self.output_layer = nn.Linear(32*7*7, 10)
        
#     def forward(self, x):
#         x = self.layer1(x)
#         x = self.layer2(x)
#         x = x.reshape(x.size(0), -1)
#         output = self.output_layer(x)
#         return output

# 超参数
EPOCH = 2
BATCH_SIZE = 100
LR = 0.001
DOWNLOAD = False # 若已经下载mnist数据集则设为False

# 下载mnist数据
train_data = datasets.MNIST(
    root='./data', # 保存路径
    train=True, # True表示训练集,False表示测试集
    transform=transforms.ToTensor(), # 将0~255压缩为0~1
    download=DOWNLOAD
)

# 旧的写法
print(train_data.train_data.size())
print(train_data.train_labels.size())

# 新的写法
print(train_data.data.size())
print(train_data.targets.size())

# 打印部分数据集的图片
for i in range(2):
    print(train_data.targets[i].item())
    plt.imshow(train_data.data[i].numpy(), cmap='gray')
    plt.show()
    
# DataLoader
train_loader = Data.DataLoader(
    dataset=train_data,
    batch_size=BATCH_SIZE,
    shuffle=True,
    num_workers=2
)

# 如果train_data下载好后,test_data也就下载好了
test_data = datasets.MNIST(
    root='./data',
    train=False
)

print(test_data.data.size())
print(test_data.targets.size())

# 新建网络
cnn = CNN()
print(cnn)

# 查看网络的结构
model = CNN()
if torch.cuda.is_available():
    model.cuda()
summary(model, input_size=(1,28,28))

# 优化器
optimizer = torch.optim.Adam(cnn.parameters(), lr=LR)

# 损失函数
loss_func = nn.CrossEntropyLoss()

# 为了节约时间,只使用测试集的前2000个数据
test_x = Variable(
    torch.unsqueeze(test_data.data, dim=1),
    volatile=True
).type(torch.FloatTensor)[:2000]/255 # 将将0~255压缩为0~1

test_y = test_data.targets[:2000]

# # 使用所有的测试集
# test_x = Variable(
#     torch.unsqueeze(test_data.test_data, dim=1),
#     volatile=True
# ).type(torch.FloatTensor)/255 # 将将0~255压缩为0~1

# test_y = test_data.test_labels


# 训练神经网络
for epoch in range(EPOCH):
    for step, (batch_x, batch_y) in enumerate(train_loader):
        output = cnn(batch_x)
        loss = loss_func(output, batch_y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        # 每隔50步输出一次信息
        if step%50 == 0:
            test_output = cnn(test_x)
            predict_y = torch.max(test_output, 1)[1].data.squeeze()
            accuracy = (predict_y == test_y).sum().item() / test_y.size(0)
            print('Epoch', epoch, '|', 'Step', step, '|', 'Loss', loss.data.item(), '|', 'Test Accuracy', accuracy)
            
# 预测
test_output = cnn(test_x[:100])
predict_y = torch.max(test_output, 1)[1].data.numpy().squeeze()
real_y = test_y[:100].numpy()
print(predict_y)
print(real_y)

# 打印预测和实际结果
for i in range(10):
    print('Predict', predict_y[i])
    print('Real', real_y[i])
    plt.imshow(test_data.data[i].numpy(), cmap='gray')
    plt.show()
相关标签: PyTorch pytorch