寫在前面
參考的是https://zh.d2l.ai/index.html
代碼運行的相關(guān)實操移步視頻https://www.bilibili.com/video/BV1XP411C7Hs/
一、大作業(yè)設(shè)計目的與要求
(1)利用所學(xué)習(xí)的聚類算法完成簡單的圖像分割系統(tǒng)。
(2)編程并利用相關(guān)軟件完成大作業(yè)測試,得到實驗結(jié)果。
(3)通過對實驗結(jié)果的分析得出實驗結(jié)論,培養(yǎng)學(xué)生創(chuàng)新思維和編寫實驗報告的能力,以及處理一般工程設(shè)計技術(shù)問題的初步能力及實事求是的科學(xué)態(tài)度。
(4)利用實驗更加直觀、方便和易于操作的優(yōu)勢,提高學(xué)生學(xué)習(xí)興趣,讓學(xué)生自主發(fā)揮設(shè)計和實施實驗,發(fā)揮出學(xué)生潛在的積極性和創(chuàng)造性。
(5)通過實驗的鍛煉,使學(xué)生進一步掌握基于卷積神經(jīng)網(wǎng)絡(luò)的圖像分類問題,也進一步領(lǐng)會學(xué)習(xí)機器學(xué)習(xí)知識的重要意義。
二、大作業(yè)設(shè)計內(nèi)容
大作業(yè)1 :手寫數(shù)字識別系統(tǒng)。
本項目要求選擇機器學(xué)習(xí)算法設(shè)計實現(xiàn)手寫數(shù)字識別系統(tǒng)。手寫數(shù)字識別在日常生活中有重要應(yīng)用,例如匯款單、銀行支票的處理,以及郵件的分揀等。手寫數(shù)字識別通常對精度要求較高,雖然只有10類,但是每個人的字跡不同,要做到精確識別有一定難度。項目的具體要求如下:
(1)使用MNIST手寫數(shù)字數(shù)據(jù)集,進行手寫數(shù)字識別(參考課本P186, 例6.2 )。
(2)選擇合適的機器學(xué)習(xí)算法進行手寫數(shù)字識別,訓(xùn)練分類模型,要求識別精度盡可能高。
(3)編寫簡單用戶界面,可以加載手寫數(shù)字圖片,并調(diào)用算法識別數(shù)字。
三、程序開發(fā)與運行環(huán)境
顯卡:NVIDIA顯卡,CUDA 11.7。
系統(tǒng)與環(huán)境:Windows11操作系統(tǒng),Anaconda3的base虛擬環(huán)境。
IDE:Pycharm Community集成開發(fā)環(huán)境,Jupyter Notebook
深度學(xué)習(xí)框架:PyTorch深度學(xué)習(xí)框架,基于GPU版本。
圖形界面框架:PyQt5
四、設(shè)計正文
(包括分析與設(shè)計思路、各模塊流程圖、主要算法偽代碼等,如有改進或者拓展,請重點用一小節(jié)進行說明)
4.1 分析與設(shè)計思路與流程圖
本次實驗任務(wù)是使用MNIST手寫數(shù)據(jù)集進行手寫數(shù)字識別。使用傳統(tǒng)的多層感知機等神經(jīng)網(wǎng)絡(luò)模型不能很好地解決此類問題,因為這種模型直接讀取圖像的原始像素,基于圖像的原始像素進行分類。然而,圖像特征的提取還需要人工設(shè)計函數(shù)進行提取。所以,卷積神經(jīng)網(wǎng)絡(luò)模型可以很好地對圖像進行自動的特征提取。
本次大作業(yè)使用經(jīng)典的AlexNet卷積神經(jīng)網(wǎng)絡(luò)模型。AlexNet卷積神經(jīng)網(wǎng)絡(luò)模型具有以下整體結(jié)構(gòu):
包含8層變換,包括5層卷積和2層全連接的隱藏層,1個全連接的輸出層。其中,第一層的卷積窗口形狀為1111,可以支持輸入更大的圖像。第二層卷積窗口形狀減小到55,之后的3層卷積采用33的窗口。在第一、第二、第五個卷積層之后都使用了卷積窗口大小為33、且步幅為2的最大池化。卷積通道數(shù)比LeNet大了10倍。在最后一個卷積與池化層后,就是兩個輸出個數(shù)為4096的全連接層,最后輸出結(jié)果。
1.引入了圖像增廣、翻轉(zhuǎn)、裁剪等方法,進一步從原始數(shù)據(jù)集中制作、擴大數(shù)據(jù)集。
AlexNet流程圖如下:
在本實驗中,因為運行的是MNIST數(shù)據(jù)集,所以最后一個全連接層只有10個結(jié)點,而非該流程圖中的1000。
為了進行圖形化的界面展示,還利用PyQt框架設(shè)置了前端圖形界面。
在訓(xùn)練完成數(shù)據(jù)集后,將模型寫入硬盤文件并保存,以供前端的圖形界面調(diào)用、讀取。
所以,前端的圖形界面在初始化過程中,就預(yù)先加載好了訓(xùn)練好的模型。用戶可以從文件中讀入需要識別的手寫數(shù)字圖片,由前端圖形界面根據(jù)加載好的模型自動給出該手寫數(shù)字圖片的識別結(jié)果。所以,本次實驗中各個模塊的交互邏輯如下圖所示。
4.2 主要算法代碼
訓(xùn)練模型
import numpy as np # numpy數(shù)組庫
import math # 數(shù)學(xué)運算庫
import matplotlib.pyplot as plt # 畫圖庫
import torch # torch基礎(chǔ)庫
import torchvision.datasets as dataset # 公開數(shù)據(jù)集的下載和管理
import torchvision.transforms as transforms # 公開數(shù)據(jù)集的預(yù)處理庫,格式轉(zhuǎn)換
import torchvision.utils as utils
import torch.utils.data as data_utils # 對數(shù)據(jù)集進行分批加載的工具集
from torch.utils import data
from d2l import torch as d2l
d2l.use_svg_display()
from torch import nn
net = nn.Sequential(
# 這里,我們使用一個11*11的更大窗口來捕捉對象。
# 同時,步幅為4,以減少輸出的高度和寬度。
# 另外,輸出通道的數(shù)目遠大于LeNet
nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2),
# 減小卷積窗口,使用填充為2來使得輸入與輸出的高和寬一致,且增大輸出通道數(shù)
nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2),
# 使用三個連續(xù)的卷積層和較小的卷積窗口。
# 除了最后的卷積層,輸出通道的數(shù)量進一步增加。
# 在前兩個卷積層之后,匯聚層不用于減少輸入的高度和寬度
nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),
nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),
nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Flatten(),
# 這里,全連接層的輸出數(shù)量是LeNet中的好幾倍。使用dropout層來減輕過擬合
nn.Linear(6400, 4096), nn.ReLU(),
nn.Dropout(p=0.5),
nn.Linear(4096, 4096), nn.ReLU(),
nn.Dropout(p=0.5),
# 最后是輸出層。由于這里使用MNIST,所以用類別數(shù)為10,而非論文中的1000
nn.Linear(4096, 10))
X = torch.randn(1, 1, 224, 224)#隨機初值
for layer in net:#用隨機權(quán)重參數(shù)初始化CNN
X=layer(X)
print(layer.__class__.__name__,'output shape:\t',X.shape)
def load_data_mnist(batch_size, resize=None):#讀取、加載MNIST數(shù)據(jù)集,并batch
trans = [transforms.ToTensor()]
if resize:
trans.insert(0, transforms.Resize(resize))
trans = transforms.Compose(trans)
mnist_train = dataset.MNIST(
root="../data", train=True, transform=trans, download=True)
mnist_test = dataset.MNIST(
root="../data", train=False, transform=trans, download=True)
return (data.DataLoader(mnist_train, batch_size, shuffle=True,
num_workers=4),
data.DataLoader(mnist_test, batch_size, shuffle=False,
num_workers=4))
batch_size = 128
train_iter, test_iter = load_data_mnist(batch_size=batch_size,resize=224)
for i, (X, y) in enumerate(train_iter):
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
X, y = X.to(device), y.to(device)
print("X:",X.shape)
print("y:",y.shape)
def evaluate_accuracy_gpu(net, data_iter, device=None): #@save
"""使用GPU計算模型在數(shù)據(jù)集上的精度"""
if isinstance(net, nn.Module):
net.eval() # 設(shè)置為評估模式
if not device:
device = next(iter(net.parameters())).device
# 正確預(yù)測的數(shù)量,總預(yù)測的數(shù)量
metric = d2l.Accumulator(2)
with torch.no_grad():
for X, y in data_iter:
if isinstance(X, list):
# BERT微調(diào)所需的
X = [x.to(device) for x in X]
else:
X = X.to(device)
y = y.to(device)
metric.add(d2l.accuracy(net(X), y), y.numel())
return metric[0] / metric[1]
def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
"""用GPU訓(xùn)練模型(在第六章定義)"""
def init_weights(m):
if type(m) == nn.Linear or type(m) == nn.Conv2d:
nn.init.xavier_uniform_(m.weight)
net.apply(init_weights)
print('training on', device)
net.to(device)
optimizer = torch.optim.SGD(net.parameters(), lr=lr)
loss = nn.CrossEntropyLoss()
animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],
legend=['train loss', 'train acc', 'test acc'])
timer, num_batches = d2l.Timer(), len(train_iter)
for epoch in range(num_epochs):
# 訓(xùn)練損失之和,訓(xùn)練準(zhǔn)確率之和,樣本數(shù)
metric = d2l.Accumulator(3)
net.train()
for i, (X, y) in enumerate(train_iter):
timer.start()
optimizer.zero_grad()
X, y = X.to(device), y.to(device)
y_hat = net(X)
l = loss(y_hat, y)
l.backward()
optimizer.step()
with torch.no_grad():
metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
timer.stop()
train_l = metric[0] / metric[2]
train_acc = metric[1] / metric[2]
if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
animator.add(epoch + (i + 1) / num_batches,
(train_l, train_acc, None))
test_acc = evaluate_accuracy_gpu(net, test_iter)
animator.add(epoch + 1, (None, None, test_acc))
animator.show()
print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, '
f'test acc {test_acc:.3f}')
print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec '
f'on {str(device)}')
lr, num_epochs = 0.01, 10
train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())
torch.save(net, "cnn.pt")
如果需要在colab上運行,可以使用如下代碼
import torch # torch基礎(chǔ)庫
import torchvision.datasets as dataset # 公開數(shù)據(jù)集的下載和管理
import torchvision.transforms as transforms # 公開數(shù)據(jù)集的預(yù)處理庫,格式轉(zhuǎn)換
from torch.utils import data
from torch import nn
net = nn.Sequential(
# 這里,我們使用一個11*11的更大窗口來捕捉對象。
# 同時,步幅為4,以減少輸出的高度和寬度。
# 另外,輸出通道的數(shù)目遠大于LeNet
nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2),
# 減小卷積窗口,使用填充為2來使得輸入與輸出的高和寬一致,且增大輸出通道數(shù)
nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2),
# 使用三個連續(xù)的卷積層和較小的卷積窗口。
# 除了最后的卷積層,輸出通道的數(shù)量進一步增加。
# 在前兩個卷積層之后,匯聚層不用于減少輸入的高度和寬度
nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),
nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),
nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Flatten(),
# 這里,全連接層的輸出數(shù)量是LeNet中的好幾倍。使用dropout層來減輕過擬合
nn.Linear(6400, 4096), nn.ReLU(),
nn.Dropout(p=0.5),
nn.Linear(4096, 4096), nn.ReLU(),
nn.Dropout(p=0.5),
# 最后是輸出層。由于這里使用MNIST,所以用類別數(shù)為10,而非論文中的1000
nn.Linear(4096, 10))
X = torch.randn(1, 1, 224, 224)#隨機初值
for layer in net:#用隨機權(quán)重參數(shù)初始化CNN
X=layer(X)
print(layer.__class__.__name__,'output shape:\t',X.shape)
def load_data_mnist(batch_size, resize=None):#讀取、加載MNIST數(shù)據(jù)集,并batch
trans = [transforms.ToTensor()]
if resize:
trans.insert(0, transforms.Resize(resize))
trans = transforms.Compose(trans)
mnist_train = dataset.MNIST(
root="../data", train=True, transform=trans, download=True)
mnist_test = dataset.MNIST(
root="../data", train=False, transform=trans, download=True)
return (data.DataLoader(mnist_train, batch_size, shuffle=True,
num_workers=4),
data.DataLoader(mnist_test, batch_size, shuffle=False,
num_workers=4))
batch_size = 128
train_iter, test_iter = load_data_mnist(batch_size=batch_size,resize=224)
for i, (X, y) in enumerate(train_iter):
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
X, y = X.to(device), y.to(device)
print("X:",X.shape)
print("y:",y.shape)
def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
"""用GPU訓(xùn)練模型(在第六章定義)"""
def init_weights(m):
if type(m) == nn.Linear or type(m) == nn.Conv2d:
nn.init.xavier_uniform_(m.weight)
net.apply(init_weights)
print('training on', device)
net.to(device)
optimizer = torch.optim.SGD(net.parameters(), lr=lr)
loss = nn.CrossEntropyLoss()
for epoch in range(num_epochs):
# 訓(xùn)練損失之和,訓(xùn)練準(zhǔn)確率之和,樣本數(shù)
net.train()
for i, (X, y) in enumerate(train_iter):
optimizer.zero_grad()
X, y = X.to(device), y.to(device)
y_hat = net(X)
l = loss(y_hat, y)
l.backward()
optimizer.step()
def try_gpu(i=0):
if torch.cuda.device_count() >= i + 1:
return torch.device(f'cuda:{i}')
return torch.device('cpu')
lr, num_epochs = 0.01, 10
train_ch6(net, train_iter, test_iter, num_epochs, lr, try_gpu())
torch.save(net, "cnn.pt")
用戶界面
from PIL import Image, ImageDraw, ImageFont
from PyQt5.QtWidgets import (QMainWindow, QMenuBar, QToolBar, QTextEdit, QAction, QApplication,
qApp, QMessageBox, QFileDialog, QLabel, QHBoxLayout, QGroupBox,
QComboBox, QGridLayout, QLineEdit, QSlider, QPushButton)
from PyQt5.QtGui import *
from PyQt5.QtGui import QPalette, QImage, QPixmap, QBrush
from PyQt5.QtCore import *
import sys
import cv2 as cv
import cv2
import numpy as np
import time
from pylab import *
import os
from torchvision import transforms
from PIL import Image
import torch
import numpy as np
class Window(QMainWindow):
path = ' '
change_path = "change.png"#被處理過的圖像的路徑
IMG1 = ' '
IMG2 = 'null'
def __init__(self):
super(Window, self).__init__()
# 界面初始化
self.createMenu()#創(chuàng)建左上角菜單欄
self.cwd = os.getcwd()#當(dāng)前工作目錄
self.image_show()
self.label1 = QLabel(self)
self.initUI()
# 菜單欄
def createMenu(self):
# menubar = QMenuBar(self)
menubar = self.menuBar()
menu1 = menubar.addMenu("文件")
menu1.addAction("打開")
menu1.triggered[QAction].connect(self.menu1_process)
#展示大圖片
def image_show(self):
self.lbl = QLabel(self)
self.lbl.setPixmap(QPixmap('source.png'))
self.lbl.setAlignment(Qt.AlignCenter) # 圖像顯示區(qū),居中
self.lbl.setGeometry(35, 35, 800, 700)
self.lbl.setStyleSheet("border: 2px solid black")
def initUI(self):
self.setGeometry(50, 50, 900, 800)
self.setWindowTitle('mnist識別系統(tǒng)')
palette = QPalette()
palette.setColor(self.backgroundRole(), QColor(255, 255, 255))
self.setPalette(palette)
self.label1.setText("TextLabel")
self.label1.move(100,730)
self.show()
# 菜單1處理
def menu1_process(self, q):
self.path = QFileDialog.getOpenFileName(self, '打開文件', self.cwd,
"All Files (*);;(*.bmp);;(*.tif);;(*.png);;(*.jpg)")
self.image = cv.imread(self.path[0])
self.lbl.setPixmap(QPixmap(self.path[0]))
cv2.imwrite(self.change_path, self.image)
transforms1 = transforms.Compose([
transforms.ToTensor()
])
self.label1.setText("識別中")
img = Image.open(self.change_path)
img = img.convert("L")
img = img.resize((224, 224))
tensor = transforms1(img)
print(tensor.shape)
tensor = tensor.type(torch.FloatTensor)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
tensor = tensor.to(device)
tensor = tensor.reshape((1, 1, 224, 224))
print(tensor.shape)
y = net(tensor)
print(y)
print(torch.argmax(y))
self.label1.setText(str(int(torch.argmax(y))))
if __name__ == '__main__':
net = torch.load('cnn.pt')
app = QApplication(sys.argv)
ex = Window()
ex.show()
sys.exit(app.exec_())
4.3 改進與拓展
1.重新配置了環(huán)境,安裝了基于GPU版本的Pytorch。與CPU版本相比,GPU能夠支持更快的卷積運算。同時,更大的顯存也能夠支持將更多的數(shù)據(jù)batch分批處理,有利于訓(xùn)練的穩(wěn)定性防止“梯度消失”。在CPU版本中,若batch size過大則可能出現(xiàn)爆內(nèi)存等問題。
2.AlexNet將sigmoid激活函數(shù)替換成了更簡單的ReLU激活函數(shù)。ReLU的計算更簡單,使得模型更容易訓(xùn)練,不會造成“梯度消失”等使得模型無法得到有效訓(xùn)練的情況。
3.為了防止過擬合,還引入了一定概率的dropout控制全連接層的模型復(fù)雜度。
五、實驗運行結(jié)果及分析
(不同情形的運行結(jié)果及詳細分析)
以下為python控制臺輸出結(jié)果
D:\ProgramData\Anaconda3\python.exe F:/mnist/mlhw3.py
Conv2d output shape: torch.Size([1, 96, 54, 54])
ReLU output shape: torch.Size([1, 96, 54, 54])
MaxPool2d output shape: torch.Size([1, 96, 26, 26])
Conv2d output shape: torch.Size([1, 256, 26, 26])
ReLU output shape: torch.Size([1, 256, 26, 26])
MaxPool2d output shape: torch.Size([1, 256, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 256, 12, 12])
ReLU output shape: torch.Size([1, 256, 12, 12])
MaxPool2d output shape: torch.Size([1, 256, 5, 5])
Flatten output shape: torch.Size([1, 6400])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 10])
training on cuda:0
<Figure size 350x250 with 1 Axes>
<Figure size 350x250 with 1 Axes>
<Figure size 350x250 with 1 Axes>
<Figure size 350x250 with 1 Axes>
<Figure size 350x250 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
<Figure size 1920x951 with 1 Axes>
loss 0.039, train acc 0.988, test acc 0.991
624.4 examples/sec on cuda:0
可以看出,正確地建立了模型,正確地進行迭代與更新、訓(xùn)練的過程。訓(xùn)練完成后,loss函數(shù)為0.039,訓(xùn)練集準(zhǔn)確率為0.988,測試集準(zhǔn)確率為0.991。在cuda上,每一秒都運行了624個訓(xùn)練數(shù)據(jù)。
訓(xùn)練集準(zhǔn)確率、測試集準(zhǔn)確率、loss函數(shù)的變化曲線如下??梢钥闯觯渥R別精度是非常高的。
此為用戶圖形界面
可以讀取文件
讀取數(shù)字“0”的圖片并正確識別。該圖片為真實手寫并反色處理后的圖片,不來源于訓(xùn)練集。
控制臺輸出如下:
torch.Size([1, 224, 224])
torch.Size([1, 1, 224, 224])
tensor([[16.5969, -2.6974, 1.0315, -4.3109, -2.4112, -2.2494, 2.9837, -2.5753,
-1.0474, 0.4374]], device='cuda:0', grad_fn=<AddmmBackward0>)
tensor(0, device='cuda:0')
用戶界面如下:
讀取數(shù)字“6”并正確識別。該圖片為真實手寫并反色處理后的圖片,不來源于訓(xùn)練集。
控制臺輸出如下:
torch.Size([1, 224, 224])
torch.Size([1, 1, 224, 224])
tensor([[-3.4247, -0.9304, -0.6991, -1.0964, 0.0769, 2.2364, 11.2306, -6.2827,
6.0278, -7.4283]], device='cuda:0', grad_fn=<AddmmBackward0>)
tensor(6, device='cuda:0')
用戶界面如下:
六、總結(jié)與進一步改進設(shè)想
在本次實驗中,使用了經(jīng)典的AlexNet卷積神經(jīng)網(wǎng)絡(luò)對經(jīng)典的MNIST數(shù)據(jù)集進行訓(xùn)練。完成了模型搭建與訓(xùn)練的任務(wù),識別精度也足夠高,也編寫了簡單的用戶界面,用真實手寫的圖片進行測試,可以看出模型對于真實場景的效果也是適用的,而不是只適用于加載出來并分割出來的測試集。
為了進一步改進,可以引入圖像增廣、翻轉(zhuǎn)、裁剪、顏色變化等辦法進一步擴大制作數(shù)據(jù)集,用于訓(xùn)練與測試??梢允褂肦GB顏色的3通道彩圖而不是僅僅使用單通道二值化圖像進行訓(xùn)練。文章來源:http://www.zghlxwxcb.cn/news/detail-432989.html
七、參考文獻
[1]周志華. 機器學(xué)習(xí)[M]. 2016年1月第1版. 北京:清華大學(xué)出版社, 2016.
[2]趙衛(wèi)東, 董亮. 機器學(xué)習(xí)[M]. 2018年8月第1版. 北京:人民郵電出版社, 2018.
[3]李航. 統(tǒng)計學(xué)習(xí)方法[M]. 2019年5月第2版. 北京:清華大學(xué)出版社, 2019.
[4]阿斯頓·張(Aston Zhang), 李沐(Mu Li), [美]扎卡里·C.立頓(Zachary C.Lipton), 等. 動手學(xué)深度學(xué)習(xí)[M]. 2019年6月第1版. 北京:人民郵電出版社, 2019.
[5][美]Ian Goodfellow [加]Yoshua Bengio [加]Aaron Courville. 深度學(xué)習(xí)[M]. 2017年8月第1版. 北京:人民郵電出版社, 2017.文章來源地址http://www.zghlxwxcb.cn/news/detail-432989.html
到了這里,關(guān)于【機器學(xué)習(xí)/人工智能】 大作業(yè):手寫數(shù)字識別系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!