Keras/TensorFlow PlatoBlockchain Data Intelligence のコサイン減衰を使用した学習率ウォームアップ。垂直検索。あい。

Keras/TensorFlow での余弦減衰による学習率のウォームアップ

学習率は、深層学習ネットワークの重要なハイパーパラメーターです。 与えられた損失関数を最小化すると推定される重みの更新が実行されます。 シンガポールドルで:

$$
weight_{t+1} =weight_t – lr * frac{derror}{dweight_t}
$$

の学習率で 0、更新された重みはそれ自体に戻っています– 重量t. 学習率は事実上、学習を有効または無効にするために回すことができるノブであり、重みの更新の程度を直接制御することにより、学習の量に大きな影響を与えます。

オプティマイザが異なれば、学習率の利用方法も異なりますが、基本的な概念は同じままです。 言うまでもなく、学習率は多くの研究、論文、実践者のベンチマークの対象となっています。

一般的に言えば、ほとんどの人は、静的な学習率がそれをカットしないことに同意しており、トレーニング中に学習率を調整するほとんどの手法で、何らかのタイプの学習率の低下が発生します。割引。

近年定着しつつある技術として、 学習率のウォームアップ、実質的に他の削減技術と組み合わせることができます。

学習率ウォーミングアップ

学習率ウォームアップの背後にある考え方は単純です。 トレーニングの初期段階では、ウェイトは理想的な状態からかけ離れています。 これは全面的に大規模な更新を意味し、これは各重みの「過剰修正」と見なすことができます。別の大幅な更新が他の重みの更新を無効にし、トレーニングの初期段階をより不安定にする可能性があります。

これらの変更はうまくいきますが、最初は小さな学習率を使用し、より安定した次善の状態に到達してから、より大きな学習率を適用することで回避できます。 ネットワークを更新するのではなく、ネットワークを簡単に更新することができます。

それが学習率のウォームアップです! 低い (または 0) 学習率から開始し、開始学習率 (とにかく開始するもの) まで増やします。 この増加は実際にはどの関数にも従う可能性がありますが、通常は直線的です。

初期レートに達した後、コサイン減衰、線形削減などの他のスケジュールを適用して、トレーニングの終了までレートを徐々に下げることができます。 通常、学習率のウォームアップは XNUMX つのスケジュールの一部であり、LR ウォームアップが最初で、学習率が開始点に達した後に別のスケジュールが引き継がれます。

このガイドでは、Keras/TensorFlow で学習率のウォームアップを実装します。 keras.optimizers.schedules.LearningRateSchedule サブクラスと keras.callbacks.Callback 折り返し電話。 から学習率が上がります。 0 〜へ target_lr これは非常に一般的な二次スケジュールであるため、余弦減衰を適用します。 いつものように、Keras は、さまざまな方法で柔軟なソリューションを実装し、それらをネットワークと共に出荷することを簡単にします。

注: 実装は一般的であり、 Tony の Keras 実装 「」で概説されているトリックの畳み込みニューラル ネットワークを使用した画像分類のための一連のトリック」.

Keras コールバックによる学習率

学習率スケジュールを実装する最も簡単な方法は、 lr パラメータ(float32)、何らかの変換を経て、それを返します。 この関数は次に LearningRateScheduler 関数を学習率に適用するコールバック。

今、 tf.keras.callbacks.LearningRateScheduler() 学習率の計算に使用する関数にエポック番号を渡しますが、これはかなり粗いものです。 LRウォームアップはそれぞれで行う必要があります 手順 (バッチ)、エポックではないため、派生する必要があります global_step (すべてのエポックにわたって)代わりに学習率を計算し、 Callback 各呼び出しで引数を渡す必要があるため、関数を渡すだけではなく、カスタム コールバックを作成します。これは、関数を渡すだけでは不可能です。

def func():
    return ...
    
keras.callbacks.LearningRateScheduler(func)

このアプローチは、高レベルのカスタマイズを望まず、Keras の処理方法に干渉したくない場合に適しています。 lr、特に次のようなコールバックを使用する場合 ReduceLROnPlateau() フロートベースでのみ機能するため lr. 便利な関数から始めて、Keras コールバックを使用して学習率のウォームアップを実装しましょう。

def lr_warmup_cosine_decay(global_step,
                           warmup_steps,
                           hold = 0,
                           total_steps=0,
                           start_lr=0.0,
                           target_lr=1e-3):
    
    learning_rate = 0.5 * target_lr * (1 + np.cos(np.pi * (global_step - warmup_steps - hold) / float(total_steps - warmup_steps - hold)))

    
    warmup_lr = target_lr * (global_step / warmup_steps)

    
    
    if hold > 0:
        learning_rate = np.where(global_step > warmup_steps + hold,
                                 learning_rate, target_lr)
    
    learning_rate = np.where(global_step < warmup_steps, warmup_lr, learning_rate)
    return learning_rate

