PaddleHub实战:使用ERNIE预训练模型优化新闻文本分类

目录

一、PaddleHub与ERNIE模型简介

二、新闻文本分类流程

注意

PART I. 加载自定义数据集

PART II. PaddleHub一键加载ERNIE

PART III. 构建Reader

PART IV、选择Fine-Tune优化策略

PART V. 选择运行配置

PART VI. 组建Finetune Task

Part VII. 开始Finetune

PART VIII. 使用模型进行预测


在当前的大数据环境下,新闻文本分类已经成为了一个相当重要的应用领域。新闻文本分类的准确度会直接影响信息检索、个性化推荐等许多关键应用的性能。本文将详细阐述如何使用PaddlePaddle的PaddleHub和ERNIE预训练模型来优化新闻文本分类任务。

一、PaddleHub与ERNIE模型简介

PaddleHub是飞桨PaddlePaddle开发的预训练模型应用工具,可以提供大量的预训练模型,并支持一键加载和快速微调。

ERNIE(Enhanced Representation through Knowledge Integration)是百度开发的基于知识增强的语义预训练模型,它在多项中文NLP任务中都取得了显著的效果。

二、新闻文本分类流程

使用ERNIE模型进行新闻文本分类的大致流程如下:

  1. 数据准备:对原始新闻文本进行预处理,包括清理文本、分词、构建词汇表等。

  2. 模型选择:加载预训练的ERNIE模型。

  3. 模型训练:利用处理好的数据对模型进行训练,通过监督学习的方式使模型学会正确分类。

  4. 模型评估与优化:在验证集上对模型进行评估,查看其在未见过的数据上的效果,并根据结果调整模型参数进行优化。

  5. 模型测试:在测试集上运行模型,检查其最终的分类效果。

注意

本项目代码需要使用GPU环境来运行:



并且检查相关参数设置, 例如use_gpu, fluid.CUDAPlace(0)等处是否设置正确.

本项目将演示,如何使用PaddleHub语义预训练模型ERNIE对自定义数据集完成文本分类。

PART I. 加载自定义数据集

本示例数据集是由清华大学提供的新闻文本数据集THUCNews。THUCNews是根据新浪新闻RSS订阅频道2005~2011年间的历史数据筛选过滤生成,包含74万篇新闻文档(2.19 GB),均为UTF-8纯文本格式。我们在原始新浪新闻分类体系的基础上,重新整合划分出14个候选分类类别:财经、彩票、房产、股票、家居、教育、科技、社会、时尚、时政、体育、星座、游戏、娱乐。为了快速展示如何使用PaddleHub完成文本分类任务,该示例数据集从THUCNews训练集中随机抽取了9000条文本数据集作为本示例的训练集,从验证集中14个类别每个类别随机抽取100条数据作为本示例的验证集,测试集抽取方式和验证集相同。

首先解压数据集。

In [1]

# 查看当前挂载的数据集目录, 该目录下的变更重启环境后会自动还原
# View dataset directory. This directory will be recovered automatically after resetting environment.
%cd /home/aistudio/data/data16287/
!tar -zxvf thu_news.tar.gz
!ls -hl thu_news

!head -n 3 thu_news/train.txt

!pip install paddlehub==1.6.2 -i https://pypi.tuna.tsinghua.edu.cn/simple

加载自定义数据集,用户仅需要继承HubDataset类,替换数据集存放地址即可。 下面代码示例展示如何将自定义数据集加载进PaddleHub使用。

具体详情可参考 加载自定义数据集

In [2]

from paddlehub.dataset.base_nlp_dataset import BaseNLPDataset

class ThuNews(BaseNLPDataset):
    def __init__(self):
        # 数据集存放位置
        self.dataset_dir = "/home/aistudio/data/data16287/thu_news"
        super(ThuNews, self).__init__(
            base_path=self.dataset_dir,
            train_file="train.txt",
            dev_file="valid.txt",
            test_file="test.txt",
            train_file_with_header=True,
            dev_file_with_header=True,
            test_file_with_header=True,
            # 数据集类别集合
            label_list=['体育', '科技', '社会', '娱乐', '股票', '房产', '教育', '时政', '财经', '星座', '游戏', '家居', '彩票', '时尚'])
