概要
前回 RNN のサンプルを動かしましたがそもそも Keras の仕組みがさっぱりだったので簡単なデータからモデルの訓練までできる簡単なサンプルを動かしてみました
流れがわかりやすいようにクラス化もしています
環境
- macOS 14.0
- Python 3.11.6
- keras 2.14.0
- tensorflow 2.14.0
サンプルコード
from dataclasses import dataclass
from typing import Any
import numpy as np
from tensorflow.keras.layers import Dense # type: ignore
from tensorflow.keras.models import Sequential # type: ignore
# 説明変数を管理するクラス
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)
# モデルを管理するクラス
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(
loss="binary_crossentropy", optimizer="sgd", metrics=["accuracy"]
)
def show(self):
self.model.summary()
def train(
self,
independent: IndependentVariable,
dependent: DependentVariable,
epochs=300,
validation_split=0.2,
):
self.model.fit(
independent.data,
dependent.labels,
epochs=epochs,
validation_split=validation_split,
)
# 実際にモデルを評価するためのクラス
@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)
# モデルの評価
test = Test(model)
result = test.run()
print(result)
ちょっと解説
大きく「テストデータ」「モデル」「評価」というクラスに分割しました
その中で更に説明変数や目的変数といったクラスを委譲しています
main を見ると全体流れが簡単に把握できるかなと思います
基本はデータ作成 -> モデル生成 -> 評価という流れになっています
リファクタすることで学習したデータと評価するためのデータが同じクラスから作成できるのでコードの重複を排除できました
最後に
keras の既存コードをリファクタしつつ動かすだけでもかなり理解が深まる気がしました
0 件のコメント:
コメントを投稿