Подтвердить что ты не робот

Как сохранить модели выравнивания Python NLTK для последующего использования?

В Python я использую NLTK 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) повторно использовать ее позже?

4b9b3361

Ответ 1

Непосредственный ответ - рассортировать его, см. https://wiki.python.org/moin/UsingPickle

Но поскольку IBMModel1 возвращает лямбда-функцию, невозможно определить ее по умолчанию pickle/cPickle (см. https://github.com/nltk/nltk/blob/develop/nltk/align/ibm1.py#L74 и https://github.com/nltk/nltk/blob/develop/nltk/align/ibm1.py#L104)

Итак, мы будем использовать 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 возвращает функцию лямбда:

[email protected]:~$ 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()

[email protected]:~$ 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)

Ответ 2

Вы обсуждаете сохранение модели выравнивателя, но ваш вопрос, похоже, больше связан с сохранением выровненных битеков, которые вы выровняли: "Было бы хорошо сделать выравнивание в пакетном режиме в один день и использовать эти выравнивания позже". Я собираюсь ответить на этот вопрос.

В среде 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 corpus:

from nltk.corpus.reader import AlignedCorpusReader

mycorpus = AlignedCorpusReader(r"folder", r".*\.txt")
biverses_reloaded = mycorpus.aligned_sents()

Как вы можете видеть, вам не нужен сам объект выравнивателя. Выровненные предложения могут быть загружены с помощью считывателя корпусов, и сам выравниватель довольно бесполезен, если вы не хотите изучить встроенные вероятности.

Комментарий: Я не уверен, что я бы назвал объект-выравниватель "моделью". В NLTK 2 выравниватель не настроен для выравнивания нового текста - он даже не имеет метода align(). В NLTK 3 функция align() может выровнять новый текст, но , только если используется с python 2; в Python 3, она сломана, по-видимому, из-за ужесточенных правил сравнения объектов разных типов. Если, тем не менее, вы хотите иметь возможность рассортировать и перезагружать выравниватель, я буду рад добавить его к моему ответу; из того, что я видел, это можно сделать с помощью ванили cPickle.

Ответ 3

если вы хотите, и он выглядит так, вы можете сохранить его как список в формате 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)