การวอร์มอัพอัตราการเรียนรู้ด้วยการสลายตัวของโคไซน์ใน Keras/TensorFlow PlatoBlockchain Data Intelligence ค้นหาแนวตั้ง AI.

วอร์มอัพอัตราการเรียนรู้ด้วยการสลายตัวของโคไซน์ใน Keras/TensorFlow

อัตราการเรียนรู้เป็นพารามิเตอร์ไฮเปอร์พารามิเตอร์ที่สำคัญในเครือข่ายการเรียนรู้เชิงลึก และเป็นตัวกำหนด ระดับ ที่ดำเนินการอัปเดตน้ำหนัก ซึ่งคาดว่าจะลดฟังก์ชันการสูญเสียที่กำหนดบางอย่างให้น้อยที่สุด ในสกุลเงินสิงคโปร์:

$$
weight_{t+1} = น้ำหนัก_t – lr * frac{derror}{dweight_t}
$$

ด้วยอัตราการเรียนรู้ของ 0, น้ำหนักที่อัปเดตเพิ่งกลับมาเป็นตัวเอง – น้ำหนักt. อัตราการเรียนรู้เป็นปุ่มที่เราสามารถเปิดใช้งานหรือปิดใช้งานการเรียนรู้ได้อย่างมีประสิทธิภาพ และมีอิทธิพลอย่างมากต่อจำนวนการเรียนรู้ที่เกิดขึ้น โดยการควบคุมระดับการอัปเดตน้ำหนักโดยตรง

เครื่องมือเพิ่มประสิทธิภาพที่แตกต่างกันใช้อัตราการเรียนรู้ต่างกัน – แต่แนวคิดพื้นฐานยังคงเหมือนเดิม จำเป็นต้องพูด อัตราการเรียนรู้เป็นเป้าหมายของการศึกษา เอกสาร และเกณฑ์มาตรฐานของผู้ปฏิบัติงานจำนวนมาก

โดยทั่วไปแล้ว แทบทุกคนเห็นด้วยว่าอัตราการเรียนรู้แบบคงที่จะไม่ลดลง และการลดอัตราการเรียนรู้บางประเภทเกิดขึ้นในเทคนิคส่วนใหญ่ที่ปรับอัตราการเรียนรู้ระหว่างการฝึก ไม่ว่าจะเป็นแบบโมโนโทนิก โคไซน์ สามเหลี่ยม หรือแบบอื่นๆ การลดน้อยลง.

เทคนิคที่ในช่วงไม่กี่ปีที่ผ่านมาได้รับการตั้งหลักคือ วอร์มอัพอัตราการเรียนรู้ซึ่งสามารถจับคู่กับเทคนิคการลดขนาดอื่นๆ ได้จริง

วอร์มอัพอัตราการเรียนรู้

แนวคิดเบื้องหลังการวอร์มอัพอัตราการเรียนรู้นั้นเรียบง่าย ในช่วงแรกของการฝึก ตุ้มน้ำหนักอยู่ไกลจากสภาวะในอุดมคติ ซึ่งหมายความว่าการอัปเดตจำนวนมากทั่วทั้งกระดาน ซึ่งอาจเห็นได้ว่าเป็น "การแก้ไขมากเกินไป" สำหรับแต่ละน้ำหนัก ซึ่งการอัปเดตที่รุนแรงของน้ำหนักตัวอื่นอาจลบล้างการอัปเดตของน้ำหนักอื่นๆ ทำให้ระยะเริ่มต้นของการฝึกไม่เสถียรมากขึ้น

การเปลี่ยนแปลงเหล่านี้เกิดขึ้นได้ แต่สามารถหลีกเลี่ยงได้ด้วยการเริ่มต้นด้วยอัตราการเรียนรู้เล็กน้อย ไปถึงสภาวะที่ไม่เหมาะเจาะที่มีเสถียรภาพมากขึ้น จากนั้นจึงใช้อัตราการเรียนรู้ที่ใหญ่ขึ้น คุณสามารถจัดเรียงเครือข่ายให้ง่ายขึ้นในการอัปเดต แทนที่จะใช้การอัปเดต

นั่นคือการวอร์มอัพอัตราการเรียนรู้! เริ่มต้นด้วยอัตราการเรียนรู้ที่ต่ำ (หรือ 0) และเพิ่มขึ้นเป็นอัตราการเรียนรู้เริ่มต้น (สิ่งที่คุณจะเริ่มต้นด้วยต่อไป) การเพิ่มขึ้นนี้สามารถติดตามฟังก์ชันใดๆ ก็ได้ แต่โดยทั่วไปจะเป็นแบบเชิงเส้น

