Keras/TensorFlow PlatoBlockchain Data Intelligence -oppimisnopeuden lämmittely kosinivaimennuksella. Pystysuuntainen haku. Ai.

Oppimisnopeuden lämpeneminen kosinivajeella Kerasissa/TensorFlowissa

Oppimisnopeus on tärkeä hyperparametri syväoppimisverkostoissa – ja se sanelee suoraan aste joille suoritetaan painojen päivitykset, joiden arvioidaan minimoivan jonkin tietyn häviöfunktion. SGD:ssä:

$$
paino_{t+1} = paino_t – lr * frac{error}{dweight_t}
$$

Oppimisasteella 0, päivitetty paino on juuri palannut itsestään – painot. Oppimisnopeus on käytännössä nuppi, jota voimme kääntää ottaaksesi käyttöön tai estääksesi oppimisen, ja sillä on suuri vaikutus siihen, kuinka paljon oppimista tapahtuu ohjaamalla suoraan painonpäivitysten astetta.

Eri optimoijat käyttävät oppimisnopeuksia eri tavalla – mutta taustalla oleva konsepti pysyy samana. Sanomattakin on selvää, että oppimisasteet ovat olleet monien tutkimusten, papereiden ja ammatinharjoittajien vertailuarvojen kohteena.

Yleisesti ottaen lähes kaikki ovat samaa mieltä siitä, että staattinen oppimisnopeus ei hidasta sitä, ja jonkinlainen oppimisnopeuden lasku tapahtuu useimmissa tekniikoissa, jotka säätävät oppimisnopeutta harjoituksen aikana – olipa kyseessä sitten monotoninen, kosini, kolmio tai muun tyyppinen oppimisnopeus. vähentäminen.

Tekniikka, joka on viime vuosina saanut jalansijaa, on oppimisnopeuden lämmittely, joka voidaan yhdistää käytännössä minkä tahansa muun pelkistystekniikan kanssa.

Oppimisnopeuden lämmittely

Oppimisnopeuden lämmittelyn idea on yksinkertainen. Harjoittelun alkuvaiheessa painot ovat kaukana ihanteellisista tiloistaan. Tämä tarkoittaa suuria päivityksiä kaikkialla, joita voidaan pitää "ylikorjauksina" jokaiselle painolle – jossa toisen jyrkkä päivitys voi kumota jonkin muun painon päivityksen, mikä tekee harjoittelun alkuvaiheista epävakaampia.

Nämä muutokset tasoittuvat, mutta ne voidaan välttää käyttämällä aluksi pientä oppimisnopeutta, saavuttamalla vakaampi alioptimaalinen tila ja käyttämällä sitten suurempaa oppimisnopeutta. Voit tavallaan helpottaa verkkoa päivityksiin sen sijaan, että lyödä sitä niillä.

Se on oppimisnopeuden lämmittely! Alkaen alhaisella (tai 0) oppimisasteella ja nostamalla aloitusoppimisasteeseen (millä aloitat joka tapauksessa). Tämä lisäys voi seurata mitä tahansa funktiota, mutta se on yleensä lineaarinen.

Alkunopeuden saavuttamisen jälkeen voidaan käyttää muita aikatauluja, kuten kosinivaimennus, lineaarinen vähennys jne. nopeuden alentamiseksi asteittain harjoituksen loppuun asti. Oppimisnopeuden lämmittely on yleensä osa kahden aikataulun aikataulua, jossa LR-lämmittely on ensimmäinen, kun taas toinen aikataulu ottaa käyttöön sen jälkeen, kun nopeus on saavuttanut aloituspisteen.

Tässä oppaassa toteutamme Keras/TensorFlow-oppimisnopeuden lämmittelyn a keras.optimizers.schedules.LearningRateSchedule alaluokka ja keras.callbacks.Callback soita takaisin. Oppimisnopeutta nostetaan alkaen 0 että target_lr ja käytä kosinin vaimenemista, koska tämä on hyvin yleinen toissijainen aikataulu. Keras helpottaa tuttuun tapaan joustavien ratkaisujen toteuttamista eri tavoilla ja toimittaa ne verkkoosi.

