Deep learning に対応!!    Splunk DL Toolkit に触ってみた


## 概要

Splunkが DeepLearningに対応しました（驚き）。昨年(2018年)の .conf で発表があり beta 版としてアングラで動いてたらしいですが、今回正式に Deep Learning Toolkit もリリースされて追加できるようになりました。 もちろんGPUなどにも対応しており、Tensorflow /Keras / PyTorch そして 複数の NLP ライブラリが利用可能です。

今回はどんな感じで実装できるのか、まずはセットアップしてみたいと思います。

ちなみに Youtubeで概要とセットアップなどが紹介されてますので、こちらも合わせてチェックしてください。
https://www.youtube.com/watch?v=IYCvwABLyh4

マニュアルはなさそうでして、DL Toolkit アプリをインストールすると簡単なセットアップガイドが載ってるため、そこを参照しながら作成しました。

## Deep Learning Toolkit for Splunkとは？

以下のイメージのように、Splunk環境とは別に Container 環境を用意して、そこで学習や本番データへの適用を実行します。そのためコンテナ環境ではGPUなども利用し学習時間を短縮させることも可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/a6b53285-fd03-676d-4c5a-8c0e0481cbc5.png)

以下のように、Splunk側から fit / apply などのコマンドと一緒にモデルを指定すると、コンテナ環境上にデータをロードし指定したモデルに従い結果をリプライします。そのため Splunk側からは従来の機械学習用のアルゴリズムと同様にモデルのスケジュール実行やアラートなど運用に取り込むことが可能となります。<b>簡単にいうとDLに関わる部分だけを外出ししてデータの取得や前処理、結果の実装などは従来通りSplunkという Win-Win の関係なのです。</b>


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/d2364480-de9b-8ecd-2639-7704ed1d99f9.png)

あと splunkbase をみると、現在のところこのToolkitはサポート対象外のようなので、利用の際は注意してご利用ください。


## 構成について

シングル構成と、 Splunk 環境と Docker 環境を分離した構成の２パターンが構成できます。
以下のように、Client(ユーザーPC)からも Dockerにアクセスするため、分離する場合は、External IPが必要になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/f03c13db-3ee4-3188-65af-d17566dbad7f.png)




## 事前準備

・Splunk環境は、現在(2019/10/28時点）では Splunk 7.3 のみです。<font color="red"> version 3.0で8にも対応しました！</font>
・Splunk Machine Learning Toolkit 4.4 
・Python for Scientific Computing 1.4 
・Deep Learning Toolkit for Splunk 2.3 <b> (*) Splunk8の場合は 3.0が必要 </b> 
https://splunkbase.splunk.com/app/4607/

<コンテナ環境>
・ Docker 

## セットアップ

今回は、最初ということもありシンプルにシングルノード構成でセットアップします。分離する場合はおそらくリモートから Dockerhostに対して命令できるような追加の設定が必要になると思われます。


### 1. 各種アプリのインストール

まずは、Splunk 7.3 の環境に対して、以下のアプリをインストールします。やり方は通常のアプリと同じです。
・Splunk Machine Learning Toolkit 4.4 
・Python for Scientific Computing 1.4 
・Deep Learning Toolkit for Splunk 2.3 

### 2. Docker 環境の準備

今回はシングルノード構成なので、同じホスト上に Docker をインストールします。

```
## docker のインストール
$ sudo yum install docker

## docker サービスの立ち上げ
$ sudo service docker start
```
基本的にはこれだけで利用できます。あとはboot時に dockerサービスが立ち上がるように設定するとかくらいでOKです。


``` :boot時に起動設定
sudo chkconfig docker on
```

### 3. セットアップ
DL Toolkit のセットアップ画面に行くと、以下のようにあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/faaefd05-b406-22dc-8e8f-87483973d8b9.png)


最初に、MLTK/PSCがインストールされているかチェックされます。
ここで、MLTKは、Global permissionが必要とあるので、アプリ設定画面で permissionを変更しましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/e9f73fa0-08c4-bfa0-ef37-f489bcbc2bfc.png)

