

現在機械学習のプログラムを作成しております。  
その際に過学習をしているかの判定のために、epochごとのtrainとvalidationの関係をグラフ化したいのですが、お恥ずかしいことにプログラムの書き方がわかりません。  
基本的なグラフ化のサイトには目は通しましたが、自身のプログラムへ適応させたものへの変更、また環境の都合上一度ファイルとして出力する必要がある都合上、どのようにグラフをファイルとして出力すればよいかわかりません。

コードを掲載いたしますので、具体的なコード例を用いて解決策をご教授いただければ幸いです。  
普段SSHで外部のPCと接続しての作業のため、直接ターミナル等への表示ではなく、画像ファイル等の出力形態であると助かります。

[code]

    os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'                                    #警告表示の解除
    import numpy as np
    import tensorflow as tf
    import random
    from sklearn.preprocessing import LabelEncoder                              #sklearnライブラリに含まれるLabelEncoderクラスをインポートしている(LabelEncoderは数値や文字列で表されたラベルを(0~ラベル種類数-1)までの数値に変換する)
    from keras.utils import np_utils
    import pandas as pd                                                         #データ解析を容易にするためのモジュール pdという名前でインポートしている
    from keras.preprocessing.text import Tokenizer                              #Kerasライブラリに含まれるTokenizerクラスをインポートしている(Tokenizerは文章のベクトル化に必要)
    from keras.utils import pad_sequences                                       #Kerasライブラリに含まれるsequenceクラスとインポートしている(sequenceは異なる長さのテンソルの末尾を0埋めして長さを揃えてくれる)
    from sklearn.model_selection import train_test_split                        #sklearnライブラリに含まれるtrain_test_splitクラスをインポートしている(train_test_splitはデータをテストと訓練に二分割する)
    from keras.models import Sequential                                         #kerasライブラリに含まれるSequentialクラスをインポートしている(Sequentialは入力と出力が一つずつのニューラルネットワーク)
    from keras.layers import Dense, Embedding, LSTM                             #kerasライブラリに含まれるDense, Embedding, LSTMクラスをインポートしている(後日調べる)
    from keras.callbacks import EarlyStopping                                   #kerasライブラリに含まれるEarlyStoppingクラスをインポートしている(EarlyStoppingは過学習を引き起こす前に学習を止めてくれる)
    from keras.layers import Dropout                                            #kerasライブラリに含まれるDropoutクラスをインポートしている(Dropoutは過学習を抑制してくれる理論は知らん)
    from keras.backend import clear_session                                     #kerasライブラリに含まれるclear_sessionクラスをインポートしている(clear_sessionは識別子をリセットする)
    from keras.models import Sequential                                         #kerasライブラリに含まれるSequentialクラスをインポートしている(clear_sessionは識別子をリセットする)
    from keras.layers import Dense, Activation, Dropout, LSTM                   #
    from tensorflow.keras.optimizers import Adam                                #tensorflowライブラリに含まれるAdamクラスをインポートしている()
    import optuna                                                               #
    from keras.wrappers.scikit_learn import KerasClassifier                     #kerasライブラリに含まれるKerasClassifierクラスをインポートしている()
    from sklearn.model_selection import cross_val_score
    
    SEED = 0
    random.seed(SEED)
    np.random.seed(SEED)
    tf.random.set_seed(SEED)
    
    with open("all_api_call.txt") as f:
        content = f.readlines()
    content = [x.strip() for x in content]
    data = pd.DataFrame()                                                       #データフレームの作成(データフレームは表形式のデータになる)
    data['feature'] = content
    
    max_words = 800                                                             #トークン化するAPIの総数を定義
    max_len = 300
    X = data['feature']
    
    """トークン化,シーケンス番号への変換"""
    #トークン化...文章を単語や文字列単語に分割すること(今回はAPI名ごとに分割)
    #シーケンス番号...機械学習で扱いやすい数値
    tokenizer = Tokenizer(num_words=max_words)                                  #Tokenizerのインスタンスを作成・num_wordsは学習させたい単語の種数を入れる
    tokenizer.fit_on_texts(X)                                                   #XをAPI名ごと分割し,それぞれに番号を与える(トークン化)・(例)'getasynckeystate': 1, 'ntdelayexecution': 2, 'ntclose': 3...
    X = tokenizer.texts_to_sequences(X)                                         #API名をシーケンス番号に変換する
    X = pad_sequences(X, maxlen=max_len, truncating='post')                     #シーケンスの設定(maxlenはシーケンスの最大値,truncatingはmaxlen以上のシーケンスを前後どちらで切り詰めるか"post"は末尾(この場合は101回目以降がカットされる))
    #print(tokenizer.word_index)
    #print(X)
    
    """シーケンス番号とAPI名称の対応状況について(補足)"""
    #トークン化の際に与えた番号とシーケンス番号が一致している
    #上記対応付けを行うことでLSTMを使用して訓練を可能にしている
    
    """正解ラベルの読み込み"""
    with open("labels.csv") as f:
        label_data = f.readlines()
    
    """正解ラベルの整形"""
    label_data = [x.strip() for x in label_data]
    data["labels"] = label_data
    
    """検出器の作成(今回はVirusとラベリングされている物を検出する)"""
    y = data["labels"].apply(lambda x: 1 if x == "Worm.Win32.Vobfus" else 0)                #条件定義(applyはデータフレームの各行に条件を適応する)
    
    """訓練データとテストデータに分割"""
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.15,random_state=SEED)   #テストデータが15%,訓練が85%で分割
    
    
    """ニューラルネットワークの各層について(補足)"""
    #埋め込み層...整数でエンコードされた単語ベクトルを受け取り,各単語のインデックスに対する分散表現を算出する
    #分散表現...単語を低次元の実数値ベクトルで表す表現(他の方法では単語の並び順や順序を維持できない)
    #LSTM層...前層からの出力である分散表現を受け取り,それをもとに訓練を行う
    #出力層...予測値を出力する
    
    
    
    
    """LSTMを用いてモデル準備"""
    def malware_model():
        model = Sequential()                                                    #Sequential宣言
        model.add(Embedding(max_words, 300, input_length=max_len))              #整数でエンコードされた単語(API名)ベクトルを受け取り,各単語のインデックスに対する分散表現を算出する
        model.add(LSTM(32, return_sequences=False))
        model.add(Dense(1, activation='sigmoid'))
        return model
    
    """モデルを有効化して訓練"""
    model = malware_model()
    model.summary()                                                              #モデルの要約を出力する
    model.compile(                                                               #訓練に関する設定を行う
        loss='binary_crossentropy',                                              #損失関数に二値交差エントロピーを指定
        optimizer='adam',metrics=['accuracy']                                    #最適化アルゴリズムにAdamを指定
        )
    #損失関数...正解値と算出した予測値のズレを求めるのに用いる
    #二値交差エントロピー...2つの確立分布がどれくらい離れているかを表す指標
    #最適化アルゴリズム...損失を0にすることを目的としたもの
    #Adam...わからん
    history = model.fit(                                                        #訓練の実行(history = model.fit(...)は固定)
        X_train,
        y_train,
        batch_size=64,                                                          #サブセット分ける(サイズは2のn乗から決める)
        epochs=10,                                                              #学習する回数を設定(試しながら決める)
        validation_data=(X_test, y_test),                                       #検証するデータを引数として渡す
        verbose=1                                                               #結果をエポックごとのログがプログレスバーの進行状況とともに表示
        )
    
    """ハイパーパラメータチューニング"""
    class Objective:
        def __init__(self, X, y):                                               #クラス構造で情報を保持するための重要な構文
            self.X = X                                                          #クラス構造を取る際の定型の構文
            self.y = y                                                          #クラス構造を取る際の定型の構文
    
        def __call__(self, trial):                                              #インスタンスを関数のとして扱う
            # セッションのクリア
            clear_session()     #セッションのクリア
    
    
            # モデルの作成と、パラメータ探索の設定
            model = Sequential()                                                #Sequentialモデルの生成
            model.add(Embedding(max_words, 300, input_length=max_len))          #整数でエンコードされた単語(API名)ベクトルを受け取り,各単語のインデックスに対する分散表現を算出する
            model.add(LSTM(32, return_sequences=False))
            model.add(Dense(1, activation='sigmoid'))
    
            optimizer = Adam(
                learning_rate=trial.suggest_loguniform("learning_rate", 1e-5, 1e-1),
                beta_1=trial.suggest_uniform("beta_1", 0.0, 1.0),
                beta_2=trial.suggest_uniform("beta_2", 0.0, 1.0)
                )
            model.compile(
                loss='binary_crossentropy',
                optimizer=optimizer,
                metrics=['accuracy']
                )
            model.fit(
                self.X,
                self.y,
                batch_size=256,
                epochs=10,
                validation_data=(X_test, y_test)
                )
    
            return model.evaluate(X_test, y_test, verbose=0)[1]
    
    objective = Objective(X_train, y_train)
    study = optuna.create_study(sampler=optuna.samplers.RandomSampler(seed=SEED))
    study.optimize(objective, timeout=1200)
    print('params:', study.best_params)
    """実検証"""
    def buildmodel():
        model = Sequential()
        model.add(Embedding(max_words, 300, input_length=max_len))
        #model.add(LSTM(32, return_sequences=True))
        model.add(LSTM(32, return_sequences=False))
        model.add(Dense(1, activation='sigmoid'))
        # ベストのパラメータを設定
        optimizer = Adam(
            learning_rate = study.best_params['learning_rate'],
            beta_1 = study.best_params['beta_1'],
            beta_2 = study.best_params['beta_2']
        )
        model.compile(
            loss='binary_crossentropy',
            optimizer=optimizer,
            metrics=['accuracy']
            )
        return model
    
    clf = KerasClassifier(
        buildmodel,
        epochs=10,
        batch_size=256,
        verbose=1
        )
    
    results = cross_val_score(clf, X, y, cv=5)
    print('Test accuracy: ', results.mean())
    
