热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

『跟着雨哥学AI』系列之八:趣味案例——有关NLP任务数据预处理的那些事儿...

点击左上方蓝字关注我们课程简介:“跟着雨哥学AI”是百度飞桨开源框架近期针对高层API推出的系列课。本课程由多位资深飞桨工程师精心打造,不仅提供了从数据

点击左上方蓝字关注我们

课程简介:

“跟着雨哥学AI”是百度飞桨开源框架近期针对高层API推出的系列课。本课程由多位资深飞桨工程师精心打造,不仅提供了从数据处理、到模型组网、模型训练、模型评估和推理部署全流程讲解;还提供了丰富的趣味案例,旨在帮助开发者更全面清晰地掌握百度飞桨框架的用法,并能够举一反三、灵活使用飞桨框架进行深度学习实践。

嗨,同学们好久不见!我是雨哥,之前的知识大家都有好好掌握吗?本节课我们将学习自然语言处理领域的相关知识。大家都知道,深度学习模型的内部包含了各种各样的数据运算,但是这些运算都是通过数字来进行的;而在自然语言处理的任务中,输入数据都是文本类型。那么我们如何将文本类型的数据转变成模型可以识别的内容,这就是我们本节课要学习的知识啦。针对不同的任务和数据集,数据处理的细节上可能会有所不同,但是大致的流程相似。我们将以NLP任务中的文本分类和命名实体识别任务作为示范,大家可以通过本节课的学习举一反三。

本次课程链接:

https://aistudio.baidu.com/aistudio/projectdetail/1579435

1. 文本分类

文本分类即给定一段文本(也可能是文档级别,在此只讨论句子级别),然后将文本归为N个类别中的一个或者多个。文本分类常见的应用有垃圾邮件识别、情感分析等等。根据类别个数的不同,可以分为二分类和多分类问题。我们今天使用的数据集只包含0、1标签,是一个二分类的任务。多分类任务的过程与此类似,可以参考本教程稍作改动。

1.1 数据集下载

我们选用微博评论数据集为例,正负向评论均包含五万多条。

首先我们对数据集进行解压:

!unzip -q -o data/data69383/weibo_senti_100k.zip

解压后我们可以看到,该数据集包含一个csv文件,里面包含评论句子以及其对应的标签,1表示正向积极的评论,0表示负向消极的评论。

import pandas as pd
import paddlepaddle.set_device('gpu')content = pd.read_csv('weibo_senti_100k.csv')
content = content.dropna()   # 去掉有缺失值的行
content.head(5)label                                             review
0      1              更博了,爆照了,帅的呀,就是越来越爱你!生快傻缺[爱你][爱你][爱你]
1      1  @张晓鹏jonathan 土耳其的事要认真对待[哈哈],否则直接开除。@丁丁看世界 很是细心...
2      1  姑娘都羡慕你呢…还有招财猫高兴……//@爱在蔓延-JC:[哈哈]小学徒一枚,等着明天见您呢/...
3      1                                         美~~~~~[爱你]
4      1                                  梦想有多大,舞台就有多大![鼓掌]

读取数据后,我们将数据处理成[sentence, label]的格式存在列表中,并将数据集打乱。由于此数据集未划分训练集、验证集和测试集,所以我们需要手动划分,作为案例,在这里只取1000条作为训练集,100条作为验证集,大家可以根据自己的需求进行划分。

import random# 指定seed让每次打乱顺序一样
random.seed(123)label = content.iloc[:, 0]
text = content.iloc[:, 1]data = []
for i in range(len(text)):data.append([text[i], label[i]])random.shuffle(data)
print('数据集句子数:{}'.format(len(data)))train_data = data[:1000]
dev_data = data[-100:]print('训练集句子数:{}'.format(len(train_data)))
print('验证集句子数:{}'.format(len(dev_data)))
数据集句子数:119988
训练集句子数:1000
验证集句子数:100

1.2 构建词表

