Enregistrer le classificateur sur le disque dans scikit-learn

192

Comment enregistrer un classificateur Naive Bayes entraîné sur le disque et l'utiliser pour prédire les données?

J'ai l'exemple de programme suivant du 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()
garak
la source

Réponses:

201

Les classificateurs ne sont que 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)
mwv
la source
1
Fonctionne comme un charme! J'essayais d'utiliser np.savez et de le recharger tout le temps et cela n'a jamais aidé. Merci beaucoup.
Kartos
7
en python3, utilisez le module pickle, qui fonctionne exactement comme ceci.
MCSH
213

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

Joblib est inclus dans scikit-learn:

>>> 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

Edit: dans Python 3.8+, il est maintenant possible d'utiliser pickle pour un décapage efficace des objets avec de grands tableaux numériques comme attributs si vous utilisez le protocole pickle 5 (qui n'est pas la valeur par défaut).

ogrisel
la source
1
Mais d'après ce que je comprends, le pipelining fonctionne s'il fait partie d'un flux de travail unique. Si je veux construire le modèle, stockez-le sur disque et arrêtez l'exécution là-bas. Ensuite, je reviens une semaine plus tard et essaie de charger le modèle à partir du disque il me lance une erreur:
venuktan
2
Il n'y a aucun moyen d'arrêter et de reprendre l'exécution de la fitméthode si c'est ce que vous recherchez. Cela étant dit, joblib.loadne devrait pas joblib.dumpdéclencher d' exception après un succès si vous l'appelez à partir d'un Python avec la même version de la bibliothèque scikit-learn.
ogrisel le
10
Si vous utilisez IPython, n'utilisez pas l' --pylabindicateur de ligne de commande ou la %pylabmagie car la surcharge de l'espace de noms implicite est connue pour interrompre le processus de décapage. Utilisez %matplotlib inlineplutôt les importations explicites et la magie.
ogrisel le
2
voir la documentation scikit-learn pour référence: scikit-learn.org/stable/tutorial/basic/…
user1448319
1
Est-il possible de recycler le modèle précédemment enregistré? Plus précisément des modèles SVC?
Uday Sawant
108

Ce que vous recherchez s'appelle Persistance du modèle dans les mots sklearn et est documenté dans l' introduction et dans les sections de persistance du modèle .

Vous avez donc initialisé votre classificateur et l'avez formé pendant longtemps avec

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

Après cela, vous avez deux options:

1) Utilisation de cornichon

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 mentionnés ci-dessus

Salvador Dali
la source
30

Dans de nombreux cas, en particulier avec la classification de texte, il ne suffit pas de stocker le classificateur, mais vous devrez également stocker le vectoriseur afin de pouvoir vectoriser votre entrée à l'avenir.

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 vectorizer, on peut supprimer la propriété stop_words_ du vectorizer en:

vectorizer.stop_words_ = None

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

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_ en une matrice csr scipy sparse en:

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

et vous pouvez ensuite le stocker plus efficacement.

Cendre
la source
Réponse perspicace! Je voulais juste ajouter dans le cas de SVC, il renvoie un paramètre de modèle épars.
Shayan Amani
5

sklearnLes estimateurs mettent en œuvre des méthodes pour vous permettre d'enregistrer facilement les propriétés entraînées pertinentes d'un estimateur. Certains estimateurs implémentent les __getstate__méthodes eux-mêmes, mais d'autres, comme le GMMutilisent simplement l' implémentation de base qui enregistre simplement le dictionnaire interne 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 disque consiste à utiliser le picklemodule:

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 afin de pouvoir recycler votre modèle à l'avenir, ou subir des conséquences désastreuses (comme être verrouillé 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 le long du modèle pickled:

Les données d'apprentissage, 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'entraînement

Ceci est particulièrement vrai pour les estimateurs Ensemble qui s'appuient sur le tree.pyxmodule écrit en Cython (tel que IsolationForest), car il crée un couplage à l'implémentation, qui n'est pas garanti pour être stable entre les versions de sklearn. Il a vu des changements rétrocompatibles dans le passé.

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

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

Sebastian Wozny
la source
1
but can only pickle to the disk and not to a stringMais vous pouvez le ramasser dans StringIO à partir de joblib. C'est ce que je fais tout le temps.
Matthew
Mon projet actuel fait quelque chose de similaire, savez-vous quoi The training data, e.g. a reference to a immutable snapshotici? TIA!
Daisy Qin le
1

sklearn.externals.joblibest obsolète depuis 0.21et sera supprimé dans v0.23:

/usr/local/lib/python3.7/site-packages/sklearn/externals/joblib/ init .py: 15: FutureWarning: sklearn.externals.joblib est obsolète dans 0.21 et sera supprimé dans 0.23. Veuillez importer cette fonctionnalité directement depuis joblib, qui peut être installée avec: pip install joblib. Si cet avertissement apparaît lors du chargement de modèles décapés, vous devrez peut-être re-sérialiser ces modèles avec scikit-learn 0.21+.
warnings.warn (msg, catégorie = FutureWarning)


Par conséquent, vous devez installer joblib:

pip install joblib

et enfin écrivez le modèle sur le disque:

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


digits = load_digits()
clf = SGDClassifier().fit(digits.data, digits.target)

with open('myClassifier.joblib.pkl', 'wb') as f:
    joblib.dump(clf, f, compress=9)

Maintenant, pour lire le fichier sauvegardé, il vous suffit d'exécuter:

with open('myClassifier.joblib.pkl', 'rb') as f:
    my_clf = joblib.load(f)
Giorgos Myrianthous
la source