爱锋贝

 找回密码
 立即注册

只需一步,快速开始

扫一扫,极速登录

开启左侧

使用PaddleNLP进行恶意网页识别(二)

[复制链接]
发表于 2023-4-8 04:25:05 | 显示全部楼层 |阅读模式

一键注册,加入手机圈

您需要 登录 才可以下载或查看,没有帐号?立即注册   

x
本文是《使用PaddleNLP进行恶意网页识别》系列第二篇,该系列持续更新中……
系列目录


  • 使用PaddleNLP进行恶意网页识别(一)

    • 使用PaddleNLP的文本分类模型,做正常网页与被黑网页的简单二分类,根据HTML网页内容处理结果判断网页是否正常。



  • 使用PaddleNLP进行恶意网页识别(二)

    • 使用PaddleNLP的预训练模型Fine-tune,大幅提高根据HTML网页内容处理结果判断网页准确率。

  • 本文能顺利完成,要特别感谢社区@没入门的研究生大佬的指导
  • 使用PaddleNLP进行恶意网页识别(三)

    • 使用PaddleNLP的文本分类模型,做正常网页与恶意网页的简单二分类,提取HTML标签信息判断网页是否正常。



  • 使用PaddleNLP进行恶意网页识别(四)

    • 尝试使用人工判断条件,设计提取HTML标签信息识别恶意网页的流程。
    • 使用PaddleNLP的预训练模型Fine-tune,尝试提高提取HTML标签信息判断网页是否正常的效果。
    • 将动态图训练的网页分类模型导出并使用Python部署。

  • 使用PaddleNLP进行恶意网页识别(五)

    • 该项目直接对标系列第二篇,对比BERT中文预训练模型和Ernie预训练模型在HTML网页内容分类流程和效果上的差异。
    • 项目进一步完善和优化了HTML网页内容提取和数据清洗流程。
    • 验证集上模型准确率可以轻松达到91.5%以上,最高达到95%,在BERT预训练模型上进行finetune,得到了目前在该HTML网页内容分类任务上的最好表现。



  • 使用PaddleNLP进行恶意网页识别(六)

    • 该项目直接对标系列第四篇,对比BERT中文预训练模型和Ernie预训练模型在HTML网页标签分类效果上的差异。
    • 项目进一步完善和优化了HTML的tag内容提取和数据清洗流程。
    • 验证集上模型准确率可以轻松达到96.5%以上,测试集上准确率接近97%,在BERT预训练模型上进行finetune,得到了目前在该HTML网页标签序列分类任务上的最好表现。

  • 使用PaddleNLP进行恶意网页识别(七)

    • 介绍了使用自动化测试工具selenium进行网页快照抓取的方法。
    • 介绍了使用zxing开源库进行网页快照二维码定位和解析的方法。
    • 介绍使用系列第六篇训练的模型,对二维码中包含的url网页链接进行识别分类的思路。

关于Fine-tune

近年来随着深度学习的发展,模型参数数量飞速增长,为了训练这些参数,需要更大的数据集来避免过拟合。然而,对于大部分NLP任务来说,构建大规模的标注数据集成本过高,非常困难,特别是对于句法和语义相关的任务。相比之下,大规模的未标注语料库的构建则相对容易。最近的研究表明,基于大规模未标注语料库的预训练模型(Pretrained Models, PTM) 能够习得通用的语言表示,将预训练模型Fine-tune到下游任务,能够获得出色的表现。另外,预训练模型能够避免从零开始训练模型。

使用PaddleNLP进行恶意网页识别(二)-1.jpg



预训练模型一览,图片来源:https://github.com/thunlp/PLMpapers

在PaddleNLP文档中,介绍了下面这个示例:
使用预训练模型Fine-tune完成情感分析分类任务

该示例展示了以ERNIE(Enhanced Representation through Knowledge Integration)为代表的预训练模型如何Finetune完成中文情感分析任务。首先来看看这个示例的效果。
使用从源码安装的方法,安装最新的PaddleNLP develop分支
!pip install --upgrade git+https://gitee.com/PaddlePaddle/PaddleNLP.git
!git clone https://gitee.com/paddlepaddle/PaddleNLP.git
import paddle
import paddlenlp
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/layers/utils.py:26: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations
  def convert_to_list(value, n, name, dtype=np.int):预训练模型简介

PaddleNLP针对中文文本分类问题,开源了一系列模型,供用户可配置地使用:

  • BERT(Bidirectional Encoder Representations from Transformers)中文模型,简写bert-base-chinese, 其由12层Transformer网络组成。
  • ERNIE(Enhanced Representation through Knowledge Integration),支持ERNIE 1.0中文模型(简写ernie-1.0)和ERNIE Tiny中文模型(简写ernie-tiny)。 其中ernie由12层Transformer网络组成,ernie-tiny由3层Transformer网络组成。
  • RoBERTa(A Robustly Optimized BERT Pretraining Approach),支持24层Transformer网络的roberta-wwm-ext-large和12层Transformer网络的roberta-wwm-ext。
