MNIST手写数字图片识别(pytorch/神经网络)

MNIST数据集

      MNIST数据集是分类任务中最简单、最常用的数据集。人为的手写了0-9数字的图片

      MNIST大概有7w张
 

torchvision是pytorch中处理视觉和图像的包

nn是神经网络相关包

 

步骤

Load data
Build model
Train
Test

 

加载数据

import torch
from torch import nn
from torch.nn import functional as F
from torch import optim

import torchvision
from matplotlib import pyplot as plt

from utils import plot_image,plot_curve,one_hot
#utils库是自己写的
#plot_curve是画曲线
#plot_image是画图片
#one_hot编码工具


batch_size = 512  #一次处理的图片的数量
#gpu一次可以处理并行多张图片

#第一步,加载数据集 load dataset
train_loader = torch.utils.data.DataLoader(
    torchvision.datasets.MNIST('dataset/', train=True, download=True,
                               transform=torchvision.transforms.Compose([
                                   torchvision.transforms.ToTensor(),
                                   torchvision.transforms.Normalize(
                                       (0.1307,), (0.3081,))
                               ])),
    batch_size=batch_size, shuffle=True)
#train=True表示是训练数据,train=False是测试数据
#download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载
#一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensor
#torch中的数据载体都是tensor
#Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多
#shuffle=True表示在加载的时候将图片随机打散

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

#x是图片,y是label
x, y = next(iter(train_loader))
print(x.shape, y.shape, x.min(), x.max())
plot_image(x, y, 'image sample')

在DataLoader中

train=True表示是训练数据,train=False是测试数据
download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载
一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensor
torch中的数据载体都是tensor
Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多
shuffle=True表示在加载的时候将图片随机打散

 

512张图片,1个通道,28行,28列

MNIST手写数字图片识别(pytorch/神经网络)_第1张图片

 

创建网络

训练

三层

 

训练就是每次求导,然后更新

批训练:把数据分为一小批一小批进行训练
Dataloader就是用来包装使用的数据,比如说该程序中把数据5个5个的打包,每一次抛出一组数据进行操作
 

import torch
from torch import nn
from torch.nn import functional as F
from torch import optim

import torchvision
from matplotlib import pyplot as plt

from utils import plot_image,plot_curve,one_hot
#plot_curve是画曲线
#plot_image是画图片
#one_hot编码工具


batch_size = 512  #一次处理的图片的数量
#gpu一次可以处理并行多张图片

#第一步,加载数据集 load dataset
train_loader = torch.utils.data.DataLoader(
    torchvision.datasets.MNIST('mnist_data', train=True, download=True,
                               transform=torchvision.transforms.Compose([
                                   torchvision.transforms.ToTensor(),
                                   torchvision.transforms.Normalize(
                                       (0.1307,), (0.3081,))
                               ])),
    batch_size=batch_size, shuffle=True)
#train=True表示是训练数据,train=False是测试数据
#download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载
#一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensor
#torch中的数据载体都是tensor
#Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多
#shuffle=True表示在加载的时候将图片随机打散

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

x, y = next(iter(train_loader))
print(x.shape, y.shape, x.min(), x.max())
plot_image(x, y, 'image sample')


class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()

        # xw+b
        self.fc1 = nn.Linear(28*28, 256)
        self.fc2 = nn.Linear(256, 64)
        self.fc3 = nn.Linear(64, 10)

    def forward(self, x):
        # x: [b, 1, 28, 28]
        # h1 = relu(xw1+b1)
        x = F.relu(self.fc1(x))
        # h2 = relu(h1w2+b2)
        x = F.relu(self.fc2(x))
        # h3 = h2w3+b3
        x = self.fc3(x)

        return x


net = Net() #创建网络对象


#打印模型的参数直观地看一下
#k,v就分别是w和b
for k, v in net.named_parameters():
    print(k,v)



# [w1, b1, w2, b2, w3, b3]
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)


