深度學習入門第一課——神經網絡實現手寫數字識別

昨天我們講了深度學習的大致框架,下面我們用深度學習網絡來實現一個小項目——手寫數字識別。

完整代碼

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensortraining_data=datasets.MNIST(root='./data',train=True,download=True,transform=ToTensor())test_data=datasets.MNIST(root='./data',train=False,download=True,transform=ToTensor())from matplotlib import pyplot as plt, figurefigure = plt.figure()
for i in range(9):image,label = training_data[i+59000]figure.add_subplot(3,3,i+1)plt.title(label)plt.axis('off')plt.imshow(image.squeeze(),cmap='gray')a=image.squeeze()
plt.show()train_dataloader=DataLoader(training_data,32)
test_dataloader=DataLoader(test_data,32)device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)for X, y in test_dataloader:print(f"Shape of X [N, C, H, W]: {X.shape}")  # 批次大小、通道、高度、寬度print(f"Shape of y: {y.shape}, Type of y: {y.dtype}")breakclass Net(nn.Module):def __init__(self):super().__init__()self.flatten = nn.Flatten()self.hidden1 = nn.Linear(28*28,128)self.hidden2 = nn.Linear(128,400)self.output = nn.Linear(400,10)def forward(self, x):x = self.flatten(x)x = self.hidden1(x)x = nn.ReLU()(x)# x = nn.functional.sigmoid(x)x = self.hidden2(x)x = nn.ReLU()(x)# x = nn.functional.sigmoid(x)x = self.output(x)return xmodel = Net()
model.to(device)
loss_fn = nn.CrossEntropyLoss()
# optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)def train(train_dataloader,model,loss_fn,optimizer):model.train()batch_size_num=1for X, y in train_dataloader:X,y=X.to(device),y.to(device)output = model.forward(X)loss = loss_fn(output,y)optimizer.zero_grad()loss.backward()optimizer.step()a=loss.item()if batch_size_num %100 ==0:print(f"Batch size: {batch_size_num}, Loss: {a}")batch_size_num+=1# print(model)def test(dataloader,model,loss_fn):size = len(dataloader.dataset)num_batches = len(dataloader)model.eval()batch_size_num=1loss,correct=0,0with torch.no_grad():for X, y in test_dataloader:X,y=X.to(device),y.to(device)pred = model(X)loss = loss_fn(pred,y)+losscorrect += (pred.argmax(1) == y).type(torch.float).sum().item()loss/=num_batchescorrect/=sizeprint(f'Test result: \n Accuracy: {(100*correct)}%,Avg loss: {loss}')# train(train_dataloader,model,loss_fn,optimizer)
# test(test_dataloader,model,loss_fn)epochs=10
for i in range(epochs):print(f"Epoch {i+1}")train(train_dataloader,model,loss_fn,optimizer)test(test_dataloader,model,loss_fn)

結果展示

下面我來進行拆解,

?1 導入庫

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor

前面就是導入庫,沒什么多說的。

2 導入數據

training_data=datasets.MNIST(root='./data',train=True,download=True,transform=ToTensor())test_data=datasets.MNIST(root='./data',train=False,download=True,transform=ToTensor())

首先我們從datasets.MINST()這個庫中導入數據

從上面我們可以看出,這個庫中包含一些網址,然后可以從其中下載一些數據。

root='./data',? ? ? ? 這個表示把數據存儲在這樣一個文件夾中
train=False,? ? ? ? 這個表示下載的是訓練集還是測試集,True為訓練集,False為測試集
download=True,? ? ? ? 下載
transform=ToTensor())? ? ? ? 轉化為Tensor數據,將圖像數據轉換為PyTorch張量(像素值歸一化到[0,1])。

3 數據展示

from matplotlib import pyplot as plt, figurefigure = plt.figure()
for i in range(9):image,label = training_data[i+59000]figure.add_subplot(3,3,i+1)plt.title(label)plt.axis('off')plt.imshow(image.squeeze(),cmap='gray')a=image.squeeze()
plt.show()
  • 創建一個3x3的子圖,顯示訓練集中最后9個樣本(索引59000到59008)的圖像和標簽。
  • image.squeeze()將形狀從[1,28,28]變為[28,28],因為matplotlib要求單通道圖像為二維。

