BERT——ERNIE

  • 1. 安装
  • 1.1 安装 PaddlePaddle
  • 1.2 安装 ERNIE 套件
  • 1.3 下载预训练模型(可选)
  • 1.4 下载数据集
  • 2. 持续学习语义理解框架ERNIE——基本原理
  • 3. 快速运行
  • 3.1 数据获取
  • 3.2 运行Fine-tuning
  • 4. 具体实现过程
  • 5. 全部代码
  • 小结


一些链接:

  1. 百度ERNIE的官方github
  2. 全词覆盖的BERT模型
  3. 谷歌最强NLP模型BERT官方中文版
  4. 一个新闻概述

1. 安装

1.1 安装 PaddlePaddle

参考,本机和实验室配置都是PyTorch1.8.0 + cuda10.2,打开Windows命令行,输入:

python -m pip install paddlepaddle-gpu -i https://mirror.baidu.com/pypi/simple
Successfully installed astor-0.8.1 gast-0.3.3 paddlepaddle-gpu-2.0.1 protobuf-3.15.6

不知道下载到哪了,这个好像下载到python 3.8 环境下而不是Anaconda环境下,重新下载一次:

conda install paddlepaddle-gpu==2.0.1 cudatoolkit=10.2 -c paddle

报错:

RuntimeError: (PreconditionNotMet) The third-party dynamic library (cudnn64_7.dll) that Paddle depends on is not configured correctly. (error code is 126)

解决方法可参考此

import torch

print(torch.__version__)
print(torch.version.cuda)
print(torch.backends.cudnn.version())
1.8.0
10.2
7605

需要在英伟达官网下载cudnn-10.0-windows10-x64-v7.6.5.32.zip这个文件放到C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0下,cudnn下载地址,CUDA Toolkit 10.2 Download下载地址

PaddleOCR 在python中 识别不到中文 paddlepaddle pytorch_机器学习


输入:

import paddle
paddle.utils.run_check()
Running verify PaddlePaddle program ... 
PaddlePaddle works well on 1 GPU.
PaddlePaddle works well on 1 GPUs.
PaddlePaddle is installed successfully! Let's start deep learning with PaddlePaddle now.

打开服务器,输入:

(base) ysc@aaa-pc:~$ which python3
/home/ysc/anaconda3/bin/python3
(base) ysc@aaa-pc:~$ python3 --version
Python 3.8.5
(base) ysc@aaa-pc:~$ python3 -m pip --version
pip 20.2.4 from /home/ysc/anaconda3/lib/python3.8/site-packages/pip (python 3.8)
(base) ysc@aaa-pc:~$ python3 -c "import platform;print(platform.architecture()[0]);print(platform.machine())"
64bit
x86_64
conda install paddlepaddle-gpu==2.0.1 cudatoolkit=10.2 -c paddle

报错:

OSError: (External)  Cudnn error, CUDNN_STATUS_INTERNAL_ERROR  (at /paddle/paddle/fluid/platform/device_context.h:255)

查看Linux版本:

(base) ysc@aaa-pc:~$ cat /proc/version
Linux version 5.4.0-70-generic (buildd@lgw01-amd64-039) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #78~18.04.1-Ubuntu SMP Sat Mar 20 14:10:07 UTC 2021		# 18.04.1

查看有没有cuda:

(base) ysc@aaa-pc:~$ lspci | grep -i nvidia
01:00.0 VGA compatible controller: NVIDIA Corporation Device 1e04 (rev a1)
01:00.1 Audio device: NVIDIA Corporation Device 10f7 (rev a1)
01:00.2 USB controller: NVIDIA Corporation Device 1ad6 (rev a1)
01:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad7 (rev a1)
02:00.0 VGA compatible controller: NVIDIA Corporation Device 1e04 (rev a1)
02:00.1 Audio device: NVIDIA Corporation Device 10f7 (rev a1)
02:00.2 USB controller: NVIDIA Corporation Device 1ad6 (rev a1)
02:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad7 (rev a1)
04:00.0 VGA compatible controller: NVIDIA Corporation Device 1e04 (rev a1)
04:00.1 Audio device: NVIDIA Corporation Device 10f7 (rev a1)
04:00.2 USB controller: NVIDIA Corporation Device 1ad6 (rev a1)
04:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad7 (rev a1)
09:00.0 VGA compatible controller: NVIDIA Corporation Device 1e04 (rev a1)
09:00.1 Audio device: NVIDIA Corporation Device 10f7 (rev a1)
09:00.2 USB controller: NVIDIA Corporation Device 1ad6 (rev a1)
09:00.3 Serial bus controller [0c80]: NVIDIA Corporation Device 1ad7 (rev a1)