前面提到了,模型计算使用的都是数字,而我们现在获取到的数据集还是文本类型,如何将文本映射到数据呢?我们将通过这一步构建的词表来进行映射。

# 下载词汇表文件word_dict.txt,用于构造词-id映射关系。
!wget https://paddlenlp.bj.bcebos.com/data/senta_word_dict.txt

# 加载词表
def load_vocab(path):vocab = {}with open(path, 'r') as f:tokens = f.readlines()for idx, token in enumerate(tokens):token = token.rstrip("\n").split("\t")[0]vocab[token] = idxreturn vocabvocab = load_vocab('senta_word_dict.txt')print('词表大小:{}'.format(len(vocab)))# 展示词表内容
for i, (k, v) in enumerate(vocab.items()):if i in range(0, 10):print(k, v)
词表大小:1256608
[PAD] 0
[UNK] 1
一斤三 2
意面屋 3
11点25分 4
2.0三厢 5
上杭路 6
意大利菜用料 7
菲拉斯 8
還么 9

1.3 数据加载

读取数据之后,需要自定义数据集,实现一个新的Dataset类,继承父类paddle.io.Dataset,并实现父类中的两个抽象方法:__getitem__和__len__。

在__getitem__方法中,我们根据上一步构建的词表,进行了一个词-id的映射,并且根据给定的max_len对句子进行了padding或截断。

import jieba
from paddle.io import Datasetclass TextDataset(Dataset):def __init__(self, data, vocab, max_len):super(TextDataset, self).__init__()self.data &#61; dataself.vocab &#61; vocabself.max_len &#61; max_lendef __getitem__(self, idx):sent &#61; self.data[idx][0]label &#61; self.data[idx][1]# 利用jieba对中文进行分词&#xff0c;再映射到idsent_idx &#61; [self.vocab[word] if word in self.vocab else vocab[&#39;[UNK]&#39;] for word in jieba.cut(sent)]# 不够max_len长度的补0&#xff0c;超出的截掉if len(sent_idx) <&#61; self.max_len:sent_idx &#43;&#61; [vocab[&#39;[PAD]&#39;] for _ in range(self.max_len - len(sent_idx))]else:sent_idx &#61; sent_idx[:self.max_len]return sent_idx, labeldef __len__(self):return len(self.data)def get_labels(self):return [&#39;0&#39;, &#39;1&#39;]

