深層学習: 畳み込みニューラル ネットワーク CNN を使用した MNIST 手書き数字認識

導入

このプロジェクトは、pytorch に基づいて深層学習ニューラル ネットワークを構築します。ネットワークには、畳み込み層、プーリング層、全結合層が含まれます。このネットワークを通じて、MINST データセット内の手書き数字の認識が実現されます。このコードを通じてプロジェクトでは、手書きの数字は原理的に理解でき、逆伝播、勾配降下法などを含む認識プロセス全体が可能です。

1 畳み込みニューラル ネットワークの概要

1.1 畳み込みニューラル ネットワークとは

畳み込みニューラル ネットワークは、多層のフィードフォワード ニューラル ネットワークです。機能的には、特徴抽出段階と分類認識段階の 2 つの段階に分けることができます。

特徴抽出ステージでは、分類の基礎となる入力データの特徴を自動的に抽出でき、複数の特徴層を積み重ねて構成され、各特徴層は畳み込み層とプーリング層で構成されます。前面のフィーチャ レイヤーは画像内の局所的な詳細情報をキャプチャし、背面のフィーチャ レイヤーは画像内のより高いレベルの抽象的な情報をキャプチャできます。

1.1.1 コンボリューションカーネル

畳み込みニューラル ネットワークの畳み込み層では、ニューロンは隣接する層の一部のニューロンにのみ接続されます。CNN の畳み込み層には通常、複数の特徴マップ (featureMap) が含まれており、各特徴マップは長方形に配置されたいくつかのニューロンで構成され、同じ特徴マップのニューロンは重みを共有し、ここでの共有重みはボリュームです。 。畳み込みカーネルは通常、ランダム 10 進行列の形式で初期化され、畳み込みカーネルはネットワークのトレーニング プロセス中に適切な重みを取得することを学習します。重み (畳み込みカーネル) を共有することの直接的な利点は、過学習のリスクを軽減しながら、ネットワークの層間の接続を減らすことです。

1.1.2受容

定義:畳み込みニューラルネットワークでは、畳み込みニューラルネットワークの各層が出力する特徴マップ(特徴マップ)上の画素点が入力画像上の領域サイズをマッピングします。一般的な CNN 構造では、FC 層の各出力ノードの値は FC 層のすべての入力に依存しますが、CONV 層の各出力ノードの値は CONV の入力の領域にのみ依存します。この領域の外側の他の入力値は出力値に影響を与えず、この領域は受容野です。次の図は、受容野の模式図です。

 

異なるサイズのコンボリューション カーネルを使用する場合、最大の違いは受容野のサイズが異なることです。そのため、多くの場合、大きなコンボリューション カーネルの層を小さなコンボリューション カーネルの複数の層で置き換え、受容野を維持しながらパラメータを削減します。ボリュームも計算も同じです。たとえば、5*5 コンボリューション カーネルの層を 2 つの 3*3 コンボリューション カーネルの層で置き換えることは非常に一般的です。

 1.3 標準化(バッチ正規化)

BN の導入前、以前のモデルのトレーニングには体系的な問題がいくつかあり、特にシグモイド活性化関数を使用する場合、多くのアルゴリズムの収束が非常に遅くなったり、まったく機能しなくなったりすることがありました。機械学習では、通常、入力特徴を標準化または正規化します。これは、直接入力されたデータの各次元の次元が異なる可能性があり、値が大きく異なる可能性があり、その結果、モデルが各特徴からうまく学習できなくなる可能性があるためです。 。前層の出力値が大きすぎたり小さすぎたりすると、シグモイド活性化関数を通過する際に飽和領域に陥ってしまい、バックプロパゲーションでは勾配が消失するという問題が発生します。
バッチ正規化: データの小さなバッチ (バッチ) を標準化します。データを平均 0、標準偏差 1 の分布に当てはめます。

バッチ正規化層は通常、各ニューラル ネットワーク層とアクティベーション層の間に追加され、ニューラル ネットワーク層によって出力されたデータ分布を統合して調整し、平均 0、分散 1 の標準正規分布に変換します。ニューラルネットワークにおける勾配消失の問題を解決し、出力を活性化層の不飽和領域にする問題により、収束を高速化する効果が得られます。

1.1.4 プーリング層(Pooling)

