国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

用PyTorch實(shí)現(xiàn)MNIST手寫數(shù)字識(shí)別(最新,非常詳細(xì))

這篇具有很好參考價(jià)值的文章主要介紹了用PyTorch實(shí)現(xiàn)MNIST手寫數(shù)字識(shí)別(最新,非常詳細(xì))。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

引言

本文基于PyTorch框架,采用CNN卷積神經(jīng)網(wǎng)絡(luò)實(shí)現(xiàn)MNIST手寫數(shù)字識(shí)別,僅在CPU上運(yùn)行。

已分別實(shí)現(xiàn)使用Linear純線性層、CNN卷積神經(jīng)網(wǎng)絡(luò)、Inception網(wǎng)絡(luò)、和Residual殘差網(wǎng)絡(luò)四種結(jié)構(gòu)對(duì)MNIST數(shù)據(jù)集進(jìn)行手寫數(shù)字識(shí)別,并對(duì)其識(shí)別準(zhǔn)確率進(jìn)行比較分析。(另外三種還未發(fā)布)

看完B站大佬視頻后,并且剛好深度學(xué)習(xí)的一個(gè)課程實(shí)驗(yàn)就是做手寫數(shù)字識(shí)別,就記錄下這個(gè)博客。
本文是筆者一個(gè)字一個(gè)字碼上的,相信已經(jīng)是非常詳細(xì)的了,可供初學(xué)者入門使用,歡迎各位大佬提出意見和改進(jìn)!

導(dǎo)入包

import torch
import numpy as np
from matplotlib import pyplot as plt
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision import datasets
import torch.nn.functional as F

一、數(shù)據(jù)集(MNIST)

MNIST數(shù)據(jù)集是機(jī)器學(xué)習(xí)領(lǐng)域中非常經(jīng)典的一個(gè)數(shù)據(jù)集,由60000個(gè)訓(xùn)練樣本和10000個(gè)測試樣本組成,每個(gè)樣本都是一張28 * 28像素的灰度手寫數(shù)字圖片。

下載
官方網(wǎng)站:http://yann.lecun.com/exdb/mnist/
網(wǎng)盤地址:MNIST數(shù)據(jù)集(提取碼: izsq )

一共4個(gè)文件,訓(xùn)練集、訓(xùn)練集標(biāo)簽、測試集、測試集標(biāo)簽

文件名稱 大小 內(nèi)容
train-labels-idx1-ubyte.gz 9,681 kb 55000張訓(xùn)練集,5000張驗(yàn)證集
train-labels-idx1-ubyte.gz 29 kb 訓(xùn)練集圖片對(duì)應(yīng)的標(biāo)簽
t10k-images-idx3-ubyte.gz 1,611 kb 10000張測試集
t10k-labels-idx1-ubyte.gz 5 kb 測試集圖片對(duì)應(yīng)的標(biāo)簽

1.1 讀取MNIST數(shù)據(jù)集

直接下載下來的數(shù)據(jù)是無法通過解壓或者應(yīng)用程序打開的,因?yàn)檫@些文件不是任何標(biāo)準(zhǔn)的圖像格式而是以字節(jié)的形式進(jìn)行存儲(chǔ)的,所以必須編寫程序來打開它。

torchvision.datasets包中已經(jīng)包含MNIST數(shù)據(jù)集,可以通過在編譯器中輸入代碼進(jìn)行數(shù)據(jù)集的獲取,步驟如下:

  • Step1:歸一化,softmax歸一化指數(shù)函數(shù)(https://blog.csdn.net/lz_peter/article/details/84574716),其中0.1307是mean均值和0.3081是std標(biāo)準(zhǔn)差
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])
  • Step2:下載/獲取數(shù)據(jù)集,其中root為數(shù)據(jù)集存放路徑,train=True即訓(xùn)練集否則為測試集。
train_dataset = datasets.MNIST(root='./data/mnist', train=True, download=True, transform=transform)  
test_dataset = datasets.MNIST(root='./data/mnist', train=False, download=True, transform=transform)  # train=True訓(xùn)練集,=False測試集
  • Step3:實(shí)例化一個(gè)dataset后,然后用Dataloader 包起來,即載入數(shù)據(jù)集。這里的batch_size為超參數(shù),詳見第五大節(jié);shuffle=True即打亂數(shù)據(jù)集,這里我們打亂訓(xùn)練集進(jìn)行訓(xùn)練,而對(duì)測試集進(jìn)行順序測試。
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

