Подтвердить что ты не робот

Каковы подводные камни использования Dill для сериализации моделей scikit-learn/statsmodels?

Мне нужно сериализовать модели scikit-learn/statsmodels, чтобы все зависимости (код + данные) были упакованы в артефакт, и этот артефакт можно использовать для инициализации модели и создания прогнозов. Использование pickle module не является вариантом, потому что это будет только заботиться о зависимости данных (код не будет упакован). Итак, я проводил эксперименты с Dill. Чтобы уточнить мой вопрос, следующий пример - пример создания модели и ее сохранения.

from sklearn import datasets
from sklearn import svm
from sklearn.preprocessing import Normalizer
import dill

digits = datasets.load_digits()
training_data_X = digits.data[:-5]
training_data_Y = digits.target[:-5]
test_data_X = digits.data[-5:]
test_data_Y = digits.target[-5:]

class Model:
    def __init__(self):
        self.normalizer = Normalizer()
        self.clf = svm.SVC(gamma=0.001, C=100.)
    def train(self, training_data_X, training_data_Y):
        normalised_training_data_X = normalizer.fit_transform(training_data_X)
        self.clf.fit(normalised_training_data_X, training_data_Y)
    def predict(self, test_data_X):
        return self.clf.predict(self.normalizer.fit_transform(test_data_X))  

model = Model()
model.train(training_data_X, training_data_Y)
print model.predict(test_data_X)
dill.dump(model, open("my_model.dill", 'w'))

В соответствии с этим, вот как я инициализирую сохраненную модель (в новом сеансе) и сделаю прогноз. Обратите внимание, что этот код явно не инициализирует или не знает о значении class Model.

import dill
from sklearn import datasets

digits = datasets.load_digits()
training_data_X = digits.data[:-5]
training_data_Y = digits.target[:-5]
test_data_X = digits.data[-5:]
test_data_Y = digits.target[-5:]

with open("my_model.dill") as model_file:
    model = dill.load(model_file)

print model.predict(test_data_X)

Кто-нибудь использовал Уилла таким образом?. Идея состоит в том, чтобы ученый-данник расширил ModelWrapper class для каждой модели, которую они реализуют, а затем построил инфраструктуру вокруг этого, которая сохраняет модели, развертывает модели как службы и управляет всем жизненным циклом модели.

class ModelWrapper(object):
    __metaclass__ = abc.ABCMeta
    def __init__(self, model):
        self.model = model
    @abc.abstractmethod
    def predict(self, input):
        return
    def dumps(self):
        return dill.dumps(self)
    def loads(self, model_string):
        self.model = dill.loads(model_string)

Помимо последствий для безопасности (выполнение произвольного кода) и требования о том, что модули, такие как scikit-learn, должны быть установлены на машине, обслуживающей модель, есть ли и какие-либо другие подводные камни в этом подходе? Любые комментарии или слова совета были бы наиболее полезными.

Я думаю, что YHat и Dato приняли аналогичный подход, но выкатили собственный реализации Уилла для аналогичных целей.

4b9b3361

Ответ 1

Я автор dill. dill был создан для того, чтобы делать именно то, что вы делаете... (чтобы сохранить числовые значения в экземплярах класса для статистики), где эти объекты затем могут быть распределены по разным ресурсам и выполняться неловко параллельно. Итак, ответ да - у меня есть код, похожий на ваш, используя mystic и/или sklearn.

Обратите внимание, что многие из авторов sklearn используют cloudpickle для включения параллельных вычислений на объектах sklearn, а не dill. dill может рассортировать больше типов объектов, чем cloudpickle, однако cloudpickle немного лучше (в это время написания) на травильных объектах, которые ссылаются на глобальный словарь как часть закрытия - по умолчанию dill делает это по ссылке, а cloudpickle физически сохраняет зависимости. Однако dill имеет режим "recurse", который действует как cloudpickle, поэтому разница при использовании этого режима незначительна. (Чтобы включить режим "recurse", сделайте dill.settings['recurse'] = True или используйте recurse=True как флаг в dill.dump). Другое незначительное отличие состоит в том, что cloudpickle содержит специальную поддержку таких вещей, как scikits.timeseries и PIL.Image, а dill - нет.

С положительной стороны dill не разбирает классы по ссылке, поэтому, выбирая экземпляр класса, он сериализует сам объект класса - что является большим преимуществом, поскольку оно сериализует экземпляры производных классов классификаторов, моделей, и т.д. из sklearn в их точном состоянии во время травления... поэтому, если вы вносите изменения в объект класса, экземпляр все еще печатает правильно. Существуют и другие преимущества dill более cloudpickle, помимо более широкого диапазона объектов (и, как правило, меньшего рассола), однако я не буду перечислять их здесь. Вы просили ловушки, поэтому различия не являются ловушками.

Основные подводные камни:

  • У вас должно быть все, на что ссылаются ваши классы, на удаленный компьютер, на всякий случай dill (или cloudpickle) разжигает его ссылка.

  • Вы должны попытаться сделать ваши классы и методы класса такими, как самодостаточны (например, не ссылаются на объекты, определенные в глобальный охват из ваших классов).

  • sklearn объекты могут быть большими, поэтому сохранение многих из них в один pickle не всегда хорошая идея... вы можете использовать klepto который имеет интерфейс dict для кэширования и архивирования и позволяет настроить интерфейс архива для хранения каждой пары значений ключа отдельно (например, одной записи на файл).

Ответ 2

Хорошо, в вашем примере кода pickle может работать нормально, я все время использую pickle для упаковки модели и использую ее позже, если вы не хотите отправить модель напрямую на другой сервер или сохранить interpreter state, потому что это то, что Dill хорошо, а pickle не может сделать. Это также зависит от вашего кода, каких типов и т.д. Вы используете, pickle может завершиться неудачей, Dill более стабилен.

Dill в основном базируется на pickle, и поэтому они очень похожи, некоторые вещи, которые вы должны учитывать/изучать:

  • Ограничения Dill

    frame, generator, traceback стандартные типы не могут быть упакованы.

  • cloudpickle может быть хорошей идеей и для вашей проблемы, у нее есть лучшая поддержка при травлении объектов (чем рассол, а не лучше, чем у Дила), и вы также можете легко расчесывать код.

После того, как на целевой машине будут загружены правильные библиотеки (будьте осторожны для разных версий python, так как они могут привести к ошибке вашего кода), все должно работать нормально как с Dill, так и с cloudpickle, пока вы не используете нестандартные стандартные типы.

Надеюсь, это поможет.

Ответ 3

Я пакет gaussian process (GP) из scikit-learn с помощью pickle.

Основная причина в том, что GP занимает много времени, чтобы строить и загружать гораздо быстрее, используя pickle. Поэтому в моей инициализации кода я проверяю, обновлялись ли файлы данных для модели и при необходимости обновляли модель, иначе просто де-сериализуйте ее из pickle!

Я использовал бы pickle, dill, cloudpickle в соответствующем порядке.

Обратите внимание, что pickle содержит аргумент ключевого слова protocol, а некоторые значения могут значительно ускорить и значительно сократить использование памяти! Наконец, я завершаю код сокета с сжатием из CPython STL, если это необходимо.