結果展示

4 創建數據加載器

train_dataloader=DataLoader(training_data,32)
test_dataloader=DataLoader(test_data,32)
  • 訓練和測試數據加載器,每次迭代返回一個批次(32張圖片和對應的標簽)。

5??設置設備

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)
  • 檢查是否有可用的GPU,如果有則使用第一個GPU,否則用CPU。

6?打印一批測試數據的形狀

for X, y in test_dataloader:print(f"Shape of X [N, C, H, W]: {X.shape}")  # 批次大小、通道、高度、寬度print(f"Shape of y: {y.shape}, Type of y: {y.dtype}")break
  • 從測試數據加載器中取一個批次,打印輸入圖像和標簽的形狀。
  • X的形狀:[32, 1, 28, 28](32個樣本,1個通道,28x28像素)
  • y的形狀:[32](32個標簽)

7 ?定義神經網絡模型

class Net(nn.Module):def __init__(self):super().__init__()self.flatten = nn.Flatten()self.hidden1 = nn.Linear(28 * 28, 128)  # 第一層全連接self.hidden2 = nn.Linear(128, 400)     # 第二層全連接self.output = nn.Linear(400, 10)       # 輸出層(10個數字)def forward(self, x):x = self.flatten(x)        # 將圖像展平為向量:[batch, 28 * 28]x = self.hidden1(x)        # [batch, 128]#x = nn.functional.sigmoid(x)x = nn.ReLU()(x)           # ReLU激活x = self.hidden2(x)        # [batch, 400]#x = nn.functional.sigmoid(x)x = nn.ReLU()(x)           # ReLU激活x = self.output(x)         # [batch, 10]return x
  • 一個簡單的多層感知機(MLP)模型:
    • 輸入:28x28=784維
    • 兩個隱藏層:128和400個神經元,使用ReLU激活。
    • 輸出層:10個神經元(對應0-9),無激活(后面用交叉熵損失包含Softmax)。

forward為前向傳播

? ? ? ? 第一步先用flatten(x)把數據拉成一維的,例如原本28*28的二維數據,變成了28*28的一維數據

? ? ? ? 第二步傳入到隱含層

? ? ? ? 第三步使用激活函數進行激活(這里初開始使用sigmod函數進行激活,但使用ReLU激活比較好)

sigmod和ReLU函數對比

Sigmoid 激活函數的公式為:?f(x) = 1 / (1 + e^(-x))?它將輸入值映射到 (0, 1) 區間,常用于二分類問題的輸出層。Sigmoid 的優點是可以提供概率分布,但存在以下問題:

  • 梯度消失問題:當輸入值過大或過小時,梯度趨近于 0,導致深層網絡訓練困難。

  • 非零中心輸出:輸出值始終為正,可能導致權重更新不穩定。

  • 計算復雜度高:涉及指數運算,計算效率較低。

ReLU 激活函數的公式為:?f(x) = max(0, x)?ReLU 是深度學習中廣泛使用的激活函數,具有以下優點:

  • 計算效率高:只需簡單的比較操作,計算速度快。

  • 避免梯度消失:在正值范圍內梯度為常數,有助于深層網絡的訓練。

  • 稀疏激活性:部分神經元輸出為 0,減少參數依賴,緩解過擬合問題。

然而,ReLU 也存在死亡 ReLU問題,即當神經元進入負值區域時,梯度為 0,可能導致神經元永不激活。為此,改進版本如 Leaky ReLU 和 Parametric ReLU 被提出。

對比總結

  • 計算效率:ReLU 優于 Sigmoid,適合處理大規模數據。

  • 梯度問題:Sigmoid 易出現梯度消失,而 ReLU 在正值范圍內表現更優。

  • 適用場景:Sigmoid 常用于二分類問題的輸出層,而 ReLU 更適合深度網絡,如圖像識別和自然語言處理任務