输入以下代码:

ls /usr/local/cuda
ls		# 进入/home/ysc/
ls /usr/local/cuda/bin
vim ~/.bashrc		# 编辑环境变量 加入export PATH=/usr/local/cuda/bin:$PATH
source ~/.bashrc		# 应用环境变量
reset		# 清除
nvcc --version		# 查看版本信息

服务器中paddle.utils.run_check()运行结果:

PaddlePaddle works well on 1 GPU.
PaddlePaddle is installed successfully ONLY for single GPU! Let's start deep learning with PaddlePaddle now.

一块GPU那就一块GPU吧,但这样内存很小,解决办法:检查NCCL是否安装正确,

conda list | grep cuda		# 找含cuda的文件
conda info -e		# 查看虚拟环境
ls | grep nccl		# 找nccl

关于NCCL安装参考此文此文,英伟达下载网站

sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
sudo add-apt-repository "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/ /"
sudo apt update
sudo apt install libnccl2 libnccl-dev
(base) wsh@aaa-pc:/mnt/Data1/ysc$ ldconfig -p | grep libnccl
	libnccl.so.2 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libnccl.so.2
	libnccl.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libnccl.so

再次运行paddle.utils.run_check()

PaddlePaddle works well on 4 GPUs.
PaddlePaddle is installed successfully! Let's start deep learning with PaddlePaddle now.

其实还是会报错内存不足,但我们现在知道平时操作是在run下进行的,我们现在可以在Terminal界面输入

# nvidia-smi
watch -n 1 nvidia-smi

查看显卡使用情况

1.2 安装 ERNIE 套件

激活conda环境:

conda activate base

修改pip位置参考此文,输入:

python -m site
USER_BASE: 'C:\\Users\\Yang SiCheng\\AppData\\Roaming\\Python' (exists)
USER_SITE: 'C:\\Users\\Yang SiCheng\\AppData\\Roaming\\Python\\Python38\\site-packages' (exists)
ENABLE_USER_SITE: True

这里的USER_BASE 和USER_SITE其实就是用户自定义的启用Python脚本和依赖安装包的基础路径,可见这个pip的安装位置不是期望的位置

输入:

python -m site -help

找到这个E:\ProgramData\Anaconda3\lib\site.py文件,修改其中参数:

USER_SITE = 'E:\ProgramData\Anaconda3\Lib\site-packages'
USER_BASE = 'E:\ProgramData\Anaconda3\Scripts'

之后再输入:

pip install paddle-ernie

即可安装成功

1.3 下载预训练模型(可选)

这里下载的是ERNIE 1.0 Base 中文文件,大小为769MB

1.4 下载数据集

这里下载中文数据——ChnSentiCorp,这是一个中文情感分析数据集,包含酒店、笔记本电脑和书籍的网购评论,我之前把它作为训练集在用…

ChnSentiCorp推荐超参数设置:batch size = 24,learning rate = 2e-5(base)/1e-5(large)

2. 持续学习语义理解框架ERNIE——基本原理

教程见

近年来,语义表示(language representation)技术的发展,使得 “预训练-微调” 作为解决NLP任务的一种新的范式开始出现。在微调阶段,该模型会被加上不同的简单输出层用以解决下游的 NLP 任务。早期较为著名的语义表示模型包括ELMo 和 GPT ,分别基于双层双向LSTM和Transformer Decoder框架,而真正让语义表示技术大放异彩的是BERT (Bidirectional Encoder Representations from Transformers) 的提出。BERT以Transformer Encoder为骨架,以屏蔽语言模型 (Masked LM) 和下一句预测(Next Sentence Prediction)这两个无监督预测任务作为预训练任务

用语义表示模型解决特定的NLP任务是个相对简单的过程。因此,语义表示模型的预训练阶段就变得十分重要,具体来说,模型结构的选取、训练数据以及训练方法等要素都会直接影响下游任务的效果

ERNIE(Enhanced Representation through kNowledge IntEgration)是百度提出的语义表示模型,同样基于Transformer Encoder,相较于BERT,其预训练过程利用了更丰富的语义知识和更多的语义任务,在多个NLP任务上取得了比BERT等模型更好的效果

