自然语言处理(nlp)基于paddlenlp的短文本相似度计算(代码片段)

author author     2022-12-04     568

关键词:

【自然语言处理(NLP)】基于PaddleNLP的短文本相似度计算


(文章目录)


前言

(一)、任务描述

短文本语义匹配(SimailarityNet,SImNet)是一个计算短文本相似度的框架,可以根据用户输入的两个文本,计算出相似度得分。SimNet框架在百度各产品上广泛应用,主要包括BOW、CNN、RNN、MMDNN等核心网络结构形式,提供语义相似度计算训练和预测框架,适用于信息检索、新闻推荐、智能客服等多个应用场景,帮助企业解决语义匹配问题。可通过AI开放平台-短文本相似度线上体验。


(二)、工具描述

本实践将通过调用Seq2Vec中内置的模型进行序列建模,完成句子的向量表示。包含最简单的词袋模型和一系列经典的RNN类模型。


一、LCQMC数据准备

(一)、导入LCQMC

在实践中,我们使用PaddleNLP内置数据集LCQMC,这是哈尔滨工业大学在自然语言处理国际会议COLING2018构建的问题语义匹配数据集,其目标是判断两个问题的语义是否相同。部分样例数据如下图1所示:

from paddlenlp.datasets import LCQMC

train_ds, dev_dataset, test_ds = LCQMC.get_datasets([train, dev, test])

(二)、构建DataLoader

数据下载完成后需要构建一个dataloader,每次产生一个batch的数据传递给模型进行训练。

def create_dataloader(dataset,
                      trans_fn=None,
                      mode=train,
                      batch_size=1,
                      use_gpu=False,
                      batchify_fn=None):
    """
    Creats dataloader.
    Args:
        dataset(obj:`paddle.io.Dataset`): Dataset instance.
        trans_fn(obj:`callable`, optional, defaults to `None`): function to convert a data sample to input ids, etc.
        mode(obj:`str`, optional, defaults to obj:`train`): If mode is train, it will shuffle the dataset randomly.
        batch_size(obj:`int`, optional, defaults to 1): The sample number of a mini-batch.
        use_gpu(obj:`bool`, optional, defaults to obj:`False`): Whether to use gpu to run.
        batchify_fn(obj:`callable`, optional, defaults to `None`): function to generate mini-batch data by merging
            the sample list, None for only stack each fields of sample in axis
            0(same as :attr::`np.stack(..., axis=0)`).
    Returns:
        dataloader(obj:`paddle.io.DataLoader`): The dataloader which generates batches.
    """
    if trans_fn:
        dataset = dataset.map(trans_fn)

    if mode == train and use_gpu:
        sampler = paddle.io.DistributedBatchSampler(
            dataset=dataset, batch_size=batch_size, shuffle=True)
    else:
        shuffle = True if mode == train else False
        sampler = paddle.io.BatchSampler(
            dataset=dataset, batch_size=batch_size, shuffle=shuffle)
    dataloader = paddle.io.DataLoader(
        dataset,
        batch_sampler=sampler,
        return_list=True,
        collate_fn=batchify_fn)
    return dataloader

二、PaddleNLP模型配置

 # Constructs the newtork.
    model = ppnlp.models.SimNet(
        network=args.network,
        vocab_size=len(vocab),
        num_classes=len(train_ds.label_list))
    model = paddle.Model(model)

我们需要定义优化算法和损失函数,这里使用的是Adam优化算法,指定学习率为args.lr。损失函数使用的是交叉熵损失函数,该函数在分类任务上比较常用。定义了一个损失函数之后,还要对它求平均值,因为定义的是一个Batch的损失值。同时还可以定义一个准确率函数,可以在训练的时候输出分类的准确率。

optimizer = paddle.optimizer.Adam(
        parameters=model.parameters(), learning_rate=args.lr)

    # Defines loss and metric.
    criterion = paddle.nn.CrossEntropyLoss()
    metric = paddle.metric.Accuracy()

    model.prepare(optimizer, criterion, metric)

    # Loads pre-trained parameters.
    if args.init_from_ckpt:
        model.load(args.init_from_ckpt)
        print("Loaded checkpoint from %s" % args.init_from_ckpt)


三、模型训练

在模型训练之前,需要先下载词汇表文件simnet_vocab.txt,用于构造词-id映射关系。词表的选择和实际应用数据相关,需根据实际数据选择词表。然后就可以进行模型训练的评估。

!wget https://paddlenlp.bj.bcebos.com/data/simnet_vocab.txt

from functools import partial
import argparse
import os
import random
import time

import paddle
import paddlenlp as ppnlp
from paddlenlp.data import JiebaTokenizer, Pad, Stack, Tuple, Vocab
from paddlenlp.datasets import load_dataset

