PyTorch畳み込みニューラルネットワークの例の詳細な分析-MNISTデータセットを例として取り上げます

PyTorchは、一般的な深層学習ネットワークのステップを構築します

  1. データセットをロードします。
  2. ネットワーク構造モデルを定義します。
  3. 損失関数を定義します。
  4. 最適化アルゴリズムを定義します。
  5. 反復トレーニング
  6. テストセットの検証。
    その中で、トレーニングフェーズは主に4つの部分に分かれています。1:順方向プロセス、入力から出力への結果を計算します。2:結果とラベルから損失関数の値を計算します。3:後方プロセスでは、各変数の勾配が損失から計算されます。4:オプティマイザは勾配に従ってパラメータを更新します。
    以下は、特定のケース分析です。

1.構成ライブラリ

#配置库
import torch
from torch import nn,optim
from torch.autograd import Variable
from torch.utils.data import DataLoader
from torchvision import transforms
from torchvision import datasets
  1. optimはオプティマイザーモジュールであり、特定の最適化アルゴリズム(SGD、Momentum、RMSProp、AdaGrad、Adam)が含まれています。その中で、勢いは加速勾配降下アルゴリズムであり、他の3つは学習率を向上させることです。一般的に使用されるのは、SGDとAdamです。
  2. 変数はテンソルのカプセル化であり、順方向伝搬、逆方向伝搬、および自動導出の計算グラフに入れるために使用されます。これは非常に重要な基本オブジェクトです。データ、卒業生、作成者の3つの重要な属性が含まれています。その中で、データはTensor自体を表し、gradは伝播方向の勾配を表し、creatorはこの変数を作成する関数参照であり、作成リンク全体をバックトラックするために使用されます。ユーザーが作成した変数の場合、作成者はNoneであり、この変数はLeaf変数と呼ばれ、autogradはこの変数にのみグラデーションを割り当てます。
  3. DataLoaderはDatasetがパッケージングクラスであり、データをDatasetクラスにパッケージ化するために使用され、DataLoaderに渡されます。次に、このクラスのDataLoaderを使用して、データをより迅速に操作します。
    具体的には、データセットは、処理と参照を容易にするために特定の形式にパッケージ化されています。
  4. torchvision.transformsは、pytorchの画像前処理モジュールであり、画像データを変換するための多くの関数が含まれています。これらはすべて、画像データの読み取りステップで必要です。
  5. 名前が示すように、データセットは一連のデータセットであり、MNISTなどのデータセットは対応するコマンドを介してロードできます。

2.ハイパーパラメータを構成します

#配置参数
torch.manual_seed(1)
batch_size = 128    #批处理大小
learning_rate = 1e-2
num_epocher = 10    #训练次数
  1. torch.manual_seed()は、プログラム番号の再現性を確保し、テストを容易にするために、ランダム番号シードを設定します。
  2. batch_sizeは、バッチサイズ(バッチサイズ)、つまり、毎回処理されるデータの量です。反復回数=サンプルの総数/バッチサイズ。特定の範囲内では、バッチサイズが大きいほど、完全なデータセット(1エポック)を実行するために必要な反復回数が少なくなり、データ処理速度が速くなります。しかし、ブラインド増加は、特定の精度に到達するために必要なより長い時間をもたらします。
  3. Learning_rateは学習率です。学習率が小さいほど、各勾配降下のステップが小さくなり、目標の精度を達成するために必要なトレーニング時間が長くなります。ただし、学習速度が大きすぎると、勾配降下が収束せず、学習の目的を達成できなくなります。
  4. num_epocherは、データセットがトレーニングされた回数、つまり、データセットが複数回実行された回数です。

3.データセットをロードします

train_dataset = datasets.MNIST(	#训练集
    root='./data',
    train = True,
    transform=transforms.ToTensor(),
    download=False)

test_dataset = datasets.MNIST(
    root='./data',
    train=False,    #测试集
    transform=transforms.ToTensor())