1.2 展示MNIST數(shù)據(jù)集:

這里舉例展示12幅圖,包含圖片內(nèi)容和標(biāo)簽。

fig = plt.figure()
for i in range(12):
    plt.subplot(3, 4, i+1)
    plt.tight_layout()
    plt.imshow(train_dataset.train_data[i], cmap='gray', interpolation='none')
    plt.title("Labels: {}".format(train_dataset.train_labels[i]))
    plt.xticks([])
    plt.yticks([])
plt.show()

輸出結(jié)果

用PyTorch實(shí)現(xiàn)MNIST手寫數(shù)字識(shí)別(最新,非常詳細(xì))

二、構(gòu)建模型(CNN)

2.1 卷積層

每一個(gè)卷積核的通道數(shù)量要求和輸入通道數(shù)量一樣,卷積核的總數(shù)和輸出通道的數(shù)量一樣。
卷積(convolution)后,C(Channels)變,W(width)和H(Height)可變可不變,取決于填充padding。

用PyTorch實(shí)現(xiàn)MNIST手寫數(shù)字識(shí)別(最新,非常詳細(xì))

torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding)

參數(shù):

  • in_channels:輸入通道
  • out_channels:輸出通道
  • kernel_size:卷積核大小
  • stride:步長
  • padding:填充

2.2 激活層

激活層使用ReLU激活函數(shù)。
線性整流函數(shù)(Rectified Linear Unit, ReLU),又稱修正線性單元,是一種人工神經(jīng)網(wǎng)絡(luò)中常用的激活函數(shù)(activation function),通常指代以斜坡函數(shù)及其變種為代表的非線性函數(shù)。

用PyTorch實(shí)現(xiàn)MNIST手寫數(shù)字識(shí)別(最新,非常詳細(xì))

torch.nn.ReLU()

2.3 池化層

池化層采用最大池化。
池化(pooling)后,C(C.hannels)不變,W(width)和H(Height)變。

用PyTorch實(shí)現(xiàn)MNIST手寫數(shù)字識(shí)別(最新,非常詳細(xì))

torch.nn.MaxPool2d(input, kernel_size, stride, padding)

參數(shù):

  • input:輸入
  • kernel_size:卷積核大小
  • stride:步長
  • padding:填充

2.4 全連接層

之前卷積層要求輸入輸出是四維張量(B,C,W,H),而全連接層的輸入與輸出都是二維張量(B,Input_feature),經(jīng)過卷積、激活、池化后,使用view打平,進(jìn)入全連接層。

2.5 CNN模型

模型如圖所示:

用PyTorch實(shí)現(xiàn)MNIST手寫數(shù)字識(shí)別(最新,非常詳細(xì))

比如輸入一個(gè)手寫數(shù)字“5”的圖像,它的維度為(batch,1,28,28)即單通道高寬分別為28像素。

  • 首先通過一個(gè)卷積核為5×5的卷積層,其通道數(shù)從1變?yōu)?0,高寬分別為24像素;
  • 然后通過一個(gè)卷積核為2×2的最大池化層,通道數(shù)不變,高寬變?yōu)橐话?,即維度變成(batch,10,12,12);
  • 然后再通過一個(gè)卷積核為5×5的卷積層,其通道數(shù)從10變?yōu)?0,高寬分別為8像素;
  • 再通過一個(gè)卷積核為2×2的最大池化層,通道數(shù)不變,高寬變?yōu)橐话?,即維度變成(batch,20,4,4);
  • 之后將其view展平,使其維度變?yōu)?20(2044)之后進(jìn)入全連接層,用線性函數(shù)將其輸出為10類,即“0-9”10個(gè)數(shù)字。

代碼:

class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = torch.nn.Sequential(
            torch.nn.Conv2d(1, 10, kernel_size=5),
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=2),
        )
        self.conv2 = torch.nn.Sequential(
            torch.nn.Conv2d(10, 20, kernel_size=5),
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=2),
        )
        self.fc = torch.nn.Sequential(
            torch.nn.Linear(320, 50),
            torch.nn.Linear(50, 10),
        )

    def forward(self, x):
        batch_size = x.size(0)
        x = self.conv1(x)  # 一層卷積層,一層池化層,一層激活層(圖是先卷積后激活再池化,差別不大)
        x = self.conv2(x)  # 再來一次
        x = x.view(batch_size, -1)  # flatten 變成全連接網(wǎng)絡(luò)需要的輸入 (batch, 20,4,4) ==> (batch,320), -1 此處自動(dòng)算出的是320
        x = self.fc(x)
        return x  # 最后輸出的是維度為10的,也就是(對(duì)應(yīng)數(shù)學(xué)符號(hào)的0~9)

