Salva classificatore su disco in scikit-learn


192

Come posso salvare un classificatore Naive Bayes addestrato su disco e utilizzarlo per prevedere i dati?

Ho il seguente programma di esempio dal sito Web di 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()

Risposte:


201

I classificatori sono solo oggetti che possono essere decapati e scaricati come qualsiasi altro. Per continuare il tuo esempio:

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)

1
Funziona come un fascino! Stavo cercando di usare np.savez e ricaricarlo da sempre, e questo non mi ha mai aiutato. Molte grazie.
Kartos,

7
in python3, usa il modulo pickle, che funziona esattamente così.
MCSH,

213

È inoltre possibile utilizzare joblib.dump e joblib.load che è molto più efficiente nella gestione di array numerici rispetto al selettore python predefinito.

Joblib è incluso in 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

Modifica: in Python 3.8+ è ora possibile utilizzare il pickle per un efficiente decapaggio di oggetti con matrici numeriche di grandi dimensioni come attributi se si utilizza il protocollo di pickle 5 (che non è l'impostazione predefinita).


1
Ma dalla mia comprensione il pipelining funziona se fa parte di un singolo flusso di lavoro. Se voglio compilare il modello, archiviarlo su disco e interrompere l'esecuzione lì. Poi torno una settimana dopo e provo a caricare il modello dal disco che mi dà un errore:
venuktan

2
Non c'è modo di interrompere e riprendere l'esecuzione del fitmetodo se questo è ciò che stai cercando. Detto questo, joblib.loadnon dovrebbe sollevare un'eccezione dopo un successo joblib.dumpse lo chiami da un Python con la stessa versione della libreria scikit-learn.
Ogisel,

10
Se si utilizza IPython, non utilizzare il --pylabflag della riga di comando o la %pylabmagia poiché il sovraccarico dello spazio dei nomi implicito è noto per interrompere il processo di decapaggio. Usa invece le importazioni esplicite e la %matplotlib inlinemagia.
Ogrisel,

2
consultare la documentazione di scikit-learn per riferimento: scikit-learn.org/stable/tutorial/basic/…
user1448319

1
È possibile riqualificare un modello precedentemente salvato? In particolare i modelli SVC?
Uday Sawant,

108

Quello che stai cercando si chiama Persistenza del modello in parole sklearn ed è documentato nell'introduzione e nelle sezioni di persistenza del modello .

Quindi hai inizializzato il tuo classificatore e allenato a lungo con

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

Dopo questo hai due opzioni:

1) Usando Pickle

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) Utilizzo di 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')

Ancora una volta è utile leggere i link sopra menzionati


30

In molti casi, in particolare con la classificazione del testo, non è sufficiente solo memorizzare il classificatore, ma è necessario memorizzare anche il vettorizzatore in modo da poter vettorializzare l'input in futuro.

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

caso d'uso futuro:

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)

Prima di scaricare il vettorizzatore, è possibile eliminare la proprietà stop_words_ del vettorizzatore:

vectorizer.stop_words_ = None

rendere il dumping più efficiente. Inoltre, se i parametri del tuo classificatore sono scarsi (come nella maggior parte degli esempi di classificazione del testo) puoi convertire i parametri da densi a sparsi, il che farà un'enorme differenza in termini di consumo di memoria, caricamento e scaricamento. Sparsify il modello di:

clf.sparsify()

Che funzionerà automaticamente per SGDClassifier ma nel caso in cui tu sappia che il tuo modello è scarso (molti zeri in clf.coef_), puoi convertire manualmente clf.coef_ in una matrice sparse CSR di:

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

e quindi è possibile memorizzarlo in modo più efficiente.


Risposta perspicace! Volevo solo aggiungere in caso di SVC, restituisce un parametro di modello sparse.
Shayan Amani,

5

sklearngli stimatori implementano metodi per semplificare il salvataggio delle proprietà addestrate rilevanti di uno stimatore. Alcuni stimatori implementano i __getstate__metodi stessi, ma altri, come il GMMgiusto, utilizzano l' implementazione di base che salva semplicemente il dizionario interno degli oggetti:

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

Il metodo consigliato per salvare il modello su disco è utilizzare il picklemodulo:

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)

Tuttavia, è necessario salvare ulteriori dati in modo da poter riqualificare il modello in futuro o subire conseguenze terribili (come essere bloccato in una vecchia versione di sklearn) .

Dalla documentazione :

Al fine di ricostruire un modello simile con le versioni future di scikit-learn, è necessario salvare metadati aggiuntivi lungo il modello in decapaggio:

I dati di allenamento, ad esempio un riferimento a un'istantanea immutabile

Il codice sorgente di Python utilizzato per generare il modello

Le versioni di scikit-learn e le sue dipendenze

Il punteggio di convalida incrociata ottenuto sui dati di allenamento

Ciò è particolarmente vero per gli stimatori di Ensemble che si basano sul tree.pyxmodulo scritto in Cython (come IsolationForest), poiché crea un accoppiamento con l'implementazione, che non è garantito per essere stabile tra le versioni di sklearn. In passato ha visto cambiamenti incompatibili.

Se i tuoi modelli diventano molto grandi e il caricamento diventa un fastidio, puoi anche utilizzare il più efficiente joblib. Dalla documentazione:

Nel caso specifico dello scikit, potrebbe essere più interessante utilizzare la sostituzione di joblib di pickle( joblib.dump& joblib.load), che è più efficiente su oggetti che portano internamente grandi array intorpiditi come spesso accade per gli stimatori di scikit-learning montati, ma può solo decapare sul disco e non su una stringa:


1
but can only pickle to the disk and not to a stringMa potresti inserirlo in StringIO da joblib. Questo è quello che faccio sempre.
Matteo,

Il mio progetto attuale sta facendo qualcosa di simile, sai cosa c'è The training data, e.g. a reference to a immutable snapshotqui? TIA!
Daisy Qin,

1

sklearn.externals.joblibè obsoleto da 0.21e verrà rimosso in v0.23:

/usr/local/lib/python3.7/site-packages/sklearn/externals/joblib/ init .py: 15: FutureWarning: sklearn.externals.joblib è deprecato in 0.21 e verrà rimosso in 0.23. Importare questa funzionalità direttamente da joblib, che può essere installato con: pip install joblib. Se questo avviso viene generato quando si caricano modelli in salamoia, potrebbe essere necessario ricerializzare quei modelli con scikit-learn 0.21+.
warnings.warn (msg, categoria = FutureWarning)


Pertanto, è necessario installare joblib:

pip install joblib

e infine scrivere il modello su disco:

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)

Ora per leggere il file scaricato è necessario eseguire solo:

with open('myClassifier.joblib.pkl', 'rb') as f:
    my_clf = joblib.load(f)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.