train_loader = DataLoader(train_dataset,batch_size=batch_size,shuffle=True)
test_loader = DataLoader(test_dataset,batch_size=batch_size,shuffle=False)
  1. MNIST手書き数字データセットをデータセットにロードします。ローカルにダウンロードしたデータセットをロードできます。ルートはデータセットの保存場所です。trainはそれがトレーニングセットであるかどうかを示します。transform.ToTensor()はデータセットのデータを正規化し、値[0,255]のImageを[0,1.0]のTensorデータに変換して正規化します。変更により、勾配降下アルゴリズムの収束速度を向上させることができます。downlaodは、データセットをオンラインでダウンロードする必要があるかどうかを表し、ローカルではない場合はTrueである必要があります。
  2. テストセットをロードします。パラメータ設定はトレーニングセットと同様です。
  3. 前のセクションで説明したように、DataLoaderはデータをパックし、データをすばやく処理するために使用されます。シャッフルパラメータは、順序をシャッフルするかどうかです。トレーニングセットは、オーバーフィットを防ぐためにデータの順序をシャッフルする必要があります。

4.畳み込みネットワーク構造モデルを定義します(フォーカス)

#定义卷积神经网络模型
class Cnn(nn.Module):
    def __init__(self,in_dim,n_class):
        super(Cnn,self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(in_dim,6,3,stride=1,padding=1),   #28x28
            nn.ReLU(True),
            nn.MaxPool2d(2,2),  #14x14,池化层减小尺寸
            nn.Conv2d(6,16,5,stride=1,padding=0),   #10x10x16
            nn.ReLU(True),
            nn.MaxPool2d(2,2)   #5x5x16
         )
        self.fc = nn.Sequential(
            nn.Linear(400,120), #400=5*5*16
            nn.Linear(120,84),
            nn.Linear(84,n_class)
        )
    def forward(self,x):
        out = self.conv(x)
        out = out.view(out.size(0),400)
        out = self.fc(out)
        return out

model = Cnn(1,10)   #图片大小28*28,10为数据种类
#打印模型
print(model)
  1. nn.Moudleは、ネットワークの各レイヤーの定義やforword関数の定義など、非常に重要なクラスです。すべてのカスタムネットワーク構造モデルは、Moudleクラスを継承する必要があります。
"""
自定义网络结构:
    需要继承nn.Module类,并实现forward方法。
    一般把网络中具有可学习参数的层放在构造函数__init__()中,
    不具有可学习参数的层(如ReLU)可放在构造函数中,也可不放在构造函数中(而在forward中使用nn.functional来代替)
    
    只要在nn.Module的子类中定义了forward函数,backward函数就会被自动实现,而不需要像forword那样需要重新定义。
"""
  1. スーパークラスの役割は、スーパーを含む各基本クラスの__init__関数を継承時に呼び出すことです。スーパーを使用しない場合、明示的に宣言しない限り、これらのクラスの__init__関数は呼び出されません。また、superを使用すると、基本クラスが繰り返し呼び出されるのを防ぐことができます。
  2. nn.sequentialの正式な解釈は順序付きコンテナです。ニューラルネットワークモジュールは、入力コンストラクタの順序で実行するために計算グラフに追加されます。同時に、要素としてニューラルネットワークモジュールを含む順序付き辞書を入力として使用することもできます。パラメータ。ここでの役割は、ニューラルネットワーク構造を構築することです。
  3. nn.Conv2dは、畳み込みニューラルネットワークの畳み込みレイヤー関数です。デフォルトのパラメーターは次のとおりです
    。nn.Conv2d(self、in_channels、out_channels、kernel_size、stride = 1、padding = 0、dilation = 1、groups = 1、bias = True ))
    プログラムのパラメータの説明:
      in_channel:入力データチャネル番号、RGB画像チャネル番号は3、白黒画像チャネル番号1、MNISTデータセットは白黒画像であるため、パラメータは1です
      。out_channel:出力データチャネル番号、別名抽出されたフィーチャの数に関連するコンボリューションカーネルの数です。ここでは6です
      。kennel_size:コンボリューションカーネルのサイズです。これはコンボリューションカーネルのサイズです。3* 3です。
      ストライド:ステップサイズ、デフォルトは1です。
      パディング:パディングの数です。出力サイズを変更せずに、ここで1を取ります。
    畳み込み層の出力サイズを計算するための式は次のとおりです。

