گرم کردن نرخ یادگیری با واپاشی کسینوس در هوش داده پلاتو بلاک چین Keras/TensorFlow. جستجوی عمودی Ai.

گرم کردن نرخ یادگیری با واپاشی کسینوس در 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 Callbacks

ساده‌ترین راه برای پیاده‌سازی هر زمان‌بندی نرخ یادگیری، ایجاد تابعی است که از آن استفاده می‌کند lr پارامتر (float32)، آن را از طریق تغییر شکل می دهد و آن را برمی گرداند. سپس این تابع به LearningRateScheduler تماس برگشتی، که تابع را برای نرخ یادگیری اعمال می کند.

در حال حاضر، tf.keras.callbacks.LearningRateScheduler() عدد دوره را به تابعی که برای محاسبه نرخ یادگیری استفاده می کند، منتقل می کند، که بسیار درشت است. LR Warmup باید روی هر کدام انجام شود گام (دسته ای)، نه دوره، بنابراین ما باید a را استخراج کنیم global_step (در همه ادوار) برای محاسبه نرخ یادگیری به جای آن، و زیر کلاس Callback کلاس برای ایجاد یک callback سفارشی به جای ارسال تابع، زیرا در هر فراخوانی باید آرگومان هایی را ارسال کنیم، که در هنگام ارسال تابع غیرممکن است:

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

این رویکرد زمانی مطلوب است که سطح بالایی از سفارشی‌سازی را نمی‌خواهید و نمی‌خواهید با روشی که Keras رفتار می‌کند تداخل داشته باشید. lrو به خصوص اگر می‌خواهید از تماس‌های برگشتی مانند ReduceLROnPlateau() از آنجایی که فقط می تواند با یک float-based کار کند 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 را با بهترین روش ها، استانداردهای پذیرفته شده در صنعت و برگه تقلب شامل بررسی کنید. دستورات Google Git را متوقف کنید و در واقع یاد گرفتن آی تی!

ابتدا سازنده کلاس را تعریف می کنیم و فیلدهای آن را پیگیری می کنیم. در هر دسته ای که به پایان می رسد، گام جهانی را افزایش می دهیم، LR فعلی را یادداشت می کنیم و آن را به لیست LR ها تا کنون اضافه می کنیم. در ابتدای هر دسته - ما LR را با استفاده از آن محاسبه می کنیم lr_warmup_cosine_decay() عملکرد و LR را به عنوان LR فعلی بهینه ساز تنظیم کنید. این کار با backend انجام می شود 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. جستجوی عمودی Ai.

اگر تاریخچه یک مدل آموزش دیده با و بدون گرم کردن LR را ترسیم کنید - تفاوت مشخصی در پایداری تمرین مشاهده خواهید کرد:

گرم کردن نرخ یادگیری با واپاشی کسینوس در هوش داده پلاتو بلاک چین Keras/TensorFlow. جستجوی عمودی Ai.

نرخ یادگیری با زیر کلاس LearningRateSchedule

یک جایگزین برای ایجاد یک تماس، ایجاد یک است LearningRateSchedule زیر کلاس، که LR را دستکاری نمی کند - آن را جایگزین می کند. این رویکرد به شما امکان می دهد کمی بیشتر به پشتیبان Keras/TensorFlow وارد شوید، اما در صورت استفاده، نمی توان آن را با سایر تماس های مرتبط با LR، مانند ReduceLROnPlateau()، که با LR ها به عنوان اعداد ممیز شناور سروکار دارد.

علاوه بر این، استفاده از کلاس فرعی از شما می‌خواهد که آن را سریال‌سازی کنید (overload get_config()) به عنوان بخشی از مدل، اگر می خواهید وزن مدل را ذخیره کنید. نکته دیگری که باید به آن توجه کرد این است که کلاس انتظار دارد به طور انحصاری با آن کار کند tf.Tensorس خوشبختانه، تنها تفاوت در نحوه کار ما تماس خواهد بود tf.func() بجای np.func() از آنجایی که API های 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

با تابع convinience، می‌توانیم زیر کلاس 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

در نهایت، هنگام بارگذاری مدل، باید a را پاس کنید WarmupCosineDecay به عنوان یک شی سفارشی:

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

نتیجه

در این راهنما، نگاهی به شهود پشت گرم کردن نرخ یادگیری انداخته‌ایم - تکنیکی رایج برای دستکاری نرخ یادگیری در حین آموزش شبکه‌های عصبی.

ما گرم کردن نرخ یادگیری را با واپاشی کسینوس، رایج‌ترین نوع کاهش LR همراه با گرم کردن، اجرا کرده‌ایم. شما می‌توانید هر تابع دیگری را برای کاهش پیاده‌سازی کنید، یا اصلاً میزان یادگیری را کاهش ندهید - آن را به سایر تماس‌ها واگذار کنید، مانند ReduceLROnPlateau(). ما گرم کردن نرخ یادگیری را به عنوان یک Keras Callback و همچنین یک برنامه بهینه ساز Keras پیاده سازی کرده ایم و نرخ یادگیری را در طول دوره ها ترسیم کرده ایم.

تمبر زمان:

بیشتر از Stackabuse