8 創建模型對象

model = Net()
model.to(device)

這里創建了一個模型對象,并把模型傳入到我們的device也就是GPU中

9 初始化損失函數

loss_fn = nn.CrossEntropyLoss()

然后定義損失函數,這里為交叉熵損失函數。因為分類算法一般都是用交叉熵損失函數,找最優參數。還有許多損失函數的介紹看我主頁。

10 建立優化器

# optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)

這里最初建立的是SGD優化器,這個是梯度下降優化器,lr步長為0.01,后面優化成了Adam優化器,這個比較實用。適用幾乎所有哦網絡。

11 創建訓練函數

def train(train_dataloader,model,loss_fn,optimizer):model.train()batch_size_num=1for X, y in train_dataloader:X,y=X.to(device),y.to(device)output = model.forward(X)loss = loss_fn(output,y)optimizer.zero_grad()loss.backward()optimizer.step()a=loss.item()if batch_size_num %100 ==0:print(f"Batch size: {batch_size_num}, Loss: {a}")batch_size_num+=1# print(model)

第一步model.train(),這里設置為訓練模式(影響 Dropout、BatchNorm 等層),也就是說允許讀寫w。

第二部 分批次對訓練集進行導入,前行傳播,計算損失值,清空之前的梯度,反向計算梯度,更新梯度,下面就是訓練100批次就打印一下損失值。

12 創建測試函數

def test(dataloader, model, loss_fn):size = len(dataloader.dataset)     # 總樣本數num_batches = len(dataloader)      # batch 數量model.eval()                       # 設置為評估模式batch_size_num = 1loss, correct = 0, 0with torch.no_grad():  # 不計算梯度,節省內存和計算for X, y in dataloader:X, y = X.to(device), y.to(device)pred = model(X)loss += loss_fn(pred, y)  # 累積損失correct += (pred.argmax(1) == y).type(torch.float).sum().item()  # 統計正確預測的數量loss /= num_batches                # 平均損失correct /= size                    # 正確率print(f'Test result: \n Accuracy: {(100*correct):.2f}%, Avg loss: {loss:.4f}')

我們先把總樣本數求出來是因為后面要用預測對的樣本數/總樣本數就可以得到準確率了

model.eval()就是把w的模式改為僅讀模式

初始化損失值和準確率

在不對梯度進行改變的情況下,對訓練集中每一個值進行循環,得到預測值,然后用預測值和真實值作對比,然后得出的是一個列表,其中全是True和False.然后轉化為float也就是轉化為數值型0/1,然后再sum求綜合再取item()。

然后計算平均損失和正確率(其實這里損失值沒啥用了)

13 訓練和測試

train(train_dataloader,model,loss_fn,optimizer)
test(test_dataloader,model,loss_fn)

這里進行了訓練和測試,結果并不是很理想,但是我們可以疊加訓練,也就是說,在優化的時候次數太少,w權重并沒有更新到最優狀態。然后我們疊加train,這也是深度學習的一個優點,可以在前一層的基礎上繼續訓練。

epochs=10
for i in range(epochs):print(f"Epoch {i+1}")train(train_dataloader,model,loss_fn,optimizer)test(test_dataloader,model,loss_fn)

如上,我們進行了十次訓練,準確率從0.87訓練到了95

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/94410.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/94410.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/94410.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Vue中的scoped屬性

理解&#xff1a; 在 .vue 文件中&#xff0c;scoped 是 <style> 標簽的一個屬性&#xff0c;作用是讓樣式只作用于當前組件&#xff0c;避免樣式污染其他組件 scoped 讓樣式只在自己的組件內生效&#xff0c;不會影響到其他組件的同名元素 舉例 沒有 scoped 的情況&…

S2B2B系統哪個好,商淘云、數商云、金蝶云蒼穹供應鏈批發哪個比較靠譜

