基於 PyTorch 的手寫數字識別ーー神經網路介紹

基於 PyTorch 的手寫數字識別ーー神經網路介紹

很容易,對吧?ーー要知道上面的圖片代表的是 4,這對你來說可不是件容易的事。你甚至不用擔心影象的低解析度,多麼神奇。我們都應該花點時間感謝我們的大腦!想知道我們的大腦處理影象、分類和反饋是多麼自然。我們是天才!

模仿人腦會有多難?深度學習,簡單來說,是機器學習研究的領域,它允許計算機學習執行對大腦來說很自然的任務,比如手寫數字識別。從技術上講,它涉及到更多的層(稍後我們將討論這一點)和更多的資料。

在本文中,我們將討論神經網路,並沿著這個方向從頭開發一個手寫數字分類器。我們將使用 PyTorch,因為它很酷!

基於 PyTorch 的手寫數字識別ーー神經網路介紹

本文的唯一先決條件是掌握 Python 語法的基本知識。

第一步:瞭解資料集

作為一個數據科學家,最關鍵的任務是收集完美的資料集,並徹底瞭解它。相信我,剩下的就容易多了。對於這個專案,我們將使用流行的 MNIST 資料庫。它是一個由70000個手寫數字組成的集合,分成訓練集和測試集,分別有60000和10000個影象。

基於 PyTorch 的手寫數字識別ーー神經網路介紹

這個資料集最初可以在 Yann Lecun 的網站上找到。清理資料是最大的任務之一。不要忘記ーー“垃圾進,垃圾出!”。幸運的是,對於我們來說,PyTorch 提供了一個簡單的實現,只需要幾行程式碼就可以下載已經清除和準備好的資料。在開始之前,我們需要進行所有必要的匯入。

import numpy as npimport torchimport torchvisionimport matplotlib。pyplot as pltfrom time import timefrom torchvision import datasets, transformsfrom torch import nn, optim

在下載資料之前,讓我們先定義要對資料執行哪些轉換,然後再將資料輸入。換句話說,你可以把它看作是對影象進行某種自定義編輯,以使所有影象具有相同的尺寸和屬性。我們使用torchvision。transforms。

transform = transforms。Compose([transforms。ToTensor(), transforms。Normalize((0。5,), (0。5,)), ])

transforms.ToTensor():

把影象轉換成數字

, 它把影象分成三個顏色通道(單獨的影象) :

紅,綠,藍,

然後將每張影象的畫素值轉換為0到255之間的顏色亮度。然後將這些值縮小到0到1之間的範圍。圖片現在是一個

張量資料。

transforms.Normalize()

:用一個平均值和一個標準差分別作為引數使張量正規化

現在,我們終於可以下載資料集,對它們進行隨機化處理和轉換了。我們下載資料集並將它們載入到 DataLoader 中,DataLoader 將資料集和取樣器結合在一起,並在資料集上提供單個或多個程序迭代器。

trainset = datasets。MNIST(‘PATH_TO_STORE_TRAINSET’, download=True, train=True, transform=transform)valset = datasets。MNIST(‘PATH_TO_STORE_TESTSET’, download=True, train=False, transform=transform)trainloader = torch。utils。data。DataLoader(trainset, batch_size=64, shuffle=True)valloader = torch。utils。data。DataLoader(valset, batch_size=64, shuffle=True)

batch size是我們希望一次讀取的影象數量。

第二步:更好地瞭解資料集

在這個階段,我們將對影象和張量進行一些探索性資料分析處理。讓我們來看看圖片和標籤的形狀。

dataiter = iter(trainloader)images, labels = dataiter。next()print(images。shape)print(labels。shape)

你會發現,影象的形狀是torch。Size([64,1,28,28]) ,這意味著每個批處理中有64張影象,每張影象的尺寸為28 × 28畫素。同樣,標籤有一個形狀作為torch。Size([64])。猜猜為什麼?是的,你說得對!64張圖片應該分別有64個標籤。

讓我們展示一個來自訓練集的影象,例如,第一個影象。

plt。imshow(images[0]。numpy()。squeeze(), cmap=‘gray_r’);

讓我們展示一些更多的影象,這將給我們一個怎樣的資料集的感覺。

figure = plt。figure()num_of_images = 60for index in range(1, num_of_images + 1): plt。subplot(6, 10, index) plt。axis(‘off’) plt。imshow(images[index]。numpy()。squeeze(), cmap=‘gray_r’)

這將生成一個隨機順序的網格影象。現在是時候開始定義我們將要使用的神經網路了。

第三步:構建神經網路

我們將構建下面的網路,正如你所看到的,它包含一個輸入層(第一層) ,一個由十個神經元(或單位,圓圈)組成的輸出層和兩個隱藏層。

基於 PyTorch 的手寫數字識別ーー神經網路介紹

PyTorch的 torch。nn 模組允許我們非常簡單地構建上述網路。它也非常容易理解。看看下面的程式碼。

input_size = 784hidden_sizes = [128, 64]output_size = 10model = nn。Sequential(nn。Linear(input_size, hidden_sizes[0]), nn。ReLU(), nn。Linear(hidden_sizes[0], hidden_sizes[1]), nn。ReLU(), nn。Linear(hidden_sizes[1], output_size), nn。LogSoftmax(dim=1))print(model)

nn。Sequential 是網路中的一層,包括三個線性層與 ReLU 啟用(一個簡單的函式,允許正值透過,而負值修改為零)。輸出層是一個線性層與 LogSoftmax 啟用,因為這是一個分類問題。

