Splunk MLTKにONNXモデルをアップロードしてみた

この記事は[Splunk Advent Calendar 2023](https://qiita.com/advent-calendar/2023/splunk) 15日目です。

[Splunk Machine Learning Toolkit (MLTK)](https://splunkbase.splunk.com/app/2890) の最新バージョン（v5.4.0）では、[ONNX形式](https://qiita.com/motoJinC25/items/d662be70b6b9b8ebbaea)のモデルをアップロードすることが可能になりました。これは、外部で作成したモデルをSplunkに統合したいユーザーにとって素晴らしいニュースです。このブログでは、私がONNX形式のMLモデルを作成し、展開できなかった経験と、それに苦しむ中での対処法のメモです。

# ONNXモデルを作成

最初に、MLモデルを作成するためのデータセットを探し始めました。Kaggleを手始めにざっと見ている中で、クラシックな[住宅価格予測](https://www.kaggle.com/datasets/muhammadbinimran/housing-price-prediction-data/data)のデータセットに興味を持ちました。少しのクリーニングの後、次のようなデータフレームを作成しました。

![Screenshot 2023-12-03 at 19.31.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634102/c650c792-be53-3f0d-4202-9642538adb11.png)

このデータセットで、SquareFeet、Bedrooms、Bathrooms、Rural、Suburb、Urbanを使用して、Priceを予測します。ONNXのMLTK機能に焦点を当てたため、モデルの選択やトレーニングについては特に洗練されたものを探しませんでした。この回帰の問題に対して、humbleなLinearRegressorを使用しました。

```python:train.py
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression

X = data.iloc[:, :-1]
Y = data.iloc[:, -1]

X_train, X_test, Y_train, Y_test = train_test_split(X_filtered, Y, test_size=0.3)

linear_model = LinearRegression()
linear_model.fit(X_train, Y_train)
```

さて、モデルがトレーニングされました（一瞬で）、次はONNXのコートを着る時です。ONNX変換には、sklearnモデルを直接ONNXにマップするためにskl2onnxパッケージを使用しました。

```python:onnx.py
from skl2onnx import convert_sklearn
from skl2onnx.common.data_types import FloatTensorType

initial_type = [('float_input', FloatTensorType([None, X_train.shape[1]]))]
onx = convert_sklearn(linear_model, initial_types=initial_type)

with open("housing_predictor.onnx", "wb") as f:
    f.write(onx.SerializeToString())
```

# Splunk MLTKにアップロード

Splunk MLTK APPのUIで、Modelsタブに移動して、「Upload ONNX model」をクリックすると、アップロードウィンドウが表示され、モデル名（onnxファイル名と同じである必要があります）、入力フィールド名、および出力フィールド名を指定すると、アップロードは成功しました。

![Screenshot 2023-12-03 at 21.52.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634102/12f5b09f-1d52-1f05-8e55-6d3c13cf0483.png)

その後、サーチタブに移動しました。Splunkにサンプルデータセットをアップロードした状態で、次のクエリを実行してONNXモデルを呼び出そうとしましたが、残念ながらエラーが発生しました。

![Screenshot 2023-12-03 at 23.27.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634102/1fc4d13a-f6b3-c0d9-129b-3e3078636530.png)

# エラーの調査と解消

エラーについて詳しく知るために、_internalインデックスにクエリを実行し、次のエラーログを見つけました。

![Screenshot 2023-12-03 at 23.30.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634102/45a44005-0ae4-f6cf-68b2-2dc5c14fd692.png)


どうやら、私のONNXモデルのopsetは自動的に18に設定され、Splunk MLTKのONNXランタイムではサポートされていなかったようです。そのため、ONNX変換コードを修正してopsetを手動でより低いバージョンに変更する必要がありました。

```python:onnx_revised.py
initial_type = [('float_input', FloatTensorType([None, X_train.shape[1]]))]
onx = convert_sklearn(linear_model, initial_types=initial_type)

# Manually change opset version
onx.opset_import[0].version = 2
onx.opset_import[1].version = 2
with open("housing_predictor.onnx", "wb") as f:
    f.write(onx.SerializeToString())
```

ONNXファイルを更新して、サーチが成功しました。apply関数によって生成された新しいフィールド「predicted(Price)」がONNXモデルによって予測された結果を示しています。モデルのトレーニングがこのブログのメインではなかったため、精度はかなり低いですけど、これはトレーニングが十分に行われたモデルとともに非常に有用な機能になるかもしれません。

![Screenshot 2023-12-03 at 21.56.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634102/86a6a9da-e7c1-79d8-5cc0-13376876f7d7.png)