Juhend kohandatud TensorFlow/Keras tagasihelistamiste kirjutamiseks

Sissejuhatus

Oletame, et soovite, et teie Kerase mudelil oleks koolituse, hindamise või prognoosimise ajal teatud konkreetne käitumine. Näiteks võite soovida oma mudeli igal koolitusperioodil salvestada. Üks viis seda teha on tagasihelistamiste kasutamine.

Üldjuhul on tagasihelistamised funktsioonid, mida kutsutakse välja mõne sündmuse toimumisel ja mis edastatakse argumentidena teistele funktsioonidele. Kerase puhul on need tööriist oma mudeli käitumise kohandamiseks – olgu siis koolituse, hindamise või järelduste tegemisel. Mõned rakendused on logimine, mudeli püsivus, varajane peatamine või õppimiskiiruse muutmine. Seda tehakse tagasihelistamiste loendi edastamisega argumentidena keras.Model.fit(),keras.Model.evaluate() or keras.Model.predict().

Mõned tagasihelistamiste levinumad kasutusjuhud on õppimiskiiruse muutmine, logimine, jälgimine ja koolituse varajane peatamine. Kerasel on mitmeid sisseehitatud üksikasjalikke tagasihelistusi
dokumentatsioonis
.

Kuid mõned spetsiifilisemad rakendused võivad vajada kohandatud tagasihelistamist. Näiteks, Õppimiskiiruse soojendamise rakendamine koosinuslangusega pärast hoidmisperioodi ei ole praegu sisseehitatud, kuid seda kasutatakse laialdaselt ja võetakse kasutusele planeerijana.

Tagasihelistamise klass ja selle meetodid

Kerasel on kindel tagasihelistamisklass, keras.callbacks.Callback, meetoditega, mida saab välja kutsuda koolituse, testimise ja järelduste tegemise ajal globaalsel, partii- või epohhi tasemel. Selleks, et luua kohandatud tagasihelistusi, peame looma alamklassi ja alistama need meetodid.

. keras.callbacks.Callback klassis on kolme tüüpi meetodeid:

  • globaalsed meetodid: kutsutakse alguses või lõpus fit(), evaluate() ja predict().
  • partiitaseme meetodid: kutsutakse partii töötlemise alguses või lõpus.
  • epohhitaseme meetodid: kutsutakse välja treeningpartii alguses või lõpus.

Märge: Igal meetodil on juurdepääs diktaadile, mida nimetatakse logs. Võtmed ja väärtused logs on kontekstuaalsed – need sõltuvad sündmusest, mis meetodit välja kutsub. Lisaks on meil juurdepääs iga meetodi sees olevale mudelile self.model atribuut.

Vaatame kolme kohandatud tagasihelistamise näidet – üks koolituse jaoks, üks hindamiseks ja üks ennustamiseks. Igaüks prindib igas etapis, mida meie mudel teeb ja millistele logidele meil on juurdepääs. See aitab mõista, mida on võimalik kohandatud tagasihelistamisega igas etapis teha.

Alustuseks määratleme mänguasja mudeli:

import tensorflow as tf
from tensorflow import keras
import numpy as np

model = keras.Sequential()
model.add(keras.layers.Dense(10, input_dim = 1, activation='relu'))
model.add(keras.layers.Dense(10, activation='relu'))
model.add(keras.layers.Dense(1))
model.compile(
    optimizer=keras.optimizers.RMSprop(learning_rate=0.1),
    loss = "mean_squared_error",
    metrics = ["mean_absolute_error"]
)

x = np.random.uniform(low = 0, high = 10, size = 1000)
y = x**2
x_train, x_test = (x[:900],x[900:])
y_train, y_test = (y[:900],y[900:])

Kohandatud koolituse tagasihelistamine

Meie esimene tagasihelistamine tuleb treeningu ajal helistada. Jaotame alamklassi Callback klass:

class TrainingCallback(keras.callbacks.Callback):
    def __init__(self):
        self.tabulation = {"train":"", 'batch': " "*8, 'epoch':" "*4}
    def on_train_begin(self, logs=None):
        tab = self.tabulation['train']
        print(f"{tab}Training!")
        print(f"{tab}available logs: {logs}")

    def on_train_batch_begin(self, batch, logs=None):
        tab = self.tabulation['batch']
        print(f"{tab}Batch {batch}")
        print(f"{tab}available logs: {logs}")

    def on_train_batch_end(self, batch, logs=None):
        tab = self.tabulation['batch']
        print(f"{tab}End of Batch {batch}")
        print(f"{tab}available logs: {logs}")

    def on_epoch_begin(self, epoch, logs=None):
        tab = self.tabulation['epoch']
        print(f"{tab}Epoch {epoch} of training")
        print(f"{tab}available logs: {logs}")

    def on_epoch_end(self, epoch, logs=None):
        tab = self.tabulation['epoch']
        print(f"{tab}End of Epoch {epoch} of training")
        print(f"{tab}available logs: {logs}")

    def on_train_end(self, logs=None):
        tab = self.tabulation['train']
        print(f"{tab}Finishing training!")
        print(f"{tab}available logs: {logs}")

Kui mõnda neist meetoditest ei alistata, jätkub vaikekäitumine nagu varem. Meie näites prindime lihtsalt välja saadaolevad logid ja tagasihelistamise rakendamise taseme koos õige taandega.

Vaatame väljundeid:

model.fit(
    x_train,
    y_train,
    batch_size=500,
    epochs=2,
    verbose=0,
    callbacks=[TrainingCallback()],
)
Training!
available logs: {}
    Epoch 0 of training
    available logs: {}
        Batch 0
        available logs: {}
        End of Batch 0
        available logs: {'loss': 2172.373291015625, 'mean_absolute_error': 34.79669952392578}
        Batch 1
        available logs: {}
        End of Batch 1
        available logs: {'loss': 2030.1309814453125, 'mean_absolute_error': 33.30256271362305}
    End of Epoch 0 of training
    available logs: {'loss': 2030.1309814453125, 'mean_absolute_error': 33.30256271362305}
    Epoch 1 of training
    available logs: {}
        Batch 0
        available logs: {}
        End of Batch 0
        available logs: {'loss': 1746.2772216796875, 'mean_absolute_error': 30.268001556396484}
        Batch 1
        available logs: {}
        End of Batch 1
        available logs: {'loss': 1467.36376953125, 'mean_absolute_error': 27.10252571105957}
    End of Epoch 1 of training
    available logs: {'loss': 1467.36376953125, 'mean_absolute_error': 27.10252571105957}
Finishing training!
available logs: {'loss': 1467.36376953125, 'mean_absolute_error': 27.10252571105957}


Pange tähele, et saame igal etapil jälgida, mida mudel teeb ja millistele mõõdikutele meil on juurdepääs. Iga partii ja epohhi lõpus on meil juurdepääs proovisisesele kadufunktsioonile ja meie mudeli mõõdikutele.

Kohandatud hindamise tagasihelistamine

Nüüd helistame Model.evaluate() meetod. Näeme, et partii lõpus on meil juurdepääs kahjufunktsioonile ja selle aja mõõdikutele ning hindamise lõpus on meil juurdepääs üldisele kadudele ja mõõdikutele:

class TestingCallback(keras.callbacks.Callback):
    def __init__(self):
          self.tabulation = {"test":"", 'batch': " "*8}
      
    def on_test_begin(self, logs=None):
        tab = self.tabulation['test']
        print(f'{tab}Evaluating!')
        print(f'{tab}available logs: {logs}')

    def on_test_end(self, logs=None):
        tab = self.tabulation['test']
        print(f'{tab}Finishing evaluation!')
        print(f'{tab}available logs: {logs}')

    def on_test_batch_begin(self, batch, logs=None):
        tab = self.tabulation['batch']
        print(f"{tab}Batch {batch}")
        print(f"{tab}available logs: {logs}")

    def on_test_batch_end(self, batch, logs=None):
        tab = self.tabulation['batch']
        print(f"{tab}End of batch {batch}")
        print(f"{tab}available logs: {logs}")
res = model.evaluate(
    x_test, y_test, batch_size=100, verbose=0, callbacks=[TestingCallback()]
)
Evaluating!
available logs: {}
        Batch 0
        available logs: {}
        End of batch 0
        available logs: {'loss': 382.2723083496094, 'mean_absolute_error': 14.069927215576172}
