hanlp2.0版本如何使用其他的NER/分词模型?

如题。首先先赞一下hanlp工具是如此好用而且易上手!
我仔细拜读了何博士hanlp2.0版本的GitHub的说明文档,了解到2.0版本的hanlp有诸多优势,但与此同时这一版仍在开发当中;我现在使用hanlp2.0版本的工具进行分词和NER,因为2.0版本提供的中文NER模型只有2个,分别是基于bert和albert的,但由于我现在数据量太大,使用bert model太耗时,所以想换轻量级的模型,所以请问hanlp2.0版本可以使用pyhanlp1.x里面相关的分词/NER模型吗?如果可以,请问怎么用呢?谢谢!

  1. albert就是 a light bert,也就是轻量级的bert
  2. 可以,同时安装两个版本,用pipeline组合。

多谢何博士的回复。是这样的,我现在用的模型就是albert,且服务器上有gpu,我每次将120条左右的长度为125个中文字符的文本输入进行ner,但耗时还是过长,且通过nvidia-smi命令,观察到GPU使用率和显存占用都处于较低水平(显存占用率418M/32502M;GPU-util为0%),而且不论我怎样增减一次性传入ner接口的文本数量,似乎各个GPU的使用率和显存占用率都很稳定,总处于一个较低水平。所以我想了解一下如何可以更高效地利用GPU资源呢?自己写多进程实现ner的CPU层面上的并行可以提升GPU使用率吗?
此外我还想问一下和主楼有关的问题——pyhanlp中的模型是不是就无法使用GPU加速计算了?多谢何博士!

再问个小白级别的问题哈。我在运行环境没什么变化、每次输入数据总量都差不多的情况下,使用ner接口借助GPU并行运算,为什么每次耗时都越来越长呢?下图为每次计算时长,单位秒
28

因为batch size是固定的,大约32。你可以试试往预测接口传batch_size=128

在你的GPU利用率如此之低的情况下,可能可以。但与其如此,不如增大batch_size。

不看你的调用是不知道发生了什么,你可以在GitHub贴一下代码。HanLP本身的设计是线程安全,预测时不产生全局变量。

单次预测44秒是绝对不可能的,32一个批次,你120个句子就是4个批,每个批次耗时10秒也不可能。我怀疑你的GPU没有起作用,建议检查一下驱动,cuda,cudnn等等。hanlp.com 的在线预测用的就是美国服务器上的albert,包括从北京到美国的网络延时,基本看不出来延迟。

你可以查阅该模型的性能:

$ cat ~/.hanlp/ner/ner_albert_base_msra_20200104_183033/test.log 
20-01-04 17:56:34 INFO Evaluation results for test.tsv - loss: 1.5964 - f1: 0.9271 - speed: 314.01 sample/sec 
processed 177342 tokens with 5268 phrases; found: 5322 phrases; correct: 4909.
accuracy:  99.14%; precision:  92.24%; recall:  93.19%; FB1:  92.71
               NR: precision:  94.31%; recall:  95.44%; FB1:  94.87  1353
               NS: precision:  94.26%; recall:  93.43%; FB1:  93.84  2612
               NT: precision:  86.29%; recall:  90.35%; FB1:  88.28  1357

排除模型加载,首个batch热身,正常速度每秒314个句子。

想要达到这个速度,应当一次性往预测接口传入尽量多的句子。

1 Like

何博士说的这么清楚,真是太感谢了,经排查的确是GPU没用上,有关batch_size=128的提示也很有用,再次感谢!

何博士,我还想再问您一个问题:我配置好了GPU,而且确认GPU也都可用之后,我将我的程序用GPU跑了一下。我一共有4块GPU可用,但好像接口默认只使用一个,而且一直都使用编号为0的第一块。所以我该用什么方法指定代码运行的时候使用多块GPU、以及到底使用哪块GPU呢?多谢!

首先export HANLP_GREEDY_GPU=1,然后按照TensorFlow的文档自己把不同的模型放到不同的显卡上去:

https://www.tensorflow.org/guide/gpu


pipeline = hanlp.pipeline()
.append(self.tokenizer, output_key=‘tokens’)
.append(self.tagger, output_key=‘part_of_speech_tags’)
.append(self.syntactic_parser, input_key=(‘tokens’, ‘part_of_speech_tags’), output_key=‘syntactic_dependencies’)
.append(self.semantic_parser, input_key=(‘tokens’, ‘part_of_speech_tags’), output_key=‘semantic_dependencies’)
何博士,我想问个问题,我用上面pipeline进行分析时,batch>=32时就会很慢,比较卡,我设置的batch比32小,但时间长了就会出现上面的错误,(core dumped),并且在还没崩溃之前,GPU显存占用一直很高,利用率却不高,在这里想请教一下

我最近一直在测NER接口,你看上面我的回复也看得出我之前也遇到了这种问题,因为我GPU显存足够用,所以在单纯进行ner测试的时候,直接把batch_size设置到512,每次往接口里放入500+句子进行ner测试,发现也是你这个问题,而且ner接口的速度上线大概为2200(中文)字符/sec。然后我对ner的predict部分相关源码进行了耗时分析,发现造成这个速度瓶颈的关键原因在于Y_to_output()函数,这个函数主要封装了将index转为ner序列标注的special_token的任务,该部分显然是后处理部分是CPU的活儿,随着你的任务量越来越大,这函数的耗时就越来越长,最终成为你耗时的主要来源。所以我自己写了个predict_for_ner(),把作者一个个batch做GPU计算(predict_batch()函数)的模式改了一下,把后处理这部分从这个函数里提取出来,在GPU计算完毕后统一做多进程CPU计算,当前我服务器单GPU测速,速度上线约为5100中文字符/sec。
当然,我这么改也很白痴,毕竟如果数据量太大GPU计算耗时较长,那么这段时间CPU完全是待命状态,最好的似乎应该是几个batch进行一次CPU后处理,但比较麻烦我就暂时没改。我还打算把这个问题,以及hanlp2.0按GitHub用例载入用户自定义词典后(使用pipeline)就没法并行的情况在GitHub一起提一下。你可以看看你“GPU显存占用一直很高,利用率却不高”的问题是不是因为,只有tokenize()在用GPU算,而你pipeline其他任务都用的CPU,而主要耗时都在CPU导致的。

1 Like

GPU显存占用一直很高,利用率却不高,应该是中间模型一些操作在CPU上执行,关键是运行时间长了,batch处理会突然变慢,几个小时过后就会出现CPU-GPU memcpy failed, Aborted(core dumped),就会崩掉,显卡占用几乎快满了

从这些现象无法得到任何结论,建议像 @illusions 一样探索问题。

n


不好意思再打扰下,问的问题可能比较小白。通过内存占用分析,上面是连续的3个batch传入数据进行分析,得到输出结果时,占用内存一直在增加,也就是随着数据的输入,不断的分析时,内存一直在上升。不知道是不是这方面的原因?还有个问题想问下,每个batch里面的句子有长有短,当有非常长的句子时,在处理batch里面的长文本时,输入模型时你有什么操作吗

哈哈,我也想问各个模型对于长文本的处理方式是什么,或者允许的最大单条文本长度是多少?
知道的话方便自己做预处理/后处理

可以看模型的config.json文件。