2023年11月5日日曜日

Keras で Tensorboard を使う

Keras で Tensorboard を使う

概要

tensorboard はモデルや関数、データセットの内容などいろいろな情報を可視化できるツールです
今回は tensorboard を動かしてみました

コードも前回のを引き継いでいます
内容は参考サイトと同じですがコードのリファクタと執筆時点での最新の tenforflow を使って動作確認しています

環境

  • macOS 14.0
  • Python 3.11.6
    • keras 2.14.0
    • tensorflow 2.14.0
    • tensorboard 2.14.1

インストール

  • pipenv install tensorboard

サンプルコード

tensorboard は学習の際に出力されるログファイルを元に起動します
まずは学習時のコードを修正します
callbacks を使って model.fit 時に tensorboard に必要なログ情報を出力するようにします

import datetime
from dataclasses import dataclass
from typing import Any, Optional, Union

import numpy as np
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(
            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,
        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)


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)


# 実際にモデルを評価するためのクラス
@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)

実行後に logs/fit/20231101-101337/ という日付付きのフォルダがあることを確認しましょう

tensorboard 起動

  • pipenv run tensorboard --logdir logs/fit
Serving TensorBoard on localhost; to expose to the network, use a proxy or pass --bind_all
TensorBoard 2.14.1 at http://localhost:6006/ (Press CTRL+C to quit)

あとは localhost:6006 にアクセスすればいろいろな情報が確認できます

最後に

起動までは簡単ですが tensorboard 自体が複雑で使い方がわかるまでに学習が必要そうです

参考サイト

0 件のコメント:

コメントを投稿