Сохрание весов нейронной сети в Google Drive/FTP/HTTP

При работе с Google Colab периодически происходит дисконнект после которого все загруженные данные затираются и необходимо повторять загрузку.

Гораздо обиднее, когда нейронная сеть обучалась продолжительное время, например, по ночам, и произошел дисконнект. Чтобы минимизировать временные потери имеет смысл сохранять удачные веса на внешнем хранилище. Это, несомненно, замедляет тренировку нейронной сети, однако позволяет периодически сохранять уже проделанную нейронкой работу.

Сохранение весов нейронной сети из Colab на Google Drive

Проще всего сохранять веса в Google Drive, поскольку Colab и Google Drive тесно интегрированы за исключением прозрачной авторизации, что странно. Даже будучи авторизованным в Google Colab с учеткой Google приходится каждый раз проходить авторизацию в Google Drive. Для монтирования Google Drive достаточно использовать код:

from google.colab import drive
drive.mount("/content/drive/")

Затем перейти по ссылке авторизации, выбрать учетку Google и получить код для вставки на станицу Google Colab.

В Google Drive в корне самим Colab-ом при сохранении notebook-ов была создана папка «Colab Notebooks». Создадим подпапку Data для сохранения datasets.

После монтирования Google Drive найти правильный путь к папки можно кликнув на кнопку с «>».

И затем выбрать Files:

Найти нужную папку и кликнуть «Copy path». Вставляем путь в код:

gdrive_path = "/content/drive/My Drive/Colab Notebooks/Data/" 

Теперь можно создавать новые файлы, например:

filename = gdrive_path + "test.txt"

with open(filename , 'w') as file:
    file.write('whatever')

!ls "/content/drive/My Drive/Colab Notebooks/Data"   

Для сохранения весов можно написать свой callback или использовать готовый:

checkpoint = ModelCheckpoint(gdrive_path + "best_weights.hdf5", monitor='loss', verbose=1, save_best_only=True, save_weights_only = True, mode='auto', period=1)
modelImage.fit(xTrain01[:500], yTrain01[:500], epochs=300, batch_size=20, validation_data = (xTrain01[500:], yTrain01[500:]), callbacks=[checkpoint])

Сохранение весов нейронной сети из Google Colab на FTP сервер

Если не хочется при каждом дисконнекте авторизовываться на Google Drive, то можно использовать загрузку файлов на FTP. Но, в этом случае придется писать свой callback и вызывать метод для загрузки на FTP по окончании каждой эпохи.

!curl -T best_weights.hdf5 ftp://username:password@ftp.example.ru

Локально сохраненные веса будут заливатся по ftp на сервер.

import keras

class MyCallback(keras.callbacks.Callback):
  def __init__(self):
    super().__init__()

  def on_epoch_begin(self, epoch, logs={}):
    #self.epoch_time_start = time.time()  

  def on_epoch_end(self, epoch, logs=None):
    if logs['mean_squared_error'] < self.best_mse:
      print("Найдено лучшее значение MSE. Было", self.best_mse, "Новое:", logs['mean_squared_error'], "Сохраняю файл весов.")
      self.model.save_weights("best_weights.h5")
      !curl -T best_weights.h5 ftp://username:password@ftp.example.ru
      self.best_mse = logs['mean_squared_error'] #Сохраняем значение лучшего результата

Для загрузки весов после дисконнекта Google Colab можно использовать код:

#Загружаем архив с текстами с FTP/HTTP
def loadWeights(filename, fullpath):
  print("Start downloading", filename)
  !wget $fullpath

И запуск загрузки:

URL = "http://ftp.example.ru/"
filename = "best_weights.hdf5"
fullpath = URL + filename
print(fullpath)
loaded = loadWeights(filename, fullpath)

Периодичесое сохранение весов сети на FTP в Colab

Проблема с сохранением весов на ftp, что эта запись происходит очень долго, поэтому злоупотреблять постоянным сохранением нельзя. В улучшенном варианте callback-а файл весов регулярно сохраняется на диске Colab и периодически (с интервалом в 5 итераций) переносится на ftp.