for epoch in range(3):

    for batch_idx, (x, y) in enumerate(train_loader):

        # x: [b, 1, 28, 28], y: [512]
        # [b, 1, 28, 28] => [b, 784]
        x = x.view(x.size(0), 28*28)   #x.size(0)就是batch_size
        # => [b, 10]
        out = net(x)  #我们的目的是希望我们的output能够更好得接近我们y的label

        # [b, 10]
        y_onehot = one_hot(y)
        #就是将y转成onehot
        #y是512个label值,是一个512*1的tensor数组
        #y_onehot是512个10维的,即512*10的tensor数组
        #例如y的label是2,那么对应的y_onehot就是0,1,2,第三个位置为1,其余位置为0这样


        # loss = mse(out, y_onehot)
        loss = F.mse_loss(out, y_onehot) #计算均方差

        optimizer.zero_grad() #清零梯度
        loss.backward() #计算梯度
        # w' = w - lr*grad
        optimizer.step() #更新梯度

        train_loss.append(loss.item())

        if batch_idx % 10==0:  #每隔10个batch打印一下
            print(epoch, batch_idx, loss.item())

MNIST手写数字图片识别(pytorch/神经网络)_第2张图片

MNIST手写数字图片识别(pytorch/神经网络)_第3张图片

MNIST手写数字图片识别(pytorch/神经网络)_第4张图片

可以看到loss是在稳定下降的

 

加上一句绘制图形的代码

import torch
from torch import nn
from torch.nn import functional as F
from torch import optim

import torchvision
from matplotlib import pyplot as plt

from utils import plot_image,plot_curve,one_hot
#plot_curve是画曲线
#plot_image是画图片
#one_hot编码工具


batch_size = 512  #一次处理的图片的数量
#gpu一次可以处理并行多张图片

#第一步,加载数据集 load dataset
train_loader = torch.utils.data.DataLoader(
    torchvision.datasets.MNIST('mnist_data', train=True, download=True,
                               transform=torchvision.transforms.Compose([
                                   torchvision.transforms.ToTensor(),
                                   torchvision.transforms.Normalize(
                                       (0.1307,), (0.3081,))
                               ])),
    batch_size=batch_size, shuffle=True)
#train=True表示是训练数据,train=False是测试数据
#download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载
#一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensor
#torch中的数据载体都是tensor
#Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多
#shuffle=True表示在加载的时候将图片随机打散

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

x, y = next(iter(train_loader))
print(x.shape, y.shape, x.min(), x.max())
plot_image(x, y, 'image sample')


class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()

        # xw+b
        self.fc1 = nn.Linear(28*28, 256)
        self.fc2 = nn.Linear(256, 64)
        self.fc3 = nn.Linear(64, 10)

    def forward(self, x):
        # x: [b, 1, 28, 28]
        # h1 = relu(xw1+b1)
        x = F.relu(self.fc1(x))
        # h2 = relu(h1w2+b2)
        x = F.relu(self.fc2(x))
        # h3 = h2w3+b3
        x = self.fc3(x)

        return x



net = Net() #创建网络对象
# [w1, b1, w2, b2, w3, b3]
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)


train_loss = []

for epoch in range(3):

    for batch_idx, (x, y) in enumerate(train_loader):

        # x: [b, 1, 28, 28], y: [512]
        # [b, 1, 28, 28] => [b, 784]
        x = x.view(x.size(0), 28*28)
        # => [b, 10]
        out = net(x)  #我们的目的是希望我们的output能够更好得接近我们y的label
        # [b, 10]
        y_onehot = one_hot(y)
        # loss = mse(out, y_onehot)
        loss = F.mse_loss(out, y_onehot) #计算均方差

        optimizer.zero_grad() #清零梯度
        loss.backward() #计算梯度
        # w' = w - lr*grad
        optimizer.step() #更新梯度

        train_loss.append(loss.item())

        if batch_idx % 10==0:  #每隔10个batch打印一下
            print(epoch, batch_idx, loss.item())

plot_curve(train_loss)

MNIST手写数字图片识别(pytorch/神经网络)_第5张图片

 

测试

import torch
from torch import nn
from torch.nn import functional as F
from torch import optim

