Guardar clasificador en disco en scikit-learn

192

¿Cómo puedo guardar una capacitados Bayes ingenuo clasificador de disco y utilizarlo para predecir datos?

Tengo el siguiente programa de muestra del sitio 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
fuente

Respuestas:

201

Los clasificadores son solo objetos que se pueden encurtir y tirar como cualquier otro. Para continuar con tu ejemplo:

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
fuente
1
¡Funciona de maravilla! Intenté usar np.savez y cargarlo todo el tiempo y eso nunca ayudó. Muchas gracias.
Kartos
77
en python3, use el módulo pickle, que funciona exactamente así.
MCSH
213

También puede usar joblib.dump y joblib.load, que es mucho más eficiente en el manejo de matrices numéricas que el selector de python predeterminado.

Joblib está incluido en 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

Editar: en Python 3.8+ ahora es posible usar pickle para el decapado eficiente de objetos con grandes matrices numéricas como atributos si usa el protocolo 5 de pickle (que no es el predeterminado).

ogrisel
fuente
1
Pero, según tengo entendido, la canalización funciona si es parte de un solo flujo de trabajo. Si quiero construir el modelo, guárdelo en el disco y detenga la ejecución allí. Luego regreso una semana más tarde y tratar de cargar el modelo del disco que me tira un error:
venuktan
2
No hay forma de detener y reanudar la ejecución del fitmétodo si esto es lo que está buscando. Dicho esto, joblib.loadno debería generar una excepción después de un éxito joblib.dumpsi lo llama desde un Python con la misma versión de la biblioteca scikit-learn.
ogrisel
10
Si está utilizando IPython, no use el --pylabindicador de línea de comando o la %pylabmagia ya que se sabe que la sobrecarga implícita del espacio de nombres interrumpe el proceso de decapado. Utilice importaciones explícitas y la %matplotlib inlinemagia en su lugar.
ogrisel
2
consulte la documentación de scikit-learn como referencia: scikit-learn.org/stable/tutorial/basic/…
user1448319
1
¿Es posible volver a entrenar el modelo guardado anteriormente? Específicamente modelos SVC?
Uday Sawant
108

Lo que estás buscando se llama Persistencia del modelo en palabras sklearn y está documentado en la introducción y en las secciones de persistencia del modelo .

Entonces, ha inicializado su clasificador y lo ha entrenado durante mucho tiempo con

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

Después de esto tienes dos opciones:

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) Usando 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')

Una vez más, es útil leer los enlaces mencionados anteriormente

Salvador Dalí
fuente
30

En muchos casos, particularmente con la clasificación de texto, no es suficiente solo almacenar el clasificador, sino que también deberá almacenar el vectorizador para poder vectorizar su entrada en el futuro.

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

caso de 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)

Antes de descargar el vectorizador, se puede eliminar la propiedad stop_words_ del vectorizador de la siguiente manera:

vectorizer.stop_words_ = None

para que el vertido sea más eficiente. Además, si los parámetros de su clasificador son escasos (como en la mayoría de los ejemplos de clasificación de texto), puede convertir los parámetros de densos a dispersos, lo que marcará una gran diferencia en términos de consumo de memoria, carga y descarga. Sparsify el modelo por:

clf.sparsify()

Lo que funcionará automáticamente para SGDClassifier pero en caso de que sepa que su modelo es escaso (muchos ceros en clf.coef_), puede convertir manualmente clf.coef_ en una matriz dispersa scipy csr de la siguiente manera :

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

y luego puedes almacenarlo de manera más eficiente.

Ceniza
fuente
Respuesta perspicaz! Solo quería agregar en caso de SVC, devuelve un parámetro de modelo disperso.
Shayan Amani
5

sklearnlos estimadores implementan métodos para facilitarle el almacenamiento de propiedades capacitadas relevantes de un estimador. Algunos estimadores implementan __getstate__métodos ellos mismos, pero otros, como el GMMsolo usan la implementación base que simplemente guarda el diccionario interno de objetos:

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

El método recomendado para guardar su modelo en el disco es usar el picklemódulo:

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)

Sin embargo, debe guardar datos adicionales para poder volver a entrenar su modelo en el futuro o sufrir graves consecuencias (como estar bloqueado en una versión anterior de sklearn) .

De la documentación :

Para reconstruir un modelo similar con futuras versiones de scikit-learn, se deben guardar metadatos adicionales a lo largo del modelo en escabeche:

Los datos de entrenamiento, por ejemplo, una referencia a una instantánea inmutable

El código fuente de Python utilizado para generar el modelo.

Las versiones de scikit-learn y sus dependencias

La puntuación de validación cruzada obtenida en los datos de entrenamiento

Esto es especialmente cierto para los estimadores de Ensemble que se basan en el tree.pyxmódulo escrito en Cython (como IsolationForest), ya que crea un acoplamiento a la implementación, que no se garantiza que sea estable entre las versiones de sklearn. Ha visto cambios hacia atrás incompatibles en el pasado.

Si sus modelos se vuelven muy grandes y la carga se vuelve una molestia, también puede usar el más eficiente joblib. De la documentación:

En el caso específico del scikit, puede ser más interesante usar el reemplazo de pickle( joblib.dump& joblib.load) de joblib , que es más eficiente en los objetos que llevan grandes matrices numpy internamente, como suele ser el caso de los estimadores scikit-learn ajustados, pero solo puede encurtir al disco y no a una cadena:

Sebastian Wozny
fuente
1
but can only pickle to the disk and not to a stringPero podría enredar esto en StringIO desde joblib. Esto es lo que hago todo el tiempo.
Mateo
Mi proyecto actual está haciendo algo similar, ¿sabes qué hay The training data, e.g. a reference to a immutable snapshotaquí? TIA!
Daisy Qin
1

sklearn.externals.joblibha quedado en desuso desde entonces 0.21y se eliminará en v0.23:

/usr/local/lib/python3.7/site-packages/sklearn/externals/joblib/ init .py: 15: FutureWarning: sklearn.externals.joblib está en desuso en 0.21 y se eliminará en 0.23. Importe esta funcionalidad directamente desde joblib, que se puede instalar con: pip install joblib. Si se genera esta advertencia al cargar modelos en escabeche, es posible que deba volver a serializar esos modelos con scikit-learn 0.21+.
warnings.warn (msg, category = FutureWarning)


Por lo tanto, necesita instalar joblib:

pip install joblib

y finalmente escribe el modelo en el 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)

Ahora, para leer el archivo volcado, todo lo que necesita ejecutar es:

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