如何解决合并不同spacy.Language结果时的Vocab不匹配错误?
解决spaCy中合并不同Language实例Doc的Vocab不匹配问题
问题场景与报错
在处理邮件等场景时,不同字段需要用不同的实体识别规则(比如地址栏数字识别为邮编,页脚数字识别为电话),因此会创建多个spacy.Language实例分别处理,之后合并处理后的Doc对象时,触发如下错误:
ValueError('[E999] Unable to merge the Doc objects because they do not all share the same
Vocab.')
示例代码:
import spacy from spacy.tokens import Doc nlp_1 = spacy.blank("en") ruler = nlp_1.add_pipe("entity_ruler") ruler.add_patterns([{"label": "ORG", "pattern": "Apple"}, ]) doc_1 = nlp_1('Apple') nlp_2 = spacy.blank("en") ruler = nlp_2.add_pipe("entity_ruler") ruler.add_patterns([{"label": "PER", "pattern": "Peter"}, ]) doc_2 = nlp_2('Peter') print(Doc.from_docs([doc_1, doc_2])) # ValueError: [E999] Unable to merge the Doc objects because they do not all share the same `Vocab`.
解决方法
核心是让多个spacy.Language实例共享同一个Vocab对象,以下是两种常用实现方式:
1. 复用第一个nlp实例的Vocab创建第二个实例
直接将第一个nlp对象的vocab作为第二个nlp实例的初始化参数:
import spacy from spacy.tokens import Doc # 创建第一个nlp实例,自带默认Vocab nlp_1 = spacy.blank("en") ruler = nlp_1.add_pipe("entity_ruler") ruler.add_patterns([{"label": "ORG", "pattern": "Apple"}, ]) doc_1 = nlp_1('Apple') # 复用nlp_1的Vocab创建nlp_2 nlp_2 = spacy.blank("en", vocab=nlp_1.vocab) ruler = nlp_2.add_pipe("entity_ruler") ruler.add_patterns([{"label": "PER", "pattern": "Peter"}, ]) doc_2 = nlp_2('Peter') # 正常合并Doc merged_doc = Doc.from_docs([doc_1, doc_2]) print(merged_doc.text) # 输出: ApplePeter print([(ent.text, ent.label_) for ent in merged_doc.ents]) # 输出: [('Apple', 'ORG'), ('Peter', 'PER')]
2. 先创建独立Vocab,再传递给所有nlp实例
如果需要提前配置Vocab(比如自定义词向量映射),可以先单独创建Vocab对象,再传给每个nlp实例:
import spacy from spacy.tokens import Doc, Vocab # 创建共享的Vocab对象 shared_vocab = Vocab() # 两个nlp实例均使用该共享Vocab nlp_1 = spacy.blank("en", vocab=shared_vocab) ruler = nlp_1.add_pipe("entity_ruler") ruler.add_patterns([{"label": "ORG", "pattern": "Apple"}, ]) doc_1 = nlp_1('Apple') nlp_2 = spacy.blank("en", vocab=shared_vocab) ruler = nlp_2.add_pipe("entity_ruler") ruler.add_patterns([{"label": "PER", "pattern": "Peter"}, ]) doc_2 = nlp_2('Peter') # 合并成功 merged_doc = Doc.from_docs([doc_1, doc_2]) print(merged_doc.text) print([(ent.text, ent.label_) for ent in merged_doc.ents])
原理说明
spaCy的Vocab是核心词汇管理对象,负责维护字符串与哈希值的映射、词向量等数据。只有当Doc对象共享同一个Vocab时,内部的哈希映射规则才一致,才能被安全合并。不同nlp实例默认会创建独立的Vocab,这就是触发报错的根本原因。
内容的提问来源于stack exchange,提问作者Andreas
相关产品推荐
相关产品推荐

