Elastic 进阶教程:在Elasticsearch中部署中文NER模型

2022-08-05 11:22:01 浏览数 (2)

概述

自然语言处理(NLP)是指我们可以使用软件来理解口语或书面文本中的自然语言的方式。

传统上,NLP 是使用语言规则、字典、正则表达式和机器学习来执行特定任务的,例如自动分类或文本摘要。然而,近年来,深度学习技术已经占据了 NLP 领域的大部分领域。深度学习利用了大规模数据集的可用性、廉价的计算以及在较少人工参与的情况下进行大规模学习的技术。使用transformer架构的预训练语言模型特别成功。例如,BERT 是谷歌于 2018 年发布的一种预训练语言模型。从那时起,它就成为当今大多数现代 NLP 技术的灵感来源。Elastic Stack 机器学习功能围绕 BERT 和 Transformer 模型构建。这些功能支持 BERT 的标记化方案(称为 WordPiece)和符合标准 BERT 模型接口的转换器模型。

为了合并 Transformer 模型并进行预测,Elasticsearch 使用了 libtorch,它是 PyTorch 的底层原生库。经过训练的模型必须采用 TorchScript 表示,才能与 Elastic Stack 机器学习功能一起使用。

Elastic NLP工作方式

因此,我们通常需要先将模型上传到Elasticsearch当中

然后再将模型部署到机器学习的节点上:

然后,将其作为输入输出的网关,对数据进行额外处理:

才能够让其与Elasticsearch的工作模式进行无缝结合。

我们可以通过Eland和 Kibana 提供的工具,快速完成以上步骤,具体步骤简单描述为:

  1. 选择一个训练好的模型
  2. 导入训练好的模型和词汇
  3. 在集群中部署模型
  4. 试运行

在本文中,我们将主要展示,如何将一个中文的NER模型部署到elasticsearch集群当中

Elastic机器学习模块对NER模型的限制

目前,Elastic Stack支持对以下 NLP 操作:

  • 提取信息
  • 分类文本
  • 搜索和比较文本

而NER(命名实体识别)属于信息提取这一分类,填充蒙版与问答也属于这一范畴。

命名实体识别 (NER) 任务可以识别和分类非结构化文本中的某些实体(通常是专有名词)。命名实体通常是指现实世界中的对象,例如人(PERSON)、位置(LOC)、组织(ORG)和其他(MISC)由专有名称一致引用的杂项实体。

NER 是识别关键信息、添加结构和深入了解您的内容的有用工具。它在处理和探索大量文本(如新闻文章、维基页面或网站)时特别有用。它可以更容易地理解文本的主题并将相似的内容组合在一起。

因此,对于一个搜索引擎来说,NER是深度查询理解(Deep Query Understanding,简称 DQU)的底层基础信号,能应用于搜索召回、用户意图识别、实体链接、图探索等环节,NER信号的质量,直接影响到用户的搜索体验。

但很不幸的是,目前Elasticsearch仅仅兼容测试了以下几种英文的模型:

  • BERT base NER
  • DistilBERT base cased finetuned conll03 English
  • DistilRoBERTa base NER conll2003
  • DistilBERT base uncased finetuned conll03 English

并且,在目前版本,只支持以IOB(Begin, Inside, Outside)形式打标签的模型。因此,如果我们在Huggingface上选择了一个中文的NER模型,比如这个:https://huggingface.co/uer/roberta-base-finetuned-cluener2020-chinese/

然后部署到Elasticsearch集群:

代码语言:shell复制
docker run -it --rm --network host elastic/eland eland_import_hub_model 
--url http://localhost:9200 -u elastic -p yourpassword 
--hub-model-id uer/roberta-base-finetuned-cluener2020-chinese --task-type ner

会有如下提示:

