シェルスクリプトマガジン

Pythonあれこれ(Vol.83掲載)

著者:飯尾 淳

本連載では「Pythonを昔から使っているものの、それほど使いこなしてはいない」という筆者が、いろいろな日常業務をPythonで処理することで、立派な「蛇使い」に育つことを目指します。その過程を温
かく見守ってください。皆さんと共に勉強していきましょう。第13回では、PyTorchという機械学習ライブラリを使って、手書きの数字を画像認識によって分類してみます。実際に作業することで、機械学習の効果を感じてください。

シェルスクリプトマガジン Vol.83は以下のリンク先でご購入できます。

図1 MNISTデータセットをダウンロードするためのコード

data_folder = '~/data'
BATCH_SIZE = 8
mnist_data = MNIST(data_folder, 
                   train=True, 
                   download=True, 
                   transform=transforms.ToTensor())
data_loader = DataLoader(mnist_data, 
                         batch_size=BATCH_SIZE, 
                         shuffle=False)

図4 MNISTデータセットのデータを1セット表示するコード

data_iterator = iter(data_loader)
images, labels = next(data_iterator)
# 最初の画像を表示
location = 0
# 画像データを28×28画素のデータに変換して表示
data = images[location].numpy()
reshaped_data = data.reshape(28, 28)
plt.imshow(reshaped_data, cmap='inferno', interpolation='bicubic')
plt.show()
print('ラベル:', labels[location])

図6 学習データと検証データを用意するコード

# 学習データ
train_data_loader = DataLoader(
    MNIST(data_folder, train=True, download=True, 
          transform=transforms.ToTensor()),
    batch_size=BATCH_SIZE, shuffle=True)
# 検証データ
test_data_loader = DataLoader(
    MNIST(data_folder, train=False, download=True, 
          transform=transforms.ToTensor()),
    batch_size=BATCH_SIZE, shuffle=True)

図9 ニューラルネットワークモデルを定義するコード

from torch.autograd import Variable
import torch.nn as nn
# 親クラスのnn.Moduleを継承してモデルを作成
class MLP(nn.Module):
  def __init__(self):
    super().__init__()
    self.layer1 = nn.Linear(28 * 28, 100)
    self.layer2 = nn.Linear(100, 50)
    self.layer3 = nn.Linear(50, 10)
  def forward(self, input_data):
    input_data = input_data.view(-1, 28 * 28)
    input_data = self.layer1(input_data)
    input_data = self.layer2(input_data)
    input_data = self.layer3(input_data)
    return input_data

図11 学習前の準備をするコード

import torch.optim as optimizer

# モデルの作成
model = MLP()
# 評価器(誤差項)と最適化器の作成
lossResult = nn.CrossEntropyLoss()
optimizer = optimizer.SGD(model.parameters(), lr=0.01)

図12 画像認識の精度を検証するコード

import torch

# 検証した数と正解の数
total = 0
count_when_correct = 0
for data in test_data_loader:
  test_data, teacher_labels = data
  results = model(Variable(test_data))
  _, predicted = torch.max(results.data, 1)
  total += teacher_labels.size(0)
  count_when_correct += (predicted == teacher_labels).sum()
rate = int(count_when_correct) / int(total)
print(f'count_when_correct:{count_when_correct}')
print(f'total:{total}')
print(f'正解率:{count_when_correct} / {total} = {rate}')

図13 モデルを学習させるコード

# 最大学習回数
MAX_EPOCH = 4
for epoch in range(MAX_EPOCH):
  total_loss = 0.0
  for i, data in enumerate(train_data_loader):
    train_data, teacher_labels = data
    train_data, teacher_labels = \
      Variable(train_data), Variable(teacher_labels)
    # 勾配情報をリセット
    optimizer.zero_grad()
    outputs = model(train_data)
    loss = lossResult(outputs, teacher_labels)
    loss.backward()
    # 勾配を更新
    optimizer.step()
    # 誤差を積み上げる
    total_loss += loss.data
    if i % 2000 == 1999:
      print(f'学習進捗:[{epoch+1}, {i+1}]', end='')
      print(f'学習誤差(loss): {total_loss / 2000:.3f}')
      total_loss = 0.0
print('学習終了')

図15 個別の判定結果を確認するコード

# データの取得と検証
test_iterator = iter(test_data_loader)
test_data, teacher_labels = next(test_iterator)
results = model(Variable(test_data))
_, predicted_label = torch.max(results.data, 1)
# 最初のデータを検証して画像を表示
location = 0
plt.imshow(test_data[location].numpy().reshape(28, 28), 
           cmap='inferno', interpolation='bicubic')
print('ラベル:', predicted_label[location])