import numpy as np


def convert_example(example, tokenizer, is_test=False):
    """
    Builds model inputs from a sequence for sequence classification tasks. 
    It use `jieba.cut` to tokenize text.
    Args:
        example(obj:`list[str]`): List of input data, containing text and label if it have label.
        tokenizer(obj: paddlenlp.data.JiebaTokenizer): It use jieba to cut the chinese string.
        is_test(obj:`False`, defaults to `False`): Whether the example contains label or not.
    Returns:
        query_ids(obj:`list[int]`): The list of query ids.
        title_ids(obj:`list[int]`): The list of title ids.
        query_seq_len(obj:`int`): The input sequence query length.
        title_seq_len(obj:`int`): The input sequence title length.
        label(obj:`numpy.array`, data type of int64, optional): The input label if not is_test.
    """

    query, title = example["query"], example["title"]
    query_ids = np.array(tokenizer.encode(query), dtype="int64")
    query_seq_len = np.array(len(query_ids), dtype="int64")
    title_ids = np.array(tokenizer.encode(title), dtype="int64")
    title_seq_len = np.array(len(title_ids), dtype="int64")

    if not is_test:
        label = np.array(example["label"], dtype="int64")
        return query_ids, title_ids, query_seq_len, title_seq_len, label
    else:
        return query_ids, title_ids, query_seq_len, title_seq_len


# yapf: disable
parser = argparse.ArgumentParser(__doc__)
parser.add_argument("--epochs", type=int, default=10, help="Number of epoches for training.")
parser.add_argument(--use_gpu, type=eval, default=False, help="Whether use GPU for training, input should be True or False")
parser.add_argument("--lr", type=float, default=5e-4, help="Learning rate used to train.")
parser.add_argument("--save_dir", type=str, default=checkpoints/, help="Directory to save model checkpoint")
parser.add_argument("--batch_size", type=int, default=64, help="Total examples number of a batch for training.")
parser.add_argument("--vocab_path", type=str, default="./simnet_vocab.txt", help="The directory to dataset.")
parser.add_argument(--network, type=str, default="lstm", help="Which network you would like to choose bow, cnn, lstm or gru ?")
parser.add_argument("--init_from_ckpt", type=str, default=None, help="The path of checkpoint to be loaded.")
args = parser.parse_args()
# yapf: enable


def create_dataloader(dataset,
                      trans_fn=None,
                      mode=train,
                      batch_size=1,
                      use_gpu=False,
                      batchify_fn=None):
    """
    Creats dataloader.
    Args:
        dataset(obj:`paddle.io.Dataset`): Dataset instance.
        trans_fn(obj:`callable`, optional, defaults to `None`): function to convert a data sample to input ids, etc.
        mode(obj:`str`, optional, defaults to obj:`train`): If mode is train, it will shuffle the dataset randomly.
        batch_size(obj:`int`, optional, defaults to 1): The sample number of a mini-batch.
        use_gpu(obj:`bool`, optional, defaults to obj:`False`): Whether to use gpu to run.
        batchify_fn(obj:`callable`, optional, defaults to `None`): function to generate mini-batch data by merging
            the sample list, None for only stack each fields of sample in axis
            0(same as :attr::`np.stack(..., axis=0)`).
    Returns:
        dataloader(obj:`paddle.io.DataLoader`): The dataloader which generates batches.
    """
    if trans_fn:
        dataset = dataset.map(trans_fn)

    if mode == train and use_gpu:
        sampler = paddle.io.DistributedBatchSampler(
            dataset=dataset, batch_size=batch_size, shuffle=True)
    else:
        shuffle = True if mode == train else False
        sampler = paddle.io.BatchSampler(
            dataset=dataset, batch_size=batch_size, shuffle=shuffle)
    dataloader = paddle.io.DataLoader(
        dataset,
        batch_sampler=sampler,
        return_list=True,
        collate_fn=batchify_fn)
    return dataloader


