CoreNLP Android: NER NullPointerException on some models

kcrjzv8t  于 2个月前  发布在  Android
关注(0)|答案(8)|浏览(30)

我(在某种程度上)成功地将CoreNLP(3.9.2)集成到了一个Android应用中。
以下的标注器配置运行得很好:

props.setProperty("annotators", "tokenize,ssplit,pos,lemma")

但是,当我添加了NER标注器后,我开始收到以下错误:

Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
        at edu.stanford.nlp.util.HashIndex.size(HashIndex.java:94)
        at edu.stanford.nlp.ie.crf.CRFClassifier.getCliqueTree(CRFClassifier.java:1499)
        at edu.stanford.nlp.ie.crf.CRFClassifier.getSequenceModel(CRFClassifier.java:1190)
        at edu.stanford.nlp.ie.crf.CRFClassifier.getSequenceModel(CRFClassifier.java:1186)
        at edu.stanford.nlp.ie.crf.CRFClassifier.classifyMaxEnt(CRFClassifier.java:1218)
        at edu.stanford.nlp.ie.crf.CRFClassifier.classify(CRFClassifier.java:1128)
        at edu.stanford.nlp.ie.AbstractSequenceClassifier.classifySentence(AbstractSequenceClassifier.java:299)
        at edu.stanford.nlp.ie.ClassifierCombiner.classify(ClassifierCombiner.java:476)
        at edu.stanford.nlp.ie.NERClassifierCombiner.classifyWithGlobalInformation(NERClassifierCombiner.java:269)
        at edu.stanford.nlp.ie.AbstractSequenceClassifier.classifySentenceWithGlobalInformation(AbstractSequenceClassifier.java:343)
        at edu.stanford.nlp.pipeline.NERCombinerAnnotator.doOneSentence(NERCombinerAnnotator.java:368)
        at edu.stanford.nlp.pipeline.SentenceAnnotator.annotate(SentenceAnnotator.java:102)
        at edu.stanford.nlp.pipeline.NERCombinerAnnotator.annotate(NERCombinerAnnotator.java:310)
        at edu.stanford.nlp.pipeline.AnnotationPipeline.annotate(AnnotationPipeline.java:76)
        at edu.stanford.nlp.pipeline.StanfordCoreNLP.annotate(StanfordCoreNLP.java:637)
        at edu.stanford.nlp.pipeline.StanfordCoreNLP.annotate(StanfordCoreNLP.java:629)

我使用的代码(Kotlin):

val props = Properties()
props.setProperty("annotators", "tokenize,ssplit,pos,lemma,ner")
pipeline = StanfordCoreNLP(props)
val document = CoreDocument("Joe Smith is from Seattle.")
pipeline.annotate(document)

这个错误与在this issue中描述的作者尝试使用解析器标注器的错误非常相似。

调试

我调试了堆栈跟踪,发现错误是由这一行(在classIndex.size())引起的:

return CRFCliqueTree.getCalibratedCliqueTree(data, labelIndices, classIndex.size(), 
  classIndex, flags.backgroundSymbol, getCliquePotentialFunctionForTest(), featureVal);

这意味着classIndex为空且没有正确初始化。
CRFClassifierclassIndex属性是在loadClassifier(ObjectInputStream ois, Properties props)方法中初始化的:

public void loadClassifier(ObjectInputStream ois, Properties props) {
    Object o = ois.readObject();
    [...]
    classIndex = (Index<String>) ois.readObject();

我发现传递的ObjectInputStream实际上是从模型路径上的文件创建的流,该路径是在NERCombinerAnnotator构造函数中确定的:

public NERCombinerAnnotator(Properties properties) throws IOException {
    List<String> models = new ArrayList<>();
    String modelNames = properties.getProperty("ner.model");
    if (modelNames == null) {
      modelNames = DefaultPaths.DEFAULT_NER_THREECLASS_MODEL + ',' + DefaultPaths.DEFAULT_NER_MUC_MODEL + ',' + DefaultPaths.DEFAULT_NER_CONLL_MODEL;
    }
    [...]
    String[] loadPaths = models.toArray(new String[models.size()]);

这些loadPathsloadClassifiers方法中迭代:

private void loadClassifiers(Properties props, List<String> paths) throws IOException {
    baseClassifiers = new ArrayList<>();
    [...]
    for(String path: paths) {
      AbstractSequenceClassifier<IN> cls = loadClassifierFromPath(props, path);
      baseClassifiers.add(cls);
      [...]
    }

通过在这个方法中添加断点,我发现for循环中第一次迭代的第一个模型路径(DefaultPaths.DEFAULT_NER_THREECLASS_MODEL)加载没有问题,并且classIndex属性被正确设置:

但是,在第二次迭代时,从DefaultPaths.DEFAULT_NER_MUC_MODEL加载失败:

解决方法

我目前的解决方法是将ner模型仅设置为三类和conll模型:

props.setProperty("ner.model", DefaultPaths.DEFAULT_NER_THREECLASS_MODEL + "," + DefaultPaths.DEFAULT_NER_CONLL_MODEL)

但实际上,如果缺少MUC模型,我不知道会产生什么后果。

解释

我的理论是MUC模型特别大,因此无法将其加载到移动设备的内存中。这是真的吗?特别是这个模型有多大?
但是,当我监控应用程序的内存消耗时,我没有发现任何关键问题,应用程序在崩溃之前始终保持在512 MB以下。

tgabmvqs

tgabmvqs1#

MUC的文件大小比all或conll小,但它有7个类别,所以在加载时可能会增加内存占用。如果你只加载MUC模型会发生什么?也许在低内存环境下加载该模型时会有一些东西默默失败......
在2019年10月27日的周日,erksch ***@***.***用户在Stack Overflow上发帖称:

我(在某种程度上)成功地将CoreNLP集成到了一个Android应用中。以下注解器配置运行得很好:props.setProperty("annotators", "tokenize,ssplit,pos,lemma")但是,当我添加了命名实体识别(NER)注解器后,我开始收到以下错误:

Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference at edu.stanford.nlp.util.HashIndex.size(HashIndex.java:94) at edu.stanford.nlp.ie.crf.CRFClassifier.getCliqueTree(CRFClassifier.java:1499) at edu.stanford.nlp.ie.crf.CRFClassifier.getSequenceModel(CRFClassifier.java:1190) at edu.stanford.nlp.ie.crf.CRFClassifier.getSequenceModel(CRFClassifier.java:1186) at edu.stanford.nlp.ie.crf.CRFClassifier.classifyMaxEnt(CRFClassifier.java:1218) at edu.stanford.nlp.ie.crf.CRFClassifier.classify(CRFClassifier.java:1128) at edu.stanford.nlp.ie.AbstractSequenceClassifier.classifySentence(AbstractSequenceClassifier.java:299) at edu.stanford.nlp.ie.ClassifierCombiner.classify(ClassifierCombiner.java:476) at edu.stanford.nlp.ie.NERClassifierCombiner.classifyWithGlobalInformation(NERClassifierCombiner.java:269) at edu.stanford.nlp.ie.AbstractSequenceClassifier.classifySentenceWithGlobalInformation(AbstractSequenceClassifier.java:343) at edu.stanford.nlp.pipeline.NERCombinerAnnotator.doOneSentence(NERCombinerAnnotator.java:368) at edu.stanford.nlp.pipeline.SentenceAnnotator.annotate(SentenceAnnotator.java:102) at edu.stanford.nlp.pipeline.NERCombinerAnnotator.annotate(NERCombinerAnnotator.java:310) at edu.stanford.nlp.pipeline.AnnotationPipeline.annotate(AnnotationPipeline.java:76) at edu.stanford.nlp.pipeline.StanfordCoreNLP(StanfordCoreNLP).annotate(StanfordCoreNLP) at edu.stanford
edu/stanfordnlp/core/api/annotator/ner/NERModel$Builder$.newInstance(NERModel$Builder$.java:55) at edu

e0uiprwp

e0uiprwp2#

在我的Linux系统上,似乎all3模型需要的内存比muc7模型更多。希望当muc模型单独运行时,能够正确加载,这样的话问题很可能是内存不足。我尝试了各种低于预期的内存数量,但无法触发这个特定的错误,尽管它总是出现GC或OOM...。
MUC比所有或conll在文件大小方面都较小,但它有7个类别,因此在加载时可能会增加内存占用。如果只加载MUC模型会发生什么?也许在低内存环境中加载该模型时会有一些东西默默失败。

dgjrabp2

dgjrabp23#

当仅应用MUC时,我得到的结果与上述相同。
调试基本分类器数组时,它看起来像这样:

正如您所见,出现了与上述相同的错误。
如果模型较小,那么可能不是由于内存问题...
MUC和THREECLASS、CONLL之间有什么根本性的不同吗?
顺便说一下,我使用了maven仓库中的最新模型。
PS:
我现在使用自己的NER模型,一切顺利,没有任何问题!
非常感谢您这个出色的库,使我能够在离线环境中完成Android的NLP和NER任务。

frebpwbc

frebpwbc4#

这是一个随机问题。你确定在这个时候初始化已经完成了吗?我发现在某些情况下,Java在内存刚刚不足时,会花费很长时间尝试进行垃圾回收模型加载过程。我不知道为什么在没有先得到GC或OOM异常的情况下,你会在这里得到一个空指针,但也许问题是它在你试图查询它的时候还没有放弃并死亡。坦率地说,考虑到我们没有人从事Android开发,我们能够诊断它的几率相当低。正如我在解析器问题中所说的,改变本地的内存要求似乎并不能解决这个特定的bug。我只是总是得到一个GC或OOM异常。如果无法在本地重现这个问题,我就不确定我们该如何解决它。实际上,你是许可证持有人吗?我不是律师,但听起来你正在开发一个想要重新分发corenlp的应用,如果那是专有或付费应用,那可能不符合我们的许可限制。https://stanfordnlp.github.io/CoreNLP/#license 如果你是一个许可证持有人,那可能会给我们一些预算来投入时间和精力来调试android特定的问题。提示,提示......
2019年10月28日上午9点45分,erksch ***@***.***>写道:当我仅应用MUC时,我得到的错误与上面相同。调试baseClassifier数组时,它看起来像这样:[image: Bildschirmfoto vom 2019-10-28 17-41-52] < https://user-images.githubusercontent.com/19290349/67698229-45a97200-f9aa-11e9-8fca-4d0e001abfde.png > 如您所见,错误与上面相同。如果模型较小,那么可能不是由于内存问题......MUC和THREECLASS、CONLL之间有什么根本性的不同吗?PS:我现在仍然使用自己的NER模型,没有任何问题!非常感谢您这个精彩的库,使我能够在离线状态下为Android完成NLP和NER。——你收到这封邮件是因为你评论了。直接回复此电子邮件,查看GitHub上的<#961?email_source=notifications&email_token=AA2AYWII2JZONEEDWKQDGMDQQ4JLXA5CNFSM4JFTZIOKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECNSIFY#issuecomment-547038231>或者取消订阅< https://github.com/notifications/unsubscribe-auth/AA2AYWOR4NTYO3JZLFPLSULQQ4JLXANCNFSM4JFTZIOA >。

mkshixfv

mkshixfv5#

感谢关于许可证的提示。我还不是一个持证人(但),一旦一切按预期工作,我会联系的。
但是请记住,由于要求的最低SDK版本为26(占设备总数的8%),在B2C Android应用中使用CoreNLP并不是一个真正的选择。也许如果这个对更多设备有效,你会获得更多的软件许可提示提示;)

bsxbgnwa

bsxbgnwa6#

Java 8在这个时候已经有5.5年的历史了,它有很多功能,真的让编程变得更容易。考虑到我们通常为更新、更强大的机器开发,如果限制自己使用Java版本,将会非常有限。我理解不想需要网络连接来使用模型的想法,但如果你只考虑8%的设备可以本地运行模型,你可能需要考虑这个问题。

话虽如此,我真的不明白这个特定的错误是如何发生的。有没有调查过初始化是否完成?就像我提到的,没有错误显示出来,而所有的东西都像这样为空,这没有什么意义......

2019年10月29日星期二上午1:23,erksch***@***.***>写道:@AngledLuffa < https://github.com/AngledLuffa > 感谢关于许可证的提示。我还没有获得许可(但),一旦一切按预期工作,我会联系的。但是请记住,由于要求的最低SDK版本为26(占8%的设备),因此在B2C Android应用中使用CoreNLP并不是一个好选择。也许如果这个对更多设备有效,你会获得更多的软件许可。哈哈!——你收到这封邮件是因为有人提到了你。直接回复这封邮件,查看GitHub上的相关信息<#961?email_source=notifications&email_token=AA2AYWPVAYKUU7FNXF43OP3QQ7XH5A5CNFSM4JFTZIOKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOECPUEFA#issuecomment-547308052>,或者取消订阅< https://github.com/notifications/unsubscribe-auth/AA2AYWPNJZRAECLRORW7HH3QQ7XH5ANCNFSM4JFTZIOA >。

jc3wubiy

jc3wubiy7#

恭喜你成为我4+年来第一个在Android手机上本地运行NER的人!

bksxznpy

bksxznpy8#

作为更新,CoreNLP 4.0.0在命名实体识别(NER)方面的内存使用量比之前的版本更少,自4.0.0发布以来,主分支上甚至有更多的优化。你是否有兴趣重试MUC模型?

相关问题