Spacy:DOC如何在被删除后继续存在和工作



来自文档:

doc是一个令牌对象的序列。访问句子并命名 实体,向Numpy阵列的出口注释,无损地序列化 压缩二进制字符串。DOC对象包含Tokenc的数组 结构。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?
  3. 的两倍以上?

好吧,您可以在此处找到代码:https://github.com/explosion/spacy/tree/master/master/master/spacy/tokens。它在凯森(Cython),所以有一些额外的概念,但是您仍然会发现它有用。

简短的答案是,SpanToken对象确实保存对Doc的引用,并且即使您删除doc变量,此引用也可以使Doc对象保持活力。这使您可以继续查询文档

但是,doc对其SpanToken对象没有任何引用。这些对象严格瞬态:每次编写doc[i]时,都会重新创建一个新的Token实例。查看doc.pyx中的__getitem__实现,以查看发生这种情况。

Spacy的早期版本确实缓存了Token对象,希望提高某些访问模式的效率。但是,这会在doc及其令牌之间创建一个参考周期,从而使参考计数弄乱。有一些方法可以解决这个问题(使用弱参考),但是净成本使得最终不值得 - 最好只做简单的事情,并每次创建一个新的Token对象。这也可以帮助人们编写几乎有效的代码 - 几乎是正确的类型是不正确的。

最新更新