そして2番目の設定項目で、私の環境は Linux の single node 構成なので、下にある Exampleを参考に以下のように入力しました。

DockerHost : unix://var/run/docker.sock
Endpoint URL: localhost
External URL:  <External IPアドレス。> 

External URL は、自分のPCからアクセスできるような IPアドレスまたはホスト名を入力します。また FW設定などある場合は、8888 / 6006 に対してアクセスできるように変更してください。

あとは、Save ボタンを押すと、以下のようなメッセージが現れたら完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/d6adc3df-a1c5-e79c-8042-12635e302afd.png)

もし、うまく現れない場合は、Dockerhostにうまくアクセスできていないので、サービスが上がっているか、もしくはリモートアクセス権なども確認してみてください。


## 開発の流れ

さて、ここまで来たら基本的なセットアップは終了です。次にアプリ内にある 以下のモデル作成ガイドにしたがって進めたいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/08a688fd-ff57-412c-ea79-842ec0690cfd.png)

0 から 8までのステップが書いてあります。

0: コンテナ準備とセットアップ (開発用のコンテナ環境のロードと起動)
1. モデル作成の準備 ( jupyter labで、 pythonコードがモデル名になるため、サンプルコードを参考にコピーして新規モデルを保存します）
2. コードを書くために、サンプルデータをコンテナ上にロードします。
3. モデルの中身作成 ( jupyter labで、モデルの中身のコードを書きます。cnn / lstm など自由にモデルを作成することが出来ます）
4. 実データを使ってモデルの学習をする。 ( fit コマンドを使って、splunk上で作成したモデルを呼び出して学習させる）
5. 学習状況を確認 (tensorboardを使って、学習状況を確認します）
6. 実モデルのテスト＆評価　（apply コマンドで 学習済みのモデルを使って、今まで利用していなかったデータに対して適用し評価する）
7. モデルの反復、改良、再トレーニング (モデルをさらにいいものにするため、上記を繰り返します）
8. 本番データへの適用 (完成したモデルを使って実運用をする。 apply コマンドで適用）

### Step 0: 最初に開発用のコンテナ環境を作成します。
すでに４つのコンテナが DockerHub上に用意されており、利用したいライブラリや環境(GPUなど）により、選択してロードします。今回はGPUがないので、Tensorflow CPUを選択しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/c36ca255-7816-d0cc-296d-7837666b39f3.png)

Startすると、Jupyter NotebookやTensorboard環境にもアクセスできるようになります。

ちなみにRebuildしたりローカルのリポジトリに登録したい場合は、こちらからダウンロードして変更できます。
https://github.com/splunk/splunk-mltk-container-docker


### Step 1. JupyterLabを用いたモデル作成の準備
 
"JUPYTER LAB" ボタンをクリックして、jupyter lab にアクセスします。(pass: Splunk4DeepLearning)

/notebook に移動すると、サンプルでいくつもの pythonコードが用意されております。 (my_　と頭文字にあるのは私がコピーしたものです）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/3e942962-d63a-dfc2-6a7e-148ea4be29aa.png)

サンプルコードをコピーして、my_univariate_cnn_forecast.ipynb　として保存します。
ちなみに、今回は CNNの Conv1Dを使った時系列予測のサンプルアルゴリズムを使用します。


### Step 2.　Splunk上のデータをコンテナ環境上にロードする

Splunkのサーチで以下のコマンドを実行し、コンテナ環境にデータセットをロードします。
この後 juniper notebook を使って、モデルを作成する際に利用するためなので、サンプルデータとしていくつか取り込めれば十分です。
今回はデータの正規化のため RobustScaler を使っておりますが、必須ではありません。前処理としてお好きなように加工してください。

mode=stage と指定することで、実際には fitせずにデータをコンテナ環境にロードするようになります。 
(データはコンテナ内の /srv/notebook/data に保存されます）

```:Splunk上で実行 
| inputlookup internet_traffic.csv 
| timechart span=120min avg("bits_transferred") as bits_transferred 
| eval bits_transferred=round(bits_transferred) 
| fit RobustScaler bits_transferred 
| fit MLTKContainer mode=stage algo=my_univariate_cnn_forecast RS_bits_transferred _time by RS_bits_transferred into app:internet_traffic_forecast_model
```

今回は時系列予測で１次元の特徴量でいいのですが、順番も関係あるため _timeも指定しておりますが、実際に利用するのは RS_bits_transferred のため、byで対象のフィールドを指定しております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/6acd29c6-7ae2-d448-9153-3ede837f35bf.png)


ちなみに、コンテナ内のディレクトリを確認すると、確かにデータが読み込まれているのが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/995805c6-a1db-2235-8761-a5228f3401cc.png)

### Step 3. モデルの中身の作成

それでは、保存した my_univariate_cnn_forecast.ipynb の中身を見ていきます。

#### Stage0: ライブラリーインポート
 
こちらは、このまま実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/4aade694-f513-e827-9ca8-650fdcd784fb.png)

#### Stage1: Splunkからのデータロードの確認

先ほどコンテナ上にロードしたデータが読み込めるか確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/9eab3188-c416-f06a-0d8f-4242a4a2e123.png)

ちゃんと、データセットと epoch などのオプションが読み込めてますね。

#### Stage2.  モデルの作成と初期化

ここでロードしたデータセットを使って、モデルの作成と初期化を行います。
詳細は省きますが、今回はCNNのモデルを定義しております。お好みでレイヤーを追加してもOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/3af780ec-9736-3563-f773-21d15659a078.png)

summary関数で、定義したモデルの中身をみてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/4711e2ef-1148-dc38-5451-347b6beb23c1.png)


#### Stage3. fit モデルの定義

ここでは、fit コマンドの中身を定義していきます。
後ほど Splunkから fitコマンドでアルゴリズムが呼び出された際にこちらの関数が実行されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/9e3a1958-fee8-c7c4-8439-f8e9fd3ffc17.png)

