อัตราการเรียนรู้เป็นพารามิเตอร์ไฮเปอร์พารามิเตอร์ที่สำคัญในเครือข่ายการเรียนรู้เชิงลึก และเป็นตัวกำหนด ระดับ ที่ดำเนินการอัปเดตน้ำหนัก ซึ่งคาดว่าจะลดฟังก์ชันการสูญเสียที่กำหนดบางอย่างให้น้อยที่สุด ในสกุลเงินสิงคโปร์:
$$
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)
หากคุณพล็อตประวัติของแบบจำลองที่ฝึกทั้งแบบมีและไม่มี LR warmup คุณจะเห็นความแตกต่างที่ชัดเจนในความเสถียรของการฝึก:
อัตราการเรียนรู้ด้วยคลาสย่อย 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 และวางแผนอัตราการเรียนรู้ผ่านยุคต่างๆ