import keras
import sys
import time
from keras.callbacks import EarlyStopping, ReduceLROnPlateau

class MyCallback(keras.callbacks.Callback):

  def __init__(self):
    super().__init__()
    self.best_mse = sys.float_info.max
    self.counter = 0
    self.interval = 5 #Интервал для сохранения

  def on_epoch_begin(self, epoch, logs={}):
    self.epoch_time_start = time.time()  

  def on_epoch_end(self, epoch, logs=None):
    #'loss', 'val_loss', 'val_mean_squared_error', 'mean_squared_error'
    if (logs['val_mean_squared_error'] < self.best_mse): 
      print("\r\nНайдено лучшее значение MSE. Было", self.best_mse, "Новое:", logs['val_mean_squared_error'], "Сохраняю файл весов. Итерация:", self.counter, "\r\n")
      self.model.save_weights("best_weights.h5")     
      if ((self.counter % self.interval) == 0):
        print("Сохраняю файл весов на ftp.")
        !curl -ss -T best_weights.h5 ftp://[логин]:[пароль]@vh46.timeweb.ru
        self.best_mse = logs['val_mean_squared_error'] #Сохраняем значение лучшего результата
    self.counter += 1

early_stopping = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=10)  
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2, verbose=1, patience=3, min_lr=1e-8)

Обратите внимание на критерий сохранения весов. По логике должен быть val_loss или val_mean_squared_error. Однако, у меня был пример, что при сохранении с критерием mean_squared_error ошибка получалась ниже, хотя прямой связи нет.

При тренировки модели веса подгружаются следующим образом:

#@title Функция построения нейронной сети на сверточных слоях { display-mode: "form" }
def buildConvNN(xTrain, yTrain, xVal, yVal, load_weights):
  modelC = Sequential()

  modelC.add(Conv1D(10, 5, input_shape = (xTrain.shape[1], xTrain.shape[2]), activation="linear"))
  #modelC.add(BatchNormalization())
  #modelC.add(Dropout(0.2))
  #modelC.add(Conv1D(10, 5, activation="linear"))
  modelC.add(Flatten())
  modelC.add(Dense(5, activation="linear"))
  modelC.add(Dense(yTrain.shape[1], activation="linear"))
  if load_weights:
    modelC.load_weights("best_weights.h5")

  modelC.compile(loss="mse", optimizer=Adam(lr=1e-4), metrics=['mse'])

  history = modelC.fit(xTrain, 
                    yTrain, 
                    epochs=101, 
                    batch_size=20, 
                    verbose=1,
                    validation_data=(xVal, yVal), 
                    callbacks=[MyCallback(), early_stopping, reduce_lr])
  return history, modelC

Для загрузки файлов с ftp используется функция, которая проверяет, есть ли на локальном диске Colab подгруженный файл весов или его надо забрать с ftp.

#@title Функция для загрузки архива с данными с сервера { display-mode: "form" }
def loadfiles(filename, fullpath, user = "anonymouse", password = ""):
  loaded = True
  if os.path.isfile(filename):
      print("File \"", filename, "\" has already downloaded.")
  else:
    print("Start downloading", filename)
    if (password == ""):
      !wget $fullpath
    else:  
      print("!wget --user", user,"--password", password, fullpath, "--no-check-certificate")
      !wget --user $user --password $password $fullpath --no-check-certificate
    !unzip $filename 
    loaded = False
  return loaded

Загружаются веса вызовом этой функции так:

#@title Загрузка сохраненных весов { display-mode: "form" }
url = "http://www.test.ru/uploads/Colab/"
filename = 'best_weights.h5'
fullpath = url + filename
loaded = loadfiles(filename, fullpath, user = "", password = "") 
Spread the love
Запись опубликована в рубрике IT рецепты. Добавьте в закладки постоянную ссылку.

Добавить комментарий