При работе с 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 = "")