Transformer

简要结构图如下:

PaddleOCR 在python中 识别不到中文 paddlepaddle pytorch_机器学习_02


Transformer 的简要结构如图1所示,基于 Encoder-Decoder 框架, 其主要结构由 Attention(注意力) 机制构成:

  • Encoder 由全同的多层堆叠而成,每一层又包含了两个子层:一个Self-Attention层和一个前馈神经网络。Self-Attention 层主要用来输入语料之间各个词之间的关系(例如搭配关系),其外在体现为词汇间的权重,此外还可以帮助模型学到句法、语法之类的依赖关系的能力
  • Decoder 也由全同的多层堆叠而成,每一层同样包含了两个子层。在 Encoder 和 Decoder 之间还有一个Encoder-Decoder Attention层。Encoder-Decoder Attention层的输入来自于两部分,一部分是Encoder的输出,它可以帮助解码器关注输入序列哪些位置值得关注。另一部分是 Decoder 已经解码出来的结果再次经过Decoder的Self-Attention层处理后的输出,它可以帮助解码器在解码时把已翻译的内容中值得关注的部分考虑进来。例如将“read a book”翻译成中文,我们把“book”之所以翻译成了“书”而没有翻译成“预定”就是因为前面Read这个读的动作

BERT、GPT 与 ELMo如下:

PaddleOCR 在python中 识别不到中文 paddlepaddle pytorch_自然语言处理_03


ERNIE相较于BERT学习原始语言信号,ERNIE 1.0 可以直接对先验语义知识单元进行建模,增强了模型语义表示能力。例如对于下面的例句:“哈尔滨是黑龙江的省会,国际冰雪文化名城”,ERNIE 1.0 与 BERT 词屏蔽方式的比较:

PaddleOCR 在python中 识别不到中文 paddlepaddle pytorch_机器学习_04


因为 ERNIE 1.0 对实体级知识的学习,使得它在语言推断任务上的效果更胜一筹。ERNIE 1.0 在中文任务上全面超过了 BERT 中文模型,包括分类、语义相似度、命名实体识别、问答匹配等任务,平均带来 1~2 个百分点的提升

可以发现 ERNIE 1.0 与 BERT 相比只是学习任务 MLM 作了一些改进就可以取得不错的效果,那么如果使用更多较好的学习任务来训练模型,那是不是会取得更好的效果呢?因此 ERNIE 2.0 应运而生。ERNIE 2.0 是基于持续学习的语义理解预训练框架,使用多任务学习增量式构建预训练任务。如图4所示,在ERNIE 2.0中,大量的自然语言处理的语料可以被设计成各种类型的自然语言处理任务(Task),这些新构建的预训练类型任务(Pre-training Task)可以无缝的加入图中右侧的训练框架,从而持续让ERNIE 2.0模型进行语义理解学习,不断的提升模型效果

ERNIE 2.0框架:

PaddleOCR 在python中 识别不到中文 paddlepaddle pytorch_nlp_05


通过这些新增的语义任务,ERNIE 2.0语义理解预训练模型从训练数据中获取了词法、句法、语义等多个维度的自然语言信息,极大地增强了通用语义表示能力。ERNIE 2.0模型在英语任务上几乎全面优于BERT和XLNet,在7个GLUE任务上取得了最好的结果;中文任务上,ERNIE 2.0模型在所有9个中文NLP任务上全面优于BERT

以单句分类任务(如情感分析)为例,介绍下游 NLP 任务的解决过程:

  1. 基于tokenization.py脚本中的Tokenizer对输入的句子进行token化,即按字粒度对句子进行切分;
  2. 分类标志符号[CLS]与token化后的句子拼接在一起作为ERNIE模型的输入,经过 ERNIE 前向计算后得到每个token对应的embedding向量表示;
  3. 在单句分类任务中,[CLS]位置对应的嵌入式向量会用来作为分类特征。只需将[CLS]对应的embedding抽取出来,再经过一个全连接层得到分类的 logits 值,最后经过softmax归一化后与训练数据中的label一起计算交叉熵,就得到了优化的损失函数;
  4. 经过几轮的fine-tuning,就可以训练出解决具体任务的ERNIE模型

PaddleOCR 在python中 识别不到中文 paddlepaddle pytorch_深度学习_06


关于ERNIE更详细的介绍,可以参考这两篇学术论文:

这里不对预训练过程作过多展开,主要关注如何使用ERNIE解决下游的NLP任务

