PyTorchの概要:手書き数字を認識するためのニューラルネットワークを構築する
著者は、 Write for DOnations プログラムの一環として、 Code2040を選択して寄付を受け取りました。
序章
機械学習は、データのパターンを見つけるコンピューターサイエンスの分野です。 2021年の時点で、機械学習の実践者はこれらのパターンを使用して、自動運転車の車線を検出します。 ルービックキューブを解くためにロボットの手を訓練します。 または疑わしい芸術的嗜好の画像を生成します。 機械学習モデルの精度とパフォーマンスが向上するにつれて、主流のアプリケーションや製品での採用が増えると見られます。
ディープラーニングは、ニューラルネットワークと呼ばれる、特に複雑なモデルに焦点を当てた機械学習のサブセットです。 後の高度なDigitalOcean記事( Atariボットの構築に関するこのチュートリアルなど)では、「複雑」の意味を正式に定義します。 ニューラルネットワークは、非常に正確で誇大広告を誘発する現代のモデルであり、幅広いタスクに対応しています。 このチュートリアルでは、オブジェクト認識または画像分類と呼ばれる1つの特定のタスクに焦点を当てます。 手書きの数字の画像が与えられると、モデルはどの数字が表示されるかを予測します。
ディープラーニングのためにFacebookAI Researchによって開発されたフレームワークであるPyTorchで、ディープニューラルネットワークを構築、トレーニング、評価します。 Tensorflowなどの他のディープラーニングフレームワークと比較すると、PyTorchは、構築プロセスを支援するデバッグ機能を備えた初心者向けのフレームワークです。 また、FacebookやTeslaなどの企業全体で研究者や実務家が使用しているため、上級ユーザー向けに高度にカスタマイズできます。 このチュートリアルを終了すると、次のことができるようになります。
- PyTorchでディープニューラルネットワークを構築、トレーニング、評価します
- ディープラーニングを適用するリスクを理解する
このチュートリアルに従うために、実践的なディープラーニングやPyTorchの経験は必要ありませんが、トレーニングとテスト、機能とラベル、最適化、評価などの機械学習の用語と概念にある程度精通していることを前提としています。 これらの概念の詳細については、機械学習の概要をご覧ください。
前提条件
このチュートリアルを完了するには、少なくとも1GBのRAMを備えたPython3のローカル開発環境が必要です。 Python 3のローカルプログラミング環境をインストールおよびセットアップする方法に従って、必要なものをすべて構成できます。
ステップ1—プロジェクトの作成と依存関係のインストール
このプロジェクトのワークスペースを作成し、必要な依存関係をインストールしましょう。 ワークスペースをpytorch
と呼びます。
mkdir ~/pytorch
pytorch
ディレクトリに移動します。
cd ~/pytorch
次に、プロジェクトの新しい仮想環境を作成します。
python3 -m venv pytorch
環境をアクティブ化します。
source pytorch/bin/activate
次に、PyTorchをインストールします。 macOSでは、次のコマンドを使用してPyTorchをインストールします。
python -m pip install torch==1.4.0 torchvision==0.5.0
LinuxおよびWindowsでは、CPUのみのビルドに次のコマンドを使用します。
pip install torch==1.4.0+cpu torchvision==0.5.0+cpu -f https://download.pytorch.org/whl/torch_stable.html pip install torchvision
依存関係をインストールしたら、最初のニューラルネットワークを構築します。
ステップ2—「HelloWorld」ニューラルネットワークの構築
このステップでは、最初のニューラルネットワークを構築してトレーニングします。 Pytorchの2つのサブライブラリ、ニューラルネットワーク操作用のtorch.nn
とニューラルネットワークオプティマイザー用のtorch.optim
について学習します。 「オプティマイザー」とは何かを理解するために、勾配降下法と呼ばれるアルゴリズムについても学習します。 このチュートリアル全体を通して、次の5つのステップを使用してモデルを構築およびトレーニングします。
- 計算グラフを作成する
- オプティマイザを設定する
- 基準を設定する
- データを設定する
- モデルをトレーニングする
チュートリアルのこの最初のセクションでは、管理可能なデータセットを使用して小さなモデルを構築します。 nano
またはお気に入りのテキストエディタを使用して、新しいファイルstep_2_helloworld.py
を作成することから始めます。
nano step_2_helloworld.py
次に、小さなモデルをトレーニングする短い18行のスニペットを作成します。 いくつかのPyTorchユーティリティをインポートすることから始めます。
step_2_helloworld.py
import torch import torch.nn as nn import torch.optim as optim
ここでは、PyTorchライブラリをいくつかの一般的に使用されるショートカットにエイリアスします。
torch
には、すべてのPyTorchユーティリティが含まれています。 ただし、ルーチンのPyTorchコードには、いくつかの追加のインポートが含まれています。 PyTorchチュートリアルとランダムなコードスニペットをオンラインで理解できるように、ここでも同じ規則に従います。torch.nn
には、ニューラルネットワークを構築するためのユーティリティが含まれています。 これはしばしばnn
と呼ばれます。torch.optim
にはトレーニングユーティリティが含まれています。 これはしばしばoptim
と呼ばれます。
次に、ニューラルネットワーク、トレーニングユーティリティ、およびデータセットを定義します。
step_2_helloworld.py
. . . net = nn.Linear(1, 1) # 1. Build a computation graph (a line!) optimizer = optim.SGD(net.parameters(), lr=0.1) # 2. Setup optimizers criterion = nn.MSELoss() # 3. Setup criterion x, target = torch.randn((1,)), torch.tensor([0.]) # 4. Setup data . . .
ここでは、ディープラーニングトレーニングスクリプトのいくつかの必要な部分を定義します。
net = ...
は「ニューラルネットワーク」を定義します。 この場合、モデルはy = m * x
の形式の行です。 パラメータnn.Linear(1, 1)
は、線の傾きです。 このモデルパラメータnn.Linear(1, 1)
は、トレーニング中に更新されます。torch.nn
(nn
とも呼ばれる)には、ここで使用される完全接続層(nn.Linear
)や畳み込み層(nn.Conv2d
)など、多くの深層学習操作が含まれることに注意してください。 。optimizer = ...
はオプティマイザーを定義します。 このオプティマイザーは、ニューラルネットワークがどのように学習するかを決定します。 さらに数行のコードを記述した後、オプティマイザーについて詳しく説明します。torch.optim
(optim
とも呼ばれます)には、使用できるそのようなオプティマイザーが多数含まれていることに注意してください。criterion = ...
は損失を定義します。 つまり、損失は、モデルが最小化しようとしている何を定義します。 ラインの基本モデルの目標は、ラインの予測されたy値とトレーニングセット内の実際のy値との差を最小限に抑えることです。torch.nn
(nn
とも呼ばれる)には、使用できる他の多くの損失関数が含まれていることに注意してください。x, target = ...
は「データセット」を定義します。 現在、データセットは1つの座標(1つのx値と1つのy値)にすぎません。 この場合、torch
パッケージ自体は、新しいテンソルを作成するための tensor と、ランダムな値を持つテンソルを作成するためのrandn
を提供します。
最後に、データセットを10回反復して、モデルをトレーニングします。 毎回、モデルのパラメーターを調整します。
step_2_helloworld.py
. . . # 5. Train the model for i in range(10): output = net(x) loss = criterion(output, target) print(round(loss.item(), 2)) net.zero_grad() loss.backward() optimizer.step()
一般的な目標は、線の傾きを調整することにより、損失を最小限に抑えることです。 これを実現するために、このトレーニングコードは勾配降下法と呼ばれるアルゴリズムを実装します。 最急降下法の直感は次のとおりです。ボウルを真っ直ぐ見下ろしていると想像してください。 ボウルには多くのポイントがあり、各ポイントは異なるパラメータ値に対応しています。 ボウル自体が損失面です。ボウルの中心(最低点)は、損失が最小の最良のモデルを示します。 これがoptimumです。 ボウルのフリンジ(最も高いポイント、およびボウルの最も近い部分)は、最も損失が大きい最悪のモデルを保持します。
損失が最小の最良のモデルを見つけるには:
net = nn.Linear(1, 1)
を使用して、ランダムモデルを初期化します。 これは、ボウルのランダムなポイントを選択するのと同じです。for i in range(10)
ループで、トレーニングを開始します。 これは、ボウルの中心に近づくのと同じです。- 各ステップの方向は、勾配によって与えられます。 ここでは正式な証明をスキップしますが、要約すると、負の勾配はボウルの最低点を指します。
optimizer = ...
のlr=0.1
で、ステップサイズを指定します。 これにより、各ステップの大きさが決まります。
わずか10ステップで、ボウルの中心に到達します。これは、可能な限り損失が少なく、可能な限り最高のモデルです。 最急降下法の視覚化については、ページ上部のDistillの「WhyMomentumReallyWorks」の最初の図を参照してください。
このコードの最後の3行も重要です。
net.zero_grad
は、前のステップで残った可能性のあるすべてのグラデーションをクリアします。loss.backward
は新しい勾配を計算します。optimizer.step
は、これらのグラデーションを使用して手順を実行します。 自分で勾配を計算していないことに注意してください。 これは、PyTorchやその他のディープラーニングライブラリが自動的にを区別するためです。
これで、「HelloWorld」ニューラルネットワークは終了です。 ファイルを保存して閉じます。
スクリプトがstep_2_helloworld.pyと一致することを再確認してください。 次に、スクリプトを実行します。
python step_2_helloworld.py
スクリプトは次を出力します。
Output0.33 0.19 0.11 0.07 0.04 0.02 0.01 0.01 0.0 0.0
損失が継続的に減少し、モデルが学習中であることを示していることに注意してください。 PyTorchを使用する場合、注意すべき他の2つの実装の詳細があります。
- PyTorchは
torch.Tensor
を使用してすべてのデータとパラメーターを保持します。 ここで、torch.randn
は、指定された形状のランダムな値を持つテンソルを生成します。 たとえば、torch.randn((1, 2))
は、1x2テンソルまたは2次元の行ベクトルを作成します。 - PyTorchは、さまざまなオプティマイザーをサポートしています。 これは
torch.optim.SGD
、別名確率的勾配降下法(SGD)を特徴としています。 大まかに言えば、これはこのチュートリアルで説明されているアルゴリズムであり、最適化に向けて手順を実行しました。 SGDに加えて機能を追加する、より複雑なオプティマイザーがあります。torch.nn.MSELoss
はそのうちの1つに過ぎず、多くの損失もあります。
これで、おもちゃのデータセットの最初のモデルが完成しました。 次のステップでは、この小さなモデルをニューラルネットワークに置き換え、おもちゃのデータセットを一般的に使用される機械学習ベンチマークに置き換えます。
ステップ3—手書き数字でニューラルネットワークをトレーニングする
前のセクションでは、小さなPyTorchモデルを作成しました。 ただし、PyTorchの利点をよりよく理解するために、より多くのニューラルネットワーク操作を含むtorch.nn.functional
と、使用できる多くのデータセットをサポートするtorchvision.datasets
を使用して、深いニューラルネットワークを構築します。ボックスの。 このセクションでは、 premade データセットを使用して、比較的複雑なカスタムモデルを構築します。
パターンファインダーであるconvolutionsを使用します。 画像の場合、畳み込みはさまざまなレベルの「意味」で2Dパターンを探します。画像に直接適用される畳み込みは、エッジなどの「低レベル」の特徴を探します。 ただし、他の多くの操作の出力に適用される畳み込みは、ドアなどの「より高いレベル」の機能を探している可能性があります。 畳み込みの視覚化とより徹底的なウォークスルーについては、スタンフォードの深層学習コースの一部を参照してください。
次に、少し複雑なモデルを定義して、作成した最初のPyTorchモデルを拡張します。 これで、ニューラルネットワークには、画像入力を処理するための2つの畳み込みと1つの完全に接続されたレイヤーが含まれます。
テキストエディタを使用して、新しいファイルstep_3_mnist.py
を作成することから始めます。
nano step_3_mnist.py
以前と同じ5ステップのアルゴリズムに従います。
- 計算グラフを作成する
- オプティマイザを設定する
- 基準を設定する
- データを設定する
- モデルをトレーニングする
まず、ディープニューラルネットワークを定義します。 これは、MNISTで見つかる可能性のある他のニューラルネットワークの簡略版であることに注意してください。これは意図的なものであるため、ラップトップでニューラルネットワークをトレーニングできます。
step_3_mnist.py
import torch import torch.nn as nn import torch.optim as optim import torch.nn.functional as F from torchvision import datasets, transforms from torch.optim.lr_scheduler import StepLR # 1. Build a computation graph class Net(nn.Module): def __init__(self): super(Net, self).__init__() self.conv1 = nn.Conv2d(1, 32, 3, 1) self.conv2 = nn.Conv2d(32, 64, 3, 1) self.fc = nn.Linear(1024, 10) def forward(self, x): x = F.relu(self.conv1(x)) x = F.relu(self.conv2(x)) x = F.max_pool2d(x, 1) x = torch.flatten(x, 1) x = self.fc(x) output = F.log_softmax(x, dim=1) return output net = Net() . . .
ここでは、nn.Module
から継承するニューラルネットワーククラスを定義します。 ニューラルネットワーク内のすべての操作(ニューラルネットワーク自体を含む)は、nn.Module
から継承する必要があります。 ニューラルネットワーククラスの一般的なパラダイムは次のとおりです。
- コンストラクターで、ネットワークに必要な操作を定義します。 この場合、2つの畳み込みと完全に接続されたレイヤーがあります。 (覚えておくべきヒント:コンストラクターは常に
super().__init__()
で始まります。)PyTorchは、モジュール(nn.Conv2d
など)をインスタンス属性(self.conv1
に割り当てる前に、親クラスが初期化されることを想定しています。 ])。 forward
メソッドで、初期化された操作を実行します。 このメソッドはニューラルネットワークアーキテクチャを決定し、ニューラルネットワークがその予測を計算する方法を明示的に定義します。
このニューラルネットワークは、いくつかの異なる操作を使用します。
nn.Conv2d
:畳み込み。 畳み込みは、画像内のパターンを探します。 初期の畳み込みは、エッジのような「低レベル」のパターンを探します。 ネットワークのその後の畳み込みは、犬の足や耳のような「高レベル」のパターンを探します。nn.Linear
:完全に接続されたレイヤー。 完全に接続されたレイヤーは、すべての入力機能をすべての出力ディメンションに関連付けます。F.relu
、F.max_pool2d
:これらは非線形性のタイプです。 (非線形性とは、線形でない関数のことです。)relu
は関数f(x) = max(x, 0)
です。max_pool
は、値のすべてのパッチで最大値を取ります。 この場合、画像全体で最大値を取ります。log_softmax
:ベクトル内のすべての値を正規化して、値の合計が1になるようにします。
次に、前と同様に、オプティマイザを定義します。 今回は、別のオプティマイザーと別のハイパーパラメーター設定を使用します。 ハイパーパラメータはトレーニングを構成しますが、トレーニングはモデルパラメータを調整します。 これらのハイパーパラメータ設定は、PyTorchMNISTの例から取得されます。
step_3_mnist.py
. . . optimizer = optim.Adadelta(net.parameters(), lr=1.) # 2. Setup optimizer . . .
第三に、以前とは異なり、別の損失を使用するようになります。 この損失は、モデルの出力がクラスインデックスである分類の問題に使用されます。 この特定の例では、モデルは入力画像に含まれる数字(おそらく0から9までの任意の数字)を出力します。
step_3_mnist.py
. . . criterion = nn.NLLLoss() # 3. Setup criterion . . .
第四に、データを設定します。 この場合、手書きの数字を特徴とするMNISTというデータセットを設定します。 ディープラーニング101のチュートリアルでは、このデータセットをよく使用します。 各画像は手書きの数字を含む28x28ピクセルの小さな画像であり、目標は各手書きの数字を0、1、2、…、または9に分類することです。
step_3_mnist.py
. . . # 4. Setup data transform = transforms.Compose([ transforms.Resize((8, 8)), transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) train_dataset = datasets.MNIST( 'data', train=True, download=True, transform=transform) train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=512) . . .
ここでは、transform = ...
で画像のサイズを変更し、画像をPyTorchテンソルに変換し、テンソルを平均0と分散1になるように正規化することにより、画像を前処理します。
次の2行では、train=True
を設定します。これはトレーニングデータセットであり、download=True
を設定して、まだダウンロードしていない場合はデータセットをダウンロードします。
batch_size=512
は、ネットワークが一度にトレーニングされる画像の数を決定します。 途方もなく大きなバッチサイズ(たとえば、数万)を除けば、大まかに高速なトレーニングには、より大きなバッチが望ましいです。
第五に、モデルを訓練します。 次のコードブロックでは、最小限の変更を加えます。 同じサンプルで10回実行する代わりに、提供されたデータセット内のすべてのサンプルを1回繰り返すようになりました。 すべてのサンプルを1回渡すことにより、以下は1つのエポックのトレーニングです。
step_3_mnist.py
. . . # 5. Train the model for inputs, target in train_loader: output = net(inputs) loss = criterion(output, target) print(round(loss.item(), 2)) net.zero_grad() loss.backward() optimizer.step() . . .
ファイルを保存して閉じます。
スクリプトがstep_3_mnist.pyと一致することを再確認してください。 次に、スクリプトを実行します。
python step_3_mnist.py
スクリプトは次を出力します。
Output2.31 2.18 2.03 1.78 1.52 1.35 1.3 1.35 1.07 1.0 ... 0.21 0.2 0.23 0.12 0.12 0.12
最終損失は初期損失値の10% o未満であることに注意してください。 これは、ニューラルネットワークが正しくトレーニングしていることを意味します。
これでトレーニングは終了です。 ただし、0.12の損失について推論するのは困難です。つまり、0.12が「良い」か「悪い」かはわかりません。 モデルのパフォーマンスを評価するには、次にこの分類モデルの精度を計算します。
ステップ4—ニューラルネットワークの評価
以前、データセットのtrain分割で損失値を計算しました。 ただし、データセットの検証分割を個別に保持することをお勧めします。 この検証分割を使用して、モデルの精度を計算します。 ただし、トレーニングには使用できません。 次に、検証データセットを設定し、そのデータセットでモデルを評価します。 このステップでは、MNISTデータセット用のtorchvision.datasets
を含め、以前と同じPyTorchユーティリティを使用します。
step_3_mnist.py
ファイルをstep_4_eval.py
にコピーすることから始めます。 次に、ファイルを開きます。
cp step_3_mnist.py step_4_eval.py nano step_4_eval.py
まず、検証データセットを設定します。
step_4_eval.py
. . . train_loader = ... val_dataset = datasets.MNIST( 'data', train=False, download=True, transform=transform) val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=512) . . .
ファイルの最後で、トレーニングループの後に、検証ループを追加します。
step_4_eval.py
. . . optimizer.step() correct = 0. net.eval() for inputs, target in val_loader: output = net(inputs) _, pred = output.max(1) correct += (pred == target).sum() accuracy = correct / len(val_dataset) * 100. print(f'{accuracy:.2f}% correct')
ここで、検証ループは精度を計算するためにいくつかの操作を実行します。
net.eval()
を実行すると、ニューラルネットワークが評価モードになり、検証の準備ができていることが保証されます。 評価モードでは、トレーニングモードとは異なる方法でいくつかの操作が実行されます。val_loader
のすべての入力とラベルを繰り返し処理します。- モデル
net(inputs)
を実行して、各クラスの確率を取得します。 - 確率が最も高いクラスを見つける
output.max(1)
。output
は、n
サンプルおよびk
クラスの次元(n, k)
のテンソルです。1
は、インデックス1
ディメンションに沿って最大値を計算することを意味します。 - 正しく分類された画像の数を計算する:
pred == target
は、ブール値のベクトルを計算します。.sum()
は、これらのブール値を整数にキャストし、真の値の数を効果的に計算します。 correct / len(val_dataset)
は、最終的に正しく分類された画像の割合を計算します。
ファイルを保存して閉じます。
スクリプトがstep_4_eval.pyと一致することを再確認してください。 次に、スクリプトを実行します。
python step_4_eval.py
スクリプトは次のように出力します。 特定の損失値と最終的な精度は異なる場合があることに注意してください。
Output2.31 2.21 ... 0.14 0.2 89% correct
これで、最初のディープニューラルネットワークのトレーニングが完了しました。 トレーニング用のハイパーパラメータを調整することで、さらに変更や改善を行うことができます。これには、さまざまなエポック数、学習率、さまざまなオプティマイザが含まれます。 調整されたハイパーパラメータを使用したサンプルスクリプトが含まれています。 このスクリプトは、同じニューラルネットワークをトレーニングしますが、10エポックで、97%の精度を取得します。
ディープラーニングのリスク
1つの落とし穴は、ディープラーニングが常に最先端の結果を得るとは限らないということです。 ディープラーニングは、機能が豊富でデータが豊富なシナリオではうまく機能しますが、逆に、データが少ない、機能が少ないレジームではパフォーマンスが低下します。 ディープラーニングの弱点について活発な研究が行われていますが、他の多くの機械学習手法は、決定木、線形回帰、サポートベクターマシン(SVM)などの機能が少ないレジームにすでに適しています。
もう1つの落とし穴は、ディープラーニングが十分に理解されていないことです。 正確性、最適性、さらには収束の保証はありません。 一方、古典的な機械学習手法は十分に研究されており、比較的解釈可能です。 繰り返しになりますが、深層学習におけるこの解釈可能性の欠如に対処するための活発な研究があります。 詳細については、「説明可能なAIが説明できないもの(およびそれを修正する方法)」を参照してください。
最も重要なことは、深層学習における解釈可能性の欠如が見過ごされているバイアスにつながることです。 たとえば、カリフォルニア大学バークレー校の研究者は、キャプションでモデルの性別の偏りを示すことができました(「Womenalso Snowboard」)。 他の研究努力は、機械学習における「公平性」などの社会的問題に焦点を当てています。 これらの問題は活発な研究が行われているため、モデルのバイアスについて所定の診断を推奨することは困難です。 結果として、責任を持ってディープラーニングを適用するのは、実践者であるあなた次第です。
結論
PyTorchは、愛好家や研究者向けのディープラーニングフレームワークです。 PyTorchに精通するために、ディープニューラルネットワークをトレーニングし、ディープラーニングをカスタマイズするためのいくつかのヒントとコツを学びました。
独自に構築する代わりに、事前に構築されたニューラルネットワークアーキテクチャを使用することもできます。 オプションのセクションへのリンクは次のとおりです。GoogleColabで既存のニューラルネットワークアーキテクチャを使用してみてください。 デモンストレーションの目的で、このオプションのステップは、はるかに大きな画像ではるかに大きなモデルをトレーニングします。
他の記事をチェックして、機械学習と関連分野をさらに深く掘り下げてください。
- モデルは十分に複雑ですか? 複雑すぎますか? 偏りと分散の深層強化学習:OpenAIGymを使用してAtariのボットを構築する方法をご覧ください。 この記事では、Atari Games用のAIボットを構築し、強化学習と呼ばれる研究分野を探ります。 または、この偏りと分散のトレードオフについての記事で、偏りと分散のトレードオフの視覚的な説明を見つけてください。
- 機械学習モデルはどのように画像を処理しますか? 詳細については、感情ベースの犬用フィルターの作成をご覧ください。 この記事では、モデルが画像を処理および分類する方法について詳しく説明し、コンピュータービジョンと呼ばれる研究分野を探ります。
- ニューラルネットワークをだますことはできますか? ニューラルネットワークのトリックでその方法を学びましょう。 この記事では、より堅牢な実世界の深層学習の展開のためにニューラルネットワークの攻撃と防御の両方を考案する研究分野である敵対的な機械学習について説明します。
- ニューラルネットワークがどのように機能するかをどのように理解すればよいでしょうか? ニューラルネットワークの視覚化と解釈の方法の「説明可能なAI」と呼ばれるアプローチの1つのクラスをお読みください。 この記事では、説明可能なAIを探求し、特にニューラルネットワークがその予測に重要であると信じているピクセルを視覚化します。