Οδηγός για τη σύνταξη προσαρμοσμένων ανακλήσεων TensorFlow/Keras

Εισαγωγή

Ας υποθέσουμε ότι θέλετε το μοντέλο Keras σας να έχει κάποια συγκεκριμένη συμπεριφορά κατά τη διάρκεια της εκπαίδευσης, της αξιολόγησης ή της πρόβλεψης. Για παράδειγμα, μπορεί να θέλετε να αποθηκεύσετε το μοντέλο σας σε κάθε περίοδο προπόνησης. Ένας τρόπος για να γίνει αυτό είναι η χρήση Επιστροφών κλήσης.

Γενικά, οι Επιστροφές κλήσης είναι συναρτήσεις που καλούνται όταν συμβαίνει κάποιο συμβάν και μεταβιβάζονται ως ορίσματα σε άλλες συναρτήσεις. Στην περίπτωση του Keras, είναι ένα εργαλείο για να προσαρμόσετε τη συμπεριφορά του μοντέλου σας – είτε κατά τη διάρκεια της εκπαίδευσης, είτε κατά την αξιολόγηση είτε κατά την εξαγωγή συμπερασμάτων. Ορισμένες εφαρμογές είναι η καταγραφή, η επιμονή του μοντέλου, η πρόωρη διακοπή ή η αλλαγή του ρυθμού εκμάθησης. Αυτό γίνεται μεταβιβάζοντας μια λίστα με Επιστροφές κλήσης ως ορίσματα για keras.Model.fit(),keras.Model.evaluate() or keras.Model.predict().

Ορισμένες συνήθεις περιπτώσεις χρήσης για επανάκληση είναι η τροποποίηση του ρυθμού εκμάθησης, η καταγραφή, η παρακολούθηση και η πρόωρη διακοπή της εκπαίδευσης. Το Keras έχει μια σειρά από ενσωματωμένες επιστροφές κλήσης, αναλυτικά
στην τεκμηρίωση
.

Ωστόσο, ορισμένες πιο συγκεκριμένες εφαρμογές ενδέχεται να απαιτούν προσαρμοσμένη επανάκληση. Για παράδειγμα, εφαρμογή προθέρμανσης ρυθμού εκμάθησης με αποσύνθεση συνημιτόνου μετά από μια περίοδο αναμονής επί του παρόντος δεν είναι ενσωματωμένο, αλλά χρησιμοποιείται ευρέως και υιοθετείται ως προγραμματιστής.

Τάξη επανάκλησης και οι μέθοδοι της

Το Keras έχει μια συγκεκριμένη κλάση επανάκλησης, keras.callbacks.Callback, με μεθόδους που μπορούν να κληθούν κατά τη διάρκεια της εκπαίδευσης, των δοκιμών και της εξαγωγής συμπερασμάτων σε παγκόσμιο, παρτίδες ή σε επίπεδο εποχής. Ωστε να δημιουργήστε προσαρμοσμένες επιστροφές κλήσης, πρέπει να δημιουργήσουμε μια υποκλάση και να παρακάμψουμε αυτές τις μεθόδους.

Η keras.callbacks.Callback Η τάξη έχει τρία είδη μεθόδων:

  • καθολικές μέθοδοι: καλούνται στην αρχή ή στο τέλος του fit(), evaluate() και predict().
  • Μέθοδοι σε επίπεδο παρτίδας: καλούνται στην αρχή ή στο τέλος της επεξεργασίας μιας παρτίδας.
  • Μέθοδοι σε επίπεδο εποχής: καλούνται στην αρχή ή στο τέλος μιας παρτίδας εκπαίδευσης.

Σημείωση: Κάθε μέθοδος έχει πρόσβαση σε ένα dict που ονομάζεται logs. Τα κλειδιά και οι αξίες του logs είναι συμφραζόμενα – εξαρτώνται από το συμβάν που καλεί τη μέθοδο. Επιπλέον, έχουμε πρόσβαση στο μοντέλο μέσα σε κάθε μέθοδο μέσω του self.model αποδίδουν.

Ας ρίξουμε μια ματιά σε τρία παραδείγματα προσαρμοσμένων επιστροφών κλήσης – ένα για εκπαίδευση, ένα για αξιολόγηση και ένα για πρόβλεψη. Κάθε ένα θα εκτυπώνει σε κάθε στάδιο τι κάνει το μοντέλο μας και σε ποια αρχεία καταγραφής έχουμε πρόσβαση. Αυτό είναι χρήσιμο για την κατανόηση του τι είναι δυνατό να γίνει με προσαρμοσμένες επανακλήσεις σε κάθε στάδιο.

Ας ξεκινήσουμε ορίζοντας ένα μοντέλο παιχνιδιού:

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

Προσαρμοσμένη επανάκληση εκπαίδευσης

Το πρώτο μας callback είναι να καλέσουμε κατά τη διάρκεια της προπόνησης. Ας υποκατηγορήσουμε το Callback τάξη:

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

Εάν κάποια από αυτές τις μεθόδους δεν παρακαμφθεί - η προεπιλεγμένη συμπεριφορά θα συνεχιστεί όπως πριν. Στο παράδειγμά μας – απλώς εκτυπώνουμε τα διαθέσιμα αρχεία καταγραφής και το επίπεδο στο οποίο εφαρμόζεται η επανάκληση, με την κατάλληλη εσοχή.

Ας ρίξουμε μια ματιά στις εξόδους:

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}


Σημειώστε ότι μπορούμε να παρακολουθούμε σε κάθε βήμα τι κάνει το μοντέλο και σε ποιες μετρήσεις έχουμε πρόσβαση. Στο τέλος κάθε παρτίδας και εποχής, έχουμε πρόσβαση στη συνάρτηση απώλειας εντός δείγματος και στις μετρήσεις του μοντέλου μας.

