SpaCy:Doc在删除后如何继续存在和工作?

时间:2019-03-09 00:20:19

标签: python spacy

documentation

  

文档是一系列令牌对象。访问句子并命名   实体,将注释导出到numpy数组,无损地序列化为   压缩的二进制字符串。 Doc对象包含一个TokenC数组   结构。 Python级的Token和Span对象是此视图   数组,即它们本身并不拥有数据。

这是有道理的,但我很想知道它到底是如何工作的,特别是因为,正如我在下面显示的那样,一个人可以删除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 个答案:

答案 0 :(得分:2)

好吧,您可以在这里找到代码:https://github.com/explosion/spaCy/tree/master/spacy/tokens。它在Cython中,因此还有一些其他概念,但是您可能仍然会发现它很有用。

简短的回答是SpanToken对象确实保存了对Doc的引用,即使删除了您的{ Doc变量。这样一来,您就可以继续查询文档。

然而,doc没有对其docSpan对象的引用。这些对象严格来说是瞬态的:每次编写Token时都会重新创建一个新的Token实例。看看doc[i]中的__getitem__实现,看看会发生这种情况。

spaCy的早期版本确实缓存了doc.pyx对象,希望提高某些访问模式的效率。但是,这会在Token及其令牌之间创建一个参考周期,这会破坏参考计数。有多种方法可以解决此问题(使用弱引用),但最终的净成本使其不值得-只做简单的事情,并每次创建一个新的doc对象,效果更好。这也有助于人们编写几乎有效的代码---几乎正确通常是最糟糕的错误类型。