第25回「近ごろの機械学習ライブラリ(2)PyTorch」

こんにちは、小澤です。

前回は、Googleの機械学習ライブラリTensorFlow / Kerasを使って、シンプルなニューラルネットワークの作り方をご紹介しました。Keras の手軽さで、深層学習の入り口としてはかなり取り組みやすいということが伝わったかと思います。

今回は、もう一つの人気ライブラリPyTorch(パイトーチ)を使って、同じようにモデルを構築してみたいと思います。TensorFlowとはまた違ったアプローチで、特に柔軟に開発や実験ができるのがPyTorchのいいところです。

なお、今回の内容も、教科書『Pythonによる新しいデータ分析の教科書(第2版)』の「近ごろの機械学習ライブラリ」(271ページ) の箇所です。

1. PyTorchとは?

PyTorchは、Facebook(現Meta)が開発したオープンソースの機械学習ライブラリです。2017年頃から急速に普及し、特に研究分野や教育現場でプロトタイピングなどの用途で使われることが多いようです。PyTorchには「動的計算グラフ(Define-by-Run)」と呼ばれる仕組みがあり、コードを実行しながらモデルの構造が決まっていく、Pythonらしい自然な書き方ができるのが特徴です。

PyTorchを使うメリットには以下のようなものがあります。

  • 柔軟で直感的なコードで初心者でも比較的取り組みやすい(NumPyのような記述ができる)
  • 実行時にモデルを定義・分岐できる
  • デバッグしやすい(Python標準のprint文やpdbといった標準のデバッグツールが使える)
  • 研究用途に強い(論文で使われる最新手法を実装しやすい)

2. PyTorchによるニューラルネットの実装

前回と同様に「Irisデータセット」を使い、シンプルなニューラルネットワークをPyTorchで構築してみましょう。

まず、ニューラルネットワークを作ることのメリットを以下にまとめます。

  1. 複雑なパターンや特徴を自動で学習できる
    従来の機械学習(例:ロジスティック回帰やSVMなど)では、特徴量を人が工夫して作る必要がありましたが、ニューラルネットワークでは、入力されたデータの中から有用な特徴を自動で見つけ出すことができます。
    • 例:画像から「エッジ」「輪郭」「形」を自動で検出
    • 例:言語データから「文脈」「文の意味」を抽出
  2. 非線形な複雑な関係性も表現できる
    線形モデルでは捉えられないような複雑な関係(例:「AかつBだとラベルCになる」など)も、中間層(隠れ層)を重ねることで柔軟に表現できます。
    • ANDやXORのような論理パターンも表現可能
    • 特徴と結果のあいだに入り組んだルールがあるときに特に強い
  3. 試行錯誤がしやすい(柔軟性がある)
    PyTorchのようなライブラリを使うことで、新しいアイデアを試しやすく、実験がしやすい環境を作れます。
    • ネットワークの構造を簡単に変えられる
    • 分岐条件や再帰的な構造も組み込める
    • デバッグもPython標準の方法で対応できる
  4. スケールアップが可能(データが多くても強い)
    ニューラルネットワークは、大量のデータを使って学習させることで精度がどんどん向上していく特性を持ちます。
  5. 実世界の応用に強い
    今のAI技術の多くは、ほぼすべてニューラルネットワークで動いています。
    • 画像認識(顔認証、医療画像分析など)
    • 自然言語処理(ChatGPT、翻訳、音声認識)
    • ゲームやロボティクス(自動運転、操作最適化)

それでは、Irisデータセットでニューラルネットワークを構築してみましょう。Irisデータセットは、機械学習入門でよく使われる有名なデータセットです。ここでは、アヤメの花の特徴量を使って、3つの品種に分類するモデルを構築してみましょう。Irisデータセットは、以下のような4つの特徴量を持っています。

  • がく片の長さ(sepal length)
  • がく片の幅(sepal width)
  • 花びらの長さ(petal length)
  • 花びらの幅(petal width)

これらの特徴量を使って、3つの品種(Setosa, Versicolor, Virginica)に分類するニューラルネットワークを作ります。

ライブラリのインポートとデータ準備

import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from torch.utils.data import TensorDataset, DataLoader

# データ準備 Xが特徴量、yが分類対象のラベル(0〜2)
iris = load_iris()
X = iris.data
y = iris.target

# 特徴量のスケールを揃えるために標準化
scaler = StandardScaler()
X = scaler.fit_transform(X)

# Tensorに変換
X = torch.tensor(X, dtype=torch.float32)
y = torch.tensor(y, dtype=torch.long)

# トレーニングデータとテストデータに分割(7:3)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# DataLoaderにまとめ、バッチ処理(1回の学習に使うデータ単位)を扱いやすくする
train_ds = TensorDataset(X_train, y_train)
train_loader = DataLoader(train_ds, batch_size=8, shuffle=True)

モデルの定義

class IrisNet(nn.Module):
    def __init__(self):
        super().__init__()
        # 全結合層(nn.Linear)を3層使ったMLP(多層パーセプトロン)
        self.fc1 = nn.Linear(4, 10)
        self.fc2 = nn.Linear(10, 10)
        self.fc3 = nn.Linear(10, 3)

    def forward(self, x):
        # 活性化関数はReLUで、最後の出力は3クラス分類(出力次元3)
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        x = self.fc3(x)
        return x
       
