web-dev-qa-db-fra.com

Enregistrez le classificateur sur le disque dans scikit-learn

Comment enregistrer une --- classificateur Naive Bayes dans disque et l'utiliser pour prévoir des données?

J'ai l'exemple de programme suivant sur le site Web scikit-learn:

from sklearn import datasets
iris = datasets.load_iris()
from sklearn.naive_bayes import GaussianNB
gnb = GaussianNB()
y_pred = gnb.fit(iris.data, iris.target).predict(iris.data)
print "Number of mislabeled points : %d" % (iris.target != y_pred).sum()
173
garak

Les classificateurs sont simplement des objets qui peuvent être décapés et vidés comme les autres. Pour continuer votre exemple:

import cPickle
# save the classifier
with open('my_dumped_classifier.pkl', 'wb') as fid:
    cPickle.dump(gnb, fid)    

# load it again
with open('my_dumped_classifier.pkl', 'rb') as fid:
    gnb_loaded = cPickle.load(fid)
182
mwv

Vous pouvez également utiliser joblib.dump et joblib.load , qui est beaucoup plus efficace pour gérer les tableaux numériques que le pickler par défaut python.

Joblib est inclus dans scikit-learn:

>>> from sklearn.externals import joblib
>>> from sklearn.datasets import load_digits
>>> from sklearn.linear_model import SGDClassifier

>>> digits = load_digits()
>>> clf = SGDClassifier().fit(digits.data, digits.target)
>>> clf.score(digits.data, digits.target)  # evaluate training error
0.9526989426822482

>>> filename = '/tmp/digits_classifier.joblib.pkl'
>>> _ = joblib.dump(clf, filename, compress=9)

>>> clf2 = joblib.load(filename)
>>> clf2
SGDClassifier(alpha=0.0001, class_weight=None, epsilon=0.1, eta0=0.0,
       fit_intercept=True, learning_rate='optimal', loss='hinge', n_iter=5,
       n_jobs=1, penalty='l2', power_t=0.5, rho=0.85, seed=0,
       shuffle=False, verbose=0, warm_start=False)
>>> clf2.score(digits.data, digits.target)
0.9526989426822482
196
ogrisel

Ce que vous recherchez est appelé Persistance du modèle dans les mots d’apprentissage et il est documenté dans introduction et dans modèle persistance sections.

Donc, vous avez initialisé votre classificateur et formé pendant longtemps avec

clf = some.classifier()
clf.fit(X, y)

Après cela, vous avez deux options:

1) Utilisation de cornichons

import pickle
# now you can save it to a file
with open('filename.pkl', 'wb') as f:
    pickle.dump(clf, f)

# and later you can load it
with open('filename.pkl', 'rb') as f:
    clf = pickle.load(f)

2) Utilisation de Joblib

from sklearn.externals import joblib
# now you can save it to a file
joblib.dump(clf, 'filename.pkl') 
# and later you can load it
clf = joblib.load('filename.pkl')

Une fois de plus, il est utile de lire les liens susmentionnés.

93
Salvador Dali

Dans de nombreux cas, en particulier avec la classification de texte, il ne suffit pas de stocker le classificateur, vous devez également stocker le vectoriseur pour pouvoir vectoriser ultérieurement votre entrée.

import pickle
with open('model.pkl', 'wb') as fout:
  pickle.dump((vectorizer, clf), fout)

cas d'utilisation futur:

with open('model.pkl', 'rb') as fin:
  vectorizer, clf = pickle.load(fin)

X_new = vectorizer.transform(new_samples)
X_new_preds = clf.predict(X_new)

Avant de vider le vectoriseur, vous pouvez supprimer la propriété stop_words_ de vectorizer en:

vectorizer.stop_words_ = None

rendre le dumping plus efficace. De plus, si vos paramètres de classificateur sont clairsemés (comme dans la plupart des exemples de classification de texte), vous pouvez convertir les paramètres de dense en clairsemé, ce qui fera une énorme différence en termes de consommation de mémoire, de chargement et de vidage. Sparsify le modèle par:

clf.sparsify()

Ce qui fonctionnera automatiquement pour SGDClassifier mais si vous savez que votre modèle est clairsemé (beaucoup de zéros dans clf.coef_), vous pouvez convertir manuellement clf.coef_ dans une csr scipy matrice crépue par:

clf.coef_ = scipy.sparse.csr_matrix(clf.coef_)

et alors vous pouvez le stocker plus efficacement.

27
Ash

Les estimateurs sklearn implémentent des méthodes facilitant la sauvegarde des propriétés formées pertinentes d’un estimateur. Certains estimateurs implémentent les méthodes ___getstate___ eux-mêmes, mais d'autres, comme le GMM, utilisent simplement le implémentation de base , qui enregistre simplement le dictionnaire intérieur des objets:

_def __getstate__(self):
    try:
        state = super(BaseEstimator, self).__getstate__()
    except AttributeError:
        state = self.__dict__.copy()

    if type(self).__module__.startswith('sklearn.'):
        return dict(state.items(), _sklearn_version=__version__)
    else:
        return state
_

La méthode recommandée pour enregistrer votre modèle sur un disque consiste à utiliser le module pickle :

_from sklearn import datasets
from sklearn.svm import SVC
iris = datasets.load_iris()
X = iris.data[:100, :2]
y = iris.target[:100]
model = SVC()
model.fit(X,y)
import pickle
with open('mymodel','wb') as f:
    pickle.dump(model,f)
_

Cependant, vous devez enregistrer des données supplémentaires pour pouvoir rééduquer votre modèle ultérieurement, ou subir des conséquences désastreuses (par exemple, être enfermé dans une ancienne version de sklearn) .

De la documentation :

Afin de reconstruire un modèle similaire avec les futures versions de scikit-learn, des métadonnées supplémentaires doivent être enregistrées dans le modèle conservé au vinaigre:

Les données de formation, par exemple une référence à un instantané immuable

Le code source python utilisé pour générer le modèle

Les versions de scikit-learn et ses dépendances

Le score de validation croisée obtenu sur les données d'apprentissage

Ceci est particulièrement vrai pour les estimateurs d'ensemble qui s'appuient sur le module tree.pyx écrit en Cython (tel que IsolationForest) , car cela crée un couplage avec l’implémentation, qui n’est pas garantie entre les versions de sklearn. Il a été témoin de changements incompatibles dans le passé.

Si vos modèles deviennent très volumineux et que le chargement devient une nuisance, vous pouvez également utiliser le plus efficace joblib. De la documentation:

Dans le cas spécifique du scikit, il peut être plus intéressant d’utiliser le remplacement par joblib de pickle (_joblib.dump_ & _joblib.load_), ce qui est plus efficace pour les objets qui portent de grands tableaux numpy en interne, comme c’est souvent le cas. pour les estimateurs ajustés scikit-learn, mais ne peut décaper que sur le disque et non sur une chaîne:

4
Sebastian Wozny