Huomautus: Toteutus on yleinen ja inspiroitunut Tonyn Keras-toteutus artikkelissa kuvatuista temppuistaLaukku temppuja kuvien luokitteluun konvoluutiohermoverkkojen kanssa”.

Oppimisnopeus Kerasin takaisinsoittojen avulla

Yksinkertaisin tapa toteuttaa mikä tahansa oppimisnopeusaikataulu on luoda funktio, joka ottaa lr parametri (float32), siirtää sen jonkin muunnoksen läpi ja palauttaa sen. Tämä toiminto välitetään sitten LearningRateScheduler takaisinsoitto, joka soveltaa funktiota oppimisnopeuteen.

Nyt tf.keras.callbacks.LearningRateScheduler() välittää epookkiluvun funktiolle, jota se käyttää oppimisnopeuden laskemiseen, mikä on melko karkea. LR Warmup tulisi tehdä jokaiselle vaihe (erä), ei aikakausi, joten meidän on johdettava a global_step (kaikilta aikakausilta) laskeaksesi sen sijaan oppimisnopeuden ja alaluokkaan Callback luokassa mukautetun takaisinkutsun luomiseen funktion välittämisen sijaan, koska meidän on välitettävä argumentit jokaisessa kutsussa, mikä on mahdotonta, kun vain välitetään funktio:

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

Tämä lähestymistapa on edullinen, kun et halua korkeatasoista räätälöintiä etkä halua puuttua tapaan, jolla Keras kohtelee lr, ja varsinkin jos haluat käyttää takaisinsoittoja, kuten ReduceLROnPlateau() koska se voi toimia vain float-pohjaisen kanssa lr. Toteutetaan oppimisnopeuden lämmittely Keras-takaisinkutsun avulla, alkaen mukavuustoiminnosta:

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

Jokaisessa vaiheessa laskemme oppimisnopeuden ja alkulämmittelyn oppimisnopeuden (molemmat aikataulun elementit) suhteessa start_lr ja target_lr. start_lr alkaa yleensä klo 0.0, samalla kun target_lr riippuu verkostasi ja optimoijastasi – 1e-3 ei ehkä ole hyvä oletusarvo, joten muista asettaa aloitus-LR-kohde, kun kutsut menetelmää.

Jos global_step koulutuksessa on korkeampi kuin warmup_steps olemme asettaneet – käytämme kosinin vaimenemisaikataulua LR. Jos ei, se tarkoittaa, että olemme edelleen lämmittelyssä, joten lämmittely LR on käytössä. Jos hold argumentti on asetettu, pidämme sen target_lr tälle askelmäärälle lämpenemisen jälkeen ja ennen kosinin vaimenemista. np.where() tarjoaa loistavan syntaksin tälle:

np.where(condition, value_if_true, value_if_false)

Voit visualisoida toiminnon seuraavilla tavoilla:

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)

Nyt haluamme käyttää tätä toimintoa osana takaisinsoittoa ja välittää optimointivaiheen global_step mieluummin kuin mielivaltaisen taulukon elementti – tai voit suorittaa laskennan luokassa. Suoritetaan aliluokitus Callback luokka:

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)

Tutustu käytännönläheiseen, käytännölliseen Gitin oppimisoppaaseemme, jossa on parhaat käytännöt, alan hyväksymät standardit ja mukana tuleva huijauslehti. Lopeta Git-komentojen googlailu ja oikeastaan oppia se!

Ensin määritellään luokalle konstruktori ja seurataan sen kenttiä. Jokaisessa päättyneessä erässä lisäämme globaalia askelta, huomioimme nykyisen LR:n ja lisäämme sen tähän mennessä olevien LR:ien luetteloon. Jokaisen erän alussa – laskemme LR:n käyttämällä lr_warmup_cosine_decay() funktio ja aseta tämä LR optimoijan nykyiseksi LR:ksi. Tämä tehdään backendillä set_value().

Kun tämä on tehty – laske vain vaiheiden kokonaismäärä (pituus/erän_koko*aikakaudet) ja ota osa tästä numerosta 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)

Rakenna lopuksi mallisi ja anna takaisinsoitto fit() puhelu:

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

