PyTorch 1.8 チュートリアル : PyTorch の学習 : 分類器を訓練する (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 03/22/2021 (1.8.0)
* 本ページは、PyTorch 1.8 Tutorials の以下のページを翻訳した上で適宜、補足説明したものです:
- Learning PyTorch : Training a Classifier
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。
人工知能研究開発支援 | 人工知能研修サービス | テレワーク & オンライン授業を支援 |
PoC(概念実証)を失敗させないための支援 (本支援はセミナーに参加しアンケートに回答した方を対象としています。) |
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ ; Facebook |
PyTorch の学習 : 分類器を訓練する
This is it. 貴方はどのようにニューラルネットワークを定義するか、損失を計算するかそしてネットワークの重みを更新するかを見てきました。
今は次のように考えているかもしれません、
一般に、画像、テキスト、音声あるいは動画データを扱わなければならない時、データを numpy 配列にロードする標準的な python パッケージが使用できます。それからこの配列を torch.*Tensor に変換できます。
- 画像については、Pillow, OpenCV のようなパッケージが有用です。
- 音声については、scipy と librosa のようなパッケージ。
- テキストについては、raw Python や Cython ベースのロード、あるいは NLTK と SpaCy が有用です。
特にビジョンについては、torchvision と呼ばれるパッケージを作成しました、これは ImageNet, CIFAR10, MNIST 等のような一般的なデータセットのデータローダと画像のためのデータ変換器を持ちます、すなわち torchvision.datasets と torch.utils.data.DataLoader です。
これは多大な便利さを供給してボイラープレートなコードを書くことを回避します。
このチュートリアルのためには、CIFAR10 データセットを使用します。それはクラス: ‘飛行機’, ‘自動車’, ‘鳥’, ‘猫’, ‘鹿’, ‘犬’, ‘蛙’, ‘馬’, ‘船’, ‘トラック’ を持ちます。CIFAR-10 の画像はサイズ 3x32x32、i.e. サイズが 32×32 ピクセルの 3-チャネル・カラー画像です。
画像分類器を訓練する
次のステップを順番に行ないます :
- CIFAR10 訓練とテスト・データセットを torchvision を使用してロードして正規化します。
- 畳込みニューラルネットワークを定義します。
- 損失関数を定義します。
- 訓練データ上でネットワークを訓練します。
- テストデータ上でネットワークをテストします。
1. CIFAR10 をロードして正規化する
torchvision を使用すれば、CIFAR10 のロードは非常に簡単です。
import torch
import torchvision
import torchvision.transforms as transforms
torchvision データセットの出力は範囲 [0, 1] の PILImage 画像です。それらを正規化された範囲 [-1, 1] の Tensor に変換します。
Note
Windows 上で実行していて BrokenPipeError を得る場合には、torch.utils.data.DataLoader() の num_worker を 0 に設定してみてください。
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
shuffle=True, num_workers=2)
testset = torchvision.datasets.CIFAR10(root='./data', train=False,
download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4,
shuffle=False, num_workers=2)
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz Extracting ./data/cifar-10-python.tar.gz to ./data Files already downloaded and verified
楽しみのために、訓練画像の幾つかを表示してみましょう。
import matplotlib.pyplot as plt
import numpy as np
# functions to show an image
def imshow(img):
img = img / 2 + 0.5 # unnormalize
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
# get some random training images
dataiter = iter(trainloader)
images, labels = dataiter.next()
# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
dog truck dog frog
2. 畳込みニューラルネットワークを定義する
前のニューラルネットワークのセクションからニューラルネットワークをコピーして (それが定義された 1-チャネル画像の替わりに) それを 3-チャネル画像を取るように変更します。
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(3, 6, 5)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.fc1 = nn.Linear(16 * 5 * 5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, 16 * 5 * 5)
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
net = Net()
3. 損失関数と optimizer を定義する
分類 Cross-Entropy 損失とモメンタムを持つ SGD を使用しましょう。
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
4. ネットワークを訓練する
これが物事が興味深くなり始める時です。データ iterator に渡って単純にループさせて、ネットワークに入力を供給して最適化しなければなりません。
for epoch in range(2): # loop over the dataset multiple times
running_loss = 0.0
for i, data in enumerate(trainloader, 0):
# get the inputs; data is a list of [inputs, labels]
inputs, labels = data
# zero the parameter gradients
optimizer.zero_grad()
# forward + backward + optimize
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
# print statistics
running_loss += loss.item()
if i % 2000 == 1999: # print every 2000 mini-batches
print('[%d, %5d] loss: %.3f' %
(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
print('Finished Training')
[1, 2000] loss: 2.151 [1, 4000] loss: 1.804 [1, 6000] loss: 1.634 [1, 8000] loss: 1.591 [1, 10000] loss: 1.499 [1, 12000] loss: 1.469 [2, 2000] loss: 1.389 [2, 4000] loss: 1.378 [2, 6000] loss: 1.362 [2, 8000] loss: 1.307 [2, 10000] loss: 1.302 [2, 12000] loss: 1.272 Finished Training
訓練されたモデルを素早くセーブしましょう :
PATH = './cifar_net.pth'
torch.save(net.state_dict(), PATH)
PyTorch モデルのセーブについてのより多くの詳細は ここ を見てください。
5. テストデータ上でネットワークをテストする
ネットワークを訓練データセットに渡り 2 パスの間訓練しました。しかしネットワークが何かを学習したかどうかを確認する必要があります。
ニューラルネットワークが出力するクラスラベルを予測して、それを正解に対してチェックすることでこれを確認します。予測が正しければ、サンプルを正解予測のリストに追加します。
オーケー、最初のステップです。馴染むためにテストセットから画像を表示しましょう。
dataiter = iter(testloader)
images, labels = dataiter.next()
# print images
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))
GroundTruth: cat ship ship plane
次に、セーブされたモデルをロードし戻しましょう (note: モデルのセーブと再ロードはここでは必要ありませんでした、それをどのように行なうかを示すためにそれを行なっただけです) :
net = Net()
net.load_state_dict(torch.load(PATH))
オーケー、さてニューラルネットワークがこれらの上のサンプルを何であると考えているかを見てみましょう :
outputs = net(images)
出力は 10 クラスのためのエネルギーです。クラスに対するエネルギーが高いほど、ネットワークは画像が特定のクラスに所属するとより考えています。そこで、最も高いエネルギーのインデックスを取得しましょう :
_, predicted = torch.max(outputs, 1)
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]]
for j in range(4)))
Predicted: cat ship ship plane
結果はかなり良いようです。
ネットワークがデータセット全体の上でどのように上手く遂行するかを見ましょう。
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (
100 * correct / total))
Accuracy of the network on the 10000 test images: 56 %
それはただの偶然よりも良いようです、それは 10 % の精度です (10 クラスから無作為に一つのクラスを選択)。ネットワークは何かを学習したようです。
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
for data in testloader:
images, labels = data
outputs = net(images)
_, predicted = torch.max(outputs, 1)
c = (predicted == labels).squeeze()
for i in range(4):
label = labels[i]
class_correct[label] += c[i].item()
class_total[label] += 1
for i in range(10):
print('Accuracy of %5s : %2d %%' % (
classes[i], 100 * class_correct[i] / class_total[i]))
Accuracy of plane : 63 % Accuracy of car : 62 % Accuracy of bird : 37 % Accuracy of cat : 34 % Accuracy of deer : 49 % Accuracy of dog : 60 % Accuracy of frog : 72 % Accuracy of horse : 59 % Accuracy of ship : 68 % Accuracy of truck : 56 %
オーケー、さて次は何でしょう?
これらのニューラルネットワークを GPU 上でどのように実行するのでしょう?
GPU 上で訓練する
ちょうど Tensor を GPU 上にどのように転送するかのように、ニューラルネットワークを GPU 上に転送します。
利用可能な CUDA を持つ場合 device を最初の可視な cuda デバイスとしてまずは定義しましょう :
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# Assuming that we are on a CUDA machine, this should print a CUDA device:
print(device)
cuda:0
このセクションの残りは device が CUDA デバイスであると仮定します。
それからこれらのメソッドは総てのモジュールに渡り再帰的に進みそれらのパラメータとバッファを CUDA tensor に変換します :
net.to(device)
入力とターゲットを総てのステップで GPU に送らなければならないことも忘れないでください :
inputs, labels = data[0].to(device), data[1].to(device)
CPU と比較して何故「大幅な」スピードアップに気がつかないのでしょう?それは貴方のネットワークが非常に小さいからです。
課題:
貴方のネットワークの幅を増やしてみましょう (最初の nn.Conv2d の引数 2、そして 2 番目の nn.Conv2d の引数 1 – それらは同じ数である必要があります)、そしてどのようなスピードアップが得られるか見てみましょう。
達成された目標:
- PyTorch の Tensor ライブラリと高位のニューラルネットワークを理解する。
- 画像を分類するために小さなニューラルネットワークを訓練する。
複数の GPU 上で訓練する
GPU の総てを利用して更に「大幅な」高速化を見ることを望むのであれば、オプションの: データ並列 を確認してください。
次にどこへ行きますか?
- Train neural nets to play video games
- Train a state-of-the-art ResNet network on imagenet
- Train a face generator using Generative Adversarial Networks
- Train a word-level language model using Recurrent LSTM networks
- More examples
- More tutorials
- Discuss PyTorch on the Forums
- Chat with other users on Slack
以上