前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >手撕CNN的MNIST手写数字识别

手撕CNN的MNIST手写数字识别

作者头像
Tom2Code
发布2023-02-14 11:29:04
4650
发布2023-02-14 11:29:04
举报
文章被收录于专栏:Tom

MNIST数据集大家应该已经很熟悉了。

[完整项目]基于Mnist的手写数字识别-Pytorch版

之前这个pytorch版本的是全连接层,现在换个net,重写一下。

废话不多说直接上代码,这次研究了一下pytorch中的二维卷积的函数,所以人为的改了一下代码,毕竟一直模仿是行不通的,就和修车一样,你得拆了之后再组装起来才能说明你good at修车。

第一个版本:

使用了两个卷积层,两个dropout层最后是全连接层,这模型是一个教程给的实例,我跑了一遍准确率大概是97%徘徊,已经很高了,但是我试图拉升这个准确率,

代码语言:javascript
复制
import torch
import torch.nn as nn
import torch.nn.functional as f
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt


class MyNet(nn.Module):
    def __init__(self):
        super(MyNet,self).__init__()
        self.conv1 = nn.Conv2d(1,32,3,1)
        self.conv2 = nn.Conv2d(32,64,3,1)
        self.pool = nn.MaxPool2d(2,2)
        self.dropout1 = nn.Dropout2d(0.25)
        self.dropout2 = nn.Dropout2d(0.5)
        self.fc1 = nn.Linear(12*12*64,128)
        self.fc2 = nn.Linear(128,10)

    def forward(self,x):
        x = self.conv1(x)
        x = f.relu(x)
        x = self.conv2(x)
        x = f.relu(x)
        x = self.pool(x)
        x = self.dropout1(x)
        x = x.view(-1,12*12*64)
        x = self.fc1(x)
        x = f.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)

        return f.log_softmax(x, dim=1)


def load_MNIST(batch=128):
    transform = transforms.Compose([transforms.ToTensor(),
                                   transforms.Normalize((0.1307,), (0.3081,))])

    train_set = torchvision.datasets.MNIST(root="./data",
                                           train=True,
                                           download=True,
                                           transform=transform)
    train_loader = torch.utils.data.DataLoader(train_set,
                                               batch_size=batch,
                                               shuffle=True,
                                               num_workers=2)

    val_set = torchvision.datasets.MNIST(root="./data",
                                         train=False,
                                         download=True,
                                         transform=transform)
    val_loader =torch.utils.data.DataLoader(val_set,
                                            batch_size=batch,
                                            shuffle=True,
                                            num_workers=2)

    return {"train":train_loader, "validation":val_loader}

def main():
    
    epoch = 20
    batch_size = 64

   
    history = {
        "train_loss": [],
        "validation_loss": [],
        "validation_acc": []
    }

    
    data_loder = load_MNIST(batch=batch_size)

    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    print(device)
    net = MyNet().to(device)
    print(net)

    
    optimizer = torch.optim.Adam(params=net.parameters(), lr=0.001)

    for e in range(epoch):
        """ 学習部分 """
        loss = None
        train_loss = 0.0
        net.train()
        print("\nTrain start")
        for i,(data,target) in enumerate(data_loder["train"]):
            data,target = data.to(device),target.to(device)

            optimizer.zero_grad()
            output = net(data)
            loss = f.nll_loss(output,target)
            train_loss += loss.item()
            loss.backward()
            optimizer.step()

            if i % 100 == 99:
                print("Training: {} epoch. {} iteration. Loss: {}".format(e+1,i+1,loss.item()))

        train_loss /= len(data_loder["train"])
        print("Training loss (ave.): {}".format(train_loss))
        history["train_loss"].append(train_loss)


        """検証部分"""
        print("\nValidation start")
        net.eval() 
        val_loss = 0.0
        accuracy = 0.0

        with torch.no_grad():
            for data,target in data_loder["validation"]:
                data,target = data.to(device),target.to(device)

                output = net(data)
                loss = f.nll_loss(output,target).item()
                val_loss += f.nll_loss(output,target,reduction='sum').item()
                predict = output.argmax(dim=1,keepdim=True)
                accuracy += predict.eq(target.view_as(predict)).sum().item()

        val_loss /= len(data_loder["validation"].dataset)
        accuracy /= len(data_loder["validation"].dataset)

        print("Validation loss: {}, Accuracy: {}\n".format(val_loss,accuracy))

        history["validation_loss"].append(val_loss)
        history["validation_acc"].append(accuracy)

    PATH = "./my_mnist_model.pt"
    torch.save(net.state_dict(), PATH)

    #結果
    print(history)
    plt.figure()
    plt.plot(range(1, epoch+1), history["train_loss"], label="train_loss")
    plt.plot(range(1, epoch+1), history["validation_loss"], label="validation_loss")
    plt.xlabel("epoch")
    plt.legend()
    plt.savefig("loss.png")

    plt.figure()
    plt.plot(range(1, epoch+1), history["validation_acc"])
    plt.title("test accuracy")
    plt.xlabel("epoch")
    plt.savefig("test_acc.png")

