Caricamento di un modello Keras addestrato e continua formazione


98

Mi chiedevo se fosse possibile salvare un modello Keras parzialmente addestrato e continuare l'addestramento dopo aver caricato nuovamente il modello.

La ragione di ciò è che avrò più dati di addestramento in futuro e non voglio riaddestrare nuovamente l'intero modello.

Le funzioni che sto utilizzando sono:

#Partly train model
model.fit(first_training, first_classes, batch_size=32, nb_epoch=20)

#Save partly trained model
model.save('partly_trained.h5')

#Load partly trained model
from keras.models import load_model
model = load_model('partly_trained.h5')

#Continue training
model.fit(second_training, second_classes, batch_size=32, nb_epoch=20)

Modifica 1: aggiunto un esempio completamente funzionante

Con il primo set di dati dopo 10 epoche la perdita dell'ultima epoca sarà 0,0748 e la precisione 0,9863.

Dopo aver salvato, cancellato e ricaricato il modello, la perdita e la precisione del modello addestrato sul secondo set di dati saranno rispettivamente 0,1711 e 0,9504.

Ciò è causato dai nuovi dati di addestramento o da un modello completamente rieducato?

"""
Model by: http://machinelearningmastery.com/
"""
# load (downloaded if needed) the MNIST dataset
import numpy
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.utils import np_utils
from keras.models import load_model
numpy.random.seed(7)

def baseline_model():
    model = Sequential()
    model.add(Dense(num_pixels, input_dim=num_pixels, init='normal', activation='relu'))
    model.add(Dense(num_classes, init='normal', activation='softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model

if __name__ == '__main__':
    # load data
    (X_train, y_train), (X_test, y_test) = mnist.load_data()

    # flatten 28*28 images to a 784 vector for each image
    num_pixels = X_train.shape[1] * X_train.shape[2]
    X_train = X_train.reshape(X_train.shape[0], num_pixels).astype('float32')
    X_test = X_test.reshape(X_test.shape[0], num_pixels).astype('float32')
    # normalize inputs from 0-255 to 0-1
    X_train = X_train / 255
    X_test = X_test / 255
    # one hot encode outputs
    y_train = np_utils.to_categorical(y_train)
    y_test = np_utils.to_categorical(y_test)
    num_classes = y_test.shape[1]

    # build the model
    model = baseline_model()

    #Partly train model
    dataset1_x = X_train[:3000]
    dataset1_y = y_train[:3000]
    model.fit(dataset1_x, dataset1_y, nb_epoch=10, batch_size=200, verbose=2)

    # Final evaluation of the model
    scores = model.evaluate(X_test, y_test, verbose=0)
    print("Baseline Error: %.2f%%" % (100-scores[1]*100))

    #Save partly trained model
    model.save('partly_trained.h5')
    del model

    #Reload model
    model = load_model('partly_trained.h5')

    #Continue training
    dataset2_x = X_train[3000:]
    dataset2_y = y_train[3000:]
    model.fit(dataset2_x, dataset2_y, nb_epoch=10, batch_size=200, verbose=2)
    scores = model.evaluate(X_test, y_test, verbose=0)
    print("Baseline Error: %.2f%%" % (100-scores[1]*100))

3
L'hai provato? Non vedo ragioni per non funzionare.
maz

Quello che vedo ora è che la mia precisione diminuisce di circa il 10 percento dopo aver caricato il modello (solo nelle prime epoche). Se il ricaricamento funziona, ciò è ovviamente causato dai nuovi dati di addestramento. Ma voglio solo assicurarmi che sia davvero così.
Wilmar van Ommeren

7
Stai salvando il tuo modello direttamente con model.save o stai utilizzando un checkpoint del modello ( keras.io/callbacks/#example-model-checkpoints )? Se stai usando model.save ci sarebbe la possibilità di salvare l'ultimo modello (cioè l'ultima epoca) invece di quello migliore (errore più basso)? Potete fornire il codice effettivo?
maz

Sto salvando il mio ultimo modello, non il migliore (fino a questo punto non sapevo che fosse possibile). Preparerò un po 'di codice
Wilmar van Ommeren

3
Quindi non potresti ricaricarlo e continuare ad allenarti sugli stessi dati del treno? Questo dovrebbe assicurarti che ricaricare è ok se i risultati sarebbero comparabili.
Marcin Możejko

Risposte:


36

In realtà - model.savesalva tutte le informazioni necessarie per riavviare la formazione nel tuo caso. L'unica cosa che potrebbe essere rovinata ricaricando il modello è il tuo stato di ottimizzazione. Per verificarlo, provare a savericaricare il modello e addestrarlo sui dati di addestramento.


1
@ Marcin: quando si utilizza keras save(), salva il miglior risultato (perdita minima) del modello o l'ultimo risultato (ultimo aggiornamento) del modello? grazie
Lion Lai

5
ultimo aggiornamento. Il callback del punto di controllo del modello serve per salvare il migliore.
Holi

2
@Khaj Ti riferisci a questo keras.io/callbacks/#modelcheckpoint ? Sembra di default, salva l'ultimo aggiornamento (non il migliore); il migliore viene salvato solo se save_best_only=Trueimpostato esplicitamente.
flow2k

7

Il problema potrebbe essere che utilizzi un ottimizzatore diverso o argomenti diversi per il tuo ottimizzatore. Ho appena avuto lo stesso problema con un modello pre-addestrato personalizzato, utilizzando

reduce_lr = ReduceLROnPlateau(monitor='loss', factor=lr_reduction_factor,
                              patience=patience, min_lr=min_lr, verbose=1)

per il modello pre-addestrato, per cui il tasso di apprendimento originale inizia da 0,0003 e durante il pre-training viene ridotto al tasso min_learning, che è 0,000003

Ho appena copiato quella riga nello script che utilizza il modello pre-addestrato e ho ottenuto precisioni davvero pessime. Fino a quando non ho notato che l'ultimo tasso di apprendimento del modello pre-addestrato era il tasso di apprendimento minimo, ovvero 0,000003. E se comincio con quel tasso di apprendimento, ottengo esattamente le stesse precisioni per iniziare come l'output del modello pre-addestrato, il che ha senso, come iniziare con un tasso di apprendimento che è 100 volte più grande dell'ultimo tasso di apprendimento utilizzato nel pre-addestrato il modello si tradurrà in un enorme superamento di GD e quindi in precisioni fortemente ridotte.


5

La maggior parte delle risposte precedenti copriva punti importanti. Se stai usando Tensorflow recente ( TF2.1o superiore), il seguente esempio ti aiuterà. La parte del modello del codice proviene dal sito Web di Tensorflow.

import tensorflow as tf
from tensorflow import keras
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

def create_model():
  model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(512, activation=tf.nn.relu),  
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation=tf.nn.softmax)
    ])

  model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',metrics=['accuracy'])
  return model