model = IrisNet()

学習設定と実行

# 損失関数はクロスエントロピー(多クラス分類用)
criterion = nn.CrossEntropyLoss()
# 最適化はAdam(勾配降下法の一種)を使用
optimizer = optim.Adam(model.parameters(), lr=0.01)

# 50エポックでモデルを訓練
for epoch in range(50):
    total_loss = 0
    correct = 0
    for xb, yb in train_loader:
        optimizer.zero_grad()
        outputs = model(xb)
        loss = criterion(outputs, yb)
        loss.backward()
        optimizer.step()
        total_loss += loss.item()

        # 正解数のカウント
        _, preds = torch.max(outputs, 1)
        correct += (preds == yb).sum().item()

    acc = correct / len(train_loader.dataset)
    print(f”Epoch {epoch+1}/50 – Loss: {total_loss:.3f} – Accuracy: {acc:.3f}”)

テスト制度の評価

with torch.no_grad():
    # 学習後、テストデータに対して推論し、精度(Accuracy)を計算
    outputs = model(X_test)
    _, predicted = torch.max(outputs, 1)
    test_acc = (predicted == y_test).sum().item() / len(y_test)
    print(f”テスト精度: {test_acc:.3f}”)

実行結果

Epoch 1/50 – Loss: 14.778 – Accuracy: 0.600
Epoch 2/50 – Loss: 11.605 – Accuracy: 0.714
Epoch 3/50 – Loss: 7.283 – Accuracy: 0.810

Epoch 49/50 – Loss: 0.765 – Accuracy: 0.981
Epoch 50/50 – Loss: 0.852 – Accuracy: 0.962
テスト精度: 1.000

この実行結果から以下のようなことが読み取れます。

  1. 学習の進み具合:適切に収束している
    • 初期の Loss: 14.778 → Accuracy: 0.600 に対して、
    • 最終的には Loss: 0.852 → Accuracy: 0.962 と 損失が大きく減り、正解率も高く安定しています。
    • モデルはうまく学習できており、訓練データに対して高精度で分類できるようになったと判断できます。
  2. テスト精度: 1.000
    • テストデータに対して100%の正解率(accuracy)を記録しています。
    • これは非常に高い性能を示しており、モデルが汎化能力(新しいデータへの対応)を持っている可能性が高いです。
    • ただし、Irisデータセットは比較的単純でサイズも小さいため、100%の精度が出やすいといえます。
  3. エポック中の変化:過学習は起きていない
    • エポックが進んでもトレーニング精度が極端に上下したり、損失が増加したりしていないため、過学習(overfitting)の兆候は見られません。
    • 50エポックという設定も、早すぎず、遅すぎず、ちょうどよいと判断できます。

3. PyTorchとKerasの違い

観点PyTorchKeras(TensorFlow)
設計思想Define-by-Run(動的計算グラフ)Define-and-Run(静的計算グラフ)
柔軟性・自由度高い(処理を細かく制御できる)高くない(決まったAPIに沿って構築)
コードの見通し手続き的でPythonらしい宣言的でまとめて構築
デバッグ容易(printやpdbがそのまま使える)難しめ(内部で自動構築される処理が多いため)
教育・研究向き◎(柔軟で試行錯誤しやすい)○(簡単だが深いカスタマイズは難しい)
商用運用向き○(ONNXなどもあり)◎(TFLiteやTensorFlow Servingなどの支援あり)

PyTorchは以下のような用途に向いています。

  1. カスタマイズ性が高い
    • モデル構造、学習ループ、損失関数、最適化処理など、どこでも自分で介入できる。
    • 例えば、「途中で条件分岐して重みを変える」「ミニバッチごとに別ロジックを入れる」といった実験的な処理が可能。
  2. 論文実装や研究との相性がよい
    • PyTorchは論文コードの多くで使われており、GitHub上の実装も豊富。
    • 最先端の技術を試したい人や、再現実験をしたい人にとって非常に便利。
  3. 教育・学習での見通しの良さ
    • Pythonのような「順番通りに処理される」コードで構成されるため、初心者でも構造が把握しやすい。
    • 教材や講義での活用も多い。

一方で、Kerasは以下のような用途に向いています。

  • とにかく手軽。
  • モデルを試してみたいだけなら「model.fit()」で完結する。
  • プロトタイプやシンプルなモデルであれば、Kerasは生産性がとても高い。

目的によって使い分けるとよいでしょう。

4. まとめ

PyTorchは、柔軟で動的な記述ができる、Pythonらしい深層学習ライブラリです。コードの自由度が高く、処理の流れを細かく制御できるため、モデルの仕組みを中身から理解しながら構築したい方に最適です。一方で、学習ループや評価処理を手動で書く必要があるなど、初心者にはややステップが多く感じられるかもしれませんが、モデルの動作原理を深く理解するには最適です。

次回は、「AutoMLツール(Auto-sklearn / H2O AutoML)」について紹介します。モデルの選定やパラメータ調整といった面倒な作業をすべて自動で行なってくれる強力なツールです。「とりあえず結果を出したい」「短時間で良いモデルを作りたい」というシーンで力を発揮します。ぜひお楽しみに。

PAGE TOP