Õ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)
Kui kujutate LR-soojendusega ja ilma selleta treenitud mudeli ajalugu, näete treeningu stabiilsuses selget erinevust:
Õ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.Tensor
s. Õ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.