ステージング用のデータセットを使って fitさせた結果を確認。結果によってはモデルを作り直したり、パラメータを変更したりします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/498a22ca-0168-d530-debe-c1effd2487e8.png)



#### Stage4. Apply の定義

ここでは、Splunkから applyコマンドを呼び出された際に実行する関数を定義します。
model_batch_size などのパラメータのデフォルト値はこちらで変更するか、apply実行時に引数で指定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/a0f2fa4b-7be1-9037-84db-0c40c5a0a767.png)


#### Stage5. モデルの保存

モデルの保存先などを定義してます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/80ca396c-afb1-149a-41cb-0c531b6c1e98.png)


#### その他 ( load model / summary model) 

他の学習済みモデルを読み込んだり、モデルのサマリーを確認する関数を定義。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/f6ec005e-dcfb-ad64-ec13-fc3980e101db.png)

最後まで実行が出来たら、作成したjupyter notebookを保存してください。


### Step 4.  実際の訓練データを使った学習 (fitコマンド) 

さてアルゴリズムは作成しましたので、実際にSplunkからモデルの学習用の訓練データを使って学習させたいと思います。
（今回はstageと同じデータセットを使わせて頂きます）
mode=stage というオプションが外れ、最後に model名を指定して保存しております。
また epochs などオプションを指定しておりますが、指定しない場合はデフォルト値が利用されます。（今回はデフォルト値と同じですが）

