近期组内新增了一些自然语言处理的需求,主要是中文分词和通用文本分类的需求。关于分词已经有很多成熟的方案了(例如利用 ElasticSearch 的分词器),但文本分类的需求就需要更专业的工具来处理,恰好发现百度的 PaddleNLP 是一个不错的选择。
PaddlePaddle 是百度开源的一个深度学习平台,集深度学习核心训练和推理框架、基础模型库、端到端开发套件和丰富的工具组件于一体。PaddleNLP 是一款简单易用且功能强大的自然语言处理开发库。聚合业界优质预训练模型并提供开箱即用的开发体验,覆盖NLP多场景的模型库,搭配产业实践范例,提供极致的训练与推理性能,可满足灵活定制的开发需求。
本文基于 Python 3.9.18 以及 PaddlePaddle 2.6 + PaddleNLP 2.7.2 在 Windows 系统下进行调研,不同版本可能有所差异。因为是预研测试,暂时安装 CPU 版本的 PaddlePaddle,生产环境可根据服务器配置选择 GPU 版本加快处理速度及训练。
安装 PaddleNLP
由于 Python 相同库的不同版本可能存在不兼容的问题,因此使用 conda 进行环境管理,方便项目管理。
安装 MiniConda
Anaconda 商业化使用收费。可前往 MiniConda官网 下载安装
配置 conda 环境并安装 PaddleNLP
打开 Miniconda Prompt
,创建一个新的环境并安装 PaddlePaddle 以及 PaddleNLP。
1 2 3 4 5 6 7 8 9 10 11 12
| conda create -n paddle_39 python=3.9
conda activate paddle_39
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ conda config --set show_channel_urls yes
conda install paddlepaddle==2.6.2 --channel https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/Paddle/
conda install paddlenlp
|
使用 PaddleNLP
初次使用 PaddleNLP 的 Taskflow
功能可能需要下载官方预训练的模型,默认存储在 $HOME/.paddlenlp
目录下。如果服务器数据磁盘挂载有特殊设置或内网部署,则需要在调用时手动修改指定存储路径。
1 2
| from paddlenlp import Taskflow ner = Taskflow("ner", home_path="/workspace")
|
- 中文分词
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| (paddle_39) PS C:\Users\aofall> python Python 3.9.18 (main, Sep 11 2023, 14:09:26) [MSC v.1916 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> from paddlenlp import Taskflow
>>> seg = Taskflow("word_segmentation") >>> seg("近日国家卫健委发布第九版新型冠状病毒肺炎诊疗方案") ['近日', '国家卫健委', '发布', '第九版', '新型', '冠状病毒肺炎', '诊疗', '方案']
>>> seg_fast = Taskflow("word_segmentation", mode="fast") >>> seg_fast("近日国家卫健委发布第九版新型冠状病毒肺炎诊疗方案") ['近日', '国家', '卫健委', '发布', '第九版', '新型', '冠状病毒', '肺炎', '诊疗', '方案']
>>> seg_accurate = Taskflow("word_segmentation", mode="accurate") >>> seg_accurate("近日国家卫健委发布第九版新型冠状病毒肺炎诊疗方案") ['近日', '国家卫健委', '发布', '第九版', '新型冠状病毒肺炎', '诊疗', '方案']
|
- 零样本文本分类
1 2 3 4 5 6 7 8 9
| (paddle_39) PS C:\Users\aofall> python Python 3.9.18 (main, Sep 11 2023, 14:09:26) [MSC v.1916 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> from paddlenlp import Taskflow >>> cls = Taskflow("zero_shot_text_classification", schema=["好评", "差评"]) >>> cls("房间干净明亮,非常不错") [{'text_a': '房间干净明亮,非常不错', 'predictions': [{'label': '好评', 'score': 0.9982299185674333}]}] >>> cls("东西还可以,但是快递非常慢,下次不会再买这家了。") [{'text_a': '东西还可以,但是快递非常慢,下次不会再买这家了。', 'predictions': [{'label': '差评', 'score': 0.8738513034090186}]}]
|
接入 Java 应用
由于 PaddlePaddle 是基于 Python 的应用程序,无法直接与 Java 应用程序互通,则需要考虑接入方案,此处以零样本文本分类功能举例。
使用Java的 Runtime API 进行接入
这种方案是最简单,但需要 Java 应用和 PaddlePaddle 部署在同一台服务器上,不方便扩展。
使用 Django/Flask 等 Web 框架提供 Restful API 接入或使用 GRPC
这里举例使用 Django 提供 Restful API。
在 myapp/urls.py
中添加 URL 指定路由 /process-cls
1 2 3 4 5 6
| from django.urls import path from .views import ProcessView urlpatterns = [ path('process-cls/', ProcessView.as_view(), name='process'), ]
|
编写Controller逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| from django.http import JsonResponse from django.views import View from paddlenlp import Taskflow import json
class ProcessView(View): def post(self, request, *args, **kwargs): try: # 获取请求中的 JSON 数据 data = json.loads(request.body) schema = data.get('schema') text_list = data.get('text') cls = Taskflow("zero_shot_text_classification", schema) # 构造响应数据 response_data = [] for text, label in zip(text_list, schema): handle_data = cls(text) // 取出处理后的数据并组装,此处省略... // [{'text_a': '东西还可以,但是快递非常慢,下次不会再买这家了。', 'predictions': [{'label': '差评', 'score': 0.8738513034090186}]}] response_data.append({ "text": text, "label": label, "score": score }) return JsonResponse({"data": response_data}) except json.JSONDecodeError: return JsonResponse({"error": "Invalid JSON format"}, status=400) except Exception as e: return JsonResponse({"error": str(e)}, status=500)
|
- 使用消息队列进行处理
Java 应用侧在接收到请求后向消息队列中发送处理请求,Python 侧在拉取到请求处理,并将处理后的文本再次发回消息队列给 Java 应用侧消费。这个方案需要做好幂等控制以及消息丢失的超时处理。