3. 快速运行

3.1 数据获取

使用ERNIE 1.0中文Base模型进行推理分如下三个步骤:

  1. 数据获取。介绍如何下载ChnSentiCorp数据集,以及数据集的结构,这样用户可以参考数据集的结构构造用于Fine-tuning的数据集。此外如果用户希望使用自定义数据集进行训练,则可以仿照ChnSentiCorp数据集的结构,构建自己的数据集。
  2. 运行Fine-tuning。介绍如何设置数据和模型路径的环境变量,以及如何执行脚本进行Fine-tuning。
  3. 执行推理。使用脚本运行Fine-tuning成功的模型进行推理

ERNIE1.0/2.0和BERT的测评表:

PaddleOCR 在python中 识别不到中文 paddlepaddle pytorch_人工智能_07


在解压出的文件夹“task_data/chnsenticorp”中, 包含了三个文件“train.tsv”、“dev.tsv”、“test.tsv”,分别对应ChnSentiCorp 数据的训练集、验证集和测试集,该任务是一个单句分类任务,数据包含两个字段为“label”和“seg_a”,以“TAB”进行分隔,示例如下:

15.4寸笔记本的键盘确实爽,基本跟台式机差不多了,蛮喜欢数字小键盘,输数字特方便,样子也很美观,做工也相当不错    1
房间太小。其他的都一般。。。。。。。。。        0

3.2 运行Fine-tuning

4. 具体实现过程

ChnSentiCorp任务运行的shell脚本是 ERNIE/ernie/run_classifier.py,该文件定义了分类任务Fine-tuning 的详细过程,下面我们将通过如下几个步骤进行详细剖析:

  1. 环境准备。导入相关的依赖,解析命令行参数;
  2. 实例化ERNIE 模型,优化器以及Tokenizer, 并设置超参数
  3. 定义辅助函数
  4. 运行训练循环

文心ERNIE官网飞桨-ERNIE开源开发套件,关于短文本语义匹配—SimNet,关于PaddleHub可见官方文档,一个基于PaddlePaddle的对话情绪识别ERNIE的例子

paddle 官方API手册

PaddleOCR 在python中 识别不到中文 paddlepaddle pytorch_深度学习_08


batch = 1,Windows10跑不动啊…还是要用服务器来跑

batch = 32,服务器也会报错——空间不足:

SystemError: (Fatal) Operator transpose2 raises an paddle::memory::allocation::BadAlloc exception.
The exception content is
:ResourceExhaustedError: 

Out of memory error on GPU 0. Cannot allocate 28.125244MB memory on GPU 0, available memory is only 15.125000MB.

Please check whether there is any other process using GPU 0.
1. If yes, please stop them, or start PaddlePaddle on another GPU.
2. If no, please decrease the batch size of your model. 

 (at /paddle/paddle/fluid/memory/allocation/cuda_allocator.cc:69)
. (at /paddle/paddle/fluid/imperative/tracer.cc:172)

把batch改成16,迭代一次的结果:

处理数据...
数据处理完毕
train 0: loss 1.39022
acc 0.43750
train 10: loss 0.65691
train 20: loss 0.30401
train 30: loss 0.33995
train 40: loss 0.59606
train 50: loss 0.18500
train 60: loss 0.06302
train 70: loss 0.35887
train 80: loss 0.48943
train 90: loss 0.08381
train 100: loss 0.49257
acc 0.87583
train 110: loss 0.11619
train 120: loss 0.28160
train 130: loss 0.35791
train 140: loss 0.08042
train 150: loss 0.38628
train 160: loss 0.47405
train 170: loss 0.05887
train 180: loss 0.44965
train 190: loss 0.13820
train 200: loss 0.27198
acc 0.90083
train 210: loss 0.05554
train 220: loss 0.17605
train 230: loss 0.25577
train 240: loss 0.37898
train 250: loss 0.32266
train 260: loss 0.13249
train 270: loss 0.27485
train 280: loss 0.40180
train 290: loss 0.05420
train 300: loss 0.40033
acc 0.92083
train 310: loss 0.46246
train 320: loss 0.17745
train 330: loss 0.08070
train 340: loss 0.34510
train 350: loss 0.10435
train 360: loss 0.05032
train 370: loss 0.13808
train 380: loss 0.38950
train 390: loss 0.03985
train 400: loss 0.40710
acc 0.92667
train 410: loss 0.27796
train 420: loss 0.14017
train 430: loss 0.06830
train 440: loss 0.07608
train 450: loss 0.07652
train 460: loss 0.14043
train 470: loss 0.12281
train 480: loss 0.37106
train 490: loss 0.12451
train 500: loss 0.03355
acc 0.92333
train 510: loss 0.23477
train 520: loss 0.09174
train 530: loss 0.06336
train 540: loss 0.13199
train 550: loss 0.22460
train 560: loss 0.22263
train 570: loss 0.24220
train 580: loss 0.38265
train 590: loss 0.09730
train 0: loss 0.12224
acc 0.93833