各ステップで、学習率とウォームアップ学習率 (スケジュールの両方の要素) を計算します。 start_lr & target_lr. start_lr 通常は 0.0、一方、 target_lr ネットワークとオプティマイザに依存します – 1e-3 は適切なデフォルトではない可能性があるため、メソッドを呼び出すときは、LR を開始するターゲットを必ず設定してください。

Status global_step トレーニングでは warmup_steps 設定済み - コサイン減衰スケジュール LR を使用します。 そうでない場合は、まだウォームアップ中であることを意味するため、ウォームアップ LR が使用されます。 もし hold 引数が設定されている場合、 target_lr ウォームアップ後、余弦減衰前のそのステップ数。 np.where() このための優れた構文を提供します。

np.where(condition, value_if_true, value_if_false)

関数は次のように視覚化できます。

steps = np.arange(0, 1000, 1)
lrs = []

for step in steps:
  lrs.append(lr_warmup_cosine_decay(step, total_steps=len(steps), warmup_steps=100, hold=10))
plt.plot(lrs)

ここで、この関数をコールバックの一部として使用し、オプティマイザ ステップを global_step 任意の配列の要素ではなく、クラス内で計算を実行できます。 サブクラス化しましょう Callback クラス:

from keras import backend as K

class WarmupCosineDecay(keras.callbacks.Callback):
    def __init__(self, total_steps=0, warmup_steps=0, start_lr=0.0, target_lr=1e-3, hold=0):

        super(WarmupCosineDecay, self).__init__()
        self.start_lr = start_lr
        self.hold = hold
        self.total_steps = total_steps
        self.global_step = 0
        self.target_lr = target_lr
        self.warmup_steps = warmup_steps
        self.lrs = []

    def on_batch_end(self, batch, logs=None):
        self.global_step = self.global_step + 1
        lr = model.optimizer.lr.numpy()
        self.lrs.append(lr)

    def on_batch_begin(self, batch, logs=None):
        lr = lr_warmup_cosine_decay(global_step=self.global_step,
                                    total_steps=self.total_steps,
                                    warmup_steps=self.warmup_steps,
                                    start_lr=self.start_lr,
                                    target_lr=self.target_lr,
                                    hold=self.hold)
        K.set_value(self.model.optimizer.lr, lr)

ベストプラクティス、業界で認められた標準、および含まれているチートシートを含む、Gitを学習するための実践的で実用的なガイドを確認してください。 グーグルGitコマンドを停止し、実際に 学ぶ それ!

まず、クラスのコンストラクターを定義し、そのフィールドを追跡します。 終了したバッチごとに、グローバル ステップを増やし、現在の LR を記録し、これまでの LR のリストに追加します。 各バッチの開始時に – を使用して LR を計算します lr_warmup_cosine_decay() 関数を呼び出し、その LR をオプティマイザの現在の LR として設定します。 これは、バックエンドの set_value().

それが完了したら、合計ステップ (長さ/バッチサイズ*エポック) を計算し、その数の一部を warmup_steps:


total_steps = len(train_set)*config['EPOCHS']



warmup_steps = int(0.05*total_steps)

callback = WarmupCosineDecay(total_steps=total_steps, 
                             warmup_steps=warmup_steps,
                             hold=int(warmup_steps/2), 
                             start_lr=0.0, 
                             target_lr=1e-3)

最後に、モデルを構築し、コールバックを fit() コール:

model = keras.applications.EfficientNetV2B0(weights=None, 
                                            classes=n_classes, 
                                            input_shape=[224, 224, 3])
  
model.compile(loss="sparse_categorical_crossentropy",
                  optimizer='adam',
                  jit_compile=True,
                  metrics=['accuracy'])

トレーニングの最後に、次の方法で変更された LR を取得して視覚化できます。

lrs = callback.lrs 
plt.plot(lrs)

Keras/TensorFlow PlatoBlockchain Data Intelligence のコサイン減衰を使用した学習率ウォームアップ。垂直検索。あい。

LR ウォームアップありとなしでトレーニングされたモデルの履歴をプロットすると、トレーニングの安定性に明確な違いが見られます。

Keras/TensorFlow PlatoBlockchain Data Intelligence のコサイン減衰を使用した学習率ウォームアップ。垂直検索。あい。

LearningRateSchedule サブクラスによる学習率

コールバックを作成する代わりに、 LearningRateSchedule LR を操作しないサブクラス – 置き換えます。 このアプローチにより、Keras/TensorFlow のバックエンドをもう少し掘り下げることができますが、使用する場合、次のような他の LR 関連のコールバックと組み合わせることはできません。 ReduceLROnPlateau()、LR を浮動小数点数として扱います。