したがって、1×28×28の入力が畳み込み層を通過した後、出力は6×28×28になります(6は出力チャネルの数、つまり深さです)。次の図に示すように、畳み込み演算の出力値の計算については、ここでは詳しく説明しません。

  1. nn.Reluはアクティベーション機能であり、計算量を減らし、オーバーフィットを軽減する効果があります。分析式は次のとおりです。

  2. nn.MaxPool2dは、畳み込みニューラルネットワークのプーリングレイヤーであり、ダウンサンプリングして計算量を減らす機能があります。ここでは最大プーリングレイヤーが使用され、コンボリューションカーネルのサイズは2 * 2、ステップサイズは2です。プーリング層の出力サイズの計算方法は、
    W:画像幅、H:画像高さ、D:画像深度(チャネル数)
    F:畳み込みカーネルの幅と高さ、S:ステップサイズ
    です。プーリング後の出力画像サイズ:
    W =(WF )/ S + 1
    H =(HF)/ S + 1
    画像チャンネル数(深度)出力は変更されません。
    したがって、プログラムのプーリングレイヤーの後、画像サイズは6×14×14になり、計算量が削減されていることがわかります。
    2つのプーリング操作の出力値は、次の図に示すように計算されます。最大プーリングは、ウィンドウ内の最大の機能を取得して保持することです。

  3. 2回の畳み込みとプーリング操作の後、画像の最終的な出力サイズは16×5×5の3次元配列になります。次は完全に接続されたレイヤー(nn.liner)です。以前は3次元構造の特徴データであり、ライナーレイヤーがそれを統合していました。
    完全に接続されたレイヤーの各ノードは、前のレイヤーのすべてのノードに接続され、前面から抽出された特徴を統合するために使用されます。完全に接続された特性により、通常、完全に接続されたレイヤーのパラメーターも最も多くなります。
    プログラムでは、前のセクションで合計16×5×5ノードが渡されたため、入力は400です。手書きの番号は10のカテゴリに分割する必要があるため、最終的な出力ノード番号は10です。

  4. forward関数は、データストリームを転送する転送伝播に使用されます。フォワード関数が定義された後、バックプロパゲーション関数backward()は、フォワードプロパゲーションのように明示的に定義されるのではなく、自動的に定義されます。直接呼び出すことができます。

  5. model = Cnn(1,10)パラメータをモデルに渡し、名前を付けます。

5.モデルトレーニング

#模型训练
#定义loss和optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(),lr=learning_rate)
#开始训练
for epoch in range(num_epocher):
    running_loss = 0.0
    running_acc = 0.0
    for i,data in enumerate(train_loader,1):
        img,label = data
        img = Variable(img)
        label = Variable(label)
        #前向传播
        out = model(img)
        #print(out)
        loss = criterion(out,label) #loss
        running_loss += loss.item() * label.size(0)
        #total loss ,由于loss是取batch均值的,因此,需要把batch size成回去
        _,pred = torch.max(out,1)   #预测结果
        num_correct = (pred == label).sum() #正确结果的数量
        #accuracy = (pred == label).float().mean()   #正确率
        running_acc += num_correct.item()   #正确结果的总数
        #后向传播
        optimizer.zero_grad()   #梯度清零
        loss.backward() #后向传播计算梯度
        optimizer.step()    #利用梯度更新W,b参数
    #打印一个循环后,训练集合上的loss和正确率
    print('Train{} epoch, Loss: {:.6f},Acc: {:.6f}'.format(epoch+1,running_loss / (len(train_dataset)),running_acc / (len(train_dataset))))
  1. nn.CrossEntropyLossは、損失の計算に使用されるクロスエントロピー損失関数です。
  2. SGD機能はオプティマイザーです。その主な機能は、ニューラルネットワークを最適化して、トレーニングプロセスを高速化し、時間を節約することです。model.parameters()は、ニューラルネットワークのパラメーターを取得するために使用されます。
  3. enumerate()は、pythonの組み込み関数であり、トラバース可能なデータオブジェクト(リスト、タプル、文字列など)をインデックスシーケンスに結合し、データとデータの添え字を同時に一覧表示するために使用されます。
    enumerate(a、start)
    aは反復可能なオブジェクト、startはカウントの開始数、プログラムは1から開始してトレーニングセットをトラバースします。
  4. 最初のセクションで説明した変数は、テンソルのカプセル化です。これは、順方向伝搬、逆方向伝搬、および自動導出の計算グラフに入れるために使用されます。ここでは、imgとlabelがカプセル化されています。
  5. out = model(img)は、順方向伝搬のためにデータをモデルに渡します。
  6. 損失= criteria(out、label)ここでは、計算結果をラベルと比較して損失を計算します。
  7. running_loss + = loss.item()* label.size(0)ここで、損失は累積され、エポック全体の損失を計算するための平均として残されます。複数の次元の場合、損失は複数の次元の平均値であるため、最初に次元の数を掛ける必要があります。
  8. torch.max(a、1)は、各行で最大値を持つ要素を返し、そのインデックスを返します(この行で最大の要素の列インデックスを返します)。ここで、predは返される予測結果です。
  9. num_correct =(pred == label).sum()、正しい結果の数を見つけます(予測結果と同じ)。
  10. running_acc + = num_correct.item()正しい結果の総数を見つけます。
  11. オプティマイザー.zero_grad()、前面に蓄積された勾配をクリアして、背面での後方伝搬を容易にします。
  12. loss.backward()、逆伝播。
  13. オプティマイザー.step()は、逆伝播を使用してネットワークモデルの内部重みを更新し、それによってモデルの損失を減らします。
  14. 最後に、エポックを印刷した後、トレーニングセットの損失と正確さ