if __name__ == "__main__":
    paddle.set_device(gpu) if args.use_gpu else paddle.set_device(cpu)

    # Loads vocab.
    if not os.path.exists(args.vocab_path):
        raise RuntimeError(The vocab_path  can not be found in the path %s %
                           args.vocab_path)
    vocab = Vocab.load_vocabulary(
        args.vocab_path, unk_token=[UNK], pad_token=[PAD])

    # Loads dataset.
    train_ds, dev_ds, test_ds = load_dataset(
        "lcqmc", splits=["train", "dev", "test"])

    # Constructs the newtork.
    model = ppnlp.models.SimNet(
        network=args.network,
        vocab_size=len(vocab),
        num_classes=len(train_ds.label_list))
    model = paddle.Model(model)

    # Reads data and generates mini-batches.
    batchify_fn = lambda samples, fn=Tuple(
        Pad(axis=0, pad_val=vocab.token_to_idx.get([PAD], 0)),  # query_ids
        Pad(axis=0, pad_val=vocab.token_to_idx.get([PAD], 0)),  # title_ids
        Stack(dtype="int64"),  # query_seq_lens
        Stack(dtype="int64"),  # title_seq_lens
        Stack(dtype="int64")  # label
    ): [data for data in fn(samples)]
    tokenizer = ppnlp.data.JiebaTokenizer(vocab)
    trans_fn = partial(convert_example, tokenizer=tokenizer, is_test=False)
    train_loader = create_dataloader(
        train_ds,
        trans_fn=trans_fn,
        batch_size=args.batch_size,
        mode=train,
        use_gpu=args.use_gpu,
        batchify_fn=batchify_fn)
    dev_loader = create_dataloader(
        dev_ds,
        trans_fn=trans_fn,
        batch_size=args.batch_size,
        mode=validation,
        use_gpu=args.use_gpu,
        batchify_fn=batchify_fn)
    test_loader = create_dataloader(
        test_ds,
        trans_fn=trans_fn,
        batch_size=args.batch_size,
        mode=test,
        use_gpu=args.use_gpu,
        batchify_fn=batchify_fn)

    optimizer = paddle.optimizer.Adam(
        parameters=model.parameters(), learning_rate=args.lr)

    # Defines loss and metric.
    criterion = paddle.nn.CrossEntropyLoss()
    metric = paddle.metric.Accuracy()

    model.prepare(optimizer, criterion, metric)

    # Loads pre-trained parameters.
    if args.init_from_ckpt:
        model.load(args.init_from_ckpt)
        print("Loaded checkpoint from %s" % args.init_from_ckpt)

    # Starts training and evaluating.
    model.fit(
        train_loader,
        dev_loader,
        epochs=args.epochs,
        save_dir=args.save_dir, )

    # Finally tests model.
    results = model.eval(test_loader)
    print("Finally test acc: %.5f" % results[acc])

总结

本系列文章内容为根据清华社出版的《自然语言处理实践》所作的相关笔记和感悟,其中代码均为基于百度飞桨开发,若有任何侵权和不妥之处,请私信于我,定积极配合处理,看到必回!!!

最后,引用本次活动的一句话,来作为文章的结语~( ̄▽ ̄~)~:

【**学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。**】

lsf-scnn:一种基于cnn的短文本表达模型及相似度计算的全新优化模型

...多腾讯海量技术实践干货哦~本篇文章是我在读期间,对自然语言处理中的文本相似度问题研究取得的一点小成果。如果你对自然语言处理(naturallanguageprocessing,NLP)和卷积神经网络(convolutionalneuralnetwork,CNN)有一定的了解,可以直... 查看详情

自然语言处理(nlp)基于paddlehub的文本审核(代码片段)

【自然语言处理(NLP)】基于PaddleHub的文本审核(文章目录)前言(一)、任务描述在2017年之前,工业界和学术界对NLP文本处理依赖于序列模型RecurrentNeuralNetwork(RNN).近年来随着深度学习的发展,模型参数数量飞速增长,为了训练这些... 查看详情

自然语言处理(nlp)基于squad的机器阅读理解(代码片段)

【自然语言处理(NLP)】基于SQuAD的机器阅读理解(文章目录)前言(一)、任务描述机器阅读理解(MachingReadingComprehension,MRC)是一项基于文本的问答任务(Text-QA),也是非常重要和经典的自然语言处理任务之一。机器阅读理解旨... 查看详情

自然语言处理(nlp)基于transformer的英文自动文摘(代码片段)

【自然语言处理(NLP)】基于Transformer的英文自动文摘(文章目录)前言(一)、任务描述本示例教程介绍如何使用飞桨完成一个机器翻译任务。我们将会使用飞桨提供的开源框架完成基于Transformer的英文文本自动文摘模型。飞桨框架... 查看详情

自然语言处理(nlp)基于ernie语言模型的文本语义匹配(代码片段)

【自然语言处理(NLP)】基于ERNIE语言模型的文本语义匹配(文章目录)前言(一)、任务描述文本匹配一直是自然语言处理(NLP)领域一个基础且重要的方向,一般研究两段文本之间的关系。文本相似度计算、自然语言推理、问答系... 查看详情

自然语言处理(nlp)基于lstm的命名实体识别(代码片段)

