SQL Server 2017で機械学習(その2)

2018.12.18

こんにちは。YDCのたかもん です。
待ちに待ったSQL Server 2017が2017年10月2日にようやく正式リリースされました。 Windows ServerだけでなくLinuxとDockerコンテナにも新たに対応してます。
ワクワクしながら前回に続いてSQL Server 2017で実装された「Machine Learning Services」について紹介したいと思います。
今回は学習したモデルの保存とロードについて説明したいと思います。
機械学習では毎回学習させていては時間がかかりすぎるのでモデルの保存が必要となります。さて2017ではどのように保存するのか紹介します。
通常は、Pythonで作成したモデルはOS上のファイルとして保存します。2017ではなんとデータベースのテーブルにバイナリとして保存が可能です。データベース上で管理できるのでこれまた便利です。

前回はサポートベクターマシンを使用した分類を行いました。今回はランダムフォレスト使用した回帰を行ってみます。
使用するデータは、これまたおなじみのPythonのscikit-learnライブラリにバンドルされてるボストン住宅価格を使用してみます。
以下のような流れで進めてみます。

1.事前準備
2.学習用プロシージャ作成
3.学習とモデルの保存
4.保存したモデルのロードと検証

その前にランダムフォレストについて簡単に説明したいと思います。
ランダムフォレストは、ブートストラップ法を用いて重複なランダムサンプリングを行い複数の決定木を作成し、決定木の推定結果をバギングと呼ばれる方法で算出(分類の場合は多数決、回帰の場合は平均)することで、決定木単体での過学習しやすい欠点を補う学習モデルです。このようなモデルをアセンブル学習モデルといいます。実際に使用するパラメータも少なく扱いやすいため、人気があります。予測精度も高いことで知られています。

1.事前準備

モデルを保存するためのテーブルを作成します。

create table python_model_tbl (
"model_name" varchar(30),
"train_model" varbinary(max)
); go

2.学習用プロシージャ作成

学習用のストアド・プロシージャを作成します。処理の説明としては、ボストン住宅価格のデータをロードし、ランダムフォレスト回帰で学習します。その際、学習モデルを返り値として定義します。

create procedure proc_create_rf_model(@train_model varbinary(max) OUTPUT)
as
begin
exec sp_execute_external_script
@language = N'Python'
, @script = N'
import pandas as pd
import sklearn
import pickle
from sklearn import model_selection as ms
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor
from sklearn.datasets import load_boston
# データセットをロード
boston = load_boston()
# データセットをデータフレーム化
boston_df=pd.DataFrame(boston.data,columns=boston.feature_names)
boston_df["PRICE"]=boston.target
# 説明変数
x = boston_df.iloc[:,:13].values
# 目的変数
y = boston_df.iloc[:,13].values
# 標準化
std_scl = StandardScaler()
std_scl.fit(x)
x = std_scl.transform(x)
# クロスバリデーション(ホールドアウト)
X_train, X_test, Y_train, Y_test = ms.train_test_split(x,y, test_size=0.2,random_state=42)
# ランダムフォレストインスタンス生成
rf = RandomForestRegressor(n_estimators=10,max_features="sqrt",random_state=42)
# 学習
rf.fit(X_train, Y_train)
# モデルの保存
train_model=pickle.dumps(rf)'

,@params= N'@train_model varbinary(max) OUTPUT'
,@train_model = @train_model OUTPUT;
end;
go

3.学習とモデルの保存

ストアドプロシージャを実行し、学習結果のモデルをテーブルへ登録してみます。

truncate table python_model_tbl;

declare @train_model varbinary(max)
exec proc_create_rf_model @train_model OUTPUT

insert into python_model_tbl values('rf_model',@train_model);
select * from python_model_tbl;

go

結果
model_name train_model rf_model 0x800363736B6C6561726E2E656

バイナリで保存されているのがわかります。

4.保存したモデルのロードと検証

最後に保存したモデルをロードし、テストデータで検証します。先程と同様にストアドプロシージャを作成します。今回は学習データを事前にテーブルに登録していないため、再度ロードすることとします。

create procedure proc_exec_rf(@model varchar(30))
as
begin
exec sp_execute_external_script
@language = N'Python'
, @script = N'
import pandas as pd
import pandas as pd
import sklearn
import pickle
from sklearn import model_selection as ms
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_boston
# データセットをロード
boston = load_boston()
# データセットをデータフレーム化
boston_df=pd.DataFrame(boston.data,columns=boston.feature_names)
boston_df["PRICE"]=boston.target
# 説明変数
x = boston_df.iloc[:,:13].values
# 目的変数
y = boston_df.iloc[:,13].values
# 標準化
std_scl = StandardScaler()
std_scl.fit(x)
x = std_scl.transform(x)
# クロスバリデーション(ホールドアウト)
X_train, X_test, Y_train, Y_test = ms.train_test_split(x,y, test_size=0.2,random_state=42)
# モデルのロード
rf=pickle.loads(train_model)
# 学習データによるスコア
print ("accuracy: TRAIN",rf.score(X_train,Y_train))
# テストデータによるスコア
print ("accuracy: TEST",rf.score(X_test,Y_test))'

,@params= N'@train_model varbinary(max)'
,@train_model = @train_model
end;
go

結果
accuracy: TRAIN 0.967084811585 accuracy: TEST 0.806470024012

スコアは学習データが0.96に対して、テストデータでは0.8でした。過学習しているように見えますが0.8あるのでOKといったところでしょうか。今回は何も考えずに説明変数を全て使用しているので、フィーチャーエンジニアリングすればもっと良くなるかもしれませんね。
※ランダムフォレストには、説明変数の重要度を feature_importances_ を使用することで確認することができます。特徴量選択に有効なので調べてみてください。

今回はここまでです。データベースにモデルを保存できるのは運用面においてもとても良いですね。Standby Express やログ配布を使用すればバックアップ・災害対策もバッチリです。応用性が高いので引き続き調査してみたいと思います。

Standby Expressに関するお問合わせ

  • TEL 042-333-6217
  • FAX 042-352-6101
  • LINE
  • Mail