Õppimiskiiruse soojenemine koosinuse vähenemisega Keras/TensorFlow PlatoBlockchaini andmeluures. Vertikaalne otsing. Ai.

Õppimiskiiruse soojendus koosinuse vähenemisega Keras/TensorFlow's

Õppimiskiirus on süvaõppevõrkudes oluline hüperparameeter – ja see dikteerib otseselt kraad millele tehakse kaalude värskendused, mis hinnanguliselt minimeerivad mõnda antud kadufunktsiooni. SGD keeles:

$$
kaal_{t+1} = kaal_t – lr * frac{error}{dweight_t}
$$

Õppimismääraga 0, on uuendatud kaal lihtsalt naasnud – kaalt. Õppimiskiirus on tegelikult nupp, mida saame keerata õppimise lubamiseks või keelamiseks, ja sellel on suur mõju õppimise arvule, kuna see kontrollib otseselt kaalu uuenduste astet.

Erinevad optimeerijad kasutavad õppimismäärasid erinevalt, kuid selle aluseks olev kontseptsioon jääb samaks. Ütlematagi selge, et õppimise määrad on olnud paljude uuringute, paberite ja praktikute võrdlusnäitajate objektiks.

Üldiselt nõustuvad peaaegu kõik sellega, et staatiline õppimiskiirus seda ei vähenda ja teatud tüüpi õppimiskiiruse vähendamine toimub enamiku tehnikate puhul, mis häälestavad õppimiskiirust treeningu ajal – olgu see siis monotoonne, koosinus, kolmnurkne või muud tüüpi vähendamine.

Tehnika, mis on viimastel aastatel üha enam jalad alla võtnud, on õppimiskiiruse soojendus, mida saab siduda praktiliselt mis tahes muu reduktsioonitehnikaga.

Õppimiskiiruse soojendus

Õppimiskiiruse soojendamise idee on lihtne. Treeningu esimestel etappidel on raskused ideaalseisundist kaugel. See tähendab laiaulatuslikke uuendusi, mida võib vaadelda kui "üleparandusi" iga raskuse puhul – kus teise kaalu drastiline uuendamine võib tühistada mõne teise raskuse uuendamise, muutes treeningu algfaasid ebastabiilsemaks.

Need muutused siluvad välja, kuid neid saab vältida, alustades väikese õppimiskiirusega, saavutades stabiilsema suboptimaalse oleku ja rakendades seejärel suuremat õppimiskiirust. Saate omamoodi muuta võrgu värskendusteks, selle asemel, et nendega lüüa.

See on õppimiskiiruse soojendus! Alustades madalast (või 0) õppimise määrast ja suurendades õppimise algmäärani (millest te ikkagi alustaksite). See tõus võib tegelikult järgida mis tahes funktsiooni, kuid on tavaliselt lineaarne.

Pärast algse kiiruse saavutamist saab kasutada muid graafikuid, nagu koosinuse vähenemine, lineaarne vähendamine jne, et vähendada kiirust kuni treeningu lõpuni. Õppimiskiiruse soojendus on tavaliselt osa kahest graafikust koosnevast ajakavast, kus LR-i soojendus on esimene, samas kui teine ​​ajakava võtab üle pärast seda, kui kiirus on jõudnud alguspunkti.

Selles juhendis rakendame Keras/TensorFlow's õppimiskiiruse soojendamist a keras.optimizers.schedules.LearningRateSchedule alamklass ja keras.callbacks.Callback helista tagasi. Õppimise kiirust suurendatakse alates 0 et target_lr ja rakendage koosinuse lagunemist, kuna see on väga levinud teisene ajakava. Nagu tavaliselt, teeb Keras lihtsaks paindlike lahenduste juurutamise erinevatel viisidel ja nende tarnimise teie võrguga.

