简易CNN的实现(with Pytorch)

记录一下第一次实现一个CNN。。。

其实代码也挺简单的。。。尤其是有Pytorch这种框架。。。

### 导入各种库
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import numpy as np
from torchvision import datasets,transforms

### 使用Cuda加速。。。我是在Google的Colab上测试的,可以使用GPU加速。。。
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

### 下载人尽皆知的MNIST数据集,注意中间那个transform部分,因为原来的数据好像使用numpy格式的,需要转换一下
train_loader = torch.utils.data.DataLoader(
  datasets.MNIST('./data', train=True, download=True,
                             transform=transforms.Compose([
                               transforms.ToTensor()
                             ])),
  batch_size=100, shuffle=True)

test_loader = torch.utils.data.DataLoader(
  datasets.MNIST('./data', train=False, download=True,
                             transform=transforms.Compose([
                               transforms.ToTensor()
                             ])),
  batch_size=1000, shuffle=True)

展示一下MNIST的图片及其label:

图1

训练CNN

class CNN(nn.Module):
    def __init__(self, num_classes=10):
        super().__init__()
        self.layer1 = nn.Sequential(
            nn.Conv2d(1, 16, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(16),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2))
        self.layer2 = nn.Sequential(
            nn.Conv2d(16, 32, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(32),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2))
        self.fc = nn.Linear(7*7*32, num_classes)
        
    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = out.reshape(out.size(0), -1)
        out = self.fc(out)
        return out

model = CNN().to(device)
loss_func = nn.CrossEntropyLoss()

optim = torch.optim.Adam(model.parameters(),amsgrad=True)

n_epochs = 10
for i in range(n_epochs):
    for batch_idx,(X_train,y_train) in enumerate(train_loader):
        X_train = X_train.to(device)
        y_train = y_train.to(device)
        y_hat = model(X_train)
        loss = loss_func(y_hat,y_train)
        optim.zero_grad()
        loss.backward()
        optim.step()
        
    print('{},\t{:.2f}'.format(i, loss.item()))

用的是最简单的CNN,参考自这篇paper(O’shea, K., & Nash, R. (n.d.). An Introduction to Convolutional Neural Networks.),也就是有两个layers,每个layer都先经过一次Convolution,在把得到的matrix经过一次ReLU函数变换,然后再经过一次Max pooling,最后一个Linear的变换就好了。(中间调参部分还不太会。。。抄的官方的tutorial。。。

当然中间的model部分可以直接一个nn.Sequential写好几层layer。。。但是感觉没有继承nn.module重写一个类直观,注意__init__方法里面要调用一下父类的__init__方法

Model测试

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

print('Accuracy of the network on the 1000 test images: %d %%' % (
    100.0 * correct / total))

用1000张测试图片计算Accuracy,用我跑出的模型来看正确率在99%左右,符合CNN的预期。

还可以拿张图片来看看:

plt.imshow(X_test[2][0],cmap='gray')
outputs = model(X_test[2].view(-1,1,28,28))
_,predict = torch.max(outputs.data,1)
plt.show()
print(predict)

结果:

图2