```python:
| inputlookup internet_traffic.csv 
| timechart span=120min avg("bits_transferred") as bits_transferred 
| eval bits_transferred=round(bits_transferred) 
| fit RobustScaler bits_transferred 
| fit MLTKContainer algo=my_univariate_cnn_forecast epochs=100 batch_size=3 RS_bits_transferred _time by RS_bits_transferred into app:MyFirstModel 
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/2c4c01db-69af-6fa6-3086-2160ce782504.png)

"predicted_0" というフィールドが出来てますね。こちらが予測値になります。
今回は Conv1D を使用しており、inputがbatch_sizeになっているので、３つのデータを使って、次の一つを予測するようなモデルになっております。


### Step 5. Tensorboard を用いた学習状況の確認

学習したモデルについては、学習中の経過や精度などを Tensorboardを使って確認できます。
Tensorboard の見方はよく分からないため、イメージ図だけ貼り付けておきます。（勉強せねば。。。）

・　モデルの中身を図示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/bce848ab-b516-c226-5148-7ddbdae678f8.png)

・ epoch ごとのロス率
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/801cca4a-6955-0b73-d628-640d6ec34566.png)

・(Distributions)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/ce2cab39-b6d2-a1b9-c906-fc31637f705c.png)

・(Histgrams)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/73c46192-aad9-fb1d-9a77-0b4ed33a9818.png)

### Step 6. 検証データへの適用・評価

Tensorboardを見ながら学習がうまく行ってそうだったら、検証データへ適用して評価します。
今回はToolの使い方がメインなので、訓練データと同じデータを利用させて頂きます。（本来は別のデータに適用し評価する必要があります）

```
| inputlookup internet_traffic.csv 
| timechart span=120min avg("bits_transferred") as bits_transferred 
| eval bits_transferred=round(bits_transferred) 
| fit RobustScaler bits_transferred 
| apply MyFirstModel
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/da561bbc-9d87-ed37-00f6-b70f7801c247.png)

見やすいように予測した最後の30箇所にズームするとこちらのようになりました。(holdback=30 のため）
予測値と実測値が同じように推移しているのがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/c01ff21a-feae-ee32-a2e4-6bb4b6944947.png)

一応評価もしてみます。

```
| inputlookup internet_traffic.csv 
| timechart span=120min avg("bits_transferred") as bits_transferred 
| eval bits_transferred=round(bits_transferred) 
| fit RobustScaler bits_transferred
| apply MyFirstModel 
| table _time RS_bits_transferred predicted_0
| where isnotnull(RS_bits_transferred)
| tail 30
| score r2_score "RS_bits_transferred" against "predicted_0"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/fdbe286a-8909-af9a-7a58-8ad79af264df.png)

流石に訓練データと同じなので精度も高いですね。


### Step 7. モデルの反復、改良、再学習

Step6 の結果を見ながら、Stage3のモデルを作り直したり、パラメーターを変更したりして納得のいくモデルを作り上げます。

ちなみに、summary コマンドの結果です。

```
| summary MyFirstModel 
| spath input=summary 
| fields - summary
| transpose
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/1642ffe0-b5f7-8ba9-462b-63fcc0b6d0fc.png)



### Step 8. 運用への実装

Step6 で実行した apply コマンドを使って、本番環境に実装を行います。学習済みのモデルを適用するだけなので負荷はそれほど高くないです。
コンテナ環境は開発用のコンテナのままなので、本番運用向けのコンテナ環境を deployして実装するのが推奨です。

コンテナ管理の画面からモデルを選択してコンテナイメージを適用するだけです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392303/431e67bc-a0dc-30a6-06c8-849dfcac3d58.png)

もちろん通常のSPLコマンドから実行できるので、今までどおりレポートやダッシュボード、アラートへの組み込みが可能になります。


## 最後に

非常にざっくりとでしたが DeepLearning Toolkit for Splunk を触ってみたのをまとめてみました。

モデル作成などに DLの知識が必要になるためハードルは高いですが、DLをかじったことがある方はpythonコードのまま理解できるので逆に扱いやすいのではないでしょうか？

またいいモデルができてしまえば、後は通常の Splunkの知識さえあれば実装ができます。データサイエンティストが苦労するデータ収集や前処理、そして最後の実装部分をSplunkに任せて、実際のモデル作成を jupyter notebookを使ってコーディング出来るため、いいところどりな気がします。

今後は、GPU環境を利用したり、NLPや Pytorch といった他のライブラリを活用したモデル・ユースケースをいつか触ってみたいと思います。