サーバーレスでも機械学習がしたい - Time Series Edition -


取り組み中につき随時アップデート予定。 

*更新
-  (2016/12/12)
-  (2017/1/14)*

2017年1月、プロトタイプの実装が完成しました。
この実装については[AWS Premier Night #3](https://aws-premier-night.doorkeeper.jp/events/54131)で登壇機会をいただきお話ししていますので、資料などは[こちら](http://blog.serverworks.co.jp/tech/2017/01/13/awspremier3-starting-serverless-ml/)の記事をご覧ください。

基本、最近のおいしいどこどりをしたいだけの記事です。
_as a Service_ にMLのロジックを乗せて、楽ちんな運用と機械学習を同時に手に入れようとする試み。

この記事では、「時系列分析」のロジックをできればFaaS系統のサーバーレスなインフラ、あるいはPaaSなどマネージドなインフラに乗せるための検討をここに記載します。分析手法の詳細には踏み込まない内容となりますので、ご了承ください。

# ゴール
分析処理の実装が動かす場所が、従来の物理／仮想サーバーより運用がラクになる（であろう）所であれば当面はゴールとします。FaaSやPaaSあたりを基本線にします。

# はじめに

やろうとしている分析は「時系列分析」です。
インフラ監視の文脈だと異常値検出／変化点検出が該当します。
最近では[Datadogがβ版の機能として実装](http://docs.datadoghq.com/ja/guides/anomalies/)しましたね。とても素敵だと思います。
=> http://docs.datadoghq.com/ja/guides/anomalies/

異常値検出／変化点検出は、過去のデータを元に、 **現在のデータが** これまでの傾向から見て特筆すべき値であるかどうかを判別するものです。現在の値を判断するための手法で、未来を占うことはできません。
対して、今回私が用いる手法は _AR(Auto Regression)_ や _MA(Moving Average)_  といった手法を用いた「未来値の予測ロジック」になります。

予測対象は「月次の売上金額」です。
集計された月次の売上実績をCRM（私の場合はSalesforce）からインポートし、時系列分析の枠組みを使ってNヶ月間の直近の売上を予測します。

## （参考）Inspired the Next
ML as a Service なワークショップです。[ServerlessConf](http://tokyo.serverlessconf.io/)のスピンオフ的なイベント。
=> <a href="https://serverless.connpass.com/event/41719/">[特別企画] Serverless Machine Learning Workshop</a>
=> [SlideShare](http://www.slideshare.net/AlexCasalboni/serverless-machine-learning-workshop-tokyo)

# 前提
使用言語は基本的にPython前提です。
機械学習周りのライブラリの充実、Pythonをサポートする環境の多さ、そして私の好みです。

今回の実装では、以下のライブラリを使用しています。

- numpy
- scipy
- pandas
- statsmodels

# 検討対象
思いつく候補を列挙しています。検討できてないもの、使ったことないものも多々。有力な情報があればご指摘いただきたいです。

## まずは
「機械学習×クラウド」の界隈から。メジャーどころはやはりこの3者。

- Amazon Machine Learning
- Azure Machine Learning
- GCP Cloud Machine Learning

Amazon MLは時系列分析非対応なのでアウト。re:Inventでリリースがあるかと期待してましたが、[別](https://aws.amazon.com/jp/lex/)の[方向](https://aws.amazon.com/jp/rekognition/)で[進化](https://aws.amazon.com/jp/polly/)しましたね。非常にアツい発表ではありましたが、今回私が期待していることとは方向性が違うようです。

Azureの時系列分析は異常検出(Anomaly Detection)のみの対応なので、そのままでは非対応。
ただしPython/Rのコードを組み込めるので、それを使えば実装はなんとでもなります。実行環境は[Anaconda](https://www.continuum.io/)をサポートしており、ライブラリの対応は問題なし。

GCPの機械学習はまだちゃんと調査できてないです。TensorFlowベースとの記載があるので多分「なんでも実装できる」が答えだと思いますが、周辺サービス含めて私がまだ理解不足のため、現時点で未検討のステートです。

## 次点
所謂Function as a Serviceと呼ばれるサービス。
こちらもメジャーは以下3者。

- AWS Lambda
- Azure Functions
- GCP Cloud Funtions

Azure/GCPはまだ調査不足。
Lambdaについては、Lambda実行環境に含まれないPythonパッケージ（と共有ライブラリ）をバンドルすることで動作します。
方法としてはこちらの[ (素敵な）ハック](https://serverlesscode.com/post/deploy-scikitlearn-on-lamba/)を参考にしています。 _statsmodels_ が必要であることが差分になりますが、Labmdaのバンドルパッケージのサイズ制限（50MB）内には収まります。
=> [Using Scikit-Learn in AWS Lambda -- Serverless Code](https://serverlesscode.com/post/deploy-scikitlearn-on-lamba/)

他のFaaSも、基本的には同様の縛りがあるのかなと思ってます。
Azure Functionsについては、実行基盤はApp ServiceをベースとしているためApp Service Editorを使うことで問題がクリアできる、かもしれません。
公式ドキュメント「[App Service Editor で Node.js アプリ開発
](https://blogs.msdn.microsoft.com/tsmatsuz/2014/03/09/visual-studio-online-node-js/)」によれば、npmによるパッケージの追加もできるようなので、Pythonでも同じ理屈だろうというのがその根拠。
まだ未検証の内容ですが、↑が真実ならAzureの大ファンになりそうです。

## さらに次点
PaaSや、マネージドなコンテナ環境。
「サーバーレスやりたい」が出発点のひとつなので、基本的に採用の検討としては消極的です。

- PaaS
	- Heroku
	- Google App Engine
	- IBM Bluemix
	- Azure App Service
	- AWS Beanstalk
- Managed Container Service
	- Amazon ECS
	- GCP Container Engine
	- Azure Container Service
	- Docker Cloud（旧Tutum）

[Anaconda](https://www.continuum.io/downloads)には私が必要とする全てのライブラリが揃っています。Anacondaを実行環境にサポートするPaaSがあれば魅力的な選択肢になります。

Herokuは実行環境にAnacondaがあればいいのですが、どうやらないようです。Buildpackを調査したところ[Conda Build Pack](https://github.com/kennethreitz/conda-buildpack)というものがあるようです。非常にいい線いってるのですが、 _statsmodels_ が含まれない模様。自前で環境をビルドするしかないのですが、その苦労をするくらいならFaaSでがんばる方向を検討します。

Cloud DockerはバックにAWSを使うならばECSと実質変わりがないのでいったん除外。ただ、マルチプラットフォーム対応はTerraformみたいで興味深いですね。別の機会に一度触ってみたいサービスではあります。

GAEはβリリースの[Flexible Environment](https://cloud.google.com/appengine/docs/flexible/)であれば、ユーザー定義のDockerfileベースのランタイムを利用できるとのこと。可能性はありそうです。

# 実装
## AWS Lambdaを採用
[会社のブログ](http://blog.serverworks.co.jp/tech/2017/01/13/awspremier3-starting-serverless-ml/)に資料がありますので、そちらをご覧ください。スライドp.30あたりから実装に関する話が書いてあります。

※そもそもの話として、（扱う題材の都合上）現実問題として会社支給のAWSアカウントくらいしかデータを扱える場所がなかった...というのが大きいです。
検証自体はサンプルデータを使って行うことができますが、実データへの適用を考えると個人契約のアカウントにデータを持たせるのはリテラシー的にどうよ、ということです。

## 実装後の所感
荒削りすぎる実装なので構成も関数もどんどんリファクタリングの必要があります。前処理と後処理は予測ロジックを動かすFunctionから切り離して数珠つなぎ的な構成にしたい。
データソースがSalesforce上にあるのでそこの連携も手を入れたいですね。

### Lambdaに関するあれこれ
パッケージを追加する手段が「自前でzipアーカイブに突っ込む」しかない所が残念です。サーバーレスと言いつつ、構築の周辺でこうした苦労をするのではなんだか本末転倒。。。

まぁ、ただ、今はFaaSをターゲットにしたデプロイツールも出てきていますし、ツールの力でカバーできる範囲も多いと思います。面倒ではありますが、それほど深刻に懸念する問題ではないかなというのが現状の認識です。

デプロイツールに関しては、今の私の現状的に[Lamvery](https://github.com/marcy-terui/lamvery)が便利そうです。Pythonパッケージだけでなく共有ライブラリも収集してバンドルしてくれる機能を持っているようで、ビルド作業が捗りそうです。管理単位がFunction単位になっているのも好都合。特にデプロイツールは採用していなかったので、今後の開発ではLamveryを採用します。

### 検討漏れしたその他（というかAzure）について
所属会社的な背景もあってAWS Lambdaを採用しましたが、現在の状況ではAzureを使ったほうがいいというのが正直なところです。

Azure Machine Learningの _"Execute Python Script"_ の実行環境は、私が必要とするパッケージ全てを網羅していました。また、Azure Machine Learningではデータストアやアプリケーションとの連携も考慮されています。（分析部分の）ロジックも弄りたいし外部サービスとの連携もしたい、というニーズであればAzure Machine Learningが最適だと思います。

注意として、必要なパッケージが _Execute Python Script_ の実行環境（Anaconda）に含まれているかどうかは確認が必要です。含まれていない場合もなんとかなるようですが、それをクリアするためには上記のLambdaに近い手間を踏む必要があるので、手軽に利用できるメリットが失われます。（[公式参照](https://docs.microsoft.com/ja-jp/azure/machine-learning/machine-learning-execute-python-scripts)）

# まとめ
S3にuploadされた「月次の売上情報」をAWS Lambdaの実行基盤で分析し、直近の売上を予測してみました。

予測ロジックを動かすためにはLambda functionの実行環境に含まれないパッケージを利用する必要がありましたが、デプロイパッケージにそれらをバンドル＋実行時の起動処理に.soのローディング処理を追加することでこの問題をクリアしています。

実装はまだまだ荒削りなので改善ポイント多数。
2017/1/14時点で、やり残したことと今後の展望については以下の通りです。

- ビルド、デプロイ作業の省力化
	- デプロイツールの利用。Lamveryを使う方向で検討
- バージョン管理
	- 同上
- 1つのFunctionに多くの処理を詰め込みすぎ
	- 前処理と後処理はFunctionを分離して数珠つなぎにする
	- Step Functionsを利用してフロー定義
- データソースのインポート（from Salesforce）も自動化したい
	- SkyOnDemandなどの連携ツールの利用 or データ取得用のLambda Functionを書く
- 可視化
	- 基本的にはスクラッチしない方針
	- BIツールに任せる or Salesforce側の可視化機能で賄う
- 予測精度の追求
	- データソース自体のサンプル数が少ないため、単純なARMAモデルだけでは精度向上にも限度がある
	- 現在いい案は持ち合わせていないので、今後検討する
- 他分野への応用
	- サーバー監視への応用を検討中