Märge: Rakendus on üldine ja inspireeritud Tony Kerase teostus artiklis kirjeldatud nippidestTrikkide kott kujutiste klassifitseerimiseks konvolutsiooniliste närvivõrkudega”.

Õppimise määr Kerase tagasihelistamisega

Lihtsaim viis mis tahes õppimiskiiruse ajakava rakendamiseks on luua funktsioon, mis võtab lr parameeter (float32), läbib selle mõne teisenduse ja tagastab selle. See funktsioon edastatakse seejärel LearningRateScheduler tagasihelistamine, mis rakendab funktsiooni õppimiskiirusele.

Nüüd tf.keras.callbacks.LearningRateScheduler() edastab epohhi numbri funktsioonile, mida ta kasutab õppimiskiiruse arvutamiseks, mis on üsna jäme. LR Warmup tuleks teha igaühel samm (partii), mitte epohhi, seega peame tuletama a global_step (kõigi ajastute lõikes), et arvutada selle asemel õppimiskiirus ja alamklass Callback klassis, et luua kohandatud tagasihelistus, mitte lihtsalt funktsiooni edasi anda, kuna peame iga kõne puhul edastama argumendid, mis on lihtsalt funktsiooni edastamisel võimatu:

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

See lähenemine on soodne, kui te ei soovi kõrgetasemelist kohandamist ja te ei soovi sekkuda sellesse, kuidas Keras kohtleb lr, ja eriti kui soovite kasutada tagasihelistusi nagu ReduceLROnPlateau() kuna see saab töötada ainult ujukipõhisega lr. Rakendame Kerase tagasihelistamise abil õppimiskiiruse soojendust, alustades mugavusfunktsioonist:

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

Igal etapil arvutame õppimiskiiruse ja soojendusõppe kiiruse (mõlemad ajakava elemendid), võttes arvesse start_lr ja target_lr. start_lr algab tavaliselt kell 0.0, Samal ajal kui target_lr oleneb teie võrgust ja optimeerijast – 1e-3 ei pruugi olla hea vaikeseade, nii et määrake meetodi väljakutsumise ajal kindlasti siht-algav LR.

Kui global_step koolitusel on kõrgem kui warmup_steps oleme määranud – kasutame koosinuse vähenemise ajakava LR. Kui ei, tähendab see, et soojeneme veel, seega kasutatakse soojendus-LR-i. Kui hold argument on seatud, jätame selle alles target_lr selle sammude arvu jaoks pärast soojendamist ja enne koosinuse lagunemist. np.where() pakub selleks suurepärase süntaksi:

np.where(condition, value_if_true, value_if_false)

Funktsiooni saate visualiseerida järgmiste funktsioonidega:

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)

Nüüd tahame seda funktsiooni kasutada tagasihelistamise osana ja edastame optimeerija sammu kui global_step mitte suvalise massiivi elemendina – või saate arvutuse teha klassi sees. Alamklasseerime Callback klass:

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)

Tutvuge meie praktilise ja praktilise Giti õppimise juhendiga, mis sisaldab parimaid tavasid, tööstusharus aktsepteeritud standardeid ja kaasas olevat petulehte. Lõpetage Giti käskude guugeldamine ja tegelikult õppima seda!

Esiteks määratleme klassi konstruktori ja jälgime selle välju. Iga lõppenud partii puhul suurendame globaalset sammu, võtame teadmiseks praeguse LR-i ja lisame selle seniste LR-ide loendisse. Iga partii alguses arvutame LR-i kasutades lr_warmup_cosine_decay() funktsiooni ja määrake see LR optimeerija praeguseks LR-iks. Seda tehakse taustaprogrammiga set_value().

Kui see on tehtud – lihtsalt arvutage sammude koguarv (pikkus/partii_suurus*perioodid) ja võtke osa sellest arvust oma jaoks 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)

Lõpuks koostage oma mudel ja esitage tagasihelistamine fit() helistama:

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'])