實(shí)例化模型:

model = Net()

三、損失函數(shù)和優(yōu)化器

損失函數(shù)使用交叉熵?fù)p失
參數(shù)優(yōu)化使用隨機(jī)梯度下降

criterion = torch.nn.CrossEntropyLoss()  # 交叉熵?fù)p失
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, momentum=momentum)  # lr學(xué)習(xí)率,momentum沖量

四、定義訓(xùn)練輪和測試輪

4.1 訓(xùn)練輪

  • Step1:前饋(forward propagation)

  • Step2:反饋(backward propagation)

  • Step3:更新(update)

訓(xùn)練輪代碼:

def train(epoch):
    running_loss = 0.0  # 這整個(gè)epoch的loss清零
    running_total = 0
    running_correct = 0
    for batch_idx, data in enumerate(train_loader, 0):
        inputs, target = data
        optimizer.zero_grad()

        # forward + backward + update
        outputs = model(inputs)
        loss = criterion(outputs, target)

        loss.backward()
        optimizer.step()

        # 把運(yùn)行中的loss累加起來,為了下面300次一除
        running_loss += loss.item()
        # 把運(yùn)行中的準(zhǔn)確率acc算出來
        _, predicted = torch.max(outputs.data, dim=1)
        running_total += inputs.shape[0]
        running_correct += (predicted == target).sum().item()

        if batch_idx % 300 == 299:  # 不想要每一次都出loss,浪費(fèi)時(shí)間,選擇每300次出一個(gè)平均損失,和準(zhǔn)確率
            print('[%d, %5d]: loss: %.3f , acc: %.2f %%'
                  % (epoch + 1, batch_idx + 1, running_loss / 300, 100 * running_correct / running_total))
            running_loss = 0.0  # 這小批300的loss清零
            running_total = 0
            running_correct = 0  # 這小批300的acc清零

4.2 測試輪

測試集不用算梯度(無需反饋),首先從test_loader中讀取每一次的圖片和標(biāo)簽,進(jìn)行前饋運(yùn)算后,預(yù)測每一輪的準(zhǔn)確率
測試輪代碼:

def test():
    correct = 0
    total = 0
    with torch.no_grad():  # 測試集不用算梯度
        for data in test_loader:
            images, labels = data
            outputs = model(images)
            _, predicted = torch.max(outputs.data, dim=1)  # dim = 1 列是第0個(gè)維度,行是第1個(gè)維度,沿著行(第1個(gè)維度)去找1.最大值和2.最大值的下標(biāo)
            total += labels.size(0)  # 張量之間的比較運(yùn)算
            correct += (predicted == labels).sum().item()
    acc = correct / total
    print('[%d / %d]: Accuracy on test set: %.1f %% ' % (epoch+1, EPOCH, 100 * acc))  # 求測試的準(zhǔn)確率,正確數(shù)/總數(shù)
    return acc

五、開始訓(xùn)練

超參數(shù):用到的超參數(shù)主要有小批量數(shù)據(jù)的batch size,梯度下降算法中用到的學(xué)習(xí)率(learning rate)和沖量(momentum),同時(shí)定義進(jìn)行10輪次的訓(xùn)練。

# super parameters
batch_size = 64
learning_rate = 0.01
momentum = 0.5
EPOCH = 10

主函數(shù):共進(jìn)行10輪次的訓(xùn)練:每訓(xùn)練一輪,就進(jìn)行一次測試。

if __name__ == '__main__':
    acc_list_test = []
    for epoch in range(EPOCH):
        train(epoch)
        # if epoch % 10 == 9:  #每訓(xùn)練10輪 測試1次
        acc_test = test()
        acc_list_test.append(acc_test)

    plt.plot(acc_list_test)
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy On TestSet')
    plt.show()

六、結(jié)果和分析

下表為訓(xùn)練集和測試集上的損失值和識(shí)別準(zhǔn)確率的輸入結(jié)果。

