如何在 Python 中加速 Stanford NLP?
How to speedup Stanford NLP in Python?
import numpy as np
from nltk.tag import StanfordNERTagger
from nltk.tokenize import word_tokenize
#english.all.3class.distsim.crf.ser.gz
st = StanfordNERTagger('/media/sf_codebase/modules/stanford-ner-2018-10-16/classifiers/english.all.3class.distsim.crf.ser.gz',
'/media/sf_codebase/modules/stanford-ner-2018-10-16/stanford-ner.jar',
encoding='utf-8')
初始化上面的代码后,Stanford NLP 下面的代码需要 10 秒来标记文本,如下所示。如何加速?
%%time
text="My name is John Doe"
tokenized_text = word_tokenize(text)
classified_text = st.tag(tokenized_text)
print (classified_text)
输出
[('My', 'O'), ('name', 'O'), ('is', 'O'), ('John', 'PERSON'), ('Doe', 'PERSON')]
CPU times: user 4 ms, sys: 20 ms, total: 24 ms
Wall time: 10.9 s
找到答案。
在 Stanford NLP 解压文件夹中后台启动 Stanford NLP 服务器。
java -Djava.ext.dirs=./lib -cp stanford-ner.jar edu.stanford.nlp.ie.NERServer -port 9199 -loadClassifier ./classifiers/english.all.3class.distsim.crf.ser.gz
然后使用 sner 库在 Python 中启动 Stanford NLP Server 标注器。
from sner import Ner
tagger = Ner(host='localhost',port=9199)
然后 运行 标注器。
%%time
classified_text=tagger.get_entities(text)
print (classified_text)
输出:
[('My', 'O'), ('name', 'O'), ('is', 'O'), ('John', 'PERSON'), ('Doe', 'PERSON')]
CPU times: user 4 ms, sys: 0 ns, total: 4 ms
Wall time: 18.2 ms
在计时方面的性能提高了近 300 倍!哇!
NLTK 中的另一个解决方案是 不使用 旧的 nltk.tag.StanfordNERTagger
而是使用更新的 nltk.parse.CoreNLPParser
。参见,例如,https://github.com/nltk/nltk/wiki/Stanford-CoreNLP-API-in-NLTK .
更一般地说,获得良好性能的秘诀确实是在 Java 端使用服务器,您可以重复调用它,而不必为每个处理的句子启动新的子进程。如果您只需要 NER,您可以使用 NERServer
,或者对所有 CoreNLP 功能使用 StanfordCoreNLPServer
。它有许多 Python 接口,请参阅:https://stanfordnlp.github.io/CoreNLP/other-languages.html#python
尝试了几个选项后,我喜欢Stanza。它由 Stanford 开发,实现起来非常简单,我不必自己弄清楚如何正确启动服务器,它极大地提高了我的程序速度。它实现了 18 种不同的对象分类。
我通过 link provided in Christopher Manning's answer.
找到了 Stanza
下载:
pip install stanza
然后在 Python:
import stanza
stanza.download('en') # download English model
nlp = stanza.Pipeline('en') # initialize English neural pipeline
doc = nlp("My name is John Doe.") # run annotation over a sentence or multiple sentences
如果你只想要一个特定的工具(NER),你可以用 processors
指定为:
nlp = stanza.Pipeline('en',processors='tokenize,ner')
对于类似于 OP 生成的输出:
classified_text = [(token.text,token.ner) for i, sentence in enumerate(doc.sentences) for token in sentence.tokens]
print(classified_text)
[('My', 'O'), ('name', 'O'), ('is', 'O'), ('John', 'B-PERSON'), ('Doe', 'E-PERSON')]
但要生成仅包含可识别实体的单词的列表:
classified_text = [(ent.text,ent.type) for ent in doc.ents]
[('John Doe', 'PERSON')]
它产生了一些我非常喜欢的特性:
- 它不是将每个单词归类为一个单独的人实体,而是将 John Doe 合并为一个 'PERSON' 对象。
- 如果您确实需要每个单独的词,您可以提取这些词并识别它是对象的哪一部分('B' 表示对象中的第一个词,'I' 表示中间词, 'E' 对象中的最后一个单词)
import numpy as np
from nltk.tag import StanfordNERTagger
from nltk.tokenize import word_tokenize
#english.all.3class.distsim.crf.ser.gz
st = StanfordNERTagger('/media/sf_codebase/modules/stanford-ner-2018-10-16/classifiers/english.all.3class.distsim.crf.ser.gz',
'/media/sf_codebase/modules/stanford-ner-2018-10-16/stanford-ner.jar',
encoding='utf-8')
初始化上面的代码后,Stanford NLP 下面的代码需要 10 秒来标记文本,如下所示。如何加速?
%%time
text="My name is John Doe"
tokenized_text = word_tokenize(text)
classified_text = st.tag(tokenized_text)
print (classified_text)
输出
[('My', 'O'), ('name', 'O'), ('is', 'O'), ('John', 'PERSON'), ('Doe', 'PERSON')]
CPU times: user 4 ms, sys: 20 ms, total: 24 ms
Wall time: 10.9 s
找到答案。
在 Stanford NLP 解压文件夹中后台启动 Stanford NLP 服务器。
java -Djava.ext.dirs=./lib -cp stanford-ner.jar edu.stanford.nlp.ie.NERServer -port 9199 -loadClassifier ./classifiers/english.all.3class.distsim.crf.ser.gz
然后使用 sner 库在 Python 中启动 Stanford NLP Server 标注器。
from sner import Ner
tagger = Ner(host='localhost',port=9199)
然后 运行 标注器。
%%time
classified_text=tagger.get_entities(text)
print (classified_text)
输出:
[('My', 'O'), ('name', 'O'), ('is', 'O'), ('John', 'PERSON'), ('Doe', 'PERSON')]
CPU times: user 4 ms, sys: 0 ns, total: 4 ms
Wall time: 18.2 ms
在计时方面的性能提高了近 300 倍!哇!
NLTK 中的另一个解决方案是 不使用 旧的 nltk.tag.StanfordNERTagger
而是使用更新的 nltk.parse.CoreNLPParser
。参见,例如,https://github.com/nltk/nltk/wiki/Stanford-CoreNLP-API-in-NLTK .
更一般地说,获得良好性能的秘诀确实是在 Java 端使用服务器,您可以重复调用它,而不必为每个处理的句子启动新的子进程。如果您只需要 NER,您可以使用 NERServer
,或者对所有 CoreNLP 功能使用 StanfordCoreNLPServer
。它有许多 Python 接口,请参阅:https://stanfordnlp.github.io/CoreNLP/other-languages.html#python
尝试了几个选项后,我喜欢Stanza。它由 Stanford 开发,实现起来非常简单,我不必自己弄清楚如何正确启动服务器,它极大地提高了我的程序速度。它实现了 18 种不同的对象分类。
我通过 link provided in Christopher Manning's answer.
找到了 Stanza下载:
pip install stanza
然后在 Python:
import stanza
stanza.download('en') # download English model
nlp = stanza.Pipeline('en') # initialize English neural pipeline
doc = nlp("My name is John Doe.") # run annotation over a sentence or multiple sentences
如果你只想要一个特定的工具(NER),你可以用 processors
指定为:
nlp = stanza.Pipeline('en',processors='tokenize,ner')
对于类似于 OP 生成的输出:
classified_text = [(token.text,token.ner) for i, sentence in enumerate(doc.sentences) for token in sentence.tokens]
print(classified_text)
[('My', 'O'), ('name', 'O'), ('is', 'O'), ('John', 'B-PERSON'), ('Doe', 'E-PERSON')]
但要生成仅包含可识别实体的单词的列表:
classified_text = [(ent.text,ent.type) for ent in doc.ents]
[('John Doe', 'PERSON')]
它产生了一些我非常喜欢的特性:
- 它不是将每个单词归类为一个单独的人实体,而是将 John Doe 合并为一个 'PERSON' 对象。
- 如果您确实需要每个单独的词,您可以提取这些词并识别它是对象的哪一部分('B' 表示对象中的第一个词,'I' 表示中间词, 'E' 对象中的最后一个单词)