代码语言:shell复制
2022-08-05 02:54:41,792 INFO : Establishing connection to Elasticsearch
2022-08-05 02:54:41,882 INFO : Connected to cluster named 'docker-cluster' (version: 8.4.0-SNAPSHOT)
2022-08-05 02:54:41,883 INFO : Loading HuggingFace transformer tokenizer and model 'uer/roberta-base-finetuned-cluener2020-chinese'
Downloading: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 295/295 [00:00<00:00, 280kB/s]
Downloading: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1.76k/1.76k [00:00<00:00, 3.02MB/s]
Downloading: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 107k/107k [00:01<00:00, 74.2kB/s]
Downloading: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 112/112 [00:00<00:00, 132kB/s]
Downloading: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 388M/388M [19:02<00:00, 356kB/s]
Asking to pad to max_length but no maximum length is provided and the model has no predefined maximum length. Default to no padding.
2022-08-05 03:14:18,830 INFO : Creating model with id 'uer__roberta-base-finetuned-cluener2020-chinese'
Traceback (most recent call last):
  File "/usr/local/bin/eland_import_hub_model", line 219, in <module>
    ptm.put_config(config=config)
  File "/usr/local/lib/python3.9/dist-packages/eland/ml/pytorch/_pytorch_model.py", line 78, in put_config
    self._client.ml.put_trained_model(model_id=self.model_id, **config_map)
  File "/usr/local/lib/python3.9/dist-packages/elasticsearch/_sync/client/utils.py", line 414, in wrapped
    return api(*args, **kwargs)
  File "/usr/local/lib/python3.9/dist-packages/elasticsearch/_sync/client/ml.py", line 3258, in put_trained_model
    return self.perform_request(  # type: ignore[return-value]
  File "/usr/local/lib/python3.9/dist-packages/elasticsearch/_sync/client/_base.py", line 390, in perform_request
    return self._client.perform_request(
  File "/usr/local/lib/python3.9/dist-packages/elasticsearch/_sync/client/_base.py", line 321, in perform_request
    raise HTTP_EXCEPTIONS.get(meta.status, ApiError)(
elasticsearch.BadRequestError: BadRequestError(400, 'x_content_parse_exception', '[ner] only allows IOB tokenization tagging for classification labels; provided [S_address, S_book, S_company, S_game, S_government, S_movie, S_name, S_organization, S_position, S_scene, [PAD]]')

部署中文模型的解决方案

为了解决以上问题,我们需要对模型做一些修改,使其符合当前Elasticsearch的限制。

也就是说,我们需要将目前模型的打标方式,改成elasticsearch兼容的模式:

代码语言:javascript复制
{
  "architectures": [
    "BertForTokenClassification"
  ],
  "attention_probs_dropout_prob": 0.1,
  "hidden_act": "gelu",
  "hidden_dropout_prob": 0.1,
  "hidden_size": 768,
  "id2label": {
    "0": "O",
    "1": "B-address",
    "2": "I-address",
    "3": "B-book",
    "4": "I-book",
    "5": "B-company",
    "6": "I-company",
    "7": "B-game",
    "8": "I-game",
    "9": "B-government",
    "10": "I-government",
    "11": "B-movie",
    "12": "I-movie",
    "13": "B-name",
    "14": "I-name",
    "15": "B-organization",
    "16": "I-organization",
    "17": "B-position",
    "18": "I-position",
    "19": "B-scene",
    "20": "I-scene",
    "21": "S-address",
    "22": "S-book",
    "23": "S-company",
    "24": "S-game",
    "25": "S-government",
    "26": "S-movie",
    "27": "S-name",
    "28": "S-organization",
    "29": "S-position",
    "30": "S-scene",
    "31": "[PAD]"
  },
  "initializer_range": 0.02,
  "intermediate_size": 3072,
  "label2id": {
    "B-address": 1,
    "B-book": 3,
    "B-company": 5,
    "B-game": 7,
    "B-government": 9,
    "B-movie": 11,
    "B-name": 13,
    "B-organization": 15,
    "B-position": 17,
    "B-scene": 19,
    "I-address": 2,
    "I-book": 4,
    "I-company": 6,
    "I-game": 8,
    "I-government": 10,
    "I-movie": 12,
    "I-name": 14,
    "I-organization": 16,
    "I-position": 18,
    "I-scene": 20,
    "O": 0,
    "S-address": 21,
    "S-book": 22,
    "S-company": 23,
    "S-game": 24,
    "S-government": 25,
    "S-movie": 26,
    "S-name": 27,
    "S-organization": 28,
    "S-position": 29,
    "S-scene": 30,
    "[PAD]": 31
  },
  "layer_norm_eps": 1e-12,
  "max_position_embeddings": 512,
  "model_type": "bert",
  "num_attention_heads": 12,
  "num_hidden_layers": 12,
  "pad_token_id": 0,
  "vocab_size": 21128
}

问题是我们是直接从Huggingface将模型导入到elasticsearch的,我们如何能够对别人的模型进行修改?

很简单,参考我的上一篇博文:在Huggingface上fork repository

我们可以把模型转移到自己的仓库中,然后可自行修改配置文件。在下图中:

image.pngimage.png

我们将模型搬移到自己的仓库,然后在线将congfig.json修改为符合IOB的模式。这里的修改包括:

  • S-address等标签改为B-address1
  • [PAD]标签改为B-no

然后通过自己的仓库进行重新部署:

代码语言:shell复制
docker run -it --rm --network host elastic/eland eland_import_hub_model 
--url http://localhost:9200 -u elastic -p yourpassword 
--hub-model-id canIjoin/datafun --task-type ner

部署后,即可在界面上进行测试:

image.pngimage.png

总结

本文中,我们介绍了在Elasticsearch中NLP的工作愿意,以及在集群中部署中文NER模型的一些限制与解决的办法。

而当下,像搜索深度理解,智能推荐等需要更为精准的搜索的场景,和NLP的结合已经成为必然。而在Elasticsearch中直接实现NLP,将帮助我们以极简的架构、极低的成本,极快的速度去上线一个包含了NLP功能的搜索项目

0 人点赞