在數字化商業浪潮洶涌的當下&#xff0c;S2B2B系統已成為眾多企業優化供應鏈、提升運營效率、拓展業務版圖的關鍵利器。從大型企業的復雜產業鏈協同&#xff0c;到中小企業對上下游資源的整合與把控&#xff0c;S2B2B系統的身影無處不在。但面對市場上層出不窮的各類S2B2B系統&…

利用3臺機器搭建Kubernetes集群

文章目錄1 機器準備修改主機名(可選)配置IP地址和主機名映射關閉防火墻關閉swap2 安裝docker修改并更新軟件源安裝docker設置路由轉發規則&#xff0c;并使配置生效安裝 kubelet&#xff0c;kubeadm&#xff0c;kubectl3 初始化集群4 集群初始化5 work節點加入6 部署網絡插件本…

C6.3:發射結交流電阻

當一個小交流電壓加在發射結上&#xff0c;會產生發射極交流電流&#xff0c;該交流電流的大小取決于Q點位置&#xff0c;而曲線是彎曲的&#xff0c;所以Q點在曲線上的位置越高&#xff0c;發射極交流電流的峰值越大。發射極總電流是直流分量和交流分量疊加而成&#xff0c;即…

python中生成器

生成器是根據算法生成數據的一種機制&#xff0c;每次調用生成器只生成一個值&#xff0c;可以節省大量內存生成器推導式gg ( i * 2 for i in range(5))print(gg)print(next(gg)) # 0 print(next(gg)) # 2 print(next(gg)) # 4 print(next(gg)) # 6 print(next(gg)) # 8yield…

【RAGFlow代碼詳解-28】部署和基礎設施

Docker 部署架構 RAGFlow 使用多階段 Docker 構建過程和 Docker Compose 編排進行部署。該系統支持完整和輕量級部署變體。 多階段 Docker 構建構建過程由 Dockerfile 2-214中定義的三個階段組成&#xff1a; 基礎階段 &#xff1a;使用系統依賴項、ML 模型和運行時環境設置 Ub…

【prism】Prism 彈窗在 ViewModel 中控制大小的實踐總結

好 &#x1f44d; 這個思路非常適合寫成一篇 實用型博客&#xff0c;主題就是 “Prism 彈窗如何在 ViewModel 中控制窗口大小”。我幫你整理了一篇文章草稿&#xff0c;你可以直接拿去修改/發布。Prism 彈窗在 ViewModel 中控制大小的實踐總結 在 WPF 中使用 Prism 的 IDialogS…

項目管理進階——研發項目立項管理制度

為使公司研究開發(以下簡稱研發)項目的管理工作規范化、程序化、充分調度研發人員的積極性,提高研發成果的產出率和成果轉化率,特制定管理辦法。 一、 研發項目的立項: 原則上公司部設立基礎研究項目。研發項目的重點放在符合市場需要。能很快轉化成產品,或對現有生產工…

CMake構建學習筆記20-iconv庫的構建

1. 構建 iconv是一個用于在不同字符編碼&#xff08;如 UTF-8、GBK、ISO-8859-1 等&#xff09;之間進行轉換的開源庫。筆者在《c中utf8字符串和gbk字符串的轉換》這篇文章中介紹過如何在Windows下實現utf8字符串和gbk字符串的轉換&#xff0c;不過該實現是基于Win32 API的&am…

STM32的Sg90舵機

1.舵機到底要的是什么信號&#xff1f;想象舵機就像一個“聽秒表的工人”&#xff1a;這個工人每隔 20ms 就抬頭看看秒表一次。秒表上的 高電平持續多久&#xff0c;他就把這個時間當成“指令角度”。高 1ms → 轉到最左&#xff08;0&#xff09; 高 1.5ms → 轉到中間&#x…

動態帶寬擴展(DBE):下一代Wi-Fi性能提升的關鍵技術

動態帶寬擴展(DBE):下一代Wi-Fi性能提升的關鍵技術 引言 在無線通信技術快速發展的今天,用戶對網絡帶寬和傳輸速率的需求呈指數級增長。為了滿足這種需求,IEEE 802.11標準不斷演進,引入了多項創新技術。其中,動態帶寬擴展(Dynamic Bandwidth Expansion, DBE) 作為80…

