Pytorch 手寫數字識別 深度學習基礎分享

金色旭光發表於2024-12-09

image

本篇是一次內部分享,給專案開發的同事分享什麼是深度學習。用最簡單的手寫數字識別做例子,講解了大概的原理。

手寫數字識別

展示首先數字識別專案的使用。專案實現過程:

  1. 訓練出模型
  2. 準備html手寫板
  3. flask 框架搭建簡單後端



深度學習必備知識介紹

機器學習的概念

通俗解釋
機器學習的關鍵內涵之一在於利用計算機的運算能力從大量的資料中發現一個規律,用這個規律實現預測或判斷的功能。

深度學習演算法分類

以演算法區分深度學習應用,演算法類別可分成三大類:

  • 常用於圖片資料進行分析處理的卷積神經網路
  • 文字分析或自然語言處理的遞迴神經網路
  • 常用於資料生成的對抗神經網路

卷積神經網路(CNN)主要應用可分為影像分類、目標檢測、語義分割

圖片儲存的本質

圖片在計算機中以數字矩陣的形式儲存。
https://h.markbuild.com/doc/binary-viewer-cn.html

圖片的儲存:

模型訓練的通用步驟

模型訓練的思想:

  1. 準備資料集
  2. 構建神經網路模型(物件導向中定義的一個類)
  3. 選擇損失函式和最佳化器
  4. 訓練模型
    • 從模型訓練得出數值
    • 透過損失函式得到預測值和實際值的差距
    • 透過最佳化器調整模型中的引數,讓結果越來越準確
    • 迴圈以上步驟

損失函式:衡量訓練結果和實際偏差的函式。數值越大代表差距越大
最佳化器:最佳化模型的演算法,讓損失函式減小的方法

Q&A


Pytorch 手寫數字識別講解

模型訓練使用pytorch框架,同樣可以實現的框架還由tensorflow、keras。

資料集獲取

手寫識別使用的是MNIST資料集,手寫數字圖片。MNIST資料集由畫素是28 × 28 的0~9的手寫數字圖片組成,一共有7萬張圖片,其中6萬張是訓練集,1萬張是測試集。每個圖片是黑底白字的形式。

pytorch 中提供了torchvision 包,可以透過該包可以下載資料集

import torchvision 
import matplotlib.pyplot as plt

# 訓練資料集
train_data = torchvision.datasets.MNIST(
    root="data",    # 表示把MINST儲存在data資料夾下
    download=True,  # 表示需要從網路上下載。下載過一次後,下一次就不會再重複下載了
    train=True,     # 表示這是訓練資料集
    transform=torchvision.transforms.ToTensor()
                    # 要把資料集中的資料轉換為pytorch能夠使用的Tensor型別
)

# 測試資料集
test_data = torchvision.datasets.MNIST(
    root="data",    # 表示把MINST儲存在data資料夾下
    download=True,  # 表示需要從網路上下載。下載過一次後,下一次就不會再重複下載了
    train=False,    # 表示這是測試資料集
    transform=torchvision.transforms.ToTensor()
                    # 要把資料集中的資料轉換為pytorch能夠使用的Tensor型別
)

演示


模型定義

模型使用的是卷積神經網路模型。定義的神經網路模型如下:

import torch.nn as nn


# 定義卷積神經網路類
class RLS_CNN(nn.Module):
    def __init__(self):
        super(RLS_CNN, self).__init__()
        self.net = nn.Sequential(
            nn.Conv2d(in_channels=1, out_channels=16,   # 輸入、輸出通道數,輸出通道數可以理解為提取了幾種特徵
                      kernel_size=(3, 3),               # 卷積核尺寸
                      stride=(1, 1),                    # 卷積核每次移動多少個畫素
                      padding=1),                       # 原圖片邊緣加幾個空白畫素
                                                        # 輸入圖片尺寸為 1×28×28
                                                        # 第一次卷積,尺寸為                 16×28×28
            nn.MaxPool2d(kernel_size=2),                # 第一次池化,尺寸為                 16×14×14
            nn.Conv2d(16, 32, 3, 1, 1),                 # 第二次卷積,尺寸為                 32×14×14
            nn.MaxPool2d(2),                            # 第二次池化,尺寸為                 32×7 ×7
            nn.Flatten(),                               # 將三維陣列變成一維陣列
            nn.Linear(32*7*7, 16),                      # 變成16個卷積核,每一個卷積核是1*1,最後輸出16個數字
            nn.ReLU(),                                  # 啟用函式 x<0 y=0  x>0 y=x,用在反向反向傳導
            nn.Linear(16, 10)                           # 將16變成10,預測0-9之間機率值
        )

    def forward(self, x):
        return self.net(x)

卷積神經網路模型組成

卷積神經網路通常由3個部分構成:卷積層,池化層,全連線層。各部分的功能:

  • 卷積層:負責提取影像中的特徵,可以輸出一張圖片的很多種特徵。
  • 池化層:用來縮小尺寸,大幅降低引數量級,降低計算量
  • 全連線層:合併特徵並輸出結果