從技術上講,LogSoftmax 函式是一個柔性最大啟用函式的對數,正如它的名字所說,它看起來像這樣,如下所示。

基於 PyTorch 的手寫數字識別ーー神經網路介紹

接下來,我們定義 negative log-likelihood loss。用 C 類訓練一個分類問題是有用的。LogSoftmax()和 NLLLoss ()一起充當交叉熵損失,如上面的網路體系結構圖所示。

另外,你一定想知道為什麼我們有784個單元在第一層。很好!這是因為我們在將影象輸入到神經網路之前先將其拉平。(28x28 = 784)

criterion = nn。NLLLoss()images, labels = next(iter(trainloader))images = images。view(images。shape[0], -1)logps = model(images) #log probabilitiesloss = criterion(logps, labels) #calculate the NLL loss

我們將在以後的文章中更多地討論神經網路、啟用函式、最佳化演算法等。

第四步:調整權重

神經網路透過對可用資料進行多次迭代學習。“學習”是指透過調整網路的權重使損失最小化。讓我們想象一下它是如何工作的。

print(‘Before backward pass: \n’, model[0]。weight。grad)loss。backward()print(‘After backward pass: \n’, model[0]。weight。grad)

在反向傳播之前,模型權重被設定為預設的 none 值。有一次,我們呼叫了 backward()函式來更新權重。

Before backward pass: NoneAfter backward pass: tensor([[-0。0003, -0。0003, -0。0003, 。。。, -0。0003, -0。0003, -0。0003], [ 0。0008, 0。0008, 0。0008, 。。。, 0。0008, 0。0008, 0。0008], [-0。0037, -0。0037, -0。0037, 。。。, -0。0037, -0。0037, -0。0037], 。。。, [-0。0005, -0。0005, -0。0005, 。。。, -0。0005, -0。0005, -0。0005], [ 0。0043, 0。0043, 0。0043, 。。。, 0。0043, 0。0043, 0。0043], [-0。0006, -0。0006, -0。0006, 。。。, -0。0006, -0。0006, -0。0006]])

第五步:核心訓練過程

這就是真正的魔術發生的地方。你的神經網路遍歷訓練集並更新權重。我們使用 PyTorch 提供的模組 torch。optim 對模型進行最佳化,執行梯度下降法分析,並透過反向傳播更新權值。因此,在每個epoch(遍歷訓練集的次數)中,我們將看到訓練損失的逐漸減少。

optimizer = optim。SGD(model。parameters(), lr=0。003, momentum=0。9)time0 = time()epochs = 15for e in range(epochs): running_loss = 0 for images, labels in trainloader: # Flatten MNIST images into a 784 long vector images = images。view(images。shape[0], -1) # Training pass optimizer。zero_grad() output = model(images) loss = criterion(output, labels) #This is where the model learns by backpropagating loss。backward() #And optimizes its weights here optimizer。step() running_loss += loss。item() else: print(“Epoch {} - Training loss: {}”。format(e, running_loss/len(trainloader)))print(“\nTraining Time (in minutes) =”,(time()-time0)/60)

這可能需要一些時間來執行,並且因系統而異。

第六步:測試及評估

我們的工作幾乎完成了。模型已經準備好了,但是我們必須先對它進行評估。我建立了一個效用函式 view_classify ()來顯示影象和預測的類機率。

我從前面建立的驗證集中將一個影象傳遞給訓練好的模型,以檢視模型是如何工作的。

images, labels = next(iter(valloader))img = images[0]。view(1, 784)with torch。no_grad(): logps = model(img)ps = torch。exp(logps)probab = list(ps。numpy()[0])print(“Predicted Digit =”, probab。index(max(probab)))view_classify(img。view(1, 28, 28), ps)

基於 PyTorch 的手寫數字識別ーー神經網路介紹

現在,我們使用 for 迴圈迭代驗證集,並計算正確預測的總數。這就是我們計算準確度的方法。

correct_count, all_count = 0, 0for images,labels in valloader: for i in range(len(labels)): img = images[i]。view(1, 784) with torch。no_grad(): logps = model(img) ps = torch。exp(logps) probab = list(ps。numpy()[0]) pred_label = probab。index(max(probab)) true_label = labels。numpy()[i] if(true_label == pred_label): correct_count += 1 all_count += 1print(“Number Of Images Tested =”, all_count)print(“\nModel Accuracy =”, (correct_count/all_count))

現在讓我們看看結果,這是最有趣的部分!

Number Of Images Tested = 10000Model Accuracy = 0。9751

哇!我們得到了超過97。5% 的準確率。這是值得慶祝的。我們之所以能得到如此高的精確度,是因為我們的資料集是乾淨的,有各種混亂的影象和大量的影象。這使得我們的模型能夠很好地識別大量看不見的數字。

第七步:儲存模型

現在我們已經把一切都做完了,我們不想失去這個訓練好的模型。我們不想每次使用它的時候都訓練它。為此,我們將儲存模型。當我們將來需要它的時候,我們可以直接載入並使用它,而不需要重新訓練。

torch。save(model, ‘。/my_mnist_model。pt’)

第一個引數是模型物件,第二個引數是儲存路徑。PyTorch 模型通常使用。pt或。pth作為模型字尾。

總結

我希望你喜歡構建神經網路的過程,訓練它,測試它,並最終儲存它。除了建立一個很酷的專案,你肯定還掌握了一些概念,學到了一些新東西。