import torchvision
from matplotlib import pyplot as plt

from utils import plot_image,plot_curve,one_hot
#plot_curve是画曲线
#plot_image是画图片
#one_hot编码工具


batch_size = 512  #一次处理的图片的数量
#gpu一次可以处理并行多张图片

#第一步,加载数据集 load dataset
train_loader = torch.utils.data.DataLoader(
    torchvision.datasets.MNIST('mnist_data', train=True, download=True,
                               transform=torchvision.transforms.Compose([
                                   torchvision.transforms.ToTensor(),
                                   torchvision.transforms.Normalize(
                                       (0.1307,), (0.3081,))
                               ])),
    batch_size=batch_size, shuffle=True)
#train=True表示是训练数据,train=False是测试数据
#download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载
#一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensor
#torch中的数据载体都是tensor
#Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多
#shuffle=True表示在加载的时候将图片随机打散

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

x, y = next(iter(train_loader))
print(x.shape, y.shape, x.min(), x.max())
plot_image(x, y, 'image sample')


class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()

        # xw+b
        self.fc1 = nn.Linear(28*28, 256)
        self.fc2 = nn.Linear(256, 64)
        self.fc3 = nn.Linear(64, 10)

    def forward(self, x):
        # x: [b, 1, 28, 28]
        # h1 = relu(xw1+b1)
        x = F.relu(self.fc1(x))
        # h2 = relu(h1w2+b2)
        x = F.relu(self.fc2(x))
        # h3 = h2w3+b3
        x = self.fc3(x)

        return x



net = Net() #创建网络对象
# [w1, b1, w2, b2, w3, b3]
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)


train_loss = []

for epoch in range(3):

    for batch_idx, (x, y) in enumerate(train_loader):

        # x: [b, 1, 28, 28], y: [512]
        # [b, 1, 28, 28] => [b, 784]
        x = x.view(x.size(0), 28*28)
        # => [b, 10]
        out = net(x)  #我们的目的是希望我们的output能够更好得接近我们y的label
        # [b, 10]
        y_onehot = one_hot(y)
        # loss = mse(out, y_onehot)
        loss = F.mse_loss(out, y_onehot) #计算均方差

        optimizer.zero_grad() #清零梯度
        loss.backward() #计算梯度
        # w' = w - lr*grad
        optimizer.step() #更新梯度

        train_loss.append(loss.item())

        if batch_idx % 10==0:  #每隔10个batch打印一下
            print(epoch, batch_idx, loss.item())

plot_curve(train_loss)
# we get optimal [w1, b1, w2, b2, w3, b3]


total_correct = 0
for x,y in test_loader:
    x  = x.view(x.size(0), 28*28)
    out = net(x)  #网络的输出
    # out: [b, 10] => pred: [b]
    pred = out.argmax(dim=1)
    correct = pred.eq(y).sum().float().item() #当前batch预测正确的数量
    total_correct += correct

total_num = len(test_loader.dataset)
acc = total_correct / total_num
print('test accurancy:', acc)

MNIST手写数字图片识别(pytorch/神经网络)_第6张图片

总体的准确度是88%

 

 

在这里还不够直观,因为我们希望拿到每一个具体图片的预测结果,看一下到底是不是真的预测对了

import torch
from torch import nn
from torch.nn import functional as F
from torch import optim

import torchvision
from matplotlib import pyplot as plt

from utils import plot_image,plot_curve,one_hot
#plot_curve是画曲线
#plot_image是画图片
#one_hot编码工具


batch_size = 512  #一次处理的图片的数量
#gpu一次可以处理并行多张图片

#第一步,加载数据集 load dataset
train_loader = torch.utils.data.DataLoader(
    torchvision.datasets.MNIST('mnist_data', train=True, download=True,
                               transform=torchvision.transforms.Compose([
                                   torchvision.transforms.ToTensor(),
                                   torchvision.transforms.Normalize(
                                       (0.1307,), (0.3081,))
                               ])),
    batch_size=batch_size, shuffle=True)