プーリングは、ニューラル ネットワーク内の特徴マップ (Feature Map) の次元を削減するために使用されます。畳み込みニューラル ネットワークでは、通常、プーリング操作の後に畳み込み操作を実行して、特徴マップの空間サイズを削減します。プーリング操作の基本的な考え方は、特徴マップをいくつかのサブ領域 (通常は長方形) に分割し、各サブ領域に対して統計的な要約を実行することです。プーリングには通常、平均プーリングと最大プーリングの 2 つの形式があります。プーリングは特別な畳み込みプロセスとみなすことができます。畳み込みとプーリングにより、モデルの複雑さが大幅に簡素化され、モデルのパラメーターが削減されます。

  • 最大プーリングで画像テクスチャを抽出可能
  • 平均プーリングによりバックグラウンド機能が保持される

 

1.2 コンボリューションの計算過程

5*5*1 の画像を入力するとします。中央の 3*3*1 は、元の入力画像とコンボリューションを通じて定義したコンボリューション カーネルです (簡単に言えば、行列演算子とみなすことができます)。緑色の部分の結果はコアの操作で得られますが、どのような操作ですか? これは実際には非常に単純です。左の図の暗い部分に注目してください。中央の数字は画像のピクセル、右下隅の数字はコンボリューション カーネルの数です。単純に乗算して加算するだけです。対応する数値を入力して結果を取得します。たとえば、図の「3*0+1*1+2*​​2+2*2+0*2+0*0+2*0+0*1+0*2=9」

計算プロセスは次のとおりです。

 図の左端の 3 つの入力行列は、3 つのチャネル マップがある場合の等価入力 d=3 です。各チャネル マップには、独自のチャネルに属する畳み込みカーネルがあります。出力 (出力) が 2 つだけであることがわかります。特徴マップは、出力 d=2 を設定し、複数の出力チャネルを持つ畳み込みカーネルの層が複数あることを意味します (たとえば、図には FilterW0 と FilterW1 があります)。これは、畳み込みカーネルの数が入力数 d と出力数 d を掛けた数 (図では 2*3=6)。ここで、チャネル マップの各層の計算は、上記の層の計算と同じであり、次に、各チャンネルの出力 出力 緑色の出力番号です。

ステップ サイズ: コンボリューション カーネルの各動作のサイズ

出力特徴量の計算: ニューラル ネットワークにおける畳み込み計算の全体プロセスを理解した後、出力特徴量マップのサイズを計算できます。以下の図に示すように、3×3 サイズのコンボリューション カーネルを使用したコンボリューション計算後の 5×5 画像の出力特徴サイズは 3×3 になります。

ゼロパディング

コンボリューション カーネル サイズが 1 より大きい場合、出力特徴マップのサイズは入力画像のサイズより小さくなります。複数の畳み込みの後、出力画像サイズは減少し続けます。畳み込み後の画像サイズが小さくなるのを避けるために、通常は次の図に示すように画像の周囲にパディングが実行されます。

全ゼロ埋め込み (パディング): 出力画像のサイズを入力画像と一致させるために、以下に示すように、入力画像の周囲にすべてゼロ埋め込みが実行されることがよくあります。5×5 の入力画像の周囲に 0 を埋め込むと、出力はフィーチャーサイズも5×5です。

 

以下の図に示すように、padding=1 および paadding=2 の場合:

2 CNN を使用して MNIST 手書き数字認識を実現する

機械画像認識のプロセス: 機械画像認識は、複雑な画像を一度に完全に認識するのではなく、画像全体を多くの小さな部分に分割し、各小さな部分の特徴を抽出し、その後、これらの小さな部分の特徴を合計して、機械による画像全体の認識が完了します。

2.1 MNIST データの概要

MNIST データセットは、国立標準技術研究所によって収集された手書き数字の大規模なデータベースで、60,000 例のトレーニング セットと 10,000 例のテスト セットが含まれています。画像サイズは28*28です。サンプリングされたデータは次のように表示されます。

2.2 pytorchに基づくコード実装

import torch
import torch.nn as nn
import torchvision.datasets as dataset
import torchvision.transforms as transforms
import torch.utils.data as data_utils
import matplotlib.pyplot as plt
import numpy as np


#获取数据集
train_data=dataset.MNIST(root="./data",
                         train=True,
                         transform=transforms.ToTensor(),
                         download=True
                         )