| 模型 | dev acc | test acc | | --- | --- | --- | | bert-base-chinese | 0.93833 | 0.94750 | | bert-wwm-chinese | 0.94583 | 0.94917 | | bert-wwm-ext-chinese | 0.94667 | 0.95500 | | ernie-1.0 | 0.94667 | 0.95333 | | ernie-tiny | 0.93917 | 0.94833 | | roberta-wwm-ext | 0.94750 | 0.95250 | | roberta-wwm-ext-large | 0.95250 | 0.95333 | | rbt3 | 0.92583 | 0.93250 | | rbtl3 | 0.9341 | 0.93583 |
详细说明可以参考:PaddleNLP文档:使用预训练模型Fine-tune完成中文文本分类任务,这里就不做赘述,主要看看训练效果:
!cd PaddleNLP/examples/text_classification/pretrained_models/ && python -m paddle.distributed.launch train.py --device gpu --save_dir ./checkpoints
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/layers/utils.py:26: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations
  def convert_to_list(value, n, name, dtype=np.int):
-----------  Configuration Arguments -----------
gpus: None
heter_worker_num: None
heter_workers:
http_port: None
ips: 127.0.0.1
log_dir: log
nproc_per_node: None
server_num: None
servers:
training_script: train.py
training_script_args: ['--device', 'gpu', '--save_dir', './checkpoints']
worker_num: None
workers:
------------------------------------------------
WARNING 2021-04-28 10:53:28,780 launch.py:316] Not found distinct arguments and compiled with cuda. Default use collective mode
launch train in GPU mode
INFO 2021-04-28 10:53:28,782 launch_utils.py:471] Local start 1 processes. First process distributed environment info (Only For Debug):
    +=======================================================================================+
    |                        Distributed Envs                      Value                    |
    +---------------------------------------------------------------------------------------+
    |                       PADDLE_TRAINER_ID                        0                      |
    |                 PADDLE_CURRENT_ENDPOINT                 127.0.0.1:48117               |
    |                     PADDLE_TRAINERS_NUM                        1                      |
    |                PADDLE_TRAINER_ENDPOINTS                 127.0.0.1:48117               |
    |                     FLAGS_selected_gpus                        0                      |
    +=======================================================================================+

INFO 2021-04-28 10:53:28,782 launch_utils.py:475] details abouts PADDLE_TRAINER_ENDPOINTS can be found in log/endpoints.log, and detail running logs maybe found in log/workerlog.0
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/layers/utils.py:26: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations
  def convert_to_list(value, n, name, dtype=np.int):
[2021-04-28 10:53:30,163] [    INFO] - Already cached /home/aistudio/.paddlenlp/models/ernie-tiny/ernie_tiny.pdparams
W0428 10:53:30.165206  8918 device_context.cc:362] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 10.1, Runtime API Version: 10.1
W0428 10:53:30.170289  8918 device_context.cc:372] device: 0, cuDNN Version: 7.6.
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py:1303: UserWarning: Skip loading for classifier.weight. classifier.weight is not found in the provided dict.
  warnings.warn(("Skip loading for {}. ".format(key) + str(err)))
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py:1303: UserWarning: Skip loading for classifier.bias. classifier.bias is not found in the provided dict.
  warnings.warn(("Skip loading for {}. ".format(key) + str(err)))