#train=True表示是训练数据,train=False是测试数据
#download=True的话,如果当前指定的文件夹中没有mnist数据集,就会自动去网上下载
#一般下载以后得到的文件是numpy格式,torchvision.transforms.ToTensor()将numpy转成tensor
#torch中的数据载体都是tensor
#Normalize做正则化,归一化,方便神经网络优化。也可以注释掉,性能会稍差一点,70%多,带着的话80%多
#shuffle=True表示在加载的时候将图片随机打散

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

x, y = next(iter(train_loader))
print(x.shape, y.shape, x.min(), x.max())
plot_image(x, y, 'image sample')


class Net(nn.Module):

    def __init__(self):
        super(Net, self).__init__()

        # xw+b
        self.fc1 = nn.Linear(28*28, 256)
        self.fc2 = nn.Linear(256, 64)
        self.fc3 = nn.Linear(64, 10)

    def forward(self, x):
        # x: [b, 1, 28, 28]
        # h1 = relu(xw1+b1)
        x = F.relu(self.fc1(x))
        # h2 = relu(h1w2+b2)
        x = F.relu(self.fc2(x))
        # h3 = h2w3+b3
        x = self.fc3(x)

        return x



net = Net() #创建网络对象
# [w1, b1, w2, b2, w3, b3]
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)


train_loss = []

for epoch in range(3):

    for batch_idx, (x, y) in enumerate(train_loader):

        # x: [b, 1, 28, 28], y: [512]
        # [b, 1, 28, 28] => [b, 784]
        x = x.view(x.size(0), 28*28)
        # => [b, 10]
        out = net(x)  #我们的目的是希望我们的output能够更好得接近我们y的label
        # [b, 10]
        y_onehot = one_hot(y)
        # loss = mse(out, y_onehot)
        loss = F.mse_loss(out, y_onehot) #计算均方差

        optimizer.zero_grad() #清零梯度
        loss.backward() #计算梯度
        # w' = w - lr*grad
        optimizer.step() #更新梯度

        train_loss.append(loss.item())

        if batch_idx % 10==0:  #每隔10个batch打印一下
            print(epoch, batch_idx, loss.item())

plot_curve(train_loss)
# we get optimal [w1, b1, w2, b2, w3, b3]


total_correct = 0
for x,y in test_loader:
    x  = x.view(x.size(0), 28*28)
    out = net(x)  #网络的输出
    # out: [b, 10] => pred: [b]
    pred = out.argmax(dim=1)
    correct = pred.eq(y).sum().float().item() #当前batch预测正确的数量
    total_correct += correct

total_num = len(test_loader.dataset)
acc = total_correct / total_num
print('test accurancy:', acc)


x, y = next(iter(test_loader))
out = net(x.view(x.size(0), 28*28))
pred = out.argmax(dim=1) #得到预测值
plot_image(x, pred, 'test')

MNIST手写数字图片识别(pytorch/神经网络)_第7张图片

这里我们拿到的就是test的图片,上面的文字是我们训练了三遍的神经网络预测的结果

全预测对了

 

 

utils.py

import  torch
from    matplotlib import pyplot as plt


def plot_curve(data):
    fig = plt.figure()
    plt.plot(range(len(data)), data, color='blue')
    plt.legend(['value'], loc='upper right')
    plt.xlabel('step')
    plt.ylabel('value')
    plt.show()



def plot_image(img, label, name):

    fig = plt.figure()
    for i in range(6):
        plt.subplot(2, 3, i + 1)
        plt.tight_layout()
        plt.imshow(img[i][0]*0.3081+0.1307, cmap='gray', interpolation='none')
        plt.title("{}: {}".format(name, label[i].item()))
        plt.xticks([])
        plt.yticks([])
    plt.show()


def one_hot(label, depth=10):
    out = torch.zeros(label.size(0), depth)
    idx = torch.LongTensor(label).view(-1, 1)
    out.scatter_(dim=1, index=idx, value=1)
    return out

 

你可能感兴趣的:(MNIST手写数字图片识别(pytorch/神经网络))