Επιστροφή κλήσης προσαρμοσμένης αξιολόγησης

Τώρα, ας καλέσουμε το Model.evaluate() μέθοδος. Μπορούμε να δούμε ότι στο τέλος μιας παρτίδας έχουμε πρόσβαση στη συνάρτηση απώλειας και στις μετρήσεις εκείνη τη στιγμή και στο τέλος της αξιολόγησης έχουμε πρόσβαση στη συνολική απώλεια και μετρήσεις:

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}

Επιστροφή κλήσης προσαρμοσμένης πρόβλεψης

Τέλος, ας καλέσουμε το Model.predict() μέθοδος. Παρατηρήστε ότι στο τέλος κάθε παρτίδας έχουμε πρόσβαση στα προβλεπόμενα αποτελέσματα του μοντέλου μας:

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

Ρίξτε μια ματιά στον πρακτικό μας οδηγό για την εκμάθηση του Git, με βέλτιστες πρακτικές, πρότυπα αποδεκτά από τον κλάδο και συμπεριλαμβανόμενο φύλλο εξαπάτησης. Σταματήστε τις εντολές του Git στο Google και πραγματικά μαθαίνουν το!

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: {}

Με αυτά – μπορείτε να προσαρμόσετε τη συμπεριφορά, να ρυθμίσετε την παρακολούθηση ή με άλλο τρόπο να τροποποιήσετε τις διαδικασίες εκπαίδευσης, αξιολόγησης ή συμπερασμάτων. Μια εναλλακτική λύση στην υποκείμενη είναι η χρήση του LambdaCallback.

Χρήση LambaCallback

Μία από τις ενσωματωμένες επιστροφές κλήσης στον Κέρα είναι το LambdaCallback τάξη. Αυτή η επανάκληση δέχεται μια λειτουργία που καθορίζει πώς συμπεριφέρεται και τι κάνει! Κατά μία έννοια, σας επιτρέπει να χρησιμοποιείτε οποιαδήποτε αυθαίρετη λειτουργία ως επιστροφή κλήσης, επιτρέποντάς σας έτσι να δημιουργείτε προσαρμοσμένες επιστροφές κλήσης.

Η κλάση έχει τις προαιρετικές παραμέτρους:
-on_epoch_begin

  • on_epoch_end
  • on_batch_begin
  • on_batch_end
  • on_train_begin
  • on_train_end

Κάθε παράμετρος δέχεται μια συνάρτηση που καλείται στο αντίστοιχο συμβάν μοντέλου. Για παράδειγμα, ας κάνουμε μια επανάκληση για να στείλουμε ένα email όταν το μοντέλο ολοκληρώσει την εκπαίδευση:

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

Για να πραγματοποιήσετε την προσαρμοσμένη μας επανάκληση χρησιμοποιώντας LambdaCallback, πρέπει απλώς να εφαρμόσουμε τη συνάρτηση που θέλουμε να ονομαστεί, να την τυλίξουμε ως α lambda λειτουργία και περάστε το στο
LambdaCallback κλάση ως παράμετρος.

Μια επανάκληση για την οπτικοποίηση της εκπαίδευσης μοντέλου

Σε αυτήν την ενότητα, θα δώσουμε ένα παράδειγμα προσαρμοσμένης επανάκλησης που κάνει μια κινούμενη εικόνα της απόδοσης του μοντέλου μας να βελτιώνεται κατά τη διάρκεια της προπόνησης. Για να γίνει αυτό, αποθηκεύουμε τις τιμές των αρχείων καταγραφής στο τέλος κάθε παρτίδας. Στη συνέχεια, στο τέλος του βρόχου εκπαίδευσης, δημιουργούμε μια κινούμενη εικόνα χρησιμοποιώντας matplotlib.

Προκειμένου να βελτιωθεί η οπτικοποίηση, η απώλεια και οι μετρήσεις θα απεικονιστούν σε κλίμακα καταγραφής:

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

Θα χρησιμοποιήσουμε το ίδιο μοντέλο με πριν, αλλά με περισσότερα δείγματα εκπαίδευσης:

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()],
)

Το αποτέλεσμα μας είναι μια κινούμενη εικόνα των μετρήσεων και της συνάρτησης απώλειας καθώς αλλάζουν κατά τη διαδικασία εκπαίδευσης:

Το πρόγραμμα περιήγησής σας δεν υποστηρίζει βίντεο HTML.

Συμπέρασμα

Σε αυτόν τον οδηγό, ρίξαμε μια ματιά στην εφαρμογή προσαρμοσμένων ανακλήσεων στο Keras.
Υπάρχουν δύο επιλογές για την εφαρμογή προσαρμοσμένων επιστροφών κλήσης – μέσω της υποκατηγορίας του keras.callbacks.Callback τάξη ή χρησιμοποιώντας το keras.callbacks.LambdaCallback τάξη.

Έχουμε δει ένα πρακτικό παράδειγμα χρήσης LambdaCallbackγια την αποστολή ενός email στο τέλος του βρόχου εκπαίδευσης και ένα παράδειγμα υποκατηγορίας του Callback τάξη που δημιουργεί ένα κινούμενο σχέδιο του βρόχου εκπαίδευσης.

Το Althoug Keras έχει πολλές ενσωματωμένες επιστροφές κλήσης, η γνώση του πώς να εφαρμόσετε μια προσαρμοσμένη επανάκληση μπορεί να είναι χρήσιμη για πιο συγκεκριμένες εφαρμογές.

Σφραγίδα ώρας:

Περισσότερα από Stackabuse