質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.48%

カスタムされた教師なし学習モデルの使い方がわからない(keras)

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 723

score 23

現在、こちらの記事の学習モデルを実装しようとしております。

「教師なし学習でMNISTの正解率を97%以上出す簡単な手法(転移学習なし)」
https://qiita.com/Amanokawa/items/0aa24bc396dd88fb7d2a

カスタムする学習方法を作成するのは初めてで、こちらの方の記事も参考にしたのですが、(「TensorFlow2.0でDistribute Trainingしたときにfitと訓練ループで精度が違ってハマった話」https://blog.shikoan.com/tf20-distribute-error/)
train_on_batchの使い方がわからないのと、学習をスタートさせるにはどのようなコードで指示すれば良いのかわかりません。
このコードで間違っている部分と、改善策などを教えていただきたいです。(keras + tensorflowを用いております。)

また、今後もモデルを自作する機会があるかと思われますので、データ作成からモデル構築、学習までのひな型のようなものを教えていただけるとありがたいです。

入力は(100,100,3)の画像データをnumpy形式にしております。
今までは

model.fit(x,y,batch,epoch,validation,...)


のようにしておりました。
ひとまず、以下のようなコードを作成しましたが(とはいってもほぼコピーになりますが)、

import tensorflow as tf
import os
from tensorflow.keras import layers
import pickle
strategy = tf.distribute.get_strategy()

x = np.load(---)
x_ = np.load(---)
x_test = np.load(---)
x_test_ = np.load(---)

class Model(layers.Layer):

    def create_model(self):
        inputs = layers.Input((100,100,3))

        x = layers.Conv2D(32, 3, padding="same")(inputs)
        x = layers.BatchNormalization()(x)
        x = layers.Activation("relu")(x)
        x = layers.MaxPooling2D(2)(x)

        x = layers.Conv2D(64, 3, padding="same")(x)
        x = layers.BatchNormalization()(x)
        x = layers.Activation("relu")(x)
        x = layers.MaxPooling2D(2)(x)

        x = layers.Conv2D(128, 3, padding="same")(x)
        x = layers.BatchNormalization()(x)
        x = layers.Activation("relu")(x)
        x = layers.MaxPooling2D(2)(x)

        x = layers.Conv2D(256, 3, padding="same")(x)
        x = layers.BatchNormalization()(x)
        x = layers.Activation("relu")(x)
        conv_out = layers.GlobalAveragePooling2D()(x)

        x = layers.Dense(128, activation="relu")(conv_out)
        x = layers.Dense(64, activation="relu")(x)
        Z = layers.Dense(10, activation="softmax")(x)

        x = layers.Dense(128, activation="relu")(conv_out)
        x = layers.Dense(64, activation="relu")(x)
        overclustering = layers.Dense(50, activation="softmax")(x)

        return Model(inputs, [Z, overclustering])


def load_dataset(batch_size):
    (X_train, y_train), (X_test, y_test) = (x,x_),(x_test,x_test_)
    trainset = (X_train, y_train)
    testset = (X_test, y_test)
    return trainset, testset 

def main():
    batch_size = 10
    trainset, valset = load_dataset(batch_size)
    result = {"val_acc": [], "lr": []}
    with strategy.scope():
        model = Model()
        optim = tf.keras.optimizers.Adam(0.0001)

        # Distributed用のデータセットの変換を行う
        trainset = strategy.experimental_distribute_dataset(trainset)
        valset = strategy.experimental_distribute_dataset(valset)

        def IIC(self, z, z_, c=10):
            z = tf.reshape(z, [-1, c, 1])
            z_ = tf.reshape(z_, [-1, 1, c])
            P = tf.math.reduce_sum(z * z_, axis=0)  # 同時確率
            P = (P + tf.transpose(P)) / 2  # 対称化
            P = tf.clip_by_value(P, 1e-7, tf.float32.max)  # logが発散しないようにバイアス
            P = P / tf.math.reduce_sum(P)  # 規格化

            # 周辺確率
            Pi = tf.math.reduce_sum(P, axis=0)
            Pi = tf.reshape(Pi, [c, 1])
            Pi = tf.tile(Pi, [1,c])
            Pj = tf.math.reduce_sum(P, axis=1)
            Pj = tf.reshape(Pj, [1, c])
            Pj = tf.tile(Pj, [c,1])

            loss = tf.math.reduce_sum(P * (tf.math.log(Pi) + tf.math.log(Pj) - tf.math.log(P)))

            return loss
        acc = tf.keras.metrics.SparseCategoricalAccuracy()


        @tf.function
        def train_on_batch( X, X_):
            with tf.GradientTape() as tape:
                z, overclustering = model(X, training=True)
                z_, overclustering_ = model(X_, training=True)
                loss_cluster = IIC(z, z_)
                loss_overclustering = IIC(overclustering, overclustering_, c=50)

                loss = (loss_cluster + loss_overclustering) / 2

            graidents = tape.gradient(loss, self.model.trainable_weights)
            self.optim.apply_gradients(zip(graidents, self.model.trainable_weights))
            return loss_cluster, loss_overclustering


        def validation_on_batch(X, y_true):
            y_pred = model(X, training=False)
            acc.update_state(y_true, y_pred)


        for i in range(100):
            acc.reset_states()
            print("Epoch = ", i)
            for X, y in trainset:
                train_on_batch(X, y)
            train_acc = acc.result().numpy()

            acc.reset_states()
            for X, y in valset:
                validation_on_batch(X, y)
            print(f"Train acc = {train_acc}, Validation acc = {acc.result().numpy()}")

            if i == 60:
                optim.lr = 0.01
            elif i == 85:
                optim.lr = 0.001

            result["val_acc"].append(acc.result().numpy())
            result["lr"].append(optim.lr.numpy()) # numpyにしないとWeaker objectが云々言うから

    with open("history_correct.dat", "wb") as fp:
        pickle.dump(result, fp)

if __name__ == "__main__":
    main()


このようにエラーが出たため、行き詰りました。

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-6-06b2ec27c006> in <module>
    121 
    122 if __name__ == "__main__":
--> 123     main()

<ipython-input-6-06b2ec27c006> in main()
    100             acc.reset_states()
    101             print("Epoch = ", i)
--> 102             for X, y in trainset:
    103                 train_on_batch(X, y)
    104             train_acc = acc.result().numpy()

ValueError: too many values to unpack (expected 2)

おそらく、データの形などが間違っていると思われますが、これを解決しても、このコードが回るかもわかりません…

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正の依頼

  • meg_

    2020/09/01 20:33

    print(trainset)で何が出力されますか?

    キャンセル

  • blackmk

    2020/09/02 10:49

    質問ありがとうございます。
    (array([[[[0.6039216 , 0.5921569 , 0.69803923],
    [0.6039216 , 0.5921569 , 0.69803923],
    [0.60784316, 0.6 , 0.69411767],
    ...,
    [0.4627451 , 0.4627451 , 0.4627451 ],
    [0.4627451 , 0.4627451 , 0.4627451 ],
    [0.4627451 , 0.4627451 , 0.4627451 ]],
    …]]]], dtype=float32)…
    というものが出力されます。元のコードではData Augmentationを行っており、私には必要なかったので、その部分を省きました。たしかに、batch_sizeの変数が関数内に入ってないです。

    キャンセル

  • meg_

    2020/09/02 19:22

    trainsetには訓練データと正解データが格納されていることを想定したコードなのに、訓練データしかないのでエラーとなっているのだと思います。
    x,x_には正しい値が入っていますでしょうか?

    キャンセル

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.48%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る