KKkbt
@KKkbt (Kenta Kubota)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Deep Learningの学習データについて

状況

現在,機械工学部の研究室でディープラーニングを用いた研究をしています.
その研究の中で,CNNを用いて分類問題に取り組んでいます.

疑問

学習データについて疑問があります.
学習データは
(1)ラベル順に並べる
(2)ラベル順に関係なくランダムに並べる
どちらが良いのでしょうか?
できれば理由も知りたいです.

例)
ラベルがa, b, c, dだった時,

train_label = [a, a, a, a, a, b, b, b, b, b, c, c, c, c, c, d, d, d, d, d]

となるように学習データを整理するべきなのか,それとも

train_label = [a, d, b, c, a, b, ...]

とランダムなデータを使うべきなのかどうか.

自分で試したこと

使ったモデル

def build_model():
    inputs = tf.keras.layers.Input((501,3))

    x = tf.keras.layers.Conv1D(16,64,1,kernel_initializer = 'he_normal')(inputs) #畳み込み層(64*1)*16
    x = tf.keras.layers.BatchNormalization()(x)
    x = tf.keras.layers.ReLU()(x)
    #x = tf.keras.layers.MaxPooling1D(pool_size=2, strides=2, padding='valid')(x)

    x = tf.keras.layers.Conv1D(16,32,1,kernel_initializer = 'he_normal')(x)
    x = tf.keras.layers.BatchNormalization()(x)
    x = tf.keras.layers.ReLU()(x)
    #x = tf.keras.layers.MaxPooling1D(pool_size=2, strides=None, padding='valid')(x)

    x = tf.keras.layers.Conv1D(16,16,1,kernel_initializer = 'he_normal')(x)
    x = tf.keras.layers.BatchNormalization()(x)
    x = tf.keras.layers.ReLU()(x)
    #x = tf.keras.layers.MaxPooling1D(pool_size=2, strides=None, padding='valid')(x)

    x = tf.keras.layers.Conv1D(16,8,1,kernel_initializer = 'he_normal')(x)
    x = tf.keras.layers.BatchNormalization()(x)
    x = tf.keras.layers.ReLU()(x)
    #x = tf.keras.layers.MaxPooling1D(pool_size=2, strides=None, padding='valid')(x)

    x = tf.keras.layers.Conv1D(16,4,1,kernel_initializer = 'he_normal')(x)
    x = tf.keras.layers.BatchNormalization()(x)
    x = tf.keras.layers.ReLU()(x)
    #x = tf.keras.layers.MaxPooling1D(pool_size=2, strides=None, padding='valid')(x)

    x = tf.keras.layers.Flatten()(x)
    x = tf.keras.layers.Dense(num_class)(x)
    x = tf.keras.activations.softmax(x)

    return tf.keras.models.Model(inputs, x)


model = build_model()
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

history = model.fit(train_dataset, train_label,epochs=100,verbose=1,batch_size=32)

実際に自分は両方試してみて,結果は
(1)正答率:約97%
(2)正答率:約20%
でした.

手元には(467, 3)のデータが一クラス当たり21あります.
総クラス数は19で,かなり少ないと思います.
したがって,(2)の並べ方が正しいのかなと個人的に思っています.

0

1Answer

ご推察のとおり、(2) が良いと思います。

DNNの訓練では、batch_sizeの入力データに対しDNNの出力y_predを計算する順伝搬と、 出力y_predと正解データy_trueとのずれ(損失関数)が小さくなるようにDNN内のパラメータを更新する逆伝搬をミニバッチごとに繰り返していきます。

まず、簡単な場合として、学習データの総数がbatch_sizeよりも小さい場合は、学習データの順番は関係ないことが分かるでしょう。

次に、学習データを2つ以上のミニバッチに分割したときを考えましょう。このとき、ミニバッチ内に偏りがある、例えばラベルaだけが入っていると、このミニバッチを使った逆伝搬では、ラベルaだけを正解することを考慮したパラメータ更新が行われると予想できます。学習データの順番がラベルでソートされている場合、このようにミニバッチごとでパラメータの更新が不安定になりそうです(ここでいう不安定とは、あるミニバッチではラベルaに特化した更新、また別のミニバッチではラベルbに特化した更新…と、全ラベルに対する損失関数や正解率が底上げされにくいことを表します)。反対に、学習データをランダムにシャッフルした場合は、それぞれのミニバッチにおいて、さまざまなラベルをより正解しようとするパラメータ更新が期待できるでしょう。

なお、パラメータをどれくらい大きく更新するかは、学習率 (learning rate) で設定することができます。エポックを追うごとに学習率を小さくしていけば、学習データをラベル順に並べた場合でも、シャッフルした場合に近い性能が得られるのではないでしょうか(学習率を小さくしていくことで、前述の不安定さが徐々に減少していくと考えられるため)。

「自分で試したこと」のとおり、自分でコードを書いて実験されているのは大変素晴らしいと思います。Adam (optimizer='adam') は学習率を適応的に調整する最適化アルゴリズムのため、学習データの並びと正解率との関係を調査する場合には、SDGなど他のアルゴリズムに変更すると、問題の切り分けがしやすくなりそうです。

0Like

Your answer might help someone💌