美顏相機的原理就是提取圖片的特徵,如下圖片第二張模糊輪廓,第三張是突出輪廓。

卷積

卷積的功能:提取圖片的多種特徵資訊
卷積的原理:用一個卷積核和圖片的矩陣相乘,得到一個新的矩陣。新矩陣就是一個新的特徵。
卷積核
卷積核也是一個矩陣,通常是33的矩陣,或者是55的矩陣。卷積運算的過程如下:

影像邊緣提取
使用如下的卷積核就可以提取影像的邊緣輪廓特徵

調參
卷積核矩陣由3*3一共9個引數組成,這些引數都是模型自動生成的,所謂的調參,其中一部分就是指調整卷積核矩陣的引數,讓其提取的特徵能夠使預測更加準確

池化

池化的功能:池化就是縮小矩陣的尺寸,從而減少後續操作的引數數量。通常會在相鄰的卷積層之間加入一個池化層。
池化的原理:池化的運算過程:將一個44的矩陣最大池化成22的矩陣,就是取4*4矩陣中對應區域中最大的一個數值。

池化通常有兩種:

  • 最大池化(max pooling):選影像區域的最大值作為該區域池化後的值。
  • 平均池化(average pooling):計算影像區域的平均值作為該區域池化後的值。

全連線

全連線功能: 全連線的作用是組合特徵分類
在前面兩個步驟中從一張圖片提取多種特徵,並將特徵矩陣進行了壓縮。當資料到達全連線層時得到是一張圖片的多種特徵。
某一個特徵並不能說整個圖片是什麼,否則就是盲人摸象。那麼全連線層就是將多種特徵組合起來形成一個完整的特徵,並根據特徵計算出圖片是某一個型別的機率。
全連線層最終輸出就是機率。比如手寫數字識別,最終全連線層輸出就是某一個手寫數字在0~9上的機率。

tensor([[ 0.949,  3.032,  0.771, -2.173, -0.038, -0.236,  0.013,  0.614, -1.125, -2.6991]])

全連線的原理
全連線層實現的是特徵組合,原理和卷積類似,也就是用一個卷積核對矩陣做運算,最後得到一個一維的陣列,也就是0-9的機率。

調參:全連線的實現也需要卷積核的參與,所以卷積核矩陣也是引數的一部分,調參就包括該部分的引數。

手寫數字識別的模型定義

手寫數字識別的卷積神經網路,下面分析卷積+池化+全連線的過程:

Q&A


選擇損失函式和最佳化器

損失函式功能:衡量訓練結果和實際偏差的函式。數值越大代表差距越大
最佳化器功能:讓模型不斷最佳化,讓損失函式減小的方法

手寫數字識別中使用的損失函式和最佳化器如下:

# 交叉熵損失函式,選擇一種方法計算誤差值
loss_func = torch.nn.CrossEntropyLoss()

# 最佳化器,隨機梯度下降演算法
optimizer = torch.optim.SGD(model.parameters(), lr=0.2)

損失函式

手寫識別中選擇了交叉熵損失函式,pytorch一共有19中損失函式可以使用,比較好理解的是平方差損失函式

最佳化器

手寫識別中選了隨機梯度下降演算法,用來實現反向傳播引數的修改。pytorch中一共有11中最佳化器可以使用。

模型訓練

模型訓練的流程:

  1. 定義訓練的次數
  2. 遍歷訓練集,呼叫模型類傳入圖片,得到機率結果
  3. 透過損失函式計算損失值
  4. 透過最佳化器調整引數
  5. 訓練完成儲存模型
# 定義訓練次數
cnt_epochs = 5 # 訓練5個迴圈

# 迴圈訓練
for cnt in range(cnt_epochs):
    # 把訓練集中的資料訓練一遍
    for imgs, labels in train_dataloader:
        outputs = model(imgs)  # 輸出0~9預測的結果機率
        loss = loss_func(outputs, labels) # 和輸入做一個比較,得到一個誤差
        optimizer.zero_grad()   # 初始化梯度,清空梯度。注意清空最佳化器的梯度,防止累計
        loss.backward()  # 方向傳播計算
        optimizer.step() # 累加1,執行一次

# 儲存訓練的結果(包括模型和引數)
torch.save(model, "my_cnn.nn")

需要注意的點:

  • 訓練的規律
  • my_cnn.nn 模型儲存的內容

Q&A

模型驗證

  • 模型在測試集上的準確率
  • 一批模型準確率展示

總結

  1. 資料集非常重要。html手寫識別中遇到的問題,以及如何解決。顏色,大小
  2. 數學知識。訓練過程中遇到的資料知識:矩陣乘法
  3. 為什麼需要GPU?如何使用GPU?
  4. 模型訓練的過程。卷積 + 池化 + 全連線 + 損失函式 + 最佳化器
  5. 目標檢查的訓練過程和手寫識別有何不同?
    影像分類:LeNet、AlexNet、VGG、GoogLeNet
    目標檢測:RCNN、Fast RCNN、Faster RCNN、YOLO、YOLOv2、SSD

相關文章