下面看在我的任务上的表现,每100个batch,即1600个句子打印一次结果:

处理数据...
句子总数:609678 测试集总数:51619 验证集总数:12887
测试集总数:6582
数据处理完毕
train 0: loss 1.21110
Valuate acc 0.45559
Test acc 0.36542
...
train 100: loss 0.29471
Valuate acc 0.80264
Test acc 0.93218
...
train 200: loss 0.43836
Valuate acc 0.81110
Test acc 0.92336
...
train 300: loss 0.49043
Valuate acc 0.79099
Test acc 0.92716
...
train 400: loss 0.28850
Valuate acc 0.81203
Test acc 0.92290
...
train 500: loss 0.37162
Valuate acc 0.80963
Test acc 0.89021
...
train 600: loss 0.41896
Valuate acc 0.80606
Test acc 0.90313

可以发现,ERNIE 1.0 在原数据集上可以达到93%左右的正确率,比之前所有的模型效果都要好

5. 全部代码

BATCH = 16      # 根据显存大小调节BATCH大小
# MAX_SEQLEN = 300    # 设置好所有的超参数, 最大句子长度不超过512.
MAX_SEQLEN = 35
LR = 5e-5       # 对于ERNIE任务学习率推荐取1e-5/2e-5/5e-5
EPOCH = 10

import paddle.fluid.dygraph as D
D.guard().__enter__()   # 为了让Paddle进入动态图模式,需要添加这一行在最前面

from ernie.modeling_ernie import ErnieModelForSequenceClassification
path = '/mnt/Data1/ysc/model-ernie1.0.1'
ernie = ErnieModelForSequenceClassification.from_pretrained(pretrain_dir_or_url=path, num_labels=3)

import paddle.fluid as F
optimizer = F.optimizer.Adam(LR, parameter_list=ernie.parameters())

from ernie.tokenizing_ernie import ErnieTokenizer
tokenizer = ErnieTokenizer.from_pretrained(pretrain_dir_or_url=path)

import numpy as np
# def make_data(path):        # 定义函数 make_data,将文本数据读入内存并转换为numpy List存储
#     data = []
#     for i, l in enumerate(open(path, 'r', encoding='utf-8')):
#         # if i == 0:
#         #     continue
#         l = l.strip().split('\t')
#         text, label = l[0], int(l[1])
#         text_id, _ = tokenizer.encode(text)  # ErnieTokenizer 会自动添加ERNIE所需要的特殊token,如[CLS], [SEP]
#         text_id = text_id[:MAX_SEQLEN]
#         text_id = np.pad(text_id, [0, MAX_SEQLEN - len(text_id)], mode='constant')  # 对所有句子都补长至300,这样会比较费显存;
#         label_id = np.array(label + 1)
#         data.append((text_id, label_id))
#     return data

import random
def make_data_split(path):        # 定义函数 make_data,将文本数据读入内存并转换为numpy List存储
    train_data = []
    valuate_data = []
    total = 0
    for i, l in enumerate(open(path, 'r', encoding='utf-8')):
        total += 1
        if random.randint(1, 100) > 30: continue  # 100/30
        if l[-4:-1] == 'ORM':continue
        line = l[:-5].strip()
        if len(line)>MAX_SEQLEN:continue

        if l[-4:-1] == 'POS':
            label = 1
        elif l[-4:-1] == 'NEG':
            label = 0
        text_id, _ = tokenizer.encode(line)  # ErnieTokenizer 会自动添加ERNIE所需要的特殊token,如[CLS], [SEP]
        text_id = text_id[:MAX_SEQLEN]
        text_id = np.pad(text_id, [0, MAX_SEQLEN - len(text_id)], mode='constant')  # 对所有句子都补长至300,这样会比较费显存;
        label_id = np.array(label + 1)

        if random.randint(1,100) > 20:
            train_data.append((text_id, label_id))
        else:
            valuate_data.append((text_id, label_id))
    print('句子总数:{} 训练集总数:{} 验证集总数:{}'.format(total, len(train_data), len(valuate_data)))
    return train_data, valuate_data


