カスタムモデルを実装する
隠れ層1層の多層パーセプトロンを実装する¶
カスタムモデルの例として、多層パーセプトロン(MLP)をKerasで実装してみます。(以下にある実装は、tensorflow 1.10.0で動作確認しています) タスクとしては非線形モデルでないと分離できないmoonの分類をやります。 カスタムモデルを実装するには、最低でもakebono.model.WrappedModel をベースにしたモデルが実装されている必要があります。
まず、カスタマイズされたモジュールを置く名前空間をcustomized
として以下のようなmodel.py
を作成します。
from tensorflow import keras as kr from akebono.model import WrappedModel from akebono.utils import ( pathjoin, ) def _get_keras_mlp_object(n_output_dim=None): model = kr.Sequential() model.add(kr.layers.Dense(64, activation='relu')) model.add(kr.layers.Dropout(0.5)) model.add(kr.layers.Dense(64, activation='relu')) model.add(kr.layers.Dropout(0.5)) model.add(kr.layers.Dense(n_output_dim, activation='softmax')) sgd = kr.optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True) model.compile(loss='categorical_crossentropy', optimizer=sgd) return model class MLP(WrappedModel): def base_init_finished(self): self.reset() def reset(self): self._value = _get_keras_mlp_object(**self._init_kwargs) def fit(self, X, y): self._value.fit(X, y, **self._fit_kwargs) return self def predict(self, X): return self._value.predict(X) def predict_proba(self, X): return self._value.predict_proba(X) def dump(self, dirpath, name): self.value.save(pathjoin(dirpath, name + '.h5')) kr.backend.clear_session() return self def load(self, dirpath, name): self._value = kr.models.load_model(pathjoin(dirpath, name + '.h5')) return self
また、Kerasの場合、目的変数の入力フォーマットがone-hot型のためmoonのような1次元ベクトル型の目的変数にそのままでは対応できません。
ここはdatasetの前処理を追加します。 dataset_preprocessor.py
として以下を作成します。
from tensorflow import keras as kr def target2categorical(df): if 'target' in df: target = df['target'].values t_categorical = list(kr.utils.to_categorical(target.reshape(target.shape[0], 1))) df['target'] = t_categorical return df
また、上記のように変換した型の目的変数は、pandas.DataFrameの型としてはnp.arrayのリストとして表現されてしまうのでKerasのモデルに入力
する際にはnp.arrayに変換する必要があります。このような目的にはFormatter
が使えるので、カスタマイズされたFormatter
を追加します。
formatter.py
として以下を保存します。
import numpy as np def convert_object2nparray(ser): return np.array(list(ser.values)).astype(np.int32)
config.py に追加する¶
先程作ったカスタムモジュールを含めた以下のようなconfig.py
を作成します。
train_config = { 'dataset_config': { 'loader_config': { 'name': 'binary_classifier_sample_moon', 'kwargs': { 'n_samples': 1000, 'noise': 0.1, 'random_state': 0, }, }, 'preprocess_func': 'target2categorical@customized.dataset_preprocessor', }, 'model_config': { 'name': 'MLP@customized.model', 'init_kwargs': { 'n_output_dim': 2, }, 'fit_kwargs': { 'epochs': 30, 'batch_size': 10, 'verbose': 0, }, 'evaluate_kwargs': { 'cross_val_iterator': 'KFold@sklearn.model_selection', 'cross_val_iterator_kwargs': { 'n_splits': 5, 'shuffle': True, 'random_state': 0, }, }, 'model_type': 'binary_classifier', }, 'formatter_config_for_target': { 'name': 'convert_object2nparray@customized.formatter', }, 'evaluate_enabled': True, 'fit_model_enabled': True, 'dump_result_enabled': True, }
今回は、MLPのdumpでHDF5で保存しているため、HDF5を扱うためのライブラリが環境にインストールされている必要があります。 また、evaluateの際、one-hot型の目的変数の場合model_typeの推論が上手くいかないのでmodel_typeを明示的に指定する必要があることに注意してください。
モデルの学習結果は、手元の環境では以下のようになりました。(実行するたび結果が変わると思います)
=== scenario summary .. tag: default === ------------------------------------------------------------ train_id: 0 accuracy f1_score log_loss precision recall roc_auc 0.99500 0.99475 0.17270 0.99193 0.99765 0.99936