Как сохранить модели выравнивания Python NLTK для последующего использования?
В Python я использую NLTK's alignment module
создавать выравнивания слов между параллельными текстами. Выравнивание кусков может быть трудоемким процессом, особенно когда выполняется над значительными корпусами. Было бы неплохо сделать выравнивания в пакетном режиме за один день и использовать их позже.
from nltk import IBMModel1 as ibm
biverses = [list of AlignedSent objects]
model = ibm(biverses, 20)
with open(path + "eng-taq_model.txt", 'w') as f:
f.write(model.train(biverses, 20)) // makes empty file
Как только я создаю модель, как я могу (1) сохранить ее на диск и (2) использовать позже?
4 ответа
Непосредственный ответ - мариновать его, см. https://wiki.python.org/moin/UsingPickle
Но поскольку IBMModel1 возвращает лямбда-функцию, ее невозможно выбрать по умолчанию pickle
/ cPickle
(см. https://github.com/nltk/nltk/blob/develop/nltk/align/ibm1.py и https://github.com/nltk/nltk/blob/develop/nltk/align/ibm1.py)
Итак, мы будем использовать dill
, Во-первых, установите dill
см. Может ли Python мариновать лямбда-функции?
$ pip install dill
$ python
>>> import dill as pickle
Затем:
>>> import dill
>>> import dill as pickle
>>> from nltk.corpus import comtrans
>>> from nltk.align import IBMModel1
>>> bitexts = comtrans.aligned_sents()[:100]
>>> ibm = IBMModel1(bitexts, 20)
>>> with open('model1.pk', 'wb') as fout:
... pickle.dump(ibm, fout)
...
>>> exit()
Для использования маринованной модели:
>>> import dill as pickle
>>> from nltk.corpus import comtrans
>>> bitexts = comtrans.aligned_sents()[:100]
>>> with open('model1.pk', 'rb') as fin:
... ibm = pickle.load(fin)
...
>>> aligned_sent = ibm.align(bitexts[0])
>>> aligned_sent.words
['Wiederaufnahme', 'der', 'Sitzungsperiode']
Если вы попытаетесь засолить IBMModel1
объект, который является лямбда-функцией, вы получите в итоге это:
>>> import cPickle as pickle
>>> from nltk.corpus import comtrans
>>> from nltk.align import IBMModel1
>>> bitexts = comtrans.aligned_sents()[:100]
>>> ibm = IBMModel1(bitexts, 20)
>>> with open('model1.pk', 'wb') as fout:
... pickle.dump(ibm, fout)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/usr/lib/python2.7/copy_reg.py", line 70, in _reduce_ex
raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle function objects
(Примечание: приведенный выше фрагмент кода взят из NLTK версии 3.0.0)
В python3 с NLTK 3.0.0 вы также столкнетесь с той же проблемой, потому что IBMModel1 возвращает лямбда-функцию:
alvas@ubi:~$ python3
Python 3.4.0 (default, Apr 11 2014, 13:05:11)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> from nltk.corpus import comtrans
>>> from nltk.align import IBMModel1
>>> bitexts = comtrans.aligned_sents()[:100]
>>> ibm = IBMModel1(bitexts, 20)
>>> with open('mode1.pk', 'wb') as fout:
... pickle.dump(ibm, fout)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
_pickle.PicklingError: Can't pickle <function IBMModel1.train.<locals>.<lambda> at 0x7fa37cf9d620>: attribute lookup <lambda> on nltk.align.ibm1 failed'
>>> import dill
>>> with open('model1.pk', 'wb') as fout:
... dill.dump(ibm, fout)
...
>>> exit()
alvas@ubi:~$ python3
Python 3.4.0 (default, Apr 11 2014, 13:05:11)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> from nltk.corpus import comtrans
>>> with open('model1.pk', 'rb') as fin:
... ibm = dill.load(fin)
...
>>> bitexts = comtrans.aligned_sents()[:100]
>>> aligned_sent = ibm.aligned(bitexts[0])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'IBMModel1' object has no attribute 'aligned'
>>> aligned_sent = ibm.align(bitexts[0])
>>> aligned_sent.words
['Wiederaufnahme', 'der', 'Sitzungsperiode']
(Примечание: в python3 pickle
является cPickle
см. http://docs.pythonsprints.com/python3_porting/py-porting.html)
Вы обсуждаете сохранение модели выравнивателя, но ваш вопрос, кажется, больше касается сохранения выровненных выровненных фрагментов: "Было бы хорошо сделать выравнивания в пакете за один день и использовать эти выравнивания позже". Я собираюсь ответить на этот вопрос.
В среде nltk наилучший способ использовать корпусный ресурс, чтобы получить к нему доступ с помощью программы чтения корпуса. NLTK не поставляется с авторами корпусов, но формат, поддерживаемый NLTK AlignedCorpusReader
очень легко создать: (версия NLTK 3)
model = ibm(biverses, 20) # As in your question
out = open("folder/newalignedtext.txt", "w")
for pair in biverses:
asent = model.align(pair)
out.write(" ".join(asent.words)+"\n")
out.write(" ".join(asent.mots)+"\n")
out.write(str(asent.alignment)+"\n")
out.close()
Вот и все. Позже вы можете перезагрузить и использовать выровненные предложения точно так же, как comtrans
корпус:
from nltk.corpus.reader import AlignedCorpusReader
mycorpus = AlignedCorpusReader(r"folder", r".*\.txt")
biverses_reloaded = mycorpus.aligned_sents()
Как видите, вам не нужен сам объект выравнивания. Выровненные предложения можно загрузить с помощью программы чтения корпуса, а сам выравниватель довольно бесполезен, если только вы не хотите изучать встроенные вероятности.
Комментарий: я не уверен, что назвал бы объект выравнивателя "моделью". В NLTK 2 выравниватель не настроен для выравнивания нового текста - он даже не имеет align()
метод. В НЛТК 3 функция align()
может выровнять новый текст, но только если он используется в python 2; в Python 3 он нарушен, по-видимому, из-за ужесточения правил сравнения объектов разных типов. Если, тем не менее, вы хотите, чтобы можно было откорректировать и перезагрузить выравниватель, я буду рад добавить его к моему ответу; из того, что я видел, это можно сделать с ванилью cPickle
,
Если вы хотите, и это выглядит так, вы можете сохранить его в виде списка AlignedSent:
from nltk.align import IBMModel1 as IBM
from nltk.align import AlignedSent
import dill as pickle
biverses = [list of AlignedSent objects]
model = ibm(biverses, 20)
for sent in range(len(biverses)):
biverses[sent].alignment = model.align(biverses[sent]).alignment
После этого вы можете сохранить его с маринованным укропом:
with open('alignedtext.pk', 'wb') as arquive:
pickle.dump(biverses, arquive)
joblib также может сохранить обученную модель nltk, например:
from nltk.lm import MLE
import joblib
model = MLE(n=2)
model.fit(train_data, padded_sents)
# save model
with open(model_path, 'wb') as fout:
joblib.dump(model, fout)
#load model
joblib.load(model_path)