บันทึกลักษณนามไปยังดิสก์ใน scikit-Learn


192

ฉันจะบันทึกลักษณนาม Naive Bayes ที่ผ่านการฝึกอบรมไปยังดิสก์และใช้เพื่อทำนายข้อมูลได้อย่างไร

ฉันมีโปรแกรมตัวอย่างต่อไปนี้จากเว็บไซต์ 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()

คำตอบ:


201

ตัวแยกประเภทเป็นเพียงวัตถุที่สามารถดองและเททิ้งได้เหมือนกัน ในการทำตัวอย่างของคุณ:

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
ทำงานเหมือนจับใจ! ฉันพยายามใช้ np.savez และโหลดมันกลับมาตลอดและนั่นก็ไม่เคยช่วยอะไร ขอบคุณมาก.
Kartos

7
ใน python3 ใช้โมดูล pickle ซึ่งใช้งานได้ดีเช่นนี้
MCSH

213

คุณยังสามารถใช้joblib.dumpและjoblib.loadซึ่งมีประสิทธิภาพมากขึ้นในการจัดการอาร์เรย์ที่เป็นตัวเลขกว่าไพ ธ อนพิกเลอร์เริ่มต้น

Joblib รวมอยู่ใน 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

แก้ไข: ใน Python 3.8+ ตอนนี้คุณสามารถใช้ pickle สำหรับการดองวัตถุที่มีประสิทธิภาพด้วยอาร์เรย์ตัวเลขขนาดใหญ่เป็นคุณลักษณะหากคุณใช้ pickle protocol 5 (ซึ่งไม่ใช่ค่าเริ่มต้น)


1
แต่จากความเข้าใจของฉันไปป์ไลน์ทำงานถ้าส่วนหนึ่งของกระบวนการทำงานเดียว ถ้าฉันต้องการสร้างแบบจำลองเก็บไว้ในดิสก์และหยุดการดำเนินการที่นั่น จากนั้นฉันจะกลับมาอีกหนึ่งสัปดาห์ต่อมาและพยายามที่จะโหลดแบบจำลองจากดิสก์มันทำให้ฉันเกิดข้อผิดพลาด:
venuktan

2
ไม่มีวิธีหยุดและดำเนินการfitวิธีต่อไปหากนี่คือสิ่งที่คุณกำลังมองหา ที่ถูกกล่าวว่าjoblib.loadไม่ควรยกข้อยกเว้นหลังจากประสบความสำเร็จjoblib.dumpถ้าคุณเรียกมันจาก Python ที่มีไลบรารี scikit-Learn รุ่นเดียวกัน
ogrisel

10
หากคุณกำลังใช้ IPython อย่าใช้การ--pylabตั้งค่าสถานะบรรทัดคำสั่งหรือ%pylabเวทมนต์เนื่องจากการโอเวอร์โหลดของเนมสเปซโดยนัยเป็นที่รู้กันว่าจะทำให้กระบวนการแตกหัก ใช้การนำเข้าและ%matplotlib inlineเวทมนตร์อย่างชัดเจนแทน
ogrisel

2
ดูเอกสารอ้างอิง scikit-Learn สำหรับการอ้างอิง: scikit-learn.org/stable/tutorial/basic/ ......
1448319

1
เป็นไปได้หรือไม่ที่จะฝึกรุ่นที่บันทึกไว้ก่อนหน้านี้? รุ่น SVC โดยเฉพาะ?
Uday Sawant

108

สิ่งที่คุณกำลังมองหาเรียกว่าการคงอยู่ของโมเดลในคำ sklearn และมีการบันทึกไว้ในบทนำและในส่วนการคงอยู่ของโมเดล

ดังนั้นคุณได้เริ่มต้นลักษณนามของคุณและฝึกฝนมาเป็นเวลานานด้วย

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

หลังจากนี้คุณมีสองตัวเลือก:

1) การใช้ดอง

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) การใช้ 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')

อีกครั้งที่เป็นประโยชน์ในการอ่านลิงก์ที่กล่าวถึงข้างต้น


30

ในหลายกรณีโดยเฉพาะอย่างยิ่งกับการจัดหมวดหมู่ข้อความมันไม่เพียงพอที่จะเก็บลักษณนาม แต่คุณจะต้องเก็บ vectorizer ด้วยเพื่อที่คุณจะได้เวกเตอร์อินพุตของคุณในอนาคต

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

กรณีการใช้ในอนาคต:

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)

ก่อนที่จะทิ้ง vectorizer หนึ่งสามารถลบคุณสมบัติ stop_words_ ของ vectorizer โดย:

vectorizer.stop_words_ = None

เพื่อให้การถ่ายโอนข้อมูลมีประสิทธิภาพมากขึ้น นอกจากนี้หากพารามิเตอร์ตัวจําแนกของคุณเบาบาง (เช่นในตัวอย่างการจัดประเภทข้อความส่วนใหญ่) คุณสามารถแปลงพารามิเตอร์จากความหนาแน่นเป็นกระจัดกระจายซึ่งจะสร้างความแตกต่างอย่างมากในแง่ของการใช้หน่วยความจำการโหลดและการทุ่มตลาด แยกโมเดลโดย:

clf.sparsify()