Koolituse lõpus saate muutunud LR-id hankida ja visualiseerida järgmiselt:

lrs = callback.lrs 
plt.plot(lrs)

Õppimiskiiruse soojenemine koosinuse vähenemisega Keras/TensorFlow PlatoBlockchaini andmeluures. Vertikaalne otsing. Ai.

Kui kujutate LR-soojendusega ja ilma selleta treenitud mudeli ajalugu, näete treeningu stabiilsuses selget erinevust:

Õppimiskiiruse soojenemine koosinuse vähenemisega Keras/TensorFlow PlatoBlockchaini andmeluures. Vertikaalne otsing. Ai.

Õppimismäär koos LearningRateSchedule alamklassiga

Alternatiiv tagasihelistamise loomisele on luua a LearningRateSchedule alamklass, mis ei manipuleeri LR-iga – see asendab selle. See lähenemine võimaldab teil Kerase/TensorFlow taustaprogrammi pisut rohkem kasutada, kuid kui seda kasutatakse, ei saa seda kombineerida teiste LR-iga seotud tagasihelistamisega, näiteks ReduceLROnPlateau(), mis käsitleb LR-e kui ujukomanumbreid.

Lisaks nõuab alamklassi kasutamine selle serialiseeritavaks muutmist (ülekoormus get_config()), kuna see muutub mudeli osaks, kui soovite salvestada mudeli kaalu. Veel üks asi, mida tuleb tähele panna, on see, et klass peaks töötama ainult koos tf.Tensors. Õnneks on ainus erinevus meie tööviisis helistamine tf.func() asemel np.func() kuna TensorFlow ja NumPy API-d on hämmastavalt sarnased ja ühilduvad.

Kirjutame mugavuse ümber lr_warmup_cosine_decay() funktsiooni TensorFlow toimingute kasutamiseks:

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

Mugavusfunktsiooni abil saame alamklassi kuuluda LearningRateSchedule klass. Igaühel __call__() (partii), arvutame funktsiooni abil LR-i ja tagastame selle. Arvutuse saab loomulikult pakendada ka alamklassidesse.

Süntaks on puhtam kui Callback alamkasutus, peamiselt seetõttu, et saame juurdepääsu step väljal, selle asemel, et seda üksinda jälgida, vaid muudab ka klassi omadustega töötamise mõnevõrra raskemaks – eriti raskendab see lr alates tf.Tensor() mis tahes muusse tüüpi, mida loendis jälgida. Sellest saab tehniliselt mööda hiilida, kui töötate innukas režiimis, kuid see tekitab tüütust LR-i silumise eesmärgil jälgimisel ja seda on kõige parem vältida:

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"
        )

Parameetrid on samad ja neid saab arvutada samamoodi nagu varem:


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)

Ja koolituskonveier erineb ainult selle poolest, et määrame optimeerija LR väärtusele 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)

Kui soovite mudelit salvestada, WarmupCosineDecay ajakava peab alistama get_config() meetod:

    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

Lõpuks peate mudeli laadimisel läbima a WarmupCosineDecay kohandatud objektina:

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

Järeldus

Selles juhendis oleme heitnud pilgu õppimiskiiruse soojendamise taga olevale intuitsioonile – levinud tehnikale õppimiskiirusega manipuleerimiseks närvivõrkude treenimise ajal.

Rakendasime õppimiskiiruse soojendamise koosinuslagundusega, mis on kõige levinum LR-i vähendamise tüüp, mis on seotud soojendusega. Saate rakendada mis tahes muid funktsioone õppimiskiiruse vähendamiseks või üldse mitte vähendada – jättes selle teistele tagasihelistamistele, näiteks ReduceLROnPlateau(). Oleme rakendanud õppimiskiiruse soojenduse Kerase tagasihelistamisena, samuti Kerase optimeerija ajakava ja joonistanud õppimiskiiruse läbi epohhide.

Ajatempel:

Veel alates Stackabus