Во многих случаях при работе с библиотекой scikit-learn вам необходимо сохранить свои модели прогнозов в файл, а затем восстановить их, чтобы повторно использовать вашу предыдущую работу для: тестирования вашей модели на новых данных, сравнения нескольких моделей или что-нибудь еще. Эта процедура сохранения также известна как сериализация объекта - представляет объект с потоком байтов, чтобы сохранить его на диске, отправить по сети или сохранить в базе данных, в то время как процедура восстановления известна как десериализация. В этой статье мы рассмотрим три возможных способа сделать это в Python и scikit-learn, каждый из которых имеет свои плюсы и минусы.
Инструменты для сохранения и восстановления моделей
Первый инструмент, который мы описываем, - это Pickle , стандартный инструмент Python для (де) сериализации объектов. После этого мы рассмотрим библиотеку Joblib, которая предлагает простую (де) сериализацию объектов, содержащих большие массивы данных, и, наконец, мы представляем ручной подход для сохранения и восстановления объектов в / из JSON (нотация объектов JavaScript). Ни один из этих подходов не представляет собой оптимального решения, но правильный выбор следует выбирать в соответствии с потребностями вашего проекта.
Инициализация модели
Для начала создадим одну модель scikit-learn. В нашем примере мы будем использовать модель логистической регрессии и набор данных Iris . Импортируем необходимые библиотеки, загрузим данные и разделим их на обучающий и тестовый наборы.
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# Load and split data
data = load_iris()
Xtrain, Xtest, Ytrain, Ytest = train_test_split(data.data, data.target, test_size=0.3, random_state=4)
Теперь давайте создадим модель с некоторыми параметрами, не заданными по умолчанию, и подгоним ее под данные обучения. Мы предполагаем, что вы ранее нашли оптимальные параметры модели, т. Е. Те, которые обеспечивают максимальную расчетную точность.
# Create a model
model = LogisticRegression(C=0.1,
max_iter=20,
fit_intercept=True,
n_jobs=3,
solver='liblinear')
model.fit(Xtrain, Ytrain)
И наша получившаяся модель:
LogisticRegression(C=0.1, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=20, multi_class='ovr', n_jobs=3,
penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
verbose=0, warm_start=False)
Используя fit
метод, модель узнала ее коэффициенты , которые хранятся
в model.coef_
. Цель состоит в том, чтобы сохранить параметры и
коэффициенты модели в файл, чтобы вам не нужно было снова повторять шаги
обучения модели и оптимизации параметров для новых данных.
Модуль рассола
В следующих нескольких строках кода модель, которую мы создали на
предыдущем шаге, сохраняется в файл, а затем загружается как новый
объект с именем pickled_model
. Затем загруженная модель используется
для расчета показателя точности и прогнозирования результатов на новых
невидимых (тестовых) данных.
import pickle
#
# Create your model here (same as above)
#
# Save to file in the current working directory
pkl_filename = "pickle_model.pkl"
with open(pkl_filename, 'wb') as file:
pickle.dump(model, file)
# Load from file
with open(pkl_filename, 'rb') as file:
pickle_model = pickle.load(file)
# Calculate the accuracy score and predict target values
score = pickle_model.score(Xtest, Ytest)
print("Test score: {0:.2f} %".format(100 * score))
Ypredict = pickle_model.predict(Xtest)
Выполнение этого кода должно дать ваш результат и сохранить модель через Pickle:
$ python save_model_pickle.py
Test score: 91.11 %
Самое замечательное в использовании Pickle для сохранения и восстановления наших моделей обучения заключается в том, что это быстро
-
вы можете сделать это в двух строках кода. Это полезно, если вы оптимизировали параметры модели на обучающих данных, поэтому вам не нужно повторять этот шаг снова. В любом случае, он не сохраняет результаты тестов или какие-либо данные. Тем не менее, вы можете сделать это, сохранив кортеж или список из нескольких объектов (и запомните, какой объект куда идет) следующим образом:
tuple_objects = (model, Xtrain, Ytrain, score)
Save tuple
pickle.dump(tuple_objects, open(“tuple_model.pkl”, ‘wb’))
Restore tuple
pickled_model, pickled_Xtrain, pickled_Ytrain, pickled_score = pickle.load(open(“tuple_model.pkl”, ‘rb’))
Модуль Joblib
Библиотека Joblib предназначена для замены Pickle для объектов, содержащих большие данные. Повторим процедуру сохранения и восстановления, как и в случае с Pickle.
from sklearn.externals import joblib
# Save to file in the current working directory
joblib_file = "joblib_model.pkl"
joblib.dump(model, joblib_file)
# Load from file
joblib_model = joblib.load(joblib_file)
# Calculate the accuracy and predictions
score = joblib_model.score(Xtest, Ytest)
print("Test score: {0:.2f} %".format(100 * score))
Ypredict = pickle_model.predict(Xtest)
$ python save_model_joblib.py
Test score: 91.11 %
Как видно из примера, библиотека Joblib предлагает немного более простой рабочий процесс по сравнению с Pickle. В то время как Pickle требует передачи файлового объекта в качестве аргумента, Joblib работает как с файловыми объектами, так и с строковыми именами файлов. Если ваша модель содержит большие массивы данных, каждый массив будет храниться в отдельном файле, но процедура сохранения и восстановления останется прежней. Joblib также поддерживает различные методы сжатия, такие как zlib, gzip, bz2, а также различные уровни сжатия.
Ручное сохранение и восстановление в JSON
В зависимости от вашего проекта, Pickle и Joblib часто оказываются неподходящими решениями. Некоторые из этих причин обсуждаются позже в разделе « Проблемы совместимости ». В любом случае, когда вы хотите иметь полный контроль над процессом сохранения и восстановления, лучший способ - создать свои собственные функции вручную.
Ниже показан пример сохранения и восстановления объектов вручную с помощью JSON. Этот подход позволяет нам выбрать данные, которые необходимо сохранить, такие как параметры модели, коэффициенты, данные обучения и все, что нам нужно.
Поскольку мы хотим сохранить все эти данные в одном объекте, один из
возможных способов сделать это - создать новый класс, наследующий от
класса модели, которым в нашем примере является LogisticRegression
.
Новый класс, названный MyLogReg
, затем реализует методы save_json
и
load_json
для сохранения и восстановления в / из файла JSON
соответственно.
Для простоты мы сохраним только три параметра модели и данные обучения. Некоторые дополнительные данные, которые мы могли бы сохранить с помощью этого подхода, - это, например, оценка перекрестной проверки обучающего набора, тестовые данные, оценка точности тестовых данных и т. Д.
import json
import numpy as np
class MyLogReg(LogisticRegression):
# Override the class constructor
def __init__(self, C=1.0, solver='liblinear', max_iter=100, X_train=None, Y_train=None):
LogisticRegression.__init__(self, C=C, solver=solver, max_iter=max_iter)
self.X_train = X_train
self.Y_train = Y_train
# A method for saving object data to JSON file
def save_json(self, filepath):
dict_ = {}
dict_['C'] = self.C
dict_['max_iter'] = self.max_iter
dict_['solver'] = self.solver
dict_['X_train'] = self.X_train.tolist() if self.X_train is not None else 'None'
dict_['Y_train'] = self.Y_train.tolist() if self.Y_train is not None else 'None'
# Creat json and save to file
json_txt = json.dumps(dict_, indent=4)
with open(filepath, 'w') as file:
file.write(json_txt)
# A method for loading data from JSON file
def load_json(self, filepath):
with open(filepath, 'r') as file:
dict_ = json.load(file)
self.C = dict_['C']
self.max_iter = dict_['max_iter']
self.solver = dict_['solver']
self.X_train = np.asarray(dict_['X_train']) if dict_['X_train'] != 'None' else None
self.Y_train = np.asarray(dict_['Y_train']) if dict_['Y_train'] != 'None' else None
Теперь попробуем класс MyLogReg
Сначала мы создаем объект mylogreg
,
передаем ему обучающие данные и сохраняем в файл. Затем мы создаем новый
объект json_mylogreg
и вызываем load_json
для загрузки данных из
файла.
filepath = "mylogreg.json"
# Create a model and train it
mylogreg = MyLogReg(X_train=Xtrain, Y_train=Ytrain)
mylogreg.save_json(filepath)
# Create a new object and load its data from JSON file
json_mylogreg = MyLogReg()
json_mylogreg.load_json(filepath)
json_mylogreg
Распечатав новый объект, мы сможем увидеть наши параметры и данные обучения по мере необходимости.
MyLogReg(C=1.0,
X_train=array([[ 4.3, 3. , 1.1, 0.1],
[ 5.7, 4.4, 1.5, 0.4],
...,
[ 7.2, 3. , 5.8, 1.6],
[ 7.7, 2.8, 6.7, 2. ]]),
Y_train=array([0, 0, ..., 2, 2]), class_weight=None, dual=False,
fit_intercept=True, intercept_scaling=1, max_iter=100,
multi_class='ovr', n_jobs=1, penalty='l2', random_state=None,
solver='liblinear', tol=0.0001, verbose=0, warm_start=False)
Поскольку сериализация данных с использованием JSON фактически сохраняет объект в строковом формате, а не в потоке байтов, файл mylogreg.json можно открывать и изменять с помощью текстового редактора. Хотя этот подход был бы удобен для разработчика, он менее безопасен, поскольку злоумышленник может просматривать и изменять содержимое файла JSON. Более того, этот подход больше подходит для объектов с небольшим количеством переменных экземпляра, таких как модели scikit-learn, потому что любое добавление новых переменных требует изменений в методах сохранения и восстановления.
Проблемы совместимости
Хотя некоторые из плюсов и минусов каждого инструмента до сих пор были рассмотрены в тексте, вероятно, самым большим недостатком инструментов Pickle и Joblib является их совместимость с различными моделями и версиями Python.
Совместимость версий Python. В документации к обоим инструментам указано, что не рекомендуется (де) сериализовать объекты в разных версиях Python, хотя это может работать при изменении второстепенных версий.
Совместимость модели. Одна из наиболее частых ошибок - сохранение модели с помощью Pickle или Joblib, а затем изменение модели перед попыткой восстановления из файла. Внутренняя структура модели должна оставаться неизменной между сохранением и перезагрузкой.
Последняя проблема с Pickle и Joblib связана с безопасностью. Оба инструмента могут содержать вредоносный код, поэтому не рекомендуется восстанавливать данные из ненадежных или непроверенных источников.
Выводы
В этом посте мы описали три инструмента для сохранения и восстановления моделей scikit-learn. Библиотеки Pickle и Joblib быстры и просты в использовании, но имеют проблемы совместимости с разными версиями Python и изменениями в модели обучения. С другой стороны, ручной подход сложнее реализовать, и его необходимо модифицировать при любых изменениях в структуре модели, но с другой стороны, он может быть легко адаптирован к различным потребностям и не имеет проблем с совместимостью.