可以看到一共進(jìn)行10輪次的訓(xùn)練和測試:每一輪的訓(xùn)練中,每300小批量數(shù)據(jù)輸出一次損失值和準(zhǔn)確率;每一輪訓(xùn)練結(jié)束后進(jìn)行一次測試,并打印其在測試集上的準(zhǔn)確率。
10輪后,在訓(xùn)練集上的平均識(shí)別準(zhǔn)確率達(dá)到98.88%,在測試集上的準(zhǔn)確率達(dá)到99%,其中測試集上準(zhǔn)確率如下圖所示。

[1, 300]: loss: 0.820 , acc: 76.82 %
[1, 600]: loss: 0.237 , acc: 93.01 %
[1, 900]: loss: 0.152 , acc: 95.35 %
Accuracy on test set: 96.4 %
[2, 300]: loss: 0.126 , acc: 96.27 %
[2, 600]: loss: 0.109 , acc: 96.77 %
[2, 900]: loss: 0.094 , acc: 97.15 %
Accuracy on test set: 97.6 %
[3, 300]: loss: 0.084 , acc: 97.55 %
[3, 600]: loss: 0.080 , acc: 97.49 %
[3, 900]: loss: 0.075 , acc: 97.64 %
Accuracy on test set: 97.7 %
[4, 300]: loss: 0.072 , acc: 97.85 %
[4, 600]: loss: 0.066 , acc: 98.08 %
[4, 900]: loss: 0.060 , acc: 98.16 %
Accuracy on test set: 98.3 %
[5, 300]: loss: 0.058 , acc: 98.21 %
[5, 600]: loss: 0.060 , acc: 98.23 %
[5, 900]: loss: 0.055 , acc: 98.31 %
Accuracy on test set: 98.5 %
[6, 300]: loss: 0.047 , acc: 98.57 %
[6, 600]: loss: 0.054 , acc: 98.29 %
[6, 900]: loss: 0.053 , acc: 98.39 %
Accuracy on test set: 98.6 %
[7, 300]: loss: 0.048 , acc: 98.61 %
[7, 600]: loss: 0.044 , acc: 98.58 %
[7, 900]: loss: 0.049 , acc: 98.54 %
Accuracy on test set: 98.7 %
[8, 300]: loss: 0.045 , acc: 98.77 %
[8, 600]: loss: 0.043 , acc: 98.60 %
[8, 900]: loss: 0.043 , acc: 98.72 %
Accuracy on test set: 98.7 %
[9, 300]: loss: 0.040 , acc: 98.78 %
[9, 600]: loss: 0.037 , acc: 98.86 %
[9, 900]: loss: 0.042 , acc: 98.73 %
Accuracy on test set: 98.8 %
[10, 300]: loss: 0.038 , acc: 98.84 %
[10, 600]: loss: 0.034 , acc: 98.98 %
[10, 900]: loss: 0.037 , acc: 98.88 %
Accuracy on test set: 99.0 %
用PyTorch實(shí)現(xiàn)MNIST手寫數(shù)字識(shí)別(最新,非常詳細(xì))

七、完整代碼

import torch
import numpy as np
from matplotlib import pyplot as plt
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision import datasets
import torch.nn.functional as F

"""
卷積運(yùn)算 使用mnist數(shù)據(jù)集,和10-4,11類似的,只是這里:1.輸出訓(xùn)練輪的acc 2.模型上使用torch.nn.Sequential
"""
# Super parameter ------------------------------------------------------------------------------------
batch_size = 64
learning_rate = 0.01
momentum = 0.5
EPOCH = 10

# Prepare dataset ------------------------------------------------------------------------------------
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])
# softmax歸一化指數(shù)函數(shù)(https://blog.csdn.net/lz_peter/article/details/84574716),其中0.1307是mean均值和0.3081是std標(biāo)準(zhǔn)差

train_dataset = datasets.MNIST(root='./data/mnist', train=True, transform=transform)  # 本地沒有就加上download=True
test_dataset = datasets.MNIST(root='./data/mnist', train=False, transform=transform)  # train=True訓(xùn)練集,=False測試集
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)

fig = plt.figure()
for i in range(12):
    plt.subplot(3, 4, i+1)
    plt.tight_layout()
    plt.imshow(train_dataset.train_data[i], cmap='gray', interpolation='none')
    plt.title("Labels: {}".format(train_dataset.train_labels[i]))
    plt.xticks([])
    plt.yticks([])
plt.show()