test_data=dataset.MNIST(root="./data",
                         train=False,
                         transform=transforms.ToTensor(),
                         download=False
                         )
train_loader=data_utils.DataLoader(dataset=train_data, batch_size=64, shuffle=True)
test_loader=data_utils.DataLoader(dataset=test_data, batch_size=64, shuffle=True)

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

#创建网络
class Net(torch.nn.Module):
   def __init__(self):
        super().__init__()
        self.conv=nn.Conv2d(1, 32, kernel_size=5, padding=2)
        self.bat2d=nn.BatchNorm2d(32)
        self.relu=nn.ReLU()
        self.pool=nn.MaxPool2d(2)
        self.linear=nn.Linear(14 * 14 * 32, 70)
        self.tanh=nn.Tanh()
        self.linear1=nn.Linear(70,30)
        self.linear2=nn.Linear(30, 10)
   def forward(self,x):
        y=self.conv(x)
        y=self.bat2d(y)
        y=self.relu(y)
        y=self.pool(y)
        y=y.view(y.size()[0],-1)
        y=self.linear(y)
        y=self.tanh(y)
        y=self.linear1(y)
        y=self.tanh(y)
        y=self.linear2(y)
        return y
cnn=Net()
cnn = cnn.to(device)

#损失函数
los=torch.nn.CrossEntropyLoss()

#优化函数
optime=torch.optim.Adam(cnn.parameters(), lr=0.001)

#训练模型
accuracy_rate = [0]
num_epochs = 10
for epo in range(num_epochs):
    for i, (images,lab) in enumerate(train_loader):
        images=images.to(device)
        lab=lab.to(device)
        out = cnn(images)
        loss=los(out,lab)
        optime.zero_grad()
        loss.backward()
        optime.step()
    print("epo:{},i:{},loss:{}".format(epo+1,i,loss))

    #测试模型
    loss_test=0
    accuracy=0
    with torch.no_grad():
        for j, (images_test,lab_test) in enumerate(test_loader):
            images_test = images_test.to(device)
            lab_test=lab_test.to(device)
            out1 = cnn(images_test)
            loss_test+=los(out1,lab_test)
            loss_test=loss_test/(len(test_data)//100)
            _,p=out1.max(1)
            accuracy += (p==lab_test).sum().item()

        accuracy=accuracy/len(test_data)
        accuracy_rate.append(accuracy)
        print("loss_test:{},accuracy:{}".format(loss_test,accuracy))


accuracy_rate = np.array(accuracy_rate)
times = np.linspace(0, num_epochs, num_epochs+1)
plt.xlabel('times')
plt.ylabel('accuracy rate')
plt.plot(times, accuracy_rate)
plt.show()

操作結果:

epo:1,i:937,loss:0.2277517020702362
loss_test:0.0017883364344015718,accuracy:0.9729
epo:2,i:937,loss:0.01490325853228569
loss_test:9.064914047485217e-05,accuracy:0.9773
epo:3,i:937,loss:0.0903361514210701
loss_test:0.0003304268466308713,accuracy:0.9791
epo:4,i:937,loss:0.003910894505679607
loss_test:0.00019427068764343858,accuracy:0.9845
epo:5,i:937,loss:0.011963552795350552
loss_test:3.232352901250124e-05,accuracy:0.983
epo:6,i:937,loss:0.04549657553434372
loss_test:0.0001462855434510857,accuracy:0.9859
epo:7,i:937,loss:0.02365218661725521
loss_test:3.670657861221116e-06,accuracy:0.9867
epo:8,i:937,loss:0.00040980291669256985
loss_test:1.4913265658833552e-05,accuracy:0.9872
epo:9,i:937,loss:0.024399513378739357
loss_test:7.590289897052571e-05,accuracy:0.9865
epo:10,i:937,loss:0.0012365489965304732
loss_test:0.00014759502664674073,accuracy:0.9869

 

 

3 まとめ

この記事では、畳み込みカーネル、プーリング、標準化、受容野などを含む畳み込みニューラル ネットワークの主要な概念を紹介し、MNIST データセットに基づいて畳み込みニューラル ネットワーク認識モデルを構築します。10 エポックのトレーニング後、精度率は次のとおりです。 98% で、画像認識における畳み込みニューラル ネットワークの役割を十分に実証しています。

おすすめ

転載: blog.csdn.net/lsb2002/article/details/132124598