dataset = ThuNews()
for e in dataset.get_train_examples()[:3]:
    print("{}\t{}\t{}".format(e.guid, e.text_a, e.label))

PART II. PaddleHub一键加载ERNIE

In [3]

import paddlehub as hub
module = hub.Module(name="ernie")

如果想尝试其他语义模型(如ernie_tiny, RoBERTa等),只需要更换Module中的name参数即可.

模型名 PaddleHub Module
ERNIE, Chinese hub.Module(name='ernie')
ERNIE 2.0 Tiny, Chinese hub.Module(name='ernie_tiny')
ERNIE 2.0 Base, English hub.Module(name='ernie_v2_eng_base')
ERNIE 2.0 Large, English hub.Module(name='ernie_v2_eng_large')
RoBERTa-Large, Chinese hub.Module(name='roberta_wwm_ext_chinese_L-24_H-1024_A-16')
RoBERTa-Base, Chinese hub.Module(name='roberta_wwm_ext_chinese_L-12_H-768_A-12')
BERT-Base, Uncased hub.Module(name='bert_uncased_L-12_H-768_A-12')
BERT-Large, Uncased hub.Module(name='bert_uncased_L-24_H-1024_A-16')
BERT-Base, Cased hub.Module(name='bert_cased_L-12_H-768_A-12')
BERT-Large, Cased hub.Module(name='bert_cased_L-24_H-1024_A-16')
BERT-Base, Multilingual Cased hub.Module(nane='bert_multi_cased_L-12_H-768_A-12')
BERT-Base, Chinese hub.Module(name='bert_chinese_L-12_H-768_A-12')

PART III. 构建Reader

接着生成一个文本分类的reader,reader负责将dataset的数据进行预处理,首先对文本进行切词,接着以特定格式组织并输入给模型进行训练。

ClassifyReader的参数有以下三个:

  • dataset: 传入PaddleHub Dataset;
  • vocab_path: 传入ERNIE/BERT模型对应的词表文件路径;
  • max_seq_len: ERNIE模型的最大序列长度,若序列长度不足,会通过padding方式补到max_seq_len, 若序列长度大于该值,则会以截断方式让序列长度为max_seq_len;
  • sp_model_path: 传入 ERNIE tiny的subword切分模型路径;
  • word_dict_path: 传入 ERNIE tiny的词语切分模型路径;

In [4]

reader = hub.reader.ClassifyReader(
    dataset=dataset,
    vocab_path=module.get_vocab_path(),
    sp_model_path=module.get_spm_path(),
    word_dict_path=module.get_word_dict_path(),
    max_seq_len=128)

PART IV、选择Fine-Tune优化策略

适用于ERNIE/BERT这类Transformer模型的迁移优化策略为AdamWeightDecayStrategy。详情请查看Strategy

AdamWeightDecayStrategy的参数:

  • learning_rate: 最大学习率
  • lr_scheduler: 有linear_decaynoam_decay两种衰减策略可选
  • warmup_proprotion: 训练预热的比例,若设置为0.1, 则会在前10%的训练step中学习率逐步提升到learning_rate
  • weight_decay: 权重衰减,类似模型正则项策略,避免模型overfitting
  • optimizer_name: 优化器名称

In [5]

strategy = hub.AdamWeightDecayStrategy(
    weight_decay=0.01,
    warmup_proportion=0.1,
    learning_rate=5e-5)

PaddleHub提供了许多优化策略,如AdamWeightDecayStrategyULMFiTStrategyDefaultFinetuneStrategy等,详细信息参见策略

PART V. 选择运行配置