หลังจากถึงอัตราเริ่มต้น ตารางเวลาอื่นๆ เช่น การสลายตัวของโคไซน์ การลดเชิงเส้น ฯลฯ สามารถใช้เพื่อลดอัตราลงไปเรื่อยๆ จนกว่าจะสิ้นสุดการฝึก การอุ่นเครื่องตามอัตราการเรียนรู้มักจะเป็นส่วนหนึ่งของกำหนดการสองกำหนดการ โดยที่ LR warmup เป็นอันดับแรก ในขณะที่กำหนดการอื่นจะเข้ามาแทนที่หลังจากอัตรานั้นถึงจุดเริ่มต้น

ในคู่มือนี้ เราจะใช้การวอร์มอัพอัตราการเรียนรู้ใน Keras/TensorFlow เป็น a keras.optimizers.schedules.LearningRateSchedule คลาสย่อยและ keras.callbacks.Callback โทรกลับ. อัตราการเรียนรู้จะเพิ่มขึ้นจาก 0 ไปยัง target_lr และใช้การสลายตัวของโคไซน์ เนื่องจากเป็นกำหนดการรองที่พบบ่อยมาก ตามปกติแล้ว Keras ทำให้ง่ายต่อการติดตั้งใช้งานโซลูชันที่ยืดหยุ่นในรูปแบบต่างๆ และจัดส่งให้กับเครือข่ายของคุณ

หมายเหตุ การใช้งานเป็นแบบทั่วไปและได้รับแรงบันดาลใจจาก การใช้งาน Keras ของ Tony ของกลเม็ดที่ระบุไว้ใน “เคล็ดลับสำหรับการจำแนกรูปภาพด้วยโครงข่ายประสาทเทียม”.

อัตราการเรียนรู้ด้วย Keras Callbacks

วิธีที่ง่ายที่สุดในการนำตารางอัตราการเรียนรู้ไปใช้คือการสร้างฟังก์ชันที่ใช้ lr พารามิเตอร์ (float32) ส่งผ่านการเปลี่ยนแปลงบางอย่างแล้วส่งคืน ฟังก์ชันนี้จะถูกส่งต่อไปยัง LearningRateScheduler โทรกลับซึ่งใช้ฟังก์ชันกับอัตราการเรียนรู้

ตอนนี้ tf.keras.callbacks.LearningRateScheduler() ส่งผ่านหมายเลขยุคไปยังฟังก์ชันที่ใช้ในการคำนวณอัตราการเรียนรู้ ซึ่งค่อนข้างหยาบ LR Warmup ควรทำในแต่ละครั้ง ขั้นตอน (batch) ไม่ใช่ epoch ดังนั้นเราจะต้องได้รับ a global_step (ข้ามยุคทั้งหมด) เพื่อคำนวณอัตราการเรียนรู้แทนและ subclass the Callback เพื่อสร้างการเรียกกลับแบบกำหนดเองแทนที่จะส่งผ่านฟังก์ชัน เนื่องจากเราจำเป็นต้องส่งผ่านอาร์กิวเมนต์ในการโทรแต่ละครั้ง ซึ่งเป็นไปไม่ได้เมื่อเพียงแค่ส่งฟังก์ชัน:

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

วิธีนี้เป็นวิธีที่ดีเมื่อคุณไม่ต้องการการปรับแต่งระดับสูง และคุณไม่ต้องการรบกวนวิธีที่ Keras ปฏิบัติต่อ lrและโดยเฉพาะอย่างยิ่งถ้าคุณต้องการใช้การโทรกลับเช่น ReduceLROnPlateau() เนื่องจากสามารถใช้ได้กับ float-based เท่านั้น lr. ลองใช้การวอร์มอัพอัตราการเรียนรู้โดยใช้ Keras callback โดยเริ่มจากฟังก์ชันอำนวยความสะดวก:

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 แทนที่จะเป็นองค์ประกอบของอาร์เรย์ที่กำหนดเอง - หรือคุณสามารถทำการคำนวณภายในคลาสได้ มา subclss the . กันเถอะ 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 ปัจจุบัน และเพิ่มลงในรายการของ LR จนถึงตอนนี้ ในการเริ่มต้นแต่ละชุดงาน – เราจะคำนวณ LR โดยใช้เครื่องหมาย lr_warmup_cosine_decay() ฟังก์ชันและตั้งค่า LR นั้นเป็น LR ปัจจุบันของเครื่องมือเพิ่มประสิทธิภาพ นี้จะทำกับแบ็กเอนด์ของ set_value().