# Create a basic model instance
model=create_model()
model.fit(x_train, y_train, epochs = 10, validation_data = (x_test,y_test),verbose=1)

Salva il modello in formato * .tf. Dalla mia esperienza, se hai definito custom_loss, il formato * .h5 non salverà lo stato dell'ottimizzatore e quindi non servirà al tuo scopo se vuoi riqualificare il modello da dove abbiamo lasciato.

# saving the model in tensorflow format
model.save('./MyModel_tf',save_format='tf')


# loading the saved model
loaded_model = tf.keras.models.load_model('./MyModel_tf')

# retraining the model
loaded_model.fit(x_train, y_train, epochs = 10, validation_data = (x_test,y_test),verbose=1)

Questo approccio riavvierà l'addestramento dal punto in cui eravamo rimasti prima di salvare il modello. Come detto da altri, se si desidera salvare i pesi di miglior modello o si desidera salvare i pesi del modello ogni epoca è necessario utilizzare la funzione keras callback (ModelCheckpoint) con opzioni come save_weights_only=True, save_freq='epoch'e save_best_only.

Per maggiori dettagli, controlla qui e un altro esempio qui .


1
bello, sembra molto promettente - grazie per le informazioni. in questo esempio, mi sembra che tu stia riqualificando il modello sugli stessi dati utilizzati per l'addestramento. in tal caso, avrei pensato che l'approccio corretto sarebbe stato quello di caricare un nuovo sottoinsieme di dati di allenamento su cui riqualificare (in modo da riflettere le nuove informazioni introdotte nel processo)?
bibzzzz

1
@bibzzzz D'accordo con te. Ottimo commento. Volevo dimostrare la riqualificazione sugli stessi dati per migliorare le prestazioni. L'essenza mostra chiaramente il miglioramento delle prestazioni dove era stato interrotto prima di salvare il modello. Sarei completamente d'accordo con te per riqualificarti su dati diversi e lo proverò più tardi. Grazie!
Vishnuvardhan Janapati

eccellente - lo hai dimostrato molto bene, grazie.
bibzzzz

2

Si noti che a volte Keras ha problemi con i modelli caricati, come qui . Questo potrebbe spiegare casi in cui non si parte dalla stessa precisione addestrata.


1

Tutto ciò di cui sopra aiuta, è necessario riprendere dalla stessa velocità di apprendimento () dell'LR quando il modello e i pesi sono stati salvati. Impostalo direttamente sull'ottimizzatore.

Si noti che il miglioramento da lì non è garantito, perché il modello potrebbe aver raggiunto il minimo locale, che potrebbe essere globale. Non ha senso riprendere un modello per cercare un altro minimo locale, a meno che non si intenda aumentare il tasso di apprendimento in modo controllato e spingere il modello in un minimo possibilmente migliore non lontano.


Perché? Non posso usare un LR più piccolo di prima?
lte__

In realtà, la formazione continua PU portarti a un modello migliore se ricevi più dati. Quindi c'è un punto per riprendere un modello per cercare un altro minimo locale.
Corey Levinson

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.