Finishing evaluation!
available logs: {'loss': 382.2723083496094, 'mean_absolute_error': 14.069927215576172}

Kohandatud ennustus tagasihelistamine

Lõpuks helistame Model.predict() meetod. Pange tähele, et iga partii lõpus on meil juurdepääs meie mudeli prognoositud väljunditele:

class PredictionCallback(keras.callbacks.Callback):
    def __init__(self):
        self.tabulation = {"prediction":"", 'batch': " "*8}

    def on_predict_begin(self, logs=None):
        tab = self.tabulation['prediction']
        print(f"{tab}Predicting!")
        print(f"{tab}available logs: {logs}")

    def on_predict_end(self, logs=None):
        tab = self.tabulation['prediction']
        print(f"{tab}End of Prediction!")
        print(f"{tab}available logs: {logs}")

    def on_predict_batch_begin(self, batch, logs=None):
        tab = self.tabulation['batch']
        print(f"{tab}batch {batch}")
        print(f"{tab}available logs: {logs}")

    def on_predict_batch_end(self, batch, logs=None):
        tab = self.tabulation['batch']
        print(f"{tab}End of batch {batch}")
        print(f"{tab}available logs:n {logs}")
res = model.predict(x_test[:10],
                    verbose = 0, 
                    callbacks=[PredictionCallback()])

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!

Predicting!
available logs: {}
        batch 0
        available logs: {}
        End of batch 0
        available logs:
 {'outputs': array([[ 7.743822],
       [27.748264],
       [33.082104],
       [26.530678],
       [27.939169],
       [18.414223],
       [42.610645],
       [36.69335 ],
       [13.096557],
       [37.120853]], dtype=float32)}
End of Prediction!
available logs: {}

Nende abil saate kohandada käitumist, seadistada jälgimist või muul viisil muuta koolituse, hindamise või järelduste tegemise protsesse. Alternatiiv alamkoopiale on kasutada LambdaCallback.

LambaCallbacki kasutamine

Üks Kerase sisseehitatud tagasihelistamisi on LambdaCallback klass. See tagasihelistamine aktsepteerib funktsiooni, mis määrab, kuidas see käitub ja mida see teeb! Teatud mõttes võimaldab see kasutada tagasihelistajana mis tahes suvalist funktsiooni, võimaldades seega luua kohandatud tagasihelistusi.

Klassil on valikulised parameetrid:
-on_epoch_begin

  • on_epoch_end
  • on_batch_begin
  • on_batch_end
  • on_train_begin
  • on_train_end

Iga parameeter nõustub funktsioon mida kutsutakse vastavas mudelisündmuses. Näiteks helistame tagasi, et saata meilisõnum, kui modell on koolituse lõpetanud:

import smtplib
from email.message import EmailMessage

def send_email(logs): 
    msg = EmailMessage()
    content = f"""The model has finished training."""
    for key, value in logs.items():
      content = content + f"n{key}:{value:.2f}"
    msg.set_content(content)
    msg['Subject'] = f'Training report'
    msg['From'] = '[email protected]'
    msg['To'] = 'receiver-email'

    s = smtplib.SMTP('smtp.gmail.com', 587)
    s.starttls()
    s.login("[email protected]", "your-gmail-app-password")
    s.send_message(msg)
    s.quit()

lambda_send_email = lambda logs : send_email(logs)

email_callback = keras.callbacks.LambdaCallback(on_train_end = lambda_send_email)

model.fit(
    x_train,
    y_train,
    batch_size=100,
    epochs=1,
    verbose=0,
    callbacks=[email_callback],
)

Meie kohandatud tagasihelistamiseks kasutades LambdaCallback, peame lihtsalt rakendama funktsiooni, mida tahame kutsuda, mähkima selle kui a lambda funktsiooni ja edastage see
LambdaCallback klass parameetrina.

Tagasihelistamine mudelikoolituse visualiseerimiseks

Selles jaotises toome näite kohandatud tagasihelistamisest, mis muudab meie mudeli jõudluse animatsiooni treeningu ajal paremaks. Selleks salvestame logide väärtused iga partii lõppu. Seejärel loome treeningtsükli lõpus animatsiooni kasutades matplotlib.

