2015-09-24 25 views
20

Ho bisogno di serializzare modelli scikit-learn/statsmodels in modo tale che tutte le dipendenze (codice + dati) siano impacchettate in un artefatto e questo artefatto possa essere usato per inizializzare il modello e fare previsioni. L'utilizzo del pickle module non è un'opzione, poiché si occuperà solo della dipendenza dei dati (il codice non sarà pacchettizzato). Quindi, sto conducendo esperimenti con Dill. Per rendere la mia domanda più precisa, il seguente è un esempio in cui costruisco un modello e lo mantengo.Quali sono le insidie ​​nell'usare Dill per serializzare modelli scikit-learn/statsmodels?

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

Corrisponde a questo, ecco come inizializzo il modello persistente (in una nuova sessione) e faccio una previsione. Si noti che questo codice non inizializza esplicitamente o non conosce lo 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) 

Qualcuno ha usato Dill in questo modo ?. L'idea è che un data scientist estenda un ModelWrapper class per ogni modello che implementano e quindi costruisca l'infrastruttura intorno a ciò che persiste nei modelli, distribuisce i modelli come servizi e gestisce l'intero ciclo di vita del modello.

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) 

Oltre le implicazioni di sicurezza (esecuzione di codice arbitrario) e il requisito che i moduli come scikit-learn dovrà essere installato sul thats macchina servono modello, ci sono e le altre insidie ​​di questo approccio? Qualsiasi commento o parola di consiglio sarebbe molto utile.

Penso che il YHat e il Dato abbiano adottato un approccio simile, ma sono state implementate le implementazioni di Dill per scopi simili.

+0

Ok. Ho un prototipo funzionante di questo e sembra funzionare bene. Ora, ho bisogno di fare lo stesso per R. Qualche suggerimento su questo? – Nikhil

risposta

14

Sono l'autore dill. dill è stato creato per eseguire esattamente ciò che si sta facendo ... (per mantenere le corrispondenze numeriche all'interno delle istanze di classe per le statistiche), in cui questi oggetti possono essere distribuiti a risorse diverse e eseguiti in modo imbarazzante e parallelo. Quindi, la risposta è sì - Ho eseguito il codice come il tuo, usando mystic e/o sklearn.

nota che molti di di sklearn utilizzo cloudpickle gli autori per consentire il calcolo parallelo su sklearn oggetti, e non dill. dill può decodificare più tipi di oggetti rispetto a cloudpickle, tuttavia cloudpickle è leggermente migliore (in questo momento di scrittura) sugli oggetti di picking che fanno riferimento al dizionario globale come parte di una chiusura: per impostazione predefinita, dill fa questo per riferimento, mentre cloudpickle memorizza fisicamente le dipendenze. Tuttavia, dill ha una modalità "recurse", che si comporta come cloudpickle, quindi la differenza quando si utilizza questa modalità è minore. (Per abilitare la modalità "recurse", fare dill.settings['recurse'] = True o utilizzare recurse=True come flag in dill.dump). Un'altra piccola differenza è che lo cloudpickle contiene un supporto speciale per cose come scikits.timeseries e PIL.Image, mentre lo dill no.

Sul lato positivo, dill non sottopone a picco le classi per riferimento, quindi, decodificando un'istanza di classe, serializza l'oggetto classe stesso - che è un grande vantaggio, poiché serializza istanze di classi derivate di classificatori, modelli, ed ecc da sklearn nel loro stato esatto al momento del decapaggio ... quindi se si apportano modifiche all'oggetto classe, l'istanza continua a scartare correttamente. Esistono altri vantaggi di dill su cloudpickle, oltre alla più ampia gamma di oggetti (e in genere un sottaceto più piccolo) - tuttavia, non li elenco qui. Hai chiesto delle insidie, quindi le differenze non sono insidie.

principali insidie:

  • si dovrebbe avere nulla vostre classi si riferiscono alla installato sulla macchina remota , nel caso in cui dill (o cloudpickle) sottaceti IT di di riferimento.

  • Si dovrebbe cercare di rendere le vostre classi e metodi di classe come autosufficiente possibile (ad esempio, non si riferiscono a oggetti definiti nel scope globale dalle classi).

  • sklearn oggetti possono essere grandi, in modo da salvare molti di loro ad un unico salamoia non è sempre una buona idea ... si potrebbe desiderare di utilizzare klepto che ha un'interfaccia dict alla cache e l'archiviazione, e consente di configurare l'interfaccia di archivio per memorizzare singolarmente ciascuna coppia chiave-valore (ad es. una voce per file).

7

Ok per cominciare, nel codice di esempio pickle potrebbe funzionare correttamente, io uso sempre il pickle per confezionare un modello e usarlo in seguito, a meno che non si desideri inviare il modello direttamente a un altro server o salvare lo interpreter state, perché questo è ciò che Dill è buono e pickle non può fare. Dipende anche dal tuo codice, dai tipi che usi, pickle potrebbe non riuscire, Dill è più stabile.

Dill si primarly basa su pickle e quindi sono molto simili, alcune cose che si dovrebbero prendere in considerazione/guardare in:

  1. Limitazioni di Dill

    frame, generator, traceback tipi standard può non essere confezionato.

  2. cloudpickle potrebbe essere una buona idea anche per il tuo problema, ha un supporto migliore negli oggetti in fase di decapaggio (rispetto al sottaceto, non per vedere meglio di Dill) e puoi anche decodificare facilmente il codice.

Una volta che il computer di destinazione ha le librerie corrette caricati, (fate attenzione per le diverse python versioni pure, perché essi possono bug il codice), tutto dovrebbe funzionare bene sia con Dill e cloudpickle, a patto che si fa non usare i tipi standard non standardizzati.

Spero che questo aiuti.

+0

Ho bisogno di eseguire il modello su un altro server. L'idea è di memorizzare i modelli in un archivio di valori-chiave e portarli dietro un endpoint di servizio come e quando richiesto. – Nikhil

+0

Quindi entrambi 'Dill' e' cloudpickle' dovrebbero funzionare bene per quello che vuoi. –

1

I pacchetto processo gaussiano (GP) da scikit-learn utilizzando pickle.

Il motivo principale è perché il GP impiega molto tempo per creare e caricare molto più velocemente utilizzando pickle. Quindi, durante l'inizializzazione del codice, controllo se i file di dati per il modello sono stati aggiornati e rigenerano il modello, se necessario, altrimenti decodificarlo semplicemente da pickle!

Vorrei utilizzare pickle, dill, cloudpickle nel rispettivo ordine.

Nota che pickle include l'argomento di parola chiave e alcuni valori possono velocizzare e ridurre notevolmente l'utilizzo della memoria! Infine, avvolgo il codice del sottaceto con la compressione da CPython STL se necessario.