カスタムモデルを実装する
隠れ層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