Visualiseerimise parandamiseks joonistatakse kadu ja mõõdikud logiskaalas:

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
from IPython import display

class TrainingAnimationCallback(keras.callbacks.Callback):
    def __init__(self, duration = 40, fps = 1000/25):
        self.duration = duration
        self.fps = fps
        self.logs_history = []

    def set_plot(self):   
        self.figure = plt.figure()
        
        plt.xticks(
            range(0,self.params['steps']*self.params['epochs'], self.params['steps']),
            range(0,self.params['epochs']))
        plt.xlabel('Epoch')
        plt.ylabel('Loss & Metrics ($Log_{10}$ scale)')

        self.plot = {}
        for metric in self.model.metrics_names:
          self.plot[metric], = plt.plot([],[], label = metric)
          
        max_y = [max(log.values()) for log in self.logs_history]
        
        self.title = plt.title(f'batches:0')
        plt.xlim(0,len(self.logs_history)) 
        plt.ylim(0,max(max_y))

           
        plt.legend(loc='upper right')
  
    def animation_function(self,frame):
        batch = frame % self.params['steps']
        self.title.set_text(f'batch:{batch}')
        x = list(range(frame))
        
        for metric in self.model.metrics_names:
            y = [log[metric] for log in self.logs_history[:frame]]
            self.plot[metric].set_data(x,y)
        
    def on_train_batch_end(self, batch, logs=None):
        logarithm_transform = lambda item: (item[0], np.log(item[1]))
        logs = dict(map(logarithm_transform,logs.items()))
        self.logs_history.append(logs)
       
    def on_train_end(self, logs=None):
        self.set_plot()
        num_frames = int(self.duration*self.fps)
        num_batches = self.params['steps']*self.params['epochs']
        selected_batches = range(0, num_batches , num_batches//num_frames )
        interval = 1000*(1/self.fps)
        anim_created = FuncAnimation(self.figure, 
                                     self.animation_function,
                                     frames=selected_batches,
                                     interval=interval)
        video = anim_created.to_html5_video()
        
        html = display.HTML(video)
        display.display(html)
        plt.close()

Kasutame sama mudelit nagu varem, kuid rohkemate treeningnäidistega:

import tensorflow as tf
from tensorflow import keras
import numpy as np

model = keras.Sequential()
model.add(keras.layers.Dense(10, input_dim = 1, activation='relu'))
model.add(keras.layers.Dense(10, activation='relu'))
model.add(keras.layers.Dense(1))
model.compile(
    optimizer=keras.optimizers.RMSprop(learning_rate=0.1),
    loss = "mean_squared_error",
    metrics = ["mean_absolute_error"]
)

def create_sample(sample_size, train_test_proportion = 0.9):
    x = np.random.uniform(low = 0, high = 10, size = sample_size)
    y = x**2
    train_test_split = int(sample_size*train_test_proportion)
    x_train, x_test = (x[:train_test_split],x[train_test_split:])
    y_train, y_test = (y[:train_test_split],y[train_test_split:])
    return (x_train,x_test,y_train,y_test)

x_train,x_test,y_train,y_test = create_sample(35200)


model.fit(
    x_train,
    y_train,
    batch_size=32,
    epochs=2,
    verbose=0,
    callbacks=[TrainingAnimationCallback()],
)

Meie väljund on animatsioon mõõdikutest ja kadufunktsioonidest, kui need treeningprotsessi käigus muutuvad:

Teie brauser ei toeta HTML-videot.

Järeldus

Selles juhendis oleme vaatlenud kohandatud tagasihelistamiste rakendamist Kerases.
Kohandatud tagasihelistamiste rakendamiseks on kaks võimalust – alamklasside kaudu keras.callbacks.Callback klassi või kasutades keras.callbacks.LambdaCallback klass.

Oleme näinud ühte praktilist näidet LambdaCallbackkoolitustsükli lõpus meili saatmiseks ja üks näide alamklassi kohta Callback klass, mis loob treeningtsüklist animatsiooni.

Althoug Kerasel on palju sisseehitatud tagasihelistusi, teadmine, kuidas kohandatud tagasihelistamist rakendada, võib olla kasulik konkreetsemate rakenduste jaoks.

Ajatempel:

Veel alates Stackabus