6.テストセット内のテストモデルの認識率

#模型测试
model.eval()    #需要说明是否模型测试
eval_loss = 0
eval_acc = 0
for data in test_loader:
    img,label = data
    img = Variable(img,volatile=True)   #改用with torch.no_grad()但还不会:这里的volatile在新的版本被移除了
    #volatile用于测试是否不调用backward
    #测试中不需要label= Variable...
    out = model(img)    #前向算法
    loss = criterion(out,label) #计算loss
    eval_loss += loss.item() * label.size(0)    #total loss
    _,pred = torch.max(out,1)   #预测结果
    num_correct = (pred == label).sum() #正确结果
    eval_acc += num_correct.item()  #正确结果总数

print('Test Loss:{:.6f},Acc: {:.6f}'
      .format(eval_loss/ (len(test_dataset)),eval_acc * 1.0/(len(test_dataset))))
  1. model.eval()、モデルをテストモードにします。モデルmodel.eval()は、バイアスパラメータが変更されないようにBNレイヤーとドロップアウトレイヤーを修正するために使用されます。ただし、これら2つの操作はこのプログラムでは使用されません。
  2. 手順の次の部分はトレーニングセットに似ているので、繰り返しません。

7.実行結果

Cnn(
(conv):Sequential(
(0):Conv2d(1、6、kernel_size =(3、3)、stride =(1、1)、padding =(1、1))
(1):ReLU(inplace = True)
(2):MaxPool2d(kernel_size = 2、stride = 2、padding = 0、dilation = 1、ceil_mode = False)
(3):Conv2d(6、16、kernel_size =(5、5)、stride =(1 、1))
(4):ReLU(inplace = True)
(5):MaxPool2d(kernel_size = 2、stride = 2、padding = 0、dilation = 1、ceil_mode = False)

(fc):Sequential(
(0) :Linear(in_features = 400、out_features = 120、bias = True)
(1):Linear(in_features = 120、out_features = 84、bias = True)
(2):Linear(in_features = 84、out_features = 10、bias = True )


Train1エポック、損失:2.285776、Acc:0.221550
Train2エポック、損失:1.370810、Acc:0.636100
Train3エポック、損失:0.411640、Acc:0.878833
Train4エポック、損失:0.294587、Acc:0.912050
Train5エポック、損失:0.231720、Acc:0.930100
Train6エポック、損失:0.188466、Acc:0.942800
Train7エポック、損失:0.158935、Acc:0.952733
Train8エポック、損失:0.139243、Acc:0.958150
Train9エポック、損失:0.125945、Acc:0.961917
Train10エポック、損失:0.115717、Acc:0.965000
E:/Pycharm/project/project_pytorch/.idea/Conv_complete.py:94:ユーザー警告: volatileは削除され、現在は効果がありません。with torch.no_grad():代わりに使用してください
。img= Variable(img、volatile = True)#torch.no_grad()で使用しますが、まだ使用していません
。 0.101987、Acc:0.967800

おすすめ

転載: blog.csdn.net/weixin_45371989/article/details/103922630