Carregando um modelo Keras treinado e continuando o treinamento

95

Eu queria saber se seria possível salvar um modelo Keras parcialmente treinado e continuar o treinamento após carregar o modelo novamente.

A razão para isso é que terei mais dados de treinamento no futuro e não quero treinar todo o modelo novamente.

As funções que estou usando são:

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

Edição 1: adicionado exemplo totalmente funcional

Com o primeiro conjunto de dados após 10 épocas, a perda da última época será de 0,0748 e a precisão de 0,9863.

Depois de salvar, excluir e recarregar o modelo, a perda e a precisão do modelo treinado no segundo conjunto de dados será de 0,1711 e 0,9504, respectivamente.

Isso é causado pelos novos dados de treinamento ou por um modelo totalmente treinado novamente?

"""
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))
Wilmar van Ommeren
fonte
3
Você já testou? Não vejo motivos para isso não funcionar.
maz
O que vejo agora é que minha precisão cai cerca de 10 por cento depois de carregar o modelo (apenas nas primeiras épocas). Se o recarregamento funcionar, isso é obviamente causado pelos novos dados de treinamento. Mas eu só quero garantir que esse seja realmente o caso.
Wilmar van Ommeren
6
Você está salvando seu modelo diretamente com model.save ou está usando um ponto de verificação de modelo ( keras.io/callbacks/#example-model-checkpoints )? Se você estiver usando model.save, haverá uma chance de que você esteja salvando o modelo mais recente (isto é, última época) em vez do melhor (menor erro)? Você pode fornecer o código real?
maz
Estou guardando meu último modelo, não o melhor (até então não sabia que era possível). Vou preparar um código
Wilmar van Ommeren
3
Então, você não poderia recarregar isso e continuar treinando nos mesmos dados de trem? Isso deve garantir que o recarregamento está correto se os resultados forem comparáveis.
Marcin Możejko

Respostas:

36

Na verdade - model.savesalva todas as informações necessárias para reiniciar o treinamento no seu caso. A única coisa que pode ser prejudicada pelo recarregamento do modelo é o estado do otimizador. Para verificar isso, tente saverecarregar o modelo e treiná-lo nos dados de treinamento.

Marcin Możejko
fonte
1
@Marcin: ao usar o keras save(), salva o melhor resultado (menor perda) do modelo ou o último resultado (última atualização) do modelo? obrigado
Leão Lai
4
última atualização. O retorno de chamada do ponto de verificação do modelo serve para salvar o melhor.
Holi
2
@Khaj Você está se referindo a este keras.io/callbacks/#modelcheckpoint ? Parece que por padrão, ele salva a última atualização (não a melhor); o melhor só é salvo se save_best_only=Truefor definido explicitamente.
flow2k
7

O problema pode ser que você use um otimizador diferente - ou argumentos diferentes para o seu otimizador. Tive o mesmo problema com um modelo personalizado pré-treinado, usando

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

para o modelo pré-treinado, em que a taxa de aprendizagem original começa em 0,0003 e durante o pré-treinamento é reduzida para a taxa min_learning, que é 0,000003

Acabei de copiar essa linha para o script que usa o modelo pré-treinado e obtive precisões realmente ruins. Até que percebi que a última taxa de aprendizado do modelo pré-treinado foi a taxa mínima de aprendizado, ou seja, 0,000003. E se eu começar com essa taxa de aprendizado, obtenho exatamente as mesmas precisões iniciais que a saída do modelo pré-treinado - o que faz sentido, como começar com uma taxa de aprendizado que é 100 vezes maior do que a última taxa de aprendizado usada no modelo pré-treinado modelo resultará em um enorme overshoot de GD e, portanto, em precisões fortemente diminuídas.

Wolfgang
fonte
5

A maioria das respostas acima cobriu pontos importantes. Se você estiver usando o Tensorflow recente ( TF2.1ou superior), o exemplo a seguir o ajudará. A parte do modelo do código é do site 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)

Salve o modelo no formato * .tf. Pela minha experiência, se você tiver qualquer custom_loss definido, o formato * .h5 não salvará o status do otimizador e, portanto, não servirá ao seu propósito se você quiser retreinar o modelo de onde deixamos.

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

Essa abordagem reiniciará o treinamento de onde paramos antes de salvar o modelo. Como mencionado por outros, se você quiser salvar pesos de melhor modelo ou você deseja salvar pesos de modelo de cada época você precisa usar keras retornos de chamada de função (ModelCheckpoint) com opções como save_weights_only=True, save_freq='epoch', e save_best_only.

Para mais detalhes, verifique aqui e outro exemplo aqui .

Vishnuvardhan Janapati
fonte
1
legal, isso parece muito promissor - obrigado pela informação. neste exemplo, parece-me que você está retreinando o modelo com os mesmos dados que foram usados ​​para o treinamento. em caso afirmativo, eu teria pensado que a abordagem correta seria carregar um novo subconjunto de dados de treinamento para retreinar (a fim de refletir as novas informações sendo introduzidas no processo).
bibzzzz
1
@bibzzzz Concordo com você. Comentário muito bom. Eu queria demonstrar um retreinamento nos mesmos dados para melhorar o desempenho. A essência mostra claramente a melhoria no desempenho onde foi interrompido antes de salvar o modelo. Eu concordaria totalmente com você em retreinar em dados diferentes e tentarei mais tarde. Obrigado!
Vishnuvardhan Janapati
excelente - você demonstrou isso muito bem, obrigado.
bibzzzz
2

Observe que Keras às vezes tem problemas com modelos carregados, como aqui . Isso pode explicar os casos em que você não começa com a mesma precisão treinada.

shahar_m
fonte
1

Tudo acima ajuda, você deve retomar da mesma taxa de aprendizagem () que o LR quando o modelo e os pesos foram salvos. Defina-o diretamente no otimizador.

Observe que a melhoria a partir daí não é garantida, porque o modelo pode ter atingido o mínimo local, que pode ser global. Não adianta retomar um modelo para buscar outro mínimo local, a menos que você pretenda aumentar a taxa de aprendizado de forma controlada e empurrar o modelo para um mínimo possivelmente melhor não muito longe.

flowgrad
fonte
Por que é que? Não posso usar um LR menor do que antes?
lte__ de
Na verdade, o treinamento contínuo PODE levá-lo a um modelo melhor se você receber mais dados. Portanto, há um ponto de retomar um modelo para buscar outro mínimo local.
Corey Levinson