Harjoittelun lopussa voit hankkia ja visualisoida muuttuneet LR:t seuraavasti:

lrs = callback.lrs 
plt.plot(lrs)

Keras/TensorFlow PlatoBlockchain Data Intelligence -oppimisnopeuden lämmittely kosinivaimennuksella. Pystysuuntainen haku. Ai.

Jos piirrät mallin historiaa, joka on harjoiteltu LR-lämmittelyllä ja ilman – näet selvän eron harjoituksen vakaudessa:

Keras/TensorFlow PlatoBlockchain Data Intelligence -oppimisnopeuden lämmittely kosinivaimennuksella. Pystysuuntainen haku. Ai.

Oppimisnopeus LearningRateSchedule-alaluokassa

Vaihtoehto takaisinsoittojen luomiselle on luoda a LearningRateSchedule alaluokka, joka ei manipuloi LR:ää – se korvaa sen. Tämän lähestymistavan avulla voit tuoda hieman enemmän Keras/TensorFlow-taustajärjestelmään, mutta käytettynä sitä ei voi yhdistää muihin LR-takaisinkutsuihin, kuten esim. ReduceLROnPlateau(), joka käsittelee LR:itä liukulukuina.

Lisäksi alaluokan käyttäminen edellyttää, että sinun on tehtävä siitä sarjoitettava (ylikuormitus get_config()), koska siitä tulee osa mallia, jos haluat tallentaa mallin painot. Toinen huomioitava asia on, että luokka odottaa työskentelevänsä yksinomaan tf.Tensors. Onneksi ainoa ero työtavassamme on soittaminen tf.func() sijasta np.func() koska TensorFlow- ja NumPy-sovellusliittymät ovat hämmästyttävän samanlaisia ​​ja yhteensopivia.

Kirjoitetaan mukavuus uudelleen lr_warmup_cosine_decay() toiminto käyttää TensorFlow-toimintoja sen sijaan:

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

Mukavuusfunktiolla voimme alaluokkia LearningRateSchedule luokkaa. Jokaisella __call__() (erä), laskemme LR:n funktiolla ja palautamme sen. Voit luonnollisesti pakata laskutoimituksen myös alaluokkiin.

Syntaksi on puhtaampi kuin Callback sublcass, ensisijaisesti siksi, että saamme pääsyn step kenttään sen sijaan, että pysyisimme itse kirjassa, vaan se myös vaikeuttaa jonkin verran luokan ominaisuuksien käsittelyä – erityisesti se vaikeuttaa lr mistä tf.Tensor() mihin tahansa muuhun tyyppiin, jota voit seurata luettelossa. Tämä voidaan teknisesti kiertää ajamalla innokkaasti, mutta se häiritsee LR:n seuraamista virheenkorjaustarkoituksiin, ja sitä on parasta välttää:

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

Parametrit ovat samat, ja ne voidaan laskea pitkälti samalla tavalla kuin ennen:


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 koulutusputkisto eroaa vain siinä, että asetamme optimoijan LR:ksi 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)

Jos haluat tallentaa mallin, WarmupCosineDecay aikataulun on ohitettava get_config() menetelmä:

    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

Lopuksi, kun lataat mallia, sinun on läpäistävä a WarmupCosineDecay mukautettuna objektina:

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

Yhteenveto

Tässä oppaassa olemme tarkastelleet Learning Rate Warmupin taustalla olevaa intuitiota – yleistä tekniikkaa oppimisnopeuden manipuloimiseksi hermoverkkoja opetettaessa.

Olemme ottaneet käyttöön oppimisnopeuden lämmittelyn kosinivaimennuksella, joka on yleisin LR-vähennystyyppi yhdistettynä lämmittelyyn. Voit toteuttaa minkä tahansa muun toiminnon pienentääksesi tai olla alentamatta oppimisnopeutta ollenkaan – jättäen sen muille takaisinkutsuille, kuten ReduceLROnPlateau(). Olemme ottaneet käyttöön oppimisnopeuden lämmittelyn Kerasin takaisinsoittona sekä Keras Optimizer Schedule -ohjelmana ja piirtäneet oppimisnopeuden eri aikakausille.

Aikaleima:

Lisää aiheesta Stackabus