🕌

MNISTをCUDAで学習して、DirectMLで推論する

2024/05/24に公開

古典的な、機械学習のサンプルであるMNISTをCUDAで学習して、DirectMLで推論してみます。

まず、CUDAで学習するコードを示します。

# %%
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import datasets, transforms

# ハイパーパラメータなどの設定値
num_epochs = 10  # 学習を繰り返す回数
num_batch = 100  # 一度に処理する画像の枚数
learning_rate = 0.001  # 学習率
image_size = 28 * 28  # 画像の画素数(幅x高さ)

# GPU(CUDA)が使えるかどうか?
device = 'cuda' if torch.cuda.is_available() else 'cpu'

# 学習用/評価用のデータセットの作成
transform = transforms.Compose([transforms.ToTensor()])

# MNISTデータの取得
train_dataset = datasets.MNIST('./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST('./data', train=False, transform=transform)

# データローダー
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=num_batch, shuffle=True)
test_dataloader = torch.utils.data.DataLoader(test_dataset, batch_size=num_batch, shuffle=True)

# ニューラルネットワークモデルの定義
class Net(nn.Module):
    def __init__(self, input_size, output_size):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(input_size, 100)
        self.fc2 = nn.Linear(100, output_size)

    def forward(self, x):
        x = self.fc1(x)
        x = torch.sigmoid(x)
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)

# ニューラルネットワークの生成
model = Net(image_size, 10).to(device)

# 損失関数の設定
criterion = nn.CrossEntropyLoss()

# 最適化手法の設定
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

# 学習
model.train()
for epoch in range(num_epochs):
    loss_sum = 0
    for inputs, labels in train_dataloader:
        inputs = inputs.to(device)
        labels = labels.to(device)
        optimizer.zero_grad()
        inputs = inputs.view(-1, image_size)
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        loss_sum += loss.item()
    print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {loss_sum / len(train_dataloader):.4f}")

# ONNX形式でモデルをエクスポート
dummy_input = torch.randn(1, image_size).to(device)
torch.onnx.export(model, dummy_input, "../Models/mnist_model.onnx", verbose=True)

print("モデルをONNX形式でエクスポートしました。")

このコードを実行すると、ONNX形式のモデルファイルが得られます。ここで得た、モデルファイルを用いてDirectMLで推論します。今回は、ONNX Runtimeを用いてみます。

# %%
import onnxruntime as ort
import numpy as np

# ONNXモデルの読み込み
onnx_model_path = "../Models/mnist_model.onnx"
session = ort.InferenceSession(onnx_model_path)

# 入力データの生成(例:手書き数字の画像)
input_data = np.random.rand(1, 784).astype(np.float32)  # 28x28の画像を1次元に変換

# 推論の実行
output = session.run(None, {"onnx::Gemm_0": input_data})

# 結果の表示
predicted_class = np.argmax(output[0])
print(f"Predicted class: {predicted_class}")

推論コードではランダムに28×28ピクセルの画像を生成して、モデルで推論を行っています。

当初はpytorch-directmlでMNISTの学習側も出来ないかなと考慮しましたが、テンソルの演算などは実装可能なようですが、MNISTの学習側のコードを作ると、Runtime Errorを引き起こし、動かないので、pytorch-directmlのissuesを見たところ、学習側を作るには足りていない機能があるようなので、一旦、そちらの方向はペンディングにし、学習側は一旦、通常のpytorchの作りにしました。

差し当たり、想定した、CUDAでモデルを作って、DirectMLで推論するというタスクは可能だと確認できました。

Discussion