إحماء معدل التعلم مع تسوس جيب التمام في ذكاء بيانات Keras / TensorFlow PlatoBlockchain. البحث العمودي. عاي.

تعلم معدل الإحماء مع تسوس جيب التمام في Keras / TensorFlow

يعد معدل التعلم من أهم العوامل في شبكات التعلم العميق - وهو ما يحدد بشكل مباشر الدرجة العلمية التي يتم إجراء تحديثات عليها للأوزان ، والتي يتم تقديرها لتقليل بعض وظائف الخسارة المحددة. في SGD:

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

مع معدل التعلم 0، الوزن المحدث يعود إلى نفسه - وزنt. يعد معدل التعلم بمثابة مقبض فعال يمكننا تشغيله لتمكين التعلم أو تعطيله ، وله تأثير كبير على مقدار التعلم الذي يحدث ، من خلال التحكم المباشر في درجة تحديثات الوزن.

تستخدم أدوات تحسين الأداء المختلفة معدلات التعلم بشكل مختلف - لكن المفهوم الأساسي يظل كما هو. وغني عن القول أن معدلات التعلم كانت موضوع العديد من الدراسات والأبحاث ومعايير الممارس.

بشكل عام ، يتفق الجميع تقريبًا على أن معدل التعلم الثابت لن يخفضه ، ويحدث نوع من خفض معدل التعلم في معظم التقنيات التي تضبط معدل التعلم أثناء التدريب - سواء كان ذلك رتيبًا أو جيب التمام أو المثلث أو أنواعًا أخرى من اختزال.

التقنية التي اكتسبت موطئ قدم في السنوات الأخيرة هي تعلم معدل الاحماء، والتي يمكن إقرانها عمليًا بأي تقنية تصغير أخرى.

تعلم معدل الإحماء

الفكرة الكامنة وراء إحماء معدل التعلم بسيطة. في المراحل الأولى من التدريب - الأوزان بعيدة كل البعد عن حالتها المثالية. وهذا يعني تحديثات كبيرة في جميع المجالات ، والتي يمكن اعتبارها "تصحيحات مفرطة" لكل وزن - حيث قد يؤدي التحديث الجذري لآخر وزن إلى إبطال تحديث بعض الوزن الآخر ، مما يجعل المراحل الأولية من التدريب أكثر استقرارًا.

يتم تسوية هذه التغييرات ، ولكن يمكن تجنبها من خلال الحصول على معدل تعليمي صغير في البداية ، والوصول إلى حالة دون المستوى الأمثل ، ثم تطبيق معدل تعلم أكبر. يمكنك نوعًا ما من تسهيل الشبكة في التحديثات ، بدلاً من الضغط عليها.

هذا تعلم معدل الإحماء! البدء بمعدل تعلم منخفض (أو 0) وزيادة معدل التعلم الأولي (ما ستبدأ به على أي حال). يمكن أن تتبع هذه الزيادة أي دالة حقًا ، ولكنها عادةً خطية.

بعد الوصول إلى المعدل الأولي ، يمكن تطبيق جداول أخرى مثل تسوس جيب التمام ، والتخفيض الخطي ، وما إلى ذلك لخفض المعدل تدريجيًا حتى نهاية التدريب. عادة ما يكون إحماء معدل التعلم جزءًا من جدولين ، حيث يكون إحماء LR هو الأول ، بينما يتولى جدول آخر بعد أن يصل المعدل إلى نقطة البداية.

في هذا الدليل ، سنقوم بتنفيذ إحماء معدل التعلم في Keras / TensorFlow كملف keras.optimizers.schedules.LearningRateSchedule فئة فرعية و keras.callbacks.Callback أتصل مرة أخرى. سيتم زيادة معدل التعلم من 0 إلى target_lr وتطبيق انحلال جيب التمام ، لأن هذا جدول ثانوي شائع جدًا. كالعادة ، تجعل Keras من السهل تنفيذ حلول مرنة بطرق مختلفة وشحنها مع شبكتك.