if __name__ == "__main__":
    main()

第二个版本:

我多加了一个卷积层,也就是代码中的conv3,卷积核没变还是3*3,stride还是1,这样做了之后需要重新计算卷积之后输出的参数个数。不过惊喜的是这样做成功的把准确率拉升到了98%

代码语言:javascript
复制
class MyNet(nn.Module):
    def __init__(self):
        super(MyNet,self).__init__()
        self.conv1 = nn.Conv2d(1,32,3,1)
        self.conv2 = nn.Conv2d(32,128,3,1)
        self.conv3 = nn.Conv2d(128,256,3,1)
        self.pool = nn.MaxPool2d(2,2)
        self.dropout1 = nn.Dropout2d(0.25)
        self.dropout2 = nn.Dropout2d(0.5)
        self.fc1 = nn.Linear(11*11*256,128)
        self.fc2 = nn.Linear(128,10)

    def forward(self,x):
        x = self.conv1(x)
        x = f.relu(x)
        x = self.conv2(x)
        x = f.relu(x)
        x=self.conv3(x)
        x = f.relu(x)
        x = self.pool(x)
        x = self.dropout1(x)
        x = x.view(-1,11*11*256)
        x = self.fc1(x)
        x = f.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)

        return f.log_softmax(x, dim=1)
代码语言:javascript
复制
import torch
import torch.nn as nn
import torch.nn.functional as f
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt



from torchsummary import summary
model = MyNet().to('cuda')
print(model)
print(summary(model, (1, 28, 28)))




def load_MNIST(batch=128):
    transform = transforms.Compose([transforms.ToTensor(),
                                   transforms.Normalize((0.1307,), (0.3081,))])

    train_set = torchvision.datasets.MNIST(root="./data",
                                           train=True,
                                           download=True,
                                           transform=transform)
    train_loader = torch.utils.data.DataLoader(train_set,
                                               batch_size=batch,
                                               shuffle=True,
                                               num_workers=2)

    val_set = torchvision.datasets.MNIST(root="./data",
                                         train=False,
                                         download=True,
                                         transform=transform)
    val_loader =torch.utils.data.DataLoader(val_set,
                                            batch_size=batch,
                                            shuffle=True,
                                            num_workers=2)

    return {"train":train_loader, "validation":val_loader}


# In[29]:



epoch = 5
batch_size = 64


history = {
    "train_loss": [],
    "validation_loss": [],
    "validation_acc": []
}

data_loder = load_MNIST(batch=batch_size)


device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)

net = MyNet().to(device)
print(net)


optimizer = torch.optim.Adam(params=net.parameters(), lr=0.001)


for e in range(epoch):
    """ 学習部分 """
    loss = None
    train_loss = 0.0
    net.train() 
    print("\nTrain start")
    for i,(data,target) in enumerate(data_loder["train"]):
        data,target = data.to(device),target.to(device)

        optimizer.zero_grad()
        output = net(data)
        loss = f.nll_loss(output,target)
        train_loss += loss.item()
        loss.backward()
        optimizer.step()

        if i % 100 == 99:
            print("Training: {} epoch. {} iteration. Loss:{}".format(e+1,i+1,loss.item()))

    train_loss /= len(data_loder["train"])
    print("Training loss (ave.): {}".format(train_loss))
    history["train_loss"].append(train_loss)

    """検証部分"""
    print("\nValidation start")
    net.eval() 
    val_loss = 0.0
    accuracy = 0.0

    with torch.no_grad():
        for data,target in data_loder["validation"]:
            data,target = data.to(device),target.to(device)

            output = net(data)
            loss = f.nll_loss(output,target).item()
            val_loss += f.nll_loss(output,target,reduction='sum').item()
            predict = output.argmax(dim=1,keepdim=True)
            accuracy += predict.eq(target.view_as(predict)).sum().item()

    val_loss /= len(data_loder["validation"].dataset)
    accuracy /= len(data_loder["validation"].dataset)

    print("Validation loss: {}, Accuracy: {}\n".format(val_loss,accuracy))
    history["validation_loss"].append(val_loss)
    history["validation_acc"].append(accuracy)
    
plt.plot(history["validation_loss"],label="validation_loss")
plt.plot(history["validation_acc"],label="validation_acc")

plt.legend()
plt.show()


PATH = "./my_mnist_model.pt"
torch.save(net.state_dict(), PATH)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-12-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Tom的小院 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档