さらに、サブクラスを使用するには、シリアライズ可能にする必要があります (オーバーロード get_config()) モデルの一部になるので、モデルの重みを保存したい場合。 注意すべきもうXNUMXつのことは、クラスが排他的に動作することを期待することです tf.Tensor秒。 ありがたいことに、私たちの働き方の唯一の違いは電話をかけることです tf.func() np.func() TensorFlow API と NumPy API は驚くほど類似しており、互換性があるためです。

都合を書き直そう lr_warmup_cosine_decay() 代わりに TensorFlow 操作を使用する関数:

def lr_warmup_cosine_decay(global_step,
                           warmup_steps,
                           hold = 0,
                           total_steps=0,
                           start_lr=0.0,
                           target_lr=1e-3):
    
    
    learning_rate = 0.5 * target_lr * (1 + tf.cos(tf.constant(np.pi) * (global_step - warmup_steps - hold) / float(total_steps - warmup_steps - hold)))

    
    warmup_lr = target_lr * (global_step / warmup_steps)

    
    
    if hold > 0:
        learning_rate = tf.where(global_step > warmup_steps + hold,
                                 learning_rate, target_lr)
    
    learning_rate = tf.where(global_step < warmup_steps, warmup_lr, learning_rate)
    return learning_rate

便利な関数を使用して、サブクラス化できます LearningRateSchedule クラス。 それぞれの __call__() (バッチ)、関数を使用して LR を計算し、それを返します。 もちろん、サブクラス化されたクラス内に計算をパッケージ化することもできます。

構文は Callback サブクラス、主にアクセスできるため step 独自に追跡するのではなく、フィールドを追跡するのではなく、クラスのプロパティを操作するのがやや難しくなります。特に、 lr から tf.Tensor() リストで追跡する他のタイプに変換します。 これは、熱心なモードで実行することで技術的に回避できますが、デバッグ目的で LR を追跡するのが煩わしいため、回避するのが最善です。

class WarmUpCosineDecay(keras.optimizers.schedules.LearningRateSchedule):
    def __init__(self, start_lr, target_lr, warmup_steps, total_steps, hold):
        super().__init__()
        self.start_lr = start_lr
        self.target_lr = target_lr
        self.warmup_steps = warmup_steps
        self.total_steps = total_steps
        self.hold = hold

    def __call__(self, step):
        lr = lr_warmup_cosine_decay(global_step=step,
                                    total_steps=self.total_steps,
                                    warmup_steps=self.warmup_steps,
                                    start_lr=self.start_lr,
                                    target_lr=self.target_lr,
                                    hold=self.hold)

        return tf.where(
            step > self.total_steps, 0.0, lr, name="learning_rate"
        )

パラメータは同じで、以前とほぼ同じ方法で計算できます。


total_steps = len(train_set)*config['EPOCHS']



warmup_steps = int(0.05*total_steps)

schedule = WarmUpCosineDecay(start_lr=0.0, target_lr=1e-3, warmup_steps=warmup_steps, total_steps=total_steps, hold=warmup_steps)

トレーニング パイプラインは、オプティマイザの LR を schedule:

model = keras.applications.EfficientNetV2B0(weights=None, 
                                            classes=n_classes, 
                                            input_shape=[224, 224, 3])
  
model.compile(loss="sparse_categorical_crossentropy",
                  optimizer=tf.keras.optimizers.Adam(learning_rate=schedule),
                  jit_compile=True,
                  metrics=['accuracy'])

history3 = model.fit(train_set,
                    epochs = config['EPOCHS'],
                    validation_data=valid_set)

モデルを保存したい場合は、 WarmupCosineDecay スケジュールは get_config() 方法:

    def get_config(self):
        config = {
          'start_lr': self.start_lr,
          'target_lr': self.target_lr,
          'warmup_steps': self.warmup_steps,
          'total_steps': self.total_steps,
          'hold': self.hold
        }
        return config

最後に、モデルをロードするときに、 WarmupCosineDecay カスタム オブジェクトとして:

model = keras.models.load_model('weights.h5', 
                                custom_objects={'WarmupCosineDecay', WarmupCosineDecay})

まとめ

このガイドでは、ニューラル ネットワークのトレーニング中に学習率を操作するための一般的な手法である Learning Rate Warmup の背後にある直感を見ていきました。

コサイン減衰を使用した学習率ウォームアップを実装しました。これは、ウォームアップと組み合わせた最も一般的なタイプの LR 削減です。 削減のために他の関数を実装するか、学習率をまったく削減しないで、次のような他のコールバックに任せることができます。 ReduceLROnPlateau(). 学習率のウォームアップを Keras コールバックとして実装し、Keras Optimizer Schedule と同様に、エポックを通じて学習率をプロットしました。

タイムスタンプ:

より多くの スタックアバス