def make_data(path):  # 定义函数 make_data,将文本数据读入内存并转换为numpy List存储
    test_data = []
    for i, l in enumerate(open(path, 'r', encoding='utf-8')):
        line = l[:-5].strip()
        if l[-4:-1] == 'POS':
            label = 1
        elif l[-4:-1] == 'NEG':
            label = 0
        text_id, _ = tokenizer.encode(line)  # ErnieTokenizer 会自动添加ERNIE所需要的特殊token,如[CLS], [SEP]
        text_id = text_id[:MAX_SEQLEN]
        text_id = np.pad(text_id, [0, MAX_SEQLEN - len(text_id)], mode='constant')  # 对所有句子都补长至300,这样会比较费显存;
        label_id = np.array(label + 1)
        test_data.append((text_id, label_id))

    print('测试集总数:{}'.format(len(test_data)))
    return test_data

print('处理数据...')
# train_data = make_data('/mnt/Data1/ysc/data-chnsenticorp/chnsenticorp/train/part.0')
# test_data = make_data('/mnt/Data1/ysc/data-chnsenticorp/chnsenticorp/dev/part.0')
train_data, valuate_data = make_data_split('/mnt/Data1/ysc/Data_Small.txt')
test_data = make_data('/mnt/Data1/ysc/Chinese review datasets/test.txt')
print('数据处理完毕')

def get_batch_data(data, i):
    d = data[i * BATCH: (i + 1) * BATCH]
    feature, label = zip(*d)        # len(feature) = 32, len(feature[0]) = 300
    feature = np.stack(feature)  # 将BATCH行样本整合在一个numpy.array中, feature.shape = (32, 300)
    label = np.stack(list(label))       # label.shape = (32,)
    feature = D.to_variable(feature)  # 使用to_variable将numpy.array转换为paddle tensor, feature.shape = [32, 300]
    label = D.to_variable(label)
    return feature, label

import paddle.fluid.layers as L
from sklearn.metrics import f1_score
for i in range(EPOCH):
    np.random.shuffle(train_data) # 每个epoch都shuffle数据以获得最佳训练效果;
    for j in range(len(train_data) // BATCH):       #train
        feature, label = get_batch_data(train_data, j)
        loss, _ = ernie(feature, labels=label)  # ernie模型的返回值包含(loss, logits);其中logits目前暂时不需要使用
        loss.backward()
        optimizer.minimize(loss)
        ernie.clear_gradients()
        if j % 10 == 0:
            print('train %d: loss %.5f' % (j, loss.numpy()))
        if j % 100 == 0:        # evaluate
            valuate_pred, valuate_label = [], []
            all_pred, all_label = [], []
            with D.base._switch_tracer_mode_guard_(is_train=False):  # 在这个with域内ernie不会进行梯度计算;
                ernie.eval()  # 控制模型进入eval模式,这将会关闭所有的dropout;
                for j in range(len(test_data) // BATCH):
                    feature, label = get_batch_data(test_data, j)
                    loss, logits = ernie(feature, labels=label)
                    all_pred.extend(L.argmax(logits, -1).numpy())
                    all_label.extend(label.numpy())
                for j in range(len(valuate_data) // BATCH):
                    feature, label = get_batch_data(valuate_data, j)
                    loss, logits = ernie(feature, labels=label)
                    valuate_pred.extend(L.argmax(logits, -1).numpy())
                    valuate_label.extend(label.numpy())
                ernie.train()

            f2 = f1_score(valuate_label, valuate_pred, average='macro')
            print(f2)
            acc = (np.array(valuate_label) == np.array(valuate_pred)).astype(np.float32).mean()
            print('Valuate acc %.5f' % acc)

            f1 = f1_score(all_label, all_pred, average='macro')
            print(f1)
            acc = (np.array(all_label) == np.array(all_pred)).astype(np.float32).mean()
            print('Test acc %.5f' % acc)

小结

ERNIE的表现可以说惊艳到我了,结果相当好,未来打算实践一下google BERT,或者哈工大讯飞的BERT,现在工作重心可以转移到语音及语言的学习上来了,有时间还可以学一下其它神经网络,例如生成对抗网络GAN、风格迁移等等…