ซึ่งจะทำงานโดยอัตโนมัติสำหรับSGDClassifierแต่ในกรณีที่คุณรู้ว่าแบบจำลองของคุณกระจัดกระจาย (ศูนย์จำนวนมากใน clf.coef_) จากนั้นคุณสามารถแปลง clf.coef_ ด้วยตนเองเป็นเมทริกซ์กระจัดกระจาย csrโดย:

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

จากนั้นคุณสามารถจัดเก็บได้อย่างมีประสิทธิภาพมากขึ้น


คำตอบที่ชาญฉลาด! แค่ต้องการเพิ่มในกรณีของ SVC มันจะส่งคืนพารามิเตอร์แบบกระจาย
Shayan Amani

5

sklearnตัวประมาณค่าใช้วิธีการต่างๆเพื่อให้คุณสามารถบันทึกคุณสมบัติที่ผ่านการฝึกอบรมที่เกี่ยวข้องของตัวประมาณค่าได้ง่าย ตัวประมาณบางตัวใช้__getstate__วิธีการด้วยตัวเอง แต่ตัวอื่น ๆ เช่นGMMเพียงแค่ใช้การติดตั้งพื้นฐานซึ่งจะบันทึกพจนานุกรมภายในวัตถุ:

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

วิธีที่แนะนำในการบันทึกรุ่นของคุณลงในแผ่นดิสก์คือการใช้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)

อย่างไรก็ตามคุณควรบันทึกข้อมูลเพิ่มเติมเพื่อให้คุณสามารถฝึกให้โมเดลของคุณในอนาคตหรือได้รับผลกระทบที่เลวร้าย(เช่นถูกขังเป็นรุ่นเก่า sklearn)

จากเอกสาร :

เพื่อสร้างโมเดลที่คล้ายกันกับ scikit-Learn รุ่นในอนาคตข้อมูลเมตาเพิ่มเติมควรได้รับการบันทึกไว้ในโมเดลดอง:

ข้อมูลการฝึกอบรมเช่นการอ้างอิงถึงสแนปชอตที่ไม่เปลี่ยนรูป

รหัสแหล่งหลามที่ใช้ในการสร้างแบบจำลอง

เวอร์ชันของ scikit-learn และการพึ่งพา

คะแนนการตรวจสอบข้ามที่ได้รับจากข้อมูลการฝึกอบรม

นี่เป็นเรื่องจริงโดยเฉพาะอย่างยิ่งสำหรับตัวประมาณค่า Ensembleที่พึ่งพาtree.pyxโมดูลที่เขียนใน Cython (เช่นIsolationForest) เนื่องจากมันสร้างการเชื่อมต่อกับการใช้งานซึ่งไม่รับประกันว่าจะมีความเสถียรระหว่างรุ่นของ sklearn มันเคยเห็นการเปลี่ยนแปลงที่เข้ากันไม่ได้ย้อนหลังในอดีต

joblibหากรุ่นที่ท่านจะมีขนาดใหญ่มากและโหลดจะกลายเป็นความรำคาญให้คุณยังสามารถใช้มีประสิทธิภาพมากขึ้น จากเอกสาร:

ในกรณีที่เฉพาะเจาะจงของ scikit มันอาจจะน่าสนใจกว่าที่จะใช้การแทนที่ของ joblib pickle( joblib.dump& joblib.load) ซึ่งมีประสิทธิภาพมากขึ้นในวัตถุที่มีอาร์เรย์ numpy ขนาดใหญ่ภายในซึ่งมักจะเป็นกรณีสำหรับการประมาณค่า scikit-Learn ที่เหมาะสม แต่สามารถดองได้ ไปยังดิสก์และไม่ใช่กับสตริง:


1
but can only pickle to the disk and not to a stringแต่คุณสามารถดองสิ่งนี้ลงใน StringIO จาก joblib นี่คือสิ่งที่ฉันทำตลอดเวลา
Matthew

โครงการปัจจุบันของฉันกำลังทำสิ่งที่คล้ายกันคุณรู้อะไรThe training data, e.g. a reference to a immutable snapshotไหม TIA!
เดซี่ฉิน

1

sklearn.externals.joblibถูกเลิกใช้ตั้งแต่0.21และจะถูกลบในv0.23:

/usr/local/lib/python3.7/site-packages/sklearn/externals/joblib/ init .py: 15: FutureWarning: sklearn.externals.joblib เลิกใช้ใน 0.21 และจะถูกลบใน 0.23 โปรดนำเข้าฟังก์ชั่นนี้โดยตรงจาก joblib ซึ่งสามารถติดตั้งได้ด้วย: pip install joblib หากคำเตือนนี้เพิ่มขึ้นเมื่อโหลดแบบจำลองที่ได้รับการดองคุณอาจต้องจัดลำดับรุ่นเหล่านั้นอีกครั้งด้วย scikit-Learn 0.21+
warnings.warn (ข้อความ, หมวดหมู่ = FutureWarning)


ดังนั้นคุณต้องติดตั้งjoblib:

pip install joblib

และสุดท้ายเขียนโมเดลลงดิสก์:

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)

ตอนนี้เพื่อที่จะอ่านไฟล์ทิ้งสิ่งที่คุณต้องใช้คือ:

with open('myClassifier.joblib.pkl', 'rb') as f:
    my_clf = joblib.load(f)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.