ملحوظة: التنفيذ عام ومستوحى من تنفيذ توني كيراس من الحيل الموضحة في "حقيبة الحيل لتصنيف الصور باستخدام الشبكات العصبية التلافيفية ".

معدل التعلم مع استرجاع Keras

إن أبسط طريقة لتنفيذ أي جدول زمني لمعدل التعلم هي عن طريق إنشاء دالة تأخذ lr معامل (float32) ، ويمررها من خلال بعض التحول ، وإعادتها. ثم يتم تمرير هذه الوظيفة إلى LearningRateScheduler رد الاتصال ، والذي يطبق الوظيفة على معدل التعلم.

الآن، tf.keras.callbacks.LearningRateScheduler() يمرر رقم الحقبة إلى الوظيفة التي تستخدمها لحساب معدل التعلم ، وهو أمر خشن جدًا. يجب أن يتم إحماء LR في كل منها . (دفعة) ، وليس حقبة ، لذلك علينا اشتقاق أ global_step (عبر كل العصور) لحساب معدل التعلم بدلاً من ذلك ، وصنف Callback class لإنشاء رد اتصال مخصص بدلاً من مجرد تمرير الوظيفة ، لأننا سنحتاج إلى تمرير الوسيطات على كل استدعاء ، وهو أمر مستحيل عند تمرير الوظيفة:

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 عند استدعاء الطريقة.

إذا كان 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 ، مع أفضل الممارسات ، والمعايير المقبولة في الصناعة ، وورقة الغش المضمنة. توقف عن أوامر Googling Git وفي الواقع تعلم ذلك!

أولاً ، نحدد المنشئ للفصل ونتابع مجالاته. في كل دفعة منتهية ، سنعمل على زيادة الخطوة العامة ، ونلاحظ LR الحالي ونضيفه إلى قائمة LRs حتى الآن. في بداية كل دفعة - سنحسب 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'])

في نهاية التدريب ، يمكنك الحصول على LRs المتغيرة وتصورها من خلال:

lrs = callback.lrs 
plt.plot(lrs)

إحماء معدل التعلم مع تسوس جيب التمام في ذكاء بيانات Keras / TensorFlow PlatoBlockchain. البحث العمودي. عاي.

إذا قمت برسم تاريخ نموذج تم تدريبه باستخدام أو بدون إحماء LR - فسترى اختلافًا واضحًا في ثبات التدريب:

إحماء معدل التعلم مع تسوس جيب التمام في ذكاء بيانات Keras / TensorFlow PlatoBlockchain. البحث العمودي. عاي.

معدل التعلم مع LearningRateSchedule Subclass

أحد البدائل لإنشاء رد اتصال هو إنشاء ملف LearningRateSchedule فئة فرعية لا تتعامل مع LR - إنها تحل محلها. يسمح لك هذا الأسلوب بالحث أكثر قليلاً على الواجهة الخلفية لـ Keras / TensorFlow ، ولكن عند استخدامه ، لا يمكن دمجه مع عمليات رد النداء الأخرى المتعلقة بـ LR ، مثل ReduceLROnPlateau()، التي تتعامل مع LRs كأرقام فاصلة عائمة.

بالإضافة إلى ذلك ، سيتطلب استخدام الفئة الفرعية جعلها قابلة للتسلسل (التحميل الزائد get_config()) لأنه يصبح جزءًا من النموذج ، إذا كنت تريد حفظ أوزان النموذج. شيء آخر يجب ملاحظته هو أن الفصل يتوقع العمل معه بشكل حصري tf.Tensorس. لحسن الحظ ، فإن الاختلاف الوحيد في طريقة عملنا هو الاتصال tf.func() بدلا من np.func() نظرًا لأن واجهات برمجة تطبيقات TensorFlow و NumPy متشابهة ومتوافقة بشكل مثير للدهشة.

دعنا نعيد كتابة الراحة 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 sublcass ، في المقام الأول لأننا نتمكن من الوصول إلى 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 Callback ، بالإضافة إلى جدول Keras Optimizer ورسمنا معدل التعلم عبر العصور.

الطابع الزمني:

اكثر من ستاكابوز