在进行Finetune前,我们可以设置一些运行时的配置,例如如下代码中的配置,表示:

  • use_cuda:设置为False表示使用CPU进行训练。如果您本机支持GPU,且安装的是GPU版本的PaddlePaddle,我们建议您将这个选项设置为True;

  • num_epoch:Finetune时遍历训练集的次数,;

  • batch_size:每次训练的时候,给模型输入的每批数据大小为16,模型训练时能够并行处理批数据,因此batch_size越大,训练的效率越高,但是同时带来了内存的负荷,过大的batch_size可能导致内存不足而无法训练,因此选择一个合适的batch_size是很重要的一步;

  • log_interval:每隔10 step打印一次训练日志;

  • eval_interval:每隔50 step在验证集上进行一次性能评估;

  • checkpoint_dir:训练的参数和数据的保存目录;

  • strategy:Fine-tune策略;

  • use_data_parallel: 设置为False表示单卡训练;设置为True表示多卡训练

  • use_pyreader: 设置为False表示不使用py_reader读取数据;设置为True表示使用py_reader读取数据

更多运行配置,请查看RunConfig

In [6]

config = hub.RunConfig(
    use_cuda=True,
    num_epoch=1,
    checkpoint_dir="hub_ernie_text_cls_demo",
    batch_size=32,
    eval_interval=50,
    strategy=strategy)

PART VI. 组建Finetune Task

有了合适的预训练模型和准备要迁移的数据集后,我们开始组建一个Task。

  1. 获取module的上下文环境,包括输入和输出的变量,以及Paddle Program;
  2. 从输出变量中找到用于情感分类的文本特征pooled_output;
  3. 在pooled_output后面接入一个全连接层,生成Task;

TextClassifierTask的参数有:

  • data_reader:读取数据的reader;

  • config: 运行配置;

  • feature:从预训练提取的特征;

  • feed_list:program需要输入的变量;

  • num_classes:数据集的类别数量;

  • metric_choic:任务评估指标,默认为"acc"。metrics_choices支持训练过程中同时评估多个指标,作为最佳模型的判断依据,例如["matthews", "acc"],"matthews"将作为主指标,为最佳模型的判断依据;

In [7]

inputs, outputs, program = module.context(
    trainable=True, max_seq_len=128)

# Use "pooled_output" for classification tasks on an entire sentence.
pooled_output = outputs["pooled_output"]

feed_list = [
    inputs["input_ids"].name,
    inputs["position_ids"].name,
    inputs["segment_ids"].name,
    inputs["input_mask"].name,
]

cls_task = hub.TextClassifierTask(
        data_reader=reader,
        feature=pooled_output,
        feed_list=feed_list,
        num_classes=dataset.num_labels,
        config=config,
        metrics_choices=["acc"])

NOTE: Reader参数max_seq_len、moduel的context接口参数max_seq_len三者应该保持一致,最大序列长度max_seq_len是可以调整的参数,建议值128,根据任务文本长度不同可以调整该值,但最大不超过512。

如果想改变迁移任务组网,详细参见自定义迁移任务

Part VII. 开始Finetune

我们选择finetune_and_eval接口来进行模型训练,这个接口在finetune的过程中,会周期性的进行模型效果的评估,以便我们了解整个训练过程的性能变化。

In [8]

run_states = cls_task.finetune_and_eval()

PART VIII. 使用模型进行预测

当Finetune完成后,我们使用模型来进行预测,整个预测流程大致可以分为以下几步:

  1. 构建网络
  2. 生成预测数据的Reader
  3. 切换到预测的Program
  4. 加载预训练好的参数
  5. 运行Program进行预测

预测代码如下:

In [9]

import numpy as np
    
inv_label_map = {val: key for key, val in reader.label_map.items()}

# Data to be prdicted
data = [[d.text_a, d.text_b] for d in dataset.get_test_examples()[:3]]

index = 0
run_states = cls_task.predict(data=data)

results = [run_state.run_results for run_state in run_states]
for batch_result in results:
    # get predict index
    batch_result = np.argmax(batch_result, axis=2)[0]
    for result in batch_result:
        print("%s\tpredict=%s" % (data[index][0], inv_label_map[result]))
        index += 1

总的来说,PaddleHub完成迁移学习过程只需下图所展示的6步即可完成。

猜你喜欢

转载自blog.csdn.net/m0_68036862/article/details/131359583