SpaCy: Как Док продолжает существовать и работать после удаления? - PullRequest
0 голосов
/ 09 марта 2019

Из документации :

Документ - это последовательность объектов токена. Доступ к предложениям и именам объекты, экспорт аннотаций в массивы, сериализация без потерь в сжатые двоичные строки. Объект Doc содержит массив TokenC Структуры. Объекты Token и Span уровня Python являются представлениями этого массив, т.е. они сами не владеют данными.

Это имеет смысл, но мне любопытно узнать, как это работает именно под капотом, тем более что, как я покажу ниже, можно удалить объект Doc (или, по крайней мере, переменную, указывающую на него) и продолжает работать.

import spacy
nlp = spacy.load('en_core_web_sm')
from sys import getsizeof

doc = nlp('King Henry VIII married six times.')
print(doc)
print(getsizeof(doc))

token = doc[0]
print(token)
print(getsizeof(token))

span = doc[:3]
del doc
span.merge() # This updates the vestigial doc despite deletion.

print(token)
print(getsizeof(token)) # Same size as before, being just a pointer.
print(token.doc) # Doc can be retrieved.
print(getsizeof(token.doc))

Выход:

King Henry VIII married six times.
184
King
80
King Henry VIII
80
King Henry VIII married six times.
184

Учитывая мои элементарные знания Python, мне интересно знать:

  1. Где и как объект Doc хранится в памяти именно для того, чтобы вышеуказанное работало.
  2. Если переменная token может вызывать этот объект со всеми его функциональными возможностями в 80 байтов, почему переменная doc должна быть более чем вдвое больше размера при 184?

1 Ответ

2 голосов
/ 09 марта 2019

Ну, вы можете найти код здесь: https://github.com/explosion/spaCy/tree/master/spacy/tokens.Это в Cython, поэтому есть некоторые дополнительные понятия, но вы все равно можете найти их полезными.

Краткий ответ: объекты Span и Token содержат ссылку на Doc, иэта ссылка поддерживает объект Doc даже после удаления переменной doc.Это позволяет вам продолжать запрашивать документ.

Однако у doc нет ссылок на его объекты Span или Token.Эти объекты строго временны: новый экземпляр Token создается заново каждый раз, когда вы пишете doc[i].Посмотрите на реализацию __getitem__ в doc.pyx, чтобы увидеть, как это происходит.

Ранние версии spaCy кэшировали объекты Token, надеясь повысить эффективность некоторых шаблонов доступа.Однако это создает цикл ссылок между doc и его токенами, что приводит к неправильному счету ссылок.Есть способы обойти это (используя слабые ссылки), но чистая стоимость в итоге не стоит того - лучше просто выполнить простую вещь и каждый раз создавать новый объект Token.Это также помогает людям при написании кода, который почти работает - почти правильный часто является худшим типом неправильного.

...