【自然语言处理(NLP)】基于LSTM的命名实体识别(文章目录)前言(一)、任务描述命名实体识别任务主要识别文本中的实体,并且给识别出的实体进行分类,比如人名、地名、机构名或其它类型。本质上,对于给定的文本,只需要... 查看详情

自然语言处理(nlp)基于lstm的谣言检测(代码片段)

【自然语言处理(NLP)】基于LSTM的谣言检测(文章目录)前言(一)、任务描述本次实践使用基于循环神经网络(RNN)的谣言检测模型,将文本中的谣言事件向量化,通过循环神经网络的学习训练来挖掘表示文本深层的特征,避免了... 查看详情

自然语言处理(nlp)基于注意力机制的英文新闻标题生成(代码片段)

【自然语言处理(NLP)】基于注意力机制的英文新闻标题生成(文章目录)前言(一)、任务描述我们将会使用飞桨提供的LSTM的API,组建一个sequencetosequencewithattention的自动文摘的模型,并在示例的数据集上完成从英文文章生成英文摘... 查看详情

自然语言处理(nlp)基于bi-daf的机器阅读理解(代码片段)

【自然语言处理(NLP)】基于Bi-DAF的机器阅读理解(文章目录)前言(一)、任务描述在机器阅读理解(MRC)任务中,我们会给定一个问题(Q)以及一个或多个段落(P)/文档(D),然后利用机器在给定的段落中寻找正确答案(A),即Q+PorD=>A.机... 查看详情

自然语言处理(nlp)基于bilstm的关系抽取(代码片段)

【自然语言处理(NLP)】基于BiLSTM的关系抽取(文章目录)前言(一)、任务描述关系抽取是信息抽取的重要子任务,其主要目的是将非结构化获半结构化描述的自然语言文本转化成结构化数据,关系抽取主要负责对文本中抽取出的... 查看详情

自然语言处理(nlp)基于bilstm+crf的事件抽取(代码片段)

【自然语言处理(NLP)】基于BiLSTM+CRF的事件抽取(文章目录)前言(一)、任务描述事件抽取技术是从非结构化信息中抽取出用户感兴趣的事件,并以结构化呈现给用户。事件抽取任务可分解为4个子任务:触发词识别、事件类型分类... 查看详情

自然语言处理(nlp)基于gru实现情感分类(代码片段)

【自然语言处理(NLP)】基于GRU实现情感分类@TOC前言任务描述任务描述:本示例教程演示如何在IMDB数据集上用GRU网络完成文本分类的任务。IMDB数据集是一个对电影评论标注为正向评论与负向评论的数据集,共有25000条文本数据... 查看详情

自然语言处理(nlp):24基于文本语义的智能问答系统

...https://edu.51cto.com/course/25919.html​​0开篇介绍问答系统是自然语言处理领域一个很经典的问题,它用于回答人们以自然语言形式提出的问题,有着广泛的应用。经典应用场景包括:智能语音交互、在线客服、知识获取、情感类聊... 查看详情

自然语言处理(nlp)基于transformer的中-英机器翻译(代码片段)

【自然语言处理(NLP)】基于Transformer的中-英机器翻译(文章目录)前言(一)、任务描述飞桨框架实现了Transformer的基本层,因此可以直接调用:TransformerEncoderLayer类定义了编码器端的一个层,包括多头注意力子层及逐位前馈网络子... 查看详情

nlp老司机带你入门自然语言处理

自然语言处理是一门用于理解人类语言、情感和思想的技术,被称为是人工智能皇冠上的明珠。 随着深度学习发展,自然语言处理技术近年来发展迅速,在技术上表现为BERT、GPT等表现极佳的模型;在应用中表现为chatbot、知... 查看详情

自然语言处理(nlp)基于循环神经网络实现情感分类(代码片段)

【自然语言处理(NLP)】基于循环神经网络实现情感分类@TOC任务描述本示例教程演示如何在IMDB数据集上用RNN网络完成文本分类的任务。IMDB数据集是一个对电影评论标注为正向评论与负向评论的数据集,共有25000条文本数据作为... 查看详情

回望2017,基于深度学习的nlp研究大盘点

...于tryolabs的文章,作者JavierCouto针对2017年基于深度学习的自然语言处理研究进行了大盘点。雷锋网AI科技评论根据原文进行了编译。在过去的几年里,深度学习(DL)架构和算法在诸如图像识别和语音处理等领域取得了世人瞩目的... 查看详情

自然语言处理(nlp)基于fnn网络的电影评论情感分析(代码片段)

【自然语言处理(NLP)】基于FNN网络的电影评论情感分析作者简介:在校大学生一枚,华为云享专家,阿里云专家博主,腾云先锋(TDP)成员,云曦智划项目总负责人,全国高等学校计算机... 查看详情