[/code]


CC BY-SA 4.0
2023-10-11T06:24:21.003
96468
2023-10-20T10:28:09.143
2023-10-11T09:52:32.910
3060
59660
question
python 機械学習 tensorflow matplotlib
機械学習の学習過程をグラフ化したい


tensorboardについては確認されましたでしょうか。  
tensorflowやkerasを利用しているのであるならば、数行の修正でグラフ化が可能なので試していただければと思います。

<https://www.tensorflow.org/tensorboard/get_started?hl=ja>

[code]

    import tensorflow as tf
    from tensorflow.keras.callbacks import TensorBoard #TensorBoardをimport
    import datetime
    
    # TensorBoardのコールバックを設定
    log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
    tensorboard_callback = TensorBoard(log_dir=log_dir, histogram_freq=1, write_images=True)
    
    model = xxxxx_model()  # あなたのモデル関数
    model.compile(
        loss='binary_crossentropy',
        optimizer='adam',
        metrics=['accuracy']
    )
    
    # モデルの訓練中にTensorBoardコールバックを使用
    history = model.fit(
        X_train,
        y_train,
        batch_size=64,
        epochs=10,
        validation_data=(X_test, y_test),
        callbacks=[tensorboard_callback],  # ここにコールバックを追加
        verbose=1
    )
    
[/code]

その後sshで接続したターミナル上で  
tensorboard --logdir logs/fit  
を実行することで結果確認のためのWebサーバが立ち上がるのでそこで確認が可能です。


CC BY-SA 4.0
2023-10-20T10:17:09.903
96533
2023-10-20T10:28:09.143
2023-10-20T10:28:09.143
19716
19716
96468
answer