Seaborn數據可視化實戰:Seaborn數據可視化基礎-從內置數據集到外部數據集的應用

Seaborn數據集探索與圖表繪制實踐 學習目標 通過本課程&#xff0c;你將學習如何使用Seaborn庫中的內置數據集&#xff0c;了解如何加載這些數據集&#xff0c;并掌握使用這些數據集繪制圖表的基本方法。此外&#xff0c;你還將學習如何導入外部數據集&#xff0c;并在Seaborn中…

漫談《數字圖像處理》之經典空域邊緣檢測Canny與LOG

在《數字圖像處理》的圖像分割領域&#xff0c;Canny 邊緣檢測與 LOG&#xff08;高斯拉普拉斯&#xff09;邊緣檢測是兩款極具代表性的先進空域算法。不同于深度學習驅動的方法&#xff0c;它們通過對圖像像素的直接計算提取邊緣&#xff0c;下面用更貼近日常認知的語言&#…

搶紅包案例加強版

加join的功能是保證線程全部運行完畢&#xff0c;之后好統計構造器剛開始為空列表&#xff0c;利用這個方法返回每個成員列表&#xff08;把每個員工弄成一個列表里面寫他們搶到的紅包大小&#xff0c;索引代表搶到的個數。&#xff09;

曲面方程的三維可視化:從數學解析到Python實現

在三維幾何建模中,我們經常遇到需要將隱式方程可視化的需求。本文將深入探討一個特定的曲面方程: XH?YH2+ZH2tan?(θ)?H2πarcsin?(YHYH2+ZH2)=0 X_H - \frac{\sqrt{Y_H^2 + Z_H^2}}{\tan(\theta)} - \frac{H}{2\pi} \arcsin\left( \frac{Y_H}{\sqrt{Y_H^2 + Z_H^2}} \r…

當GitHub宕機時,我們如何協作

引言簡述GitHub在全球開發協作中的重要性提出假設性問題&#xff1a;當GitHub不可用時&#xff0c;如何確保團隊協作不中斷常見的GitHub宕機場景服務完全不可用&#xff08;如DNS問題、全球性故障&#xff09;部分功能受限&#xff08;如API速率限制、倉庫訪問失敗&#xff09;…

如何確定哪些層應添加適配器(Adapter)?(58)

“它如何確定哪些層應添加適配器(Adapter)?是否只有量化層符合條件?我能否也將適配器添加到常規(非量化)線性層上?” 這個問題提得很好,我會逐一為你解答。首先,先給出簡潔結論: ? 主流模型架構會預配置目標層列表,適配器將應用于這些列表中的層。 ? 無論目標層…

【內網滲透】CVE-2025-21420 利用cleanmgr本地提權

目錄 原理 POC 復現 一個windows本地提權漏洞 這是一個存在于Windows磁盤清理工具&#xff08;cleanmgr.exe&#xff09;中的權限提升漏洞。攻擊者可以利用該系統組件在處理特定目錄時的邏輯缺陷&#xff0c;通過精心構造的符號鏈接&#xff08;Symbolic Link&#xff09;&a…

什么是JSON-RPC 2.0,在項目中應該怎么使用

它是什么 JSON-RPC 2.0 是一種超輕量、與傳輸無關的遠程調用協議&#xff1a;用 JSON 表達“方法名 參數 → 結果/錯誤”。可跑在 HTTP、WebSocket、Unix 管道&#xff0c;甚至 stdio 上&#xff08;很多開發協議如 LSP 就用它&#xff09;。 報文長這樣 ? 請求&#xff1a; …

基于CentOS7:Linux服務器的初始化流程

文章目錄前言一、服務器初始化1.1 配置國內 Yum 源&#xff08;加速軟件安裝&#xff09;1.1.1 使用阿里云源1.1.2 使用清華源&#xff08;可選&#xff09;1.2 更新系統與安裝必備工具1.3 網絡連接驗證1.4 配置主機名1.5 同步時間1.6 配置iptables防火墻1.6.1 手動配置iptable…