はじめに
こんにちは。
メイビスデザインのokaki(@0kak1)です。
本記事では、機械学習フレームワークとして広く利用されている
PyTorchと、当社が開発・提供するPySAMACTを比較してみます。
ただし、本記事は「どちらが優れているか」を議論するものではありません。
両者はそもそも目的が異なります。
PyTorchはGPUを活用した高速な学習・推論を得意とする一方、
PySAMACTはエンドポイントAI向けハードウェア実装を意識した設計思想を重視しています。
今回は機械学習の定番であるIrisデータセットを用いて、
実際に両者で分類タスクを実施しながら違いを見ていきます。
PySAMACTの詳細は以下の記事を参照ください。
https://qiita.com/nhnhnh/items/243d9adbd4e79c44ca29
PyTorchとPySAMACTの違い
最初に結論を書いてしまうと、
PyTorchは
「AIモデルを作るためのライブラリ」
PySAMACTは
「エンドポイントAIを設計するためのライブラリ」
という違いがあります。
| 項目 | PyTorch | PySAMACT |
|---|---|---|
| 主用途 | AIモデル開発 | エンドポイントAI PoC |
| 学習方式 | GPU学習前提 | オンチップ学習想定 |
| 重視すること | 学習速度・開発効率 | HW実装を見据えた評価 |
今回の実験
タスク
アヤメ分類 (Classification)
データセット
scikit-learnのIrisデータセット
- がく片長
- がく片幅
- 花びら長
- 花びら幅
の4特徴量から3種類のアヤメを分類するデータセットです。
比較対象
- PyTorch
- 4-16-3 MLP
- ReLU
- Adam
- CrossEntropyLoss
- 20epoch / 100epoch
- PySAMACT
- RateEncodeLayer
- SAMLayer(16)
- SAMLayer(3)
- MajorityDecodeLayer
- Compile(32)
- 20epoch
評価指標
今回は以下の3項目を比較します。
- Accuracy(分類精度)
- Training Time(学習時間)
- Inference Time(推論時間)
PyTorchでIris分類
コード(一部抜粋)
細かいところは省略しますが、モデル作って、学習・推論する根幹の部分のみコードを提示します。
# ------------------------
# モデル定義
# ------------------------
class IrisNet(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(4, 16)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(16, 3)
def forward(self, x):
x = self.fc1(x)
x = self.relu(x)
x = self.fc2(x)
return x
model = IrisNet()
# ------------------------
# 損失関数・最適化手法
# ------------------------
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)
# ------------------------
# 学習
# ------------------------
epochs = 100
train_start = time.perf_counter()
for epoch in range(epochs):
optimizer.zero_grad()
outputs = model(X_train)
loss = criterion(outputs, y_train)
loss.backward()
optimizer.step()
if (epoch + 1) % 10 == 0:
print(
f"Epoch [{epoch+1}/{epochs}], "
f"Loss: {loss.item():.4f}"
)
train_end = time.perf_counter()
print(f"Training Time = {train_end-train_start:.6f} sec")
# ------------------------
# 評価
# ------------------------
model.eval()
with torch.no_grad():
outputs = model(X_test)
_, predicted = torch.max(outputs, 1)
accuracy = (
(predicted == y_test).sum().item()
/ len(y_test)
)
print(f"Accuracy: {accuracy:.4f}")
# 平均推論時間の測定
N = 10000
sample = X_test[0].unsqueeze(0)
# warmup
for _ in range(100):
model(sample)
start_inf = time.perf_counter()
with torch.no_grad():
for _ in range(N):
model(sample)
end_inf = time.perf_counter()
avg_time = (end_inf - start_inf) / N
print(f"Inference Time = {avg_time*1e6:.3f} us/sample")
PySAMACTでIris分類
コード(一部抜粋)
PyTorchと同様に、モデル作って、学習・推論する根幹の部分のみコードを提示します。
def main():
# ------------------------
# データの準備
# ------------------------
iris = load_iris()
data:np.ndarray = np.array(iris.data)
scaler = MinMaxScaler()
normData = scaler.fit_transform(data)
label:np.ndarray = np.array(iris.target)
# 学習8:テスト2に分割。再現性のためにシードは固定。
trainData, testData, trainLabel, testLabel = train_test_split(normData, label, test_size=0.2, random_state=0)
# ------------------------
# ニューラルネットワークの構築
# ------------------------
nN1 = 4
nN2 = 16
nN3 = 3
# エンコーダの設定 (入力層)
inputLayer = RateEncodeLayer(nN1)
# SAMレイヤーの設定 (中間層・出力層)
# ハイパーパラメータa=3, p=0.75を指定。
# 重みの逆伝搬時の活性化関数にStep関数を指定。
# 教師信号生成時の活性化関数にStep関数を指定。(前段はエンコーダなので利用されない)
hiddenLayer = SAMLayer(nN2, LayerProperty(a=3, p=0.75), Step(), Step())
# ハイパーパラメータa=3, p=0.75を指定。
# 重みの逆伝搬時の活性化関数にStep関数を指定。
# 教師信号生成時の活性化関数にStep関数を指定。
outputLayer = SAMLayer(nN3, LayerProperty(a=3, p=0.75), Step(), Step())
# デコーダの設定
# 分類問題なので、出力パルスを多数決するデコーダを指定。
decoder = MajorityDecodeLayer()
# ニューラルネットワークの生成
# 上記layerを渡してモデルを構築
model = Sequential(inputLayer, decoder, [hiddenLayer, outputLayer])
# 1データを32サイクルで処理するように設定。(ハイパーパラメータ)
model.Compile(32)
# ------------------------
# 学習
# ------------------------
# 学習プロパティの設定
# 学習率eta, iotaの初期値を5, 2に設定。2エポックごとに1減衰する。
learnProperty = LearningProperty(eta=5, iota=2, decayPeriod=2)
# 学習の実施
fit_start = time.perf_counter()
# 学習エポック数は20に設定。
fitResult = model.Fit(trainData, trainLabel, 20, learnProperty)
fit_end = time.perf_counter()
print(f"Training Time = {fit_end-fit_start:.3f} sec")
# 学習結果の保存
# パラメータの学習結果を保存
dumpName = f"iris_{nN1}_{nN2}_{nN3}_ntd{len(trainData)}_step.h5"
model.Save(dumpName)
# 1epoch目から20epochまでのの学習精度(正解率)のリスト
print(fitResult.metrics)
# ------------------------
# 推論
# ------------------------
# テストデータに対する正解率
evalResult = model.Evaluate(testData, testLabel)
print(evalResult.metrics)
# 平均推論時間の測定(N=10000)
N = 10000
for _ in range(100):
model.Predict(testData[0])
start_inf = time.perf_counter()
for _ in range(N):
model.Predict(testData[0])
end_inf = time.perf_counter()
avg_time = (end_inf - start_inf) / N
print(f"Inference Time = {avg_time*1e6:.3f} us/sample")
評価結果
| 項目 | PyTorch (20epoch) | PyTorch (100epoch) | PySAMACT (20epoch) |
|---|---|---|---|
| Accuracy | 80.00% | 93.33% | 96.67% |
| Training Time [s] | 0.015 | 0.068 | 15.785 |
| Inference Time [μs/sample] | 15.377 | 18.194 | 2255.992 |
分類精度比較
| 手法 | Accuracy |
|---|---|
| PySAMACT (20epoch) | 96.67% |
| PyTorch (100epoch) | 93.33% |
| PyTorch (20epoch) | 80.00% |
- PyTorchは20epochでは十分に収束していなかった。
- 100epochまで学習させることで Accuracy が 80.0% → 93.3% に改善。
- PySAMACTでもIris分類は十分可能であり、今回の条件では96.7%のAccuracyを達成した。
- ただし、両者は学習アルゴリズムやハイパーパラメータが異なるため、本結果のみで優劣を判断できるものではない。
学習時間比較
| 手法 | Training Time [s] |
|---|---|
| PyTorch (20epoch) | 0.015 |
| PyTorch (100epoch) | 0.068 |
| PySAMACT (20epoch) | 15.785 |
PySAMACTに対する速度比
| 比較対象 | 学習速度倍率 |
|---|---|
| PyTorch (20epoch) | 約1052倍高速 |
| PyTorch (100epoch) | 約232倍高速 |
推論時間比較
| 手法 | Inference Time [μs/sample] |
|---|---|
| PyTorch (20epoch) | 15.377 |
| PyTorch (100epoch) | 18.194 |
| PySAMACT (20epoch) | 2255.992 |
PySAMACTに対する速度比
| 比較対象 | 推論速度倍率 |
|---|---|
| PyTorch (20epoch) | 約147倍高速 |
| PyTorch (100epoch) | 約124倍高速 |
総括
今回の実験では、PySAMACTは96.67%の分類精度を達成し、PyTorch(100epoch時)の93.33%を上回る結果となりました。
一方で、学習時間および推論時間についてはPyTorchが圧倒的に高速であり、学習・推論ともに2桁〜3桁程度の差が確認できました。
ただし、両者は学習アルゴリズムや設計思想が異なるため、今回の結果だけで単純な優劣を判断できるものではありません。
PyTorchは高速な学習・推論を実現するためにGPU活用や自動微分を前提として設計されています。
一方、PySAMACTは高速化を主目的としておらず、
ハードウェア実装時の挙動をPython上で再現しながら評価することを重視しています。
同じ分類問題を解いていても見ているゴールが異なります。
なお、今回の評価は両者ともCPU環境上で実施しています。
そのため、本記事はGPU性能とオンチップ性能を直接比較したものではなく、
GPU学習を前提として設計されたPyTorchと、
オンチップ学習を前提として設計されたPySAMACTの設計思想や利用目的の違いを比較したものになります。
最後に
今回、Irisデータセットを用いてPyTorchとPySAMACTの両方で分類タスクを試してみました。
結果として、両者とも "分類可能" でした。
しかし、実際に触ってみると、
- PyTorchは「より良いモデルを効率良く作る」
- PySAMACTは「将来どのようにデバイスへ実装するかを考える」
という違いが体感できました。
AIモデルを作ることが目的であればPyTorchは非常に強力な選択肢です。
一方で、
- FPGA実装
- ASIC実装
- オンチップ学習
- エンドポイントAI
といった領域に興味がある方にとっては、PySAMACTによるPoCも触ってみると面白いかもしれません。
本記事が、
GPU中心のAI開発とオンチップ学習を前提としたエンドポイントAI開発の違いを考えるきっかけになれば幸いです。
リンク集
| リソース | URL |
|---|---|
| GitHub(サンプル・ドキュメント・フォーラム) | https://github.com/maviss-design/SAMACT |
| PyPI (パッケージ) | https://pypi.org/project/samact/ |
| 弊社Webサイト | https://maviss-design.com/ |
| お問合せ | https://maviss-design.com/contact/ |
ライセンス
AGPLv3を採用しています。研究・検証目的での利用を歓迎しますが、商用利用や量産用途をご検討の場合は別途お問合せください。