[2021-04-28 10:53:37,440] [    INFO] - Found /home/aistudio/.paddlenlp/models/ernie-tiny/vocab.txt
[2021-04-28 10:53:37,441] [    INFO] - Found /home/aistudio/.paddlenlp/models/ernie-tiny/spm_cased_simp_sampled.model
[2021-04-28 10:53:37,441] [    INFO] - Found /home/aistudio/.paddlenlp/models/ernie-tiny/dict.wordseg.pickle
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/parallel.py:423: UserWarning: The program will return to single-card operation. Please check 1, whether you use spawn or fleetrun to start the program. 2, Whether it is a multi-card program. 3, Is the current environment multi-card.
  warnings.warn("The program will return to single-card operation. "
global step 10, epoch: 1, batch: 10, loss: 0.52361, accu: 0.65000, speed: 9.22 step/s
global step 20, epoch: 1, batch: 20, loss: 0.50937, accu: 0.75625, speed: 11.10 step/s
global step 30, epoch: 1, batch: 30, loss: 0.20778, accu: 0.79271, speed: 11.12 step/s
global step 40, epoch: 1, batch: 40, loss: 0.17973, accu: 0.81719, speed: 11.10 step/s
global step 50, epoch: 1, batch: 50, loss: 0.13715, accu: 0.83500, speed: 11.10 step/s
global step 60, epoch: 1, batch: 60, loss: 0.31635, accu: 0.84792, speed: 10.91 step/s
global step 70, epoch: 1, batch: 70, loss: 0.48289, accu: 0.85759, speed: 11.09 step/s
global step 80, epoch: 1, batch: 80, loss: 0.33256, accu: 0.85977, speed: 11.09 step/s
global step 90, epoch: 1, batch: 90, loss: 0.23529, accu: 0.86528, speed: 10.92 step/s
global step 100, epoch: 1, batch: 100, loss: 0.10831, accu: 0.86781, speed: 11.07 step/s
eval loss: 0.24311, accu: 0.91000
global step 110, epoch: 1, batch: 110, loss: 0.24633, accu: 0.88750, speed: 1.30 step/s
global step 120, epoch: 1, batch: 120, loss: 0.21631, accu: 0.88594, speed: 11.09 step/s
global step 130, epoch: 1, batch: 130, loss: 0.24054, accu: 0.88542, speed: 11.08 step/s
global step 140, epoch: 1, batch: 140, loss: 0.14191, accu: 0.88828, speed: 11.06 step/s
global step 150, epoch: 1, batch: 150, loss: 0.17121, accu: 0.89687, speed: 11.11 step/s
global step 160, epoch: 1, batch: 160, loss: 0.26325, accu: 0.90104, speed: 11.13 step/s
global step 170, epoch: 1, batch: 170, loss: 0.11606, accu: 0.89955, speed: 11.10 step/s
global step 180, epoch: 1, batch: 180, loss: 0.06721, accu: 0.90391, speed: 11.08 step/s
global step 190, epoch: 1, batch: 190, loss: 0.24036, accu: 0.90417, speed: 11.10 step/s
global step 200, epoch: 1, batch: 200, loss: 0.58651, accu: 0.90312, speed: 11.13 step/s
eval loss: 0.21573, accu: 0.92583
global step 210, epoch: 1, batch: 210, loss: 0.29864, accu: 0.91563, speed: 1.29 step/s
global step 220, epoch: 1, batch: 220, loss: 0.33272, accu: 0.92188, speed: 11.08 step/s
global step 230, epoch: 1, batch: 230, loss: 0.30313, accu: 0.91771, speed: 11.10 step/s
global step 240, epoch: 1, batch: 240, loss: 0.26417, accu: 0.92109, speed: 11.09 step/s
global step 250, epoch: 1, batch: 250, loss: 0.32720, accu: 0.91938, speed: 11.08 step/s
global step 260, epoch: 1, batch: 260, loss: 0.29275, accu: 0.92188, speed: 11.11 step/s
global step 270, epoch: 1, batch: 270, loss: 0.22924, accu: 0.92277, speed: 11.13 step/s
global step 280, epoch: 1, batch: 280, loss: 0.07589, accu: 0.92461, speed: 11.09 step/s
global step 290, epoch: 1, batch: 290, loss: 0.19718, accu: 0.92708, speed: 11.11 step/s
global step 300, epoch: 1, batch: 300, loss: 0.09135, accu: 0.92875, speed: 11.06 step/s
eval loss: 0.19773, accu: 0.93583
^C
Traceback (most recent call last):
  File "/opt/conda/envs/python35-paddle120-env/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/opt/conda/envs/python35-paddle120-env/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/distributed/launch.py", line 16, in <module>
    launch.launch()
  File "/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/distributed/fleet/launch.py", line 328, in launch
    launch_collective(args)
  File "/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/distributed/fleet/launch.py", line 244, in launch_collective
    time.sleep(3)
KeyboardInterrupt可以明显看出,仅用了1个epoch后,情感分析的分类准确率就来到90%以上,效果显著。因此,可以想想,Finetune将是解决使用PaddleNLP进行恶意网页识别(一)这个项目中,从0开始训练,效果不佳问题的一个答案。
使用PaddleNLP语义预训练模型ERNIE优化恶意网页识别效果

关于自定义数据集

不得不说,上面介绍的PaddleNLP Finetune示例封装程度有点高,是直接使用了DatasetBuilder 的子类实现数据集的贡献到数据集加载、模型训练的打通。但是在自定义数据集中,其实我们只需要关注训练数据是怎么整理的,格式如何即可。对应到PaddleNLP的源码中,就是text_classification/pretrained_models/train.py里的实现,相关语句摘录如下。
from paddlenlp.datasets import load_dataset
train_ds, dev_ds, test_ds = load_dataset(
    "chnsenticorp", splits=["train", "dev", "test"])
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/layers/utils.py:26: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations
  def convert_to_list(value, n, name, dtype=np.int):
train_ds.label_list
['0', '1']
train_ds.data[:5]
[{'text': '选择珠江花园的原因就是方便,有电动扶梯直接到达海边,周围餐馆、食廊、商场、超市、摊位一应俱全。酒店装修一般,但还算整洁。 泳池在大堂的屋顶,因此很小,不过女儿倒是喜欢。 包的早餐是西式的,还算丰富。 服务吗,一般',
  'label': 1},
{'text': '15.4寸笔记本的键盘确实爽,基本跟台式机差不多了,蛮喜欢数字小键盘,输数字特方便,样子也很美观,做工也相当不错',
  'label': 1},
{'text': '房间太小。其他的都一般。。。。。。。。。', 'label': 0},
{'text': '1.接电源没有几分钟,电源适配器热的不行. 2.摄像头用不起来. 3.机盖的钢琴漆,手不能摸,一摸一个印. 4.硬盘分区不好办.',
  'label': 0},
{'text': '今天才知道这书还有第6卷,真有点郁闷:为什么同一套书有两种版本呢?当当网是不是该跟出版社商量商量,单独出个第6卷,让我们的孩子不会有所遗憾。',
  'label': 1}]因此,我们现在需要做的,就是将自定义数据集整理成上面的形式,其实就是PaddleNLP的MapDataset。由于PaddleNLP的文档尚在完善中,读者可能一下找不到相关入口,这时,可以从源代码的注释里找,比如利用AI Studio或者IDE上的这个功能:
??load_dataset自定义数据集的内容则来自于上一个项目生成的webtrain.txt,webdev.txt,webtest.txt,本文已经内置。
PaddleNLP文档:如何自定义数据集
通过使用PaddleNLP提供的 load_dataset() , MapDataset 和 IterDataset 。任何人都可以方便的定义属于自己的数据集。
从本地文件创建数据集¶
从本地文件创建数据集时,我们 推荐 根据本地数据集的格式给出读取function并传入 load_dataset() 中创建数据集。
以 waybill_ie 快递单信息抽取任务中的数据为例:
```python from paddlenlp.datasets import load_dataset
def read(data_path):     with open(data_path, 'r', encoding='utf-8') as f:         # 跳过列名         next(f)         for line in f:             words, labels = line.strip('\n').split('\t')             words = words.split('\002')             labels = labels.split('\002')             yield {'tokens': words, 'labels': labels}
data_path为read()方法的参数
map_ds = load_dataset(read, data_path='train.txt',lazy=False) iter_ds = load_dataset(read, data_path='train.txt',lazy=True) ```
我们推荐将数据读取代码写成生成器(generator)的形式,这样可以更好的构建 MapDataset 和 IterDataset 两种数据集。同时我们也推荐将单条数据写成字典的格式,这样可以更方便的监测数据流向。
事实上,MapDataset 在绝大多数时候都可以满足要求。一般只有在数据集过于庞大无法一次性加载进内存的时候我们才考虑使用 IterDataset 。任何人都可以方便的定义属于自己的数据集。
注解
需要注意的是,只有从 DatasetBuilder 初始化的数据集具有将数据中的label自动转为id的功能(详细条件参见 如何贡献数据集)。
像上例中的自定义数据集需要在自定义的convert to feature方法中添加label转id的功能。
自定义数据读取function中的参数可以直接以关键字参数的的方式传入 load_dataset() 中。而且对于自定义数据集,lazy 参数是 必须 传入的。
from paddlenlp.datasets import load_dataset

def read(data_path):
    with open(data_path, 'r', encoding='utf-8') as f:
        for line in f:
            line = line.strip('\n').split('\t')
            # 注意,原数据集中可能文本里还有\t残留,因此要使用下面的方法提取文本与标签,否则会报错
            words = ''.join(line[:-1])
            labels = line[-1]
            yield {'text': words, 'label': labels}

# data_path为read()方法的参数
train_ds = load_dataset(read, data_path='webtrain.txt',lazy=False)
dev_ds = load_dataset(read, data_path='webdev.txt',lazy=False)
test_ds = load_dataset(read, data_path='webtest.txt',lazy=False)
train_ds.data[:10]
[{'text': '年以内,2万公里以内SUV1年以内易车二手车体验更好,速度更快立即前往APP看电脑版看微信版提意见购车热线:4000-189-167(,9:00,–,21:00,)易车二手车,m.taoche.com',
  'label': '0'},
{'text': 'ipaime.com/thread-694853-1-1.htmlcoryphaei.com/forum.php?mod=viewthread&tid=3074054回复返回版块参与回复©,栖霞商业网',
  'label': '0'},
{'text': '大直街店集体课表人和国际健身俱乐部首页集体课表联系我们扫描二维码用手机访问本站由业界领先的搜狐快站免费提供技术支持人和国际健身俱乐部人和健身大直街店集体课表15小时前阅读Powered,by,搜狐快站',
  'label': '0'},
{'text': '个人帐户工作或学校帐户单位或学校未分配帐户?使用,Microsoft,帐户登录厌烦了这个帐户名称?重命名您的个人,Microsoft,帐户。©,2017,Microsoft使用条款隐私与,Cookie',
  'label': '0'},
{'text': 'ONGAB4yONGAB4y精绝美女-在线直播在线播放-高清无水印九狮赌城-美女荷官All,rights,reserved.Copyright,©2016,&2017',
  'label': '0'},
{'text': '萧萧联稿...友情链接与我在线留言本站|友情连接|后台管理2008--2012|http://www.syslh.com,|管理:尘涵圣域诗联网站鲁ICP备06019539号Open,LoginBar',
  'label': '1'},
{'text': '专利加急,专利查询免责声明:本站部分资料来自互联网,转载时会注明出处;如果侵犯了你的权益,请通知我们,我们会及时删除侵权内容,谢谢合作!Powered,bywqCms5.7withWangqiInc.',
  'label': '0'},
{'text': '银河赌场澳门赌场玩法在线赌博真钱赌博网站赌博现金网线上赌博平台葡京娱乐场新葡京娱乐场金沙娱乐场bet365娱乐场真人娱乐场博彩网澳门博彩网站博彩公司博彩公司评级博彩现金网博彩网导航博彩技巧博彩公司排名',
  'label': '1'},
{'text': '云集品电子商务有限公司,版权所有.粤ICP备14072989号-2联系方式0755-33198568elapsed_time:0.1559,memory_usage:6.96MB关注微信,赢取更多优惠',
  'label': '0'},
{'text': '云集品电子商务有限公司,版权所有.粤ICP备14072989号-2联系方式0755-33198568elapsed_time:0.1958,memory_usage:6.96MB关注微信,赢取更多优惠',
  'label': '0'}]
# label_list手动添加进去就行
train_ds.label_list = ['0', '1']
dev_ds.label_list = ['0', '1']
test_ds.label_list = ['0', '1']
# 查看效果,确认自定义数据集完成
print(train_ds.label_list)

for data in train_ds.data[:5]:
    print(data)
['0', '1']
{'text': '年以内,2万公里以内SUV1年以内易车二手车体验更好,速度更快立即前往APP看电脑版看微信版提意见购车热线:4000-189-167(,9:00,–,21:00,)易车二手车,m.taoche.com', 'label': '0'}
{'text': 'ipaime.com/thread-694853-1-1.htmlcoryphaei.com/forum.php?mod=viewthread&tid=3074054回复返回版块参与回复©,栖霞商业网', 'label': '0'}
{'text': '大直街店集体课表人和国际健身俱乐部首页集体课表联系我们扫描二维码用手机访问本站由业界领先的搜狐快站免费提供技术支持人和国际健身俱乐部人和健身大直街店集体课表15小时前阅读Powered,by,搜狐快站', 'label': '0'}
{'text': '个人帐户工作或学校帐户单位或学校未分配帐户?使用,Microsoft,帐户登录厌烦了这个帐户名称?重命名您的个人,Microsoft,帐户。©,2017,Microsoft使用条款隐私与,Cookie', 'label': '0'}
{'text': 'ONGAB4yONGAB4y精绝美女-在线直播在线播放-高清无水印九狮赌城-美女荷官All,rights,reserved.Copyright,©2016,&2017', 'label': '0'}参考项目:『NLP经典项目集』02:使用预训练模型ERNIE优化情感分析 ,该项目也提供了数据处理脚本utils.py,本文已经内置。
PaddleNLP一键加载预训练模型

PaddleNLP对于各种预训练模型已经内置了对于下游任务-文本分类的Fine-tune网络。以下教程ERNIE为例,介绍如何将预训练模型Fine-tune完成文本分类任务。

  • paddlenlp.transformers.ErnieModel()一行代码即可加载预训练模型ERNIE。
  • paddlenlp.transformers.ErnieForSequenceClassification()一行代码即可加载预训练模型ERNIE用于文本分类任务的Fine-tune网络。

    • 其在ERNIE模型后拼接上一个全连接网络(Full Connected)进行分类。



  • paddlenlp.transformers.ErnieForSequenceClassification.from_pretrained() 只需指定想要使用的模型名称和文本分类的类别数即可完成网络定义。
# 设置想要使用模型的名称

MODEL_NAME = "ernie-1.0"

ernie_model = paddlenlp.transformers.ErnieModel.from_pretrained(MODEL_NAME)

model = paddlenlp.transformers.ErnieForSequenceClassification.from_pretrained(MODEL_NAME, num_classes=len(train_ds.label_list))
[2021-04-28 13:16:39,380] [    INFO] - Already cached /home/aistudio/.paddlenlp/models/ernie-1.0/ernie_v1_chn_base.pdparams
[2021-04-28 13:16:45,760] [    INFO] - Already cached /home/aistudio/.paddlenlp/models/ernie-1.0/ernie_v1_chn_base.pdparams
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py:1303: UserWarning: Skip loading for classifier.weight. classifier.weight is not found in the provided dict.
  warnings.warn(("Skip loading for {}. ".format(key) + str(err)))
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/layers.py:1303: UserWarning: Skip loading for classifier.bias. classifier.bias is not found in the provided dict.
  warnings.warn(("Skip loading for {}. ".format(key) + str(err)))调用ppnlp.transformers.ErnieTokenizer进行数据处理

预训练模型ERNIE对中文数据的处理是以字为单位。PaddleNLP对于各种预训练模型已经内置了相应的tokenizer。指定想要使用的模型名字即可加载对应的tokenizer。
tokenizer作用为将原始输入文本转化成模型model可以接受的输入数据形式。

使用PaddleNLP进行恶意网页识别(二)-2.jpg



使用PaddleNLP进行恶意网页识别(二)-3.jpg



ERNIE模型框架示意图

tokenizer = paddlenlp.transformers.ErnieTokenizer.from_pretrained(MODEL_NAME)
[2021-04-28 13:16:47,310] [    INFO] - Found /home/aistudio/.paddlenlp/models/ernie-1.0/vocab.txt数据读入

使用paddle.io.DataLoader接口多线程异步加载数据。
from functools import partial
from paddlenlp.data import Stack, Tuple, Pad
from utils import  convert_example, create_dataloader

# 模型运行批处理大小
batch_size = 16
max_seq_length = 128

trans_func = partial(
    convert_example,
    tokenizer=tokenizer,
    max_seq_length=max_seq_length)
batchify_fn = lambda samples, fn=Tuple(
    Pad(axis=0, pad_val=tokenizer.pad_token_id),  # input
    Pad(axis=0, pad_val=tokenizer.pad_token_type_id),  # segment
    Stack(dtype="int64")  # label
): [data for data in fn(samples)]

train_data_loader = create_dataloader(
    train_ds,
    mode='train',
    batch_size=batch_size,
    batchify_fn=batchify_fn,
    trans_fn=trans_func)
dev_data_loader = create_dataloader(
    dev_ds,
    mode='dev',
    batch_size=batch_size,
    batchify_fn=batchify_fn,
    trans_fn=trans_func)
test_data_loader = create_dataloader(
    test_ds,
    mode='test',
    batch_size=batch_size,
    batchify_fn=batchify_fn,
    trans_fn=trans_func)
from paddlenlp.transformers import LinearDecayWithWarmup

# 训练过程中的最大学习率
learning_rate = 5e-5
# 训练轮次
epochs = 10
# 学习率预热比例
warmup_proportion = 0.1
# 权重衰减系数,类似模型正则项策略,避免模型过拟合
weight_decay = 0.01

num_training_steps = len(train_data_loader) * epochs
lr_scheduler = LinearDecayWithWarmup(learning_rate, num_training_steps, warmup_proportion)
optimizer = paddle.optimizer.AdamW(
    learning_rate=lr_scheduler,
    parameters=model.parameters(),
    weight_decay=weight_decay,
    apply_decay_param_fun=lambda x: x in [
        p.name for n, p in model.named_parameters()
        if not any(nd in n for nd in ["bias", "norm"])
    ])

criterion = paddle.nn.loss.CrossEntropyLoss()
metric = paddle.metric.Accuracy()
# checkpoint文件夹用于保存训练模型
!mkdir /home/aistudio/checkpoint模型训练与评估

模型训练的过程通常有以下步骤:

  • 从dataloader中取出一个batch data
  • 将batch data喂给model,做前向计算
  • 将前向计算结果传给损失函数,计算loss。将前向计算结果传给评价方法,计算评价指标。
  • loss反向回传,更新梯度。重复以上步骤。
每训练一个epoch时,程序将会评估一次,评估当前模型训练的效果。
import paddle.nn.functional as F
from utils import evaluate
from visualdl import LogWriter

global_step = 0
for epoch in range(1, epochs + 1):
    with LogWriter(logdir="./visualdl") as writer:
        for step, batch in enumerate(train_data_loader, start=1):
            input_ids, segment_ids, labels = batch
            logits = model(input_ids, segment_ids)
            loss = criterion(logits, labels)
            probs = F.softmax(logits, axis=1)
            correct = metric.compute(probs, labels)
            metric.update(correct)
            acc = metric.accumulate()
            global_step += 1
            if global_step % 10 == 0 :
                print("global step %d, epoch: %d, batch: %d, loss: %.5f, acc: %.5f" % (global_step, epoch, step, loss, acc))
                # 向记录器添加一个tag为`loss`的数据
            writer.add_scalar(tag="loss", step=global_step, value=loss)
            # 向记录器添加一个tag为`acc`的数据
            writer.add_scalar(tag="acc", step=global_step, value=acc)
            loss.backward()
            optimizer.step()
            lr_scheduler.step()
            optimizer.clear_grad()
        evaluate(model, criterion, metric, dev_data_loader)

model.save_pretrained('/home/aistudio/checkpoint')
tokenizer.save_pretrained('/home/aistudio/checkpoint')
global step 10, epoch: 1, batch: 10, loss: 0.20771, acc: 0.96875
eval loss: 0.30647, accu: 0.87963
global step 20, epoch: 2, batch: 1, loss: 0.06249, acc: 1.00000
global step 30, epoch: 2, batch: 11, loss: 0.11620, acc: 0.97727
eval loss: 0.36536, accu: 0.87037
global step 40, epoch: 3, batch: 2, loss: 0.02215, acc: 1.00000
global step 50, epoch: 3, batch: 12, loss: 0.00893, acc: 0.98958
eval loss: 0.56552, accu: 0.86111
global step 60, epoch: 4, batch: 3, loss: 0.00972, acc: 0.95833
global step 70, epoch: 4, batch: 13, loss: 0.01328, acc: 0.98077
eval loss: 0.81667, accu: 0.77778
global step 80, epoch: 5, batch: 4, loss: 0.22332, acc: 0.95312
global step 90, epoch: 5, batch: 14, loss: 0.27860, acc: 0.96429
eval loss: 0.40668, accu: 0.85185
global step 100, epoch: 6, batch: 5, loss: 0.03298, acc: 1.00000
global step 110, epoch: 6, batch: 15, loss: 0.00961, acc: 0.99167
eval loss: 0.27407, accu: 0.87963
global step 120, epoch: 7, batch: 6, loss: 0.01436, acc: 1.00000
global step 130, epoch: 7, batch: 16, loss: 0.00705, acc: 1.00000
eval loss: 0.31425, accu: 0.88889
global step 140, epoch: 8, batch: 7, loss: 0.00653, acc: 1.00000
global step 150, epoch: 8, batch: 17, loss: 0.00868, acc: 1.00000
eval loss: 0.30953, accu: 0.87963
global step 160, epoch: 9, batch: 8, loss: 0.00582, acc: 1.00000
global step 170, epoch: 9, batch: 18, loss: 0.00582, acc: 1.00000
eval loss: 0.31251, accu: 0.87963
global step 180, epoch: 10, batch: 9, loss: 0.00378, acc: 1.00000
global step 190, epoch: 10, batch: 19, loss: 0.00494, acc: 1.00000
eval loss: 0.31438, accu: 0.87963
使用PaddleNLP进行恶意网页识别(二)-4.jpg



使用PaddleNLP进行恶意网页识别(二)-5.jpg



VisualDL训练过程

模型预测

训练保存好的训练,即可用于预测。如以下示例代码自定义预测数据,调用predict()函数即可一键预测。
from utils import predict

data = [
{'text': ',3,4号不发货,介意者慎拍,谢谢!有品燃脂营微信“扫一扫”立即关注微信号:picoocbxj主页最新商品有品私教有品魔秤我的订单店铺主页会员中心关注我们店铺信息有赞提供技术支持取消清除历史搜索购物车'},

{'text': 'et是什么意思weekend是什么意思warn是什么意思team是什么意思Copyright,©,2006,-,2016,XUEXILA.COM,All,Rights,Reserved学习啦,版权所有'},

{'text': '太阳娱乐城现金开户皇家堡娱乐城彩票网上投注怎么领奖彩票网上投注那个好网上赌场排行送173元,一肖中特免费资料博悦娱乐是不是正规的天苑娱乐城xvsr姦全犯罪成海うるみkzcs16.com艺考不是博彩首页'},

{'text': 'SS订阅抵制不良游戏,拒绝盗版游戏,注意自我保护,谨防受骗上当,适度游戏益脑,沉迷游戏伤身,合理安排时间,享受健康生活Copyright,©,201788130安卓下载沪ICP备16000974号-9'},

{'text': '百度架构师手把手带你实现零基础小白到AI工程师的华丽蜕变'},
]
label_map = {0: '正常页面', 1: '被黑页面'}

results = predict(
    model, data, tokenizer, label_map, batch_size=batch_size)
for idx, text in enumerate(data):
    print('Data: {} \t Lable: {}'.format(text, results[idx]))
Data: {'text': ',3,4号不发货,介意者慎拍,谢谢!有品燃脂营微信“扫一扫”立即关注微信号:picoocbxj主页最新商品有品私教有品魔秤我的订单店铺主页会员中心关注我们店铺信息有赞提供技术支持取消清除历史搜索购物车'}   Lable: 正常页面
Data: {'text': 'et是什么意思weekend是什么意思warn是什么意思team是什么意思Copyright,©,2006,-,2016,XUEXILA.COM,All,Rights,Reserved学习啦,版权所有'}   Lable: 正常页面
Data: {'text': '太阳娱乐城现金开户皇家堡娱乐城彩票网上投注怎么领奖彩票网上投注那个好网上赌场排行送173元,一肖中特免费资料博悦娱乐是不是正规的天苑娱乐城xvsr姦全犯罪成海うるみkzcs16.com艺考不是博彩首页'}   Lable: 被黑页面
Data: {'text': 'SS订阅抵制不良游戏,拒绝盗版游戏,注意自我保护,谨防受骗上当,适度游戏益脑,沉迷游戏伤身,合理安排时间,享受健康生活Copyright,©,201788130安卓下载沪ICP备16000974号-9'}   Lable: 正常页面
Data: {'text': '百度架构师手把手带你实现零基础小白到AI工程师的华丽蜕变'}   Lable: 正常页面为试验模型的泛化能力,这里还把情感分析的文本也传入模型中(脑洞大开= =),输出结果正常。
from utils import predict

data = [
    {"text":'这个宾馆比较陈旧了,特价的房间也很一般。总体来说一般'},
    {"text":'怀着十分激动的心情放映,可是看着看着发现,在放映完毕后,出现一集米老鼠的动画片'},
    {"text":'作为老的四星酒店,房间依然很整洁,相当不错。机场接机服务很好,可以在车上办理入住手续,节省时间。'},
]
label_map = {0: '正常页面', 1: '被黑页面'}

results = predict(
    model, data, tokenizer, label_map, batch_size=batch_size)
for idx, text in enumerate(data):
    print('Data: {} \t Lable: {}'.format(text, results[idx]))
Data: {'text': '这个宾馆比较陈旧了,特价的房间也很一般。总体来说一般'}     Lable: 正常页面
Data: {'text': '怀着十分激动的心情放映,可是看着看着发现,在放映完毕后,出现一集米老鼠的动画片'}    Lable: 正常页面
Data: {'text': '作为老的四星酒店,房间依然很整洁,相当不错。机场接机服务很好,可以在车上办理入住手续,节省时间。'}   Lable: 正常页面也可以通过自定义数据集的方式,从测试集直接加载数据
from paddlenlp.datasets import load_dataset

def read(data_path):
    with open(data_path, 'r', encoding='utf-8') as f:
        for line in f:
            line = line.strip('\n').split('\t')
            # 注意,原数据集中可能文本里还有\t残留,因此要使用下面的方法提取文本与标签,否则会报错
            words = ''.join(line[:-1])
            yield {'text': words}

# data_path为read()方法的参数
test_ds = load_dataset(read, data_path='webtest.txt',lazy=False)
test_ds.label_list = ['0', '1']
test_ds[-5:]
[{'text': '区永寿县三原县礼泉县长武县陕西相关分类:安康综合医院黄页宝鸡综合医院黄页汉中综合医院黄页商洛综合医院黄页铜川综合医院黄页渭南综合医院黄页西安综合医院黄页延安综合医院黄页榆林综合医院黄页分享到更多...'},
{'text': '云集品电子商务有限公司,版权所有.粤ICP备14072989号-2联系方式0755-33198568elapsed_time:0.1522,memory_usage:6.96MB关注微信,赢取更多优惠'},
{'text': '阳城娱乐开户网址实战百家乐真钱娱乐百家乐庄和闲哪个多澳门赌场攻略彩摘博彩资讯网上真钱赌博新华区体育路小学足球博彩网址大全太阳城开户澳门皇冠赌场足球盈亏指数优博博彩太阳城游戏开户皇冠在线充值平台大家比分'},
{'text': '站长统计'},
{'text': '公司名:常熟市鑫丰货运有限公司会员组:免费会员,\xa0[我要升级]状态:离线姓名:魏如文(先生)职位:总经理电话:0512-52849533手机:15962489066QQ:地址:常熟市通港路88一99号'}]
from utils import predict

label_map = {0: '正常页面', 1: '被黑页面'}

results = predict(
    model, test_ds[-5:], tokenizer, label_map, batch_size=batch_size)
for idx, text in enumerate(test_ds[-5:]):
    print('Data: {} \t Lable: {}'.format(text, results[idx]))
Data: {'text': '区永寿县三原县礼泉县长武县陕西相关分类:安康综合医院黄页宝鸡综合医院黄页汉中综合医院黄页商洛综合医院黄页铜川综合医院黄页渭南综合医院黄页西安综合医院黄页延安综合医院黄页榆林综合医院黄页分享到更多...'}   Lable: 正常页面
Data: {'text': '云集品电子商务有限公司,版权所有.粤ICP备14072989号-2联系方式0755-33198568elapsed_time:0.1522,memory_usage:6.96MB关注微信,赢取更多优惠'}   Lable: 正常页面
Data: {'text': '阳城娱乐开户网址实战百家乐真钱娱乐百家乐庄和闲哪个多澳门赌场攻略彩摘博彩资讯网上真钱赌博新华区体育路小学足球博彩网址大全太阳城开户澳门皇冠赌场足球盈亏指数优博博彩太阳城游戏开户皇冠在线充值平台大家比分'}   Lable: 被黑页面
Data: {'text': '站长统计'}   Lable: 正常页面
Data: {'text': '公司名:常熟市鑫丰货运有限公司会员组:免费会员,\xa0[我要升级]状态:离线姓名:魏如文(先生)职位:总经理电话:0512-52849533手机:15962489066QQ:地址:常熟市通港路88一99号'}    Lable: 正常页面小结


  • Finetune后模型预测效果得到了大幅提升,且收敛非常快。当然,由于第一个项目在数据预处理的时候还是采用比较粗暴的方式,因此数据集里可能有一些瑕疵,影响了指标进一步提升,在后续的项目中,会进一步研究数据清洗问题。
  • NLP的调参有点玄学,Finetune后模型如何“炼丹”,需要读者进一步探索。
  • 再次感谢社区@没入门的研究生大佬的指导,NLP果然上手难度比较大,建议初学者使用的时候,遇到问题也要多交流,避免卡很久。
参考资料:PaddleNLP更多教程


  • 使用seq2vec模块进行句子情感分类
  • 使用BiGRU-CRF模型完成快递单信息抽取
  • 使用预训练模型ERNIE优化快递单信息抽取
  • 使用Seq2Seq模型完成自动对联
  • 使用预训练模型ERNIE-GEN实现智能写诗
  • 使用TCN网络完成新冠疫情病例数预测
  • 使用预训练模型完成阅读理解
  • 自定义数据集实现文本多分类任务

-----------------------------
精选高品质二手iPhone,上爱锋贝APP
您需要登录后才可以回帖 登录 | 立即注册   

本版积分规则

快速回复 返回顶部 返回列表