เมื่อเสร็จแล้ว – เพียงคำนวณขั้นตอนทั้งหมด (length/batch_size*epochs) และนำส่วนหนึ่งของตัวเลขนั้นมาให้คุณ 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 ค้นหาแนวตั้ง AI.

หากคุณพล็อตประวัติของแบบจำลองที่ฝึกทั้งแบบมีและไม่มี LR warmup คุณจะเห็นความแตกต่างที่ชัดเจนในความเสถียรของการฝึก:

การวอร์มอัพอัตราการเรียนรู้ด้วยการสลายตัวของโคไซน์ใน Keras/TensorFlow PlatoBlockchain Data Intelligence ค้นหาแนวตั้ง AI.

อัตราการเรียนรู้ด้วยคลาสย่อย LearningRateSchedule

อีกทางเลือกหนึ่งในการสร้างการโทรกลับคือสร้าง a LearningRateSchedule คลาสย่อยซึ่งไม่ได้จัดการ LR แต่จะแทนที่ วิธีนี้ช่วยให้คุณเจาะลึกเข้าไปในแบ็กเอนด์ของ Keras/TensorFlow ได้อีกเล็กน้อย แต่เมื่อใช้แล้ว จะไม่สามารถใช้ร่วมกับการเรียกกลับอื่นๆ ที่เกี่ยวข้องกับ LR เช่น ReduceLROnPlateau()ซึ่งเกี่ยวข้องกับ LR เป็นตัวเลขทศนิยม

นอกจากนี้ การใช้คลาสย่อยจะทำให้คุณต้องทำให้เป็นอนุกรมได้ (overload get_config()) เนื่องจากมันกลายเป็นส่วนหนึ่งของโมเดล หากคุณต้องการบันทึกน้ำหนักของโมเดล สิ่งที่ควรทราบอีกประการหนึ่งคือชั้นเรียนคาดว่าจะทำงานเฉพาะกับ tf.Tensorส. โชคดีที่ความแตกต่างเพียงอย่างเดียวในวิธีการทำงานของเราคือการโทร tf.func() แทน np.func() เนื่องจาก TensorFlow และ 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

ด้วยฟังก์ชัน convinience เราสามารถจัดคลาสย่อย the LearningRateSchedule ระดับ. ในแต่ละ __call__() (แบทช์) เราจะคำนวณ LR โดยใช้ฟังก์ชันและส่งคืน คุณสามารถทำแพ็คเกจการคำนวณภายในคลาสย่อยได้เช่นกัน

ไวยากรณ์สะอาดกว่า Callback sublcas ส่วนใหญ่เป็นเพราะเราเข้าถึง 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

สุดท้ายตอนโหลด model จะต้องผ่าน a WarmupCosineDecay เป็นวัตถุที่กำหนดเอง:

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

สรุป

ในคู่มือนี้ เราได้พิจารณาสัญชาตญาณเบื้องหลังการวอร์มอัพอัตราการเรียนรู้ ซึ่งเป็นเทคนิคทั่วไปในการจัดการกับอัตราการเรียนรู้ขณะฝึกโครงข่ายประสาทเทียม

เราได้ใช้การวอร์มอัพอัตราการเรียนรู้ด้วยการสลายตัวของโคไซน์ ซึ่งเป็นประเภทการลด LR ที่พบได้บ่อยที่สุดที่จับคู่กับการวอร์มอัพ คุณสามารถใช้ฟังก์ชันอื่นเพื่อลดหรือไม่ลดอัตราการเรียนรู้เลยก็ได้ โดยปล่อยให้เป็นฟังก์ชันเรียกกลับอื่นๆ เช่น ReduceLROnPlateau(). เราได้นำการวอร์มอัพอัตราการเรียนรู้มาใช้เป็น Keras Callback รวมทั้ง Keras Optimizer Schedule และวางแผนอัตราการเรียนรู้ผ่านยุคต่างๆ

ประทับเวลา:

เพิ่มเติมจาก สแต็ค