概要
Keras で model.compile 時に独自の評価関数を指定する方法を紹介します
コードも前回のを引き継いでいます
内容は参考サイトと同じですがコードのリファクタと執筆時点での最新の tenforflow を使って動作確認しています
環境
- macOS 14.0
- Python 3.11.6
- keras 2.14.0
- tensorflow 2.14.0
サンプルコード
import datetime
from dataclasses import dataclass
from typing import Any, Optional, Union
import numpy as np
from tensorflow.keras import backend
from tensorflow.keras.callbacks import ModelCheckpoint, TensorBoard
from tensorflow.keras.layers import Dense
from tensorflow.keras.models import Sequential
# 説明変数を管理するクラス
class IndependentVariable:
NUM_TRAIN_COL = 2
# 128行2列の行列データ
data: np.ndarray[Any, np.dtype[np.float64]]
def __init__(self, row: int) -> None:
self.data = np.random.rand(row, self.NUM_TRAIN_COL)
# 目的変数を管理するクラス
class DependentVariable:
NUM_TRAIN_COL = 1
# 128行1列の行列データ、説明変数に対する答えのラベルを管理
labels: Any
def __init__(self, data: np.ndarray[Any, np.dtype[np.float64]], row: int) -> None:
# np.sum(data, axis=1) で各行ごとの合計を計算
# それが 1.0 以上なら True で True(1) or False(0) * 1 をするので最終的には128行の 0 or 1 の配列になる
self.raw_labels = (np.sum(data, axis=1) > 1.0) * 1
self.labels = self.raw_labels.reshape(row, self.NUM_TRAIN_COL)
# テストデータを管理するクラス
class TestData:
NUM_TRAIN_ROW = 128
def __init__(self) -> None:
self.independent = IndependentVariable(self.NUM_TRAIN_ROW)
self.dependent = DependentVariable(self.independent.data, self.NUM_TRAIN_ROW)
# モデルを管理するクラス
CallbackType = Union[ModelCheckpoint, TensorBoard]
class Model:
model: Sequential
def __init__(self) -> None:
self.model = Sequential()
def compile(self) -> None:
# 結合層(2層->4層)
self.model.add(Dense(4, input_dim=2, activation="tanh"))
# 結合層(4層->1層):入力次元を省略すると自動的に前の層の出力次元数を引き継ぐ
self.model.add(Dense(1, activation="sigmoid"))
self.model.compile(
# accuracy は acc, binary_accuracy と同じ
loss="binary_crossentropy",
optimizer="sgd",
# metrics=["accuracy", Metrics().mean_pred],
metrics=[Metrics().mean_pred],
)
def show(self):
self.model.summary()
def train(
self,
independent: IndependentVariable,
dependent: DependentVariable,
epochs=300,
validation_split=0.2,
callbacks: Optional[list[CallbackType]] = [],
):
self.model.fit(
independent.data,
dependent.labels,
epochs=epochs,
validation_split=validation_split,
callbacks=callbacks,
)
def save(self, file_name="my_model"):
self.model.save(file_name)
# model.fit の callback で使用する関数を管理するクラス
class Callback:
@classmethod
def save_model(cls, file_name: str = "./model.hdf5") -> ModelCheckpoint:
return ModelCheckpoint(file_name, save_best_only=True)
@classmethod
def tensorboard(cls, log_dir: str = "logs/fit/") -> TensorBoard:
log_dir = log_dir + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
return TensorBoard(log_dir=log_dir, histogram_freq=1)
# 評価関数を管理するクラス
class Metrics:
def mean_pred(self, _, y_pred):
return backend.mean(y_pred)
# 実際にモデルを評価するためのクラス
@dataclass
class Result:
accuracy: float
class Test:
NUM_TEST_ROW = 50
def __init__(self, model: Model) -> None:
self.model = model
# テストデータは Independent, DependentVariable を使える
self.independent = IndependentVariable(self.NUM_TEST_ROW)
self.dependent = DependentVariable(self.independent.data, self.NUM_TEST_ROW)
def run(self) -> Result:
predict = ((self.model.model.predict(self.independent.data) > 0.5) * 1).reshape(
self.NUM_TEST_ROW
)
# 50個中何個正解だったか
accuracy = sum(predict == self.dependent.raw_labels) / self.NUM_TEST_ROW
return Result(accuracy=accuracy)
if __name__ == "__main__":
# テストデータ作成
test_data = TestData()
# モデル生成
model = Model()
model.compile()
# モデルの訓練
model.train(
test_data.independent,
test_data.dependent,
callbacks=[Callback.save_model(), Callback.tensorboard()],
)
model.save()
# モデルの評価
test = Test(model)
result = test.run()
print(result)
ちょっと解説
評価関数は compile 時に metrics で指定します
標準で付属の評価関数もいくつかあります
今までは acc = accuracy = binary_accuracy を指定していました
今回は独自の評価関数を作成して指定します
評価関数は Metrics クラスで管理します
独自の評価関数は 2 つの引数を取ります
y_true (正解ラベル) と y_pred (予測値) が必須になります
今回は backend.mean は平均値を計算するメソッドです
最後に
acc などデフォルトで用意されている評価関数でも精度に大きな問題は出ませんが独自の評価関数にすることで精度が大きく向上する場合もあるので使えて損はない技術だと思います
0 件のコメント:
コメントを投稿