# 訓(xùn)練集亂序,測試集有序
# Design model using class ------------------------------------------------------------------------------
class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = torch.nn.Sequential(
            torch.nn.Conv2d(1, 10, kernel_size=5),
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=2),
        )
        self.conv2 = torch.nn.Sequential(
            torch.nn.Conv2d(10, 20, kernel_size=5),
            torch.nn.ReLU(),
            torch.nn.MaxPool2d(kernel_size=2),
        )
        self.fc = torch.nn.Sequential(
            torch.nn.Linear(320, 50),
            torch.nn.Linear(50, 10),
        )

    def forward(self, x):
        batch_size = x.size(0)
        x = self.conv1(x)  # 一層卷積層,一層池化層,一層激活層(圖是先卷積后激活再池化,差別不大)
        x = self.conv2(x)  # 再來一次
        x = x.view(batch_size, -1)  # flatten 變成全連接網(wǎng)絡(luò)需要的輸入 (batch, 20,4,4) ==> (batch,320), -1 此處自動(dòng)算出的是320
        x = self.fc(x)
        return x  # 最后輸出的是維度為10的,也就是(對(duì)應(yīng)數(shù)學(xué)符號(hào)的0~9)


model = Net()


# Construct loss and optimizer ------------------------------------------------------------------------------
criterion = torch.nn.CrossEntropyLoss()  # 交叉熵?fù)p失
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate, momentum=momentum)  # lr學(xué)習(xí)率,momentum沖量


# Train and Test CLASS --------------------------------------------------------------------------------------
# 把單獨(dú)的一輪一環(huán)封裝在函數(shù)類里
def train(epoch):
    running_loss = 0.0  # 這整個(gè)epoch的loss清零
    running_total = 0
    running_correct = 0
    for batch_idx, data in enumerate(train_loader, 0):
        inputs, target = data
        optimizer.zero_grad()

        # forward + backward + update
        outputs = model(inputs)
        loss = criterion(outputs, target)

        loss.backward()
        optimizer.step()

        # 把運(yùn)行中的loss累加起來,為了下面300次一除
        running_loss += loss.item()
        # 把運(yùn)行中的準(zhǔn)確率acc算出來
        _, predicted = torch.max(outputs.data, dim=1)
        running_total += inputs.shape[0]
        running_correct += (predicted == target).sum().item()

        if batch_idx % 300 == 299:  # 不想要每一次都出loss,浪費(fèi)時(shí)間,選擇每300次出一個(gè)平均損失,和準(zhǔn)確率
            print('[%d, %5d]: loss: %.3f , acc: %.2f %%'
                  % (epoch + 1, batch_idx + 1, running_loss / 300, 100 * running_correct / running_total))
            running_loss = 0.0  # 這小批300的loss清零
            running_total = 0
            running_correct = 0  # 這小批300的acc清零

        # torch.save(model.state_dict(), './model_Mnist.pth')
        # torch.save(optimizer.state_dict(), './optimizer_Mnist.pth')


def test():
    correct = 0
    total = 0
    with torch.no_grad():  # 測試集不用算梯度
        for data in test_loader:
            images, labels = data
            outputs = model(images)
            _, predicted = torch.max(outputs.data, dim=1)  # dim = 1 列是第0個(gè)維度,行是第1個(gè)維度,沿著行(第1個(gè)維度)去找1.最大值和2.最大值的下標(biāo)
            total += labels.size(0)  # 張量之間的比較運(yùn)算
            correct += (predicted == labels).sum().item()
    acc = correct / total
    print('[%d / %d]: Accuracy on test set: %.1f %% ' % (epoch+1, EPOCH, 100 * acc))  # 求測試的準(zhǔn)確率,正確數(shù)/總數(shù)
    return acc


# Start train and Test --------------------------------------------------------------------------------------
if __name__ == '__main__':
    acc_list_test = []
    for epoch in range(EPOCH):
        train(epoch)
        # if epoch % 10 == 9:  #每訓(xùn)練10輪 測試1次
        acc_test = test()
        acc_list_test.append(acc_test)

    plt.plot(acc_list_test)
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy On TestSet')
    plt.show()

參考資料:
https://www.bilibili.com/video/BV1Y7411d7Ys?p=10文章來源地址http://www.zghlxwxcb.cn/news/detail-455174.html

到了這里,關(guān)于用PyTorch實(shí)現(xiàn)MNIST手寫數(shù)字識(shí)別(最新,非常詳細(xì))的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包