train_ds &#61; TextDataset(train_data, vocab, max_len&#61;100)
dev_ds &#61; TextDataset(dev_data, vocab, max_len&#61;100)print(train_ds[0])
print(dev_ds[0])
([1, 1203981, 269746, 620612, 358475, 340363, 421393, 147537, 115030, 535777, 269746, 300363, 358475, 828868, 828868, 327208, 865881, 661652, 1, 62211, 828868, 828868, 327208, 1, 459120, 62211, 553315, 1057229, 409314, 4783, 828868, 828868, 327208, 346505, 733784, 1231390, 1, 62211, 1, 877224, 1106339, 850865, 389733, 1093154, 1106328, 1, 666731, 932352, 237839, 428598, 147537, 823066, 1106326, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0)
([1, 202379, 173188, 705655, 749968, 823066, 1106328, 1124478, 991056, 1084488, 1, 340521, 173188, 1, 348895, 1106339, 382479, 421393, 166145, 1093154, 136954, 269746, 365925, 358475, 4783, 977896, 511894, 823116, 1208194, 1211275, 115414, 173188, 489131, 667149, 1106339, 489131, 1023964, 1106328, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0)

1.4 模型训练

在数据处理好之后&#xff0c;我们就可以根据自己定义的模型进行训练啦&#xff0c;在这里仅讨论数据处理部分&#xff0c;模型的组建大家可以参考我们之前的教程。

# 省略模型组建及实例化过程# 模型训练
model.prepare(optimizer, loss, metrics)
model.fit(train_ds, dev_ds, epochs&#61;50, batch_size&#61;32, verbose&#61;1)

2. 命名实体识别

命名实体识别&#xff08;Named Entity Recognition&#xff0c;NER&#xff09;是NLP中一项非常基础的任务&#xff0c;是信息提取、问答系统、句法分析、机器翻译等众多NLP任务的重要基础工具&#xff0c;其准确度决定了下游任务的效果&#xff0c;是NLP中非常重要的一个基础问题。首先&#xff0c;我们需要了解实体的概念&#xff0c;包括人名、地名、组织结构名以及其他专有名词。根据数据集的不同&#xff0c;实体类别的个数也不相同。例如&#xff0c;本例中使用的CoNLL2003数据集只包含4种实体类别&#xff0c;而另一个NER任务的常用数据集OntoNotes5.0则包含18种实体类别。

2.1 数据集下载

我们采用命名实体识别常用数据集CoNLL2003&#xff0c;该数据集已经为我们划分好训练集、验证集以及测试集。数据集内格式为[word, label]&#xff1a;

SOCCER O 
- O 
JAPAN B-LOC 
GET O 
LUCKY O 
WIN O 
, O 
CHINA B-PER 
IN O 
SURPRISE O 
DEFEAT O 
. O 

此数据集包含四中实体类别&#xff0c;分别为人名(PER)、地名(LOC)、组织机构名(ORG)、其他(MISC)。并且采用BIO的标注方式&#xff0c;B表示实体的起始单词&#xff0c;I表示实体内部单词&#xff0c;O表示非实体。

import paddle
import numpy as npdef load_data(path):data &#61; list()with open(path, &#39;r&#39;) as f:words, labels &#61; list(), list()for line in f:line &#61; line.strip()if line:w, l &#61; line.split()words.append(w)labels.append(l)else:data.append([words, labels])words, labels &#61; list(), list()if words:data.append([words, labels])return datatrain_data &#61; load_data(&#39;data/data7933/train.txt&#39;)
dev_data &#61; load_data(&#39;data/data7933/dev.txt&#39;)print(&#39;训练集句子数&#xff1a;{}&#39;.format(len(train_data)))
print(train_data[0])
print(&#39;验证集句子数&#xff1a;{}&#39;.format(len(dev_data)))
print(dev_data[0])
训练集句子数&#xff1a;14986
[[&#39;EU&#39;, &#39;rejects&#39;, &#39;German&#39;, &#39;call&#39;, &#39;to&#39;, &#39;boycott&#39;, &#39;British&#39;, &#39;lamb&#39;, &#39;.&#39;], [&#39;B-ORG&#39;, &#39;O&#39;, &#39;B-MISC&#39;, &#39;O&#39;, &#39;O&#39;, &#39;O&#39;, &#39;B-MISC&#39;, &#39;O&#39;, &#39;O&#39;]]
验证集句子数&#xff1a;3465
[[&#39;CRICKET&#39;, &#39;-&#39;, &#39;LEICESTERSHIRE&#39;, &#39;TAKE&#39;, &#39;OVER&#39;, &#39;AT&#39;, &#39;TOP&#39;, &#39;AFTER&#39;, &#39;INNINGS&#39;, &#39;VICTORY&#39;, &#39;.&#39;], [&#39;O&#39;, &#39;O&#39;, &#39;B-ORG&#39;, &#39;O&#39;, &#39;O&#39;, &#39;O&#39;, &#39;O&#39;, &#39;O&#39;, &#39;O&#39;, &#39;O&#39;, &#39;O&#39;]]

2.2 构建词表

这里我们采用手动构建词表的方式&#xff0c;读取训练集中的数据&#xff0c;分别构建词-id、标签-id的映射关系。

# 根据训练集的数据构建词表
def create_vocab(data, save_path):word_list &#61; [&#39;[PAD]&#39;, &#39;[UNK]&#39;]label_list &#61; []for i in range(len(data)):for word in data[i][0]:if word not in word_list:word_list.append(word)for label in data[i][1]:if label not in label_list:label_list.append(label)with open(save_path &#43; &#39;word_dict.txt&#39;, &#39;w&#39;) as file1:for i, w in enumerate(word_list):file1.write(w &#43; &#39; &#39; &#43; str(i) &#43; &#39;\n&#39;)with open(save_path &#43; &#39;label_dict.txt&#39;, &#39;w&#39;) as file2:for i, l in enumerate(label_list):file2.write(l &#43; &#39; &#39; &#43; str(i) &#43; &#39;\n&#39;)create_vocab(train_data, &#39;data/data7933/&#39;)

def load_vocab(word_dict_path, label_dict_path):word_dict, label_dict &#61; {}, {}with open(word_dict_path,&#39;r&#39;) as f1:for line in f1:word, idx &#61; line.strip().split()word_dict[word] &#61; idxwith open(label_dict_path, &#39;r&#39;) as f2:for line in f2:label, idx &#61; line.strip().split()label_dict[label] &#61; idxreturn word_dict, label_dictword_dict, label_dict &#61; load_vocab(&#39;data/data7933/word_dict.txt&#39;, &#39;data/data7933/label_dict.txt&#39;)print(&#39;词表大小&#xff1a;{}&#39;.format(len(word_dict)))
print(&#39;标签个数&#xff1a;{}&#39;.format(len(label_dict)))
词表大小&#xff1a;23626
标签个数&#xff1a;9

2.3 数据加载

PaddleNLP中提供了很多用于文本处理的接口&#xff0c;这里我们结合PaddleNLP进行数据集的构建以及加载。

# 首先安装paddlenlp
!pip install paddlenlp&#61;&#61;2.0.0b

import paddlenlp
from paddlenlp.data import Stack, Tuple, Pad# 将词或标签转换为id
def convert_tokens_to_ids(tokens, vocab, unk_token&#61;None):token_ids &#61; []unk_id &#61; vocab.get(unk_token) if unk_token else Nonefor token in tokens:token_id &#61; vocab.get(token, unk_id)token_ids.append(token_id)return token_ids# 自定义数据集
class NERDataset(paddle.io.Dataset):def __init__(self, data, word_dict, label_dict):self.data &#61; dataself.word_dict &#61; word_dictself.label_dict &#61; label_dictdef __len__(self):return len(self.data)def __getitem__(self, idx):words &#61; self.data[idx][0]labels &#61; self.data[idx][1]word_ids &#61; convert_tokens_to_ids(words, self.word_dict, unk_token&#61;&#39;[UNK]&#39;)label_ids &#61; convert_tokens_to_ids(labels, self.label_dict)return word_ids, len(word_ids), label_idstrain_ds &#61; NERDataset(train_data, word_dict, label_dict)
dev_ds &#61; NERDataset(dev_data, word_dict, label_dict)print(train_ds[0])
([&#39;2&#39;, &#39;3&#39;, &#39;4&#39;, &#39;5&#39;, &#39;6&#39;, &#39;7&#39;, &#39;8&#39;, &#39;9&#39;, &#39;10&#39;], 9, [&#39;0&#39;, &#39;1&#39;, &#39;2&#39;, &#39;1&#39;, &#39;1&#39;, &#39;1&#39;, &#39;2&#39;, &#39;1&#39;, &#39;1&#39;])

 

# 构建dataloader
batchify_fn &#61; lambda samples, fn&#61;Tuple(Pad(axis&#61;0, pad_val&#61;train_ds.word_dict[&#39;[PAD]&#39;]),  # wordStack(),  # seq_lenPad(axis&#61;0, pad_val&#61;train_ds.word_dict[&#39;[PAD]&#39;])  # label 
): fn(samples)train_loader &#61; paddle.io.DataLoader(dataset&#61;train_ds,batch_size&#61;32,shuffle&#61;True,drop_last&#61;True,return_list&#61;True,collate_fn&#61;batchify_fn
)dev_loader &#61; paddle.io.DataLoader(dataset&#61;dev_ds,batch_size&#61;32,drop_last&#61;True,return_list&#61;True,collate_fn&#61;batchify_fn
)print(len(train_loader))
print(len(dev_loader))468
108

2.4 模型训练

同样的&#xff0c;我们处理好数据之后&#xff0c;根据自己的需要组建模型&#xff0c;然后就可以进行训练啦。

# 省略模型组建及实例化过程# 模型训练
model.prepare(optimizer, loss, metrics)
model.fit(train_loader, dev_loader, epochs&#61;50, verbose&#61;1)

总结

本节课和大家一起学习了如何对NLP任务中的数据进行预处理&#xff0c;下节课同学们想实现什么趣味案例呢&#xff1f;欢迎大家在评论区告诉我&#xff0c;我们将会在后续的课程中给大家安排上哈&#xff0c;今天的课程到这里就结束了&#xff0c;我是雨哥&#xff0c;下节课再见啦~

欢迎关注飞桨框架高层API官方账号&#xff1a;飞桨PaddleHapi

https://aistudio.baidu.com/aistudio/personalcenter/thirdview/564527

有任何问题可以在本项目中评论或到飞桨Github仓库提交Issue。

同时欢迎扫码加入飞桨框架高层API技术交流群

回顾往期&#xff1a;

『跟着雨哥学AI』系列&#xff1a;详解飞桨框架数据管道

『跟着雨哥学AI』系列之二&#xff1a;详解飞桨框架模型组网

『跟着雨哥学AI』系列之三&#xff1a;详解飞桨框架模型训练

『跟着雨哥学AI』系列之四&#xff1a;详解飞桨框架高阶用法

『跟着雨哥学AI』系列之五&#xff1a;快速上手趣味案例FashionMNIST

『跟着雨哥学AI』系列之六&#xff1a;趣味案例——基于U-Net的宠物图像分割

『跟着雨哥学AI』系列之七&#xff1a;趣味案例--动手制作专属证件照

如果您想详细了解更多飞桨的相关内容&#xff0c;请参阅以下文档。

·飞桨官网地址·

https://www.paddlepaddle.org.cn/

·飞桨开源框架项目地址·

GitHub: https://github.com/PaddlePaddle/Paddle 

Gitee: https://gitee.com/paddlepaddle/Paddle

????长按上方二维码立即star&#xff01;????

飞桨(PaddlePaddle)以百度多年的深度学习技术研究和业务应用为基础&#xff0c;是中国首个开源开放、技术领先、功能完备的产业级深度学习平台&#xff0c;包括飞桨开源平台和飞桨企业版。飞桨开源平台包含核心框架、基础模型库、端到端开发套件与工具组件&#xff0c;持续开源核心能力&#xff0c;为产业、学术、科研创新提供基础底座。飞桨企业版基于飞桨开源平台&#xff0c;针对企业级需求增强了相应特性&#xff0c;包含零门槛AI开发平台EasyDL和全功能AI开发平台BML。EasyDL主要面向中小企业&#xff0c;提供零门槛、预置丰富网络和模型、便捷高效的开发平台&#xff1b;BML是为大型企业提供的功能全面、可灵活定制和被深度集成的开发平台。

END


推荐阅读
  • 基于TensorFlow的鸢尾花数据集神经网络模型深度解析
    基于TensorFlow的鸢尾花数据集神经网络模型深度解析 ... [详细]
  • TensorFlow基础知识深化讲解
    批标准化批标准化(batchnormalization,BN)是为了克服神经网络层数加深导致难以训练而诞生的。深度神经网络随着深度加深,收 ... [详细]
  • 本文提供了PyTorch框架中常用的预训练模型的下载链接及详细使用指南,涵盖ResNet、Inception、DenseNet、AlexNet、VGGNet等六大分类模型。每种模型的预训练参数均经过精心调优,适用于多种计算机视觉任务。文章不仅介绍了模型的下载方式,还详细说明了如何在实际项目中高效地加载和使用这些模型,为开发者提供全面的技术支持。 ... [详细]
  • 在第七天的深度学习课程中,我们将重点探讨DGL框架的高级应用,特别是在官方文档指导下进行数据集的下载与预处理。通过详细的步骤说明和实用技巧,帮助读者高效地构建和优化图神经网络的数据管道。此外,我们还将介绍如何利用DGL提供的模块化工具,实现数据的快速加载和预处理,以提升模型训练的效率和准确性。 ... [详细]
  • 表面缺陷检测数据集综述及GitHub开源项目推荐
    本文综述了表面缺陷检测领域的数据集,并推荐了多个GitHub上的开源项目。通过对现有文献和数据集的系统整理,为研究人员提供了全面的资源参考,有助于推动该领域的发展和技术进步。 ... [详细]
  • 本文详细介绍了图表图例的语法与配置方法,包括如何通过 `loc` 参数设置图例的位置。具体位置选项包括:'best'(自动选择最佳位置)、'upper right'、'upper left'、'lower left' 和 'lower right' 等。此外,还探讨了其他高级配置选项,如图例的字体大小、边框样式和透明度等,以帮助用户更好地定制图表图例。 ... [详细]
  • 深入解析 Unity URP/SRP 渲染管线:匠心打造的全面指南
    本文深入探讨了Unity中的URP、SRP和HDRP渲染管线,详细解析了它们之间的关系及各自的特点。首先介绍了SRP的基本概念及其在Unity渲染架构中的作用,随后重点阐述了URP和HDRP的设计理念与应用场景。文章还分析了SRP诞生的背景,解释了为何Unity需要引入这一灵活的渲染框架,以满足不同项目的需求。通过对比URP和HDRP,读者可以更好地理解如何选择合适的渲染管线,以优化项目的性能和视觉效果。 ... [详细]
  • 开发笔记:校园商铺系统中店铺注册功能模块的Controller层优化与重构
    开发笔记:校园商铺系统中店铺注册功能模块的Controller层优化与重构 ... [详细]
  • 技术分享:线性回归模型的双路径构建——基于sklearn库的实践探索
    技术分享:线性回归模型的双路径构建——基于sklearn库的实践探索 ... [详细]
  • 在探索 Unity Shaders 的过程中,我逐渐意识到掌握 OpenGL 基础知识的重要性。本文将详细介绍 OpenGL 的核心概念和基本操作,帮助读者从零开始理解这一图形编程技术。通过实例和代码解析,我们将深入探讨如何利用 OpenGL 创建高效的图形应用。无论你是初学者还是有一定经验的开发者,都能从中受益匪浅。 ... [详细]
  • 从零起步:使用IntelliJ IDEA搭建Spring Boot应用的详细指南
    从零起步:使用IntelliJ IDEA搭建Spring Boot应用的详细指南 ... [详细]
  • 深入解析 Django 中用户模型的自定义方法与技巧 ... [详细]
  • Spring框架入门指南:专为新手打造的详细学习笔记
    Spring框架是Java Web开发中广泛应用的轻量级应用框架,以其卓越的功能和出色的性能赢得了广大开发者的青睐。本文为初学者提供了详尽的学习指南,涵盖基础概念、核心组件及实际应用案例,帮助新手快速掌握Spring框架的核心技术与实践技巧。 ... [详细]
  • NVIDIA CUDA Toolkit 不同版本的安装方法详解
    在安装NVIDIA CUDA Toolkit以配置GPU加速环境时,通常可以通过查阅网络文章或访问官方文档来获取安装指南。然而,这些资料往往侧重于介绍最新版本的安装方法,而忽视了不同版本之间的差异。本文将详细解析各个版本的安装步骤,帮助用户根据自身需求选择合适的CUDA Toolkit版本进行安装,确保兼容性和性能最优化。 ... [详细]
  • 上午8点一直等着ben,ben来了之后告诉我,他最近太忙,等着他发邮件。。。。****中午考完了学术规范,题目还是比较难新暖 ... [详细]
author-avatar
dmcm0006
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有