【闯关答题】PaddleHub中文新闻文本标题分类实战_副本
【闯关答题】试题三:中文新闻文本标题分类,面向小白的基于PaddleHub的简易实战Baseline,一起闯关答题赢免费算力和积分!
【闯关答题】PaddleHub中文新闻文本标题分类实战
一.引言:
在逛AI Studio时偶然打开学习地图看到了闯关答题赢积分、算力卡和战力的活动,于是选择了其中NLP赛题 试题三:“中文新闻文本标题分类问题”,并基于PaddleHub面向新手们开个简易的Baseline,还没有参加的一起来嫖免费的算力和积分吧!
活动地址:https://aistudio.baidu.com/aistudio/learnmap
闯关简介:
进入学习地图页面https://aistudio.baidu.com/aistudio/learnmap,选择试题三:中文新闻文本标题分类问题后开始答题。
需注意该答题作业环境限制了paddle版本为1.7.2,版本不兼容可能会带来较差的体验!
因此也可以选择像本案例一样直接新建一个新的notebook,训练和预测完成生成提交结果文件后将结果文件result.txt上传到试题答题环境然后提交即可!感兴趣的也可以尝试在本基线模型上进一步优化提升效果。
通关说明:
1.一键运行Baseline进行模型的训练和预测。
2.进入到本项目主目录下载已经生成好的结果文件result.txt
3.进入答题页面环境然后将result.txt文件上传至与work同级目录下后点击生成版本,生成版本时注意添加result.txt文件哦!
4.停止环境后点击提交试题选择要提交的版本及添加结果文件后进行提交即可通关,通关后可到学习地图页面领取通关奖励(算力+积分)哦!
二.数据读取与处理
2.1 数据分析处理与可视化
# 进入存放数据集的目录
%cd /home/aistudio/data/data12701/
/home/aistudio/data/data12701
# 读取数据集
import pandas as pd
train = pd.read_table('Train.txt', sep='\t',header=None) # 有标签的训练数据文件
test = pd.read_table('Test.txt', sep='\t',header=None) # 要进行预测的测试数据文件
# 查看训练数据前5条
train.head()
0 | 1 | 2 | |
---|---|---|---|
0 | 0 | 财经 | 上证50ETF净申购突增 |
1 | 0 | 财经 | 交银施罗德保本基金将发行 |
2 | 0 | 财经 | 基金公司不裁员反扩军 走访名校揽人才 |
3 | 0 | 财经 | 基金巨亏30亿 欲打开云天系跌停自救 |
4 | 0 | 财经 | 基金市场周二缩量走低 |
# 为训练集添加列名便于后续处理
train.columns = ['id',"label","text_a"]
# 查看测试集数据前5条
test.head()
0 | |
---|---|
0 | 北京君太百货璀璨秋色 满100省353020元 |
1 | 教育部:小学高年级将开始学习性知识 |
2 | 专业级单反相机 佳能7D单机售价9280元 |
3 | 星展银行起诉内地客户 银行强硬客户无奈 |
4 | 脱离中国的实际 强压人民币大幅升值只能是梦想 |
# 为测试集添加列名便于处理
test.columns = [["text_a"]]
# 查看测试数据文件信息,共83599条
test.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 83599 entries, 0 to 83598
Data columns (total 1 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 (text_a,) 83599 non-null object
dtypes: object(1)
memory usage: 653.2+ KB
# 保存处理后的测试集文件
test.to_csv('test.csv', sep='\t', index=False)
# 对训练集的格式进行简单处理,舍弃无用id列,训练集:text_a,label
train = train[['text_a','label']]
# 查看处理后的训练数据前5条
train.head()
text_a | label | |
---|---|---|
0 | 上证50ETF净申购突增 | 财经 |
1 | 交银施罗德保本基金将发行 | 财经 |
2 | 基金公司不裁员反扩军 走访名校揽人才 | 财经 |
3 | 基金巨亏30亿 欲打开云天系跌停自救 | 财经 |
4 | 基金市场周二缩量走低 | 财经 |
# 查看训练数据文件信息
# 可以看出共752475条,并不存在空值
train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 752476 entries, 0 to 752475
Data columns (total 2 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 text_a 752475 non-null object
1 label 752476 non-null object
dtypes: object(2)
memory usage: 11.5+ MB
# 训练数据类别标签分布统计
train['label'].value_counts()
科技 146637
股票 138959
体育 118444
娱乐 83369
时政 56778
社会 45765
教育 37743
财经 33389
家居 29328
游戏 21936
房产 18045
时尚 12032
彩票 6830
星座 3221
Name: label, dtype: int64
# 全局设置解决matplotlib中文显示错误的问题,参考:https://aistudio.baidu.com/aistudio/projectdetail/1658980
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager
# 设置显示中文
matplotlib.rcParams['font.sans-serif'] = ['FZSongYi-Z13S'] # 指定默认字体
matplotlib.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
# 设置字体大小
matplotlib.rcParams['font.size'] = 16
# 可视化类别标签分布情况
train['label'].value_counts(normalize=True).plot(kind='bar');
# 统计数据文本长度,可以看出文本长度普遍较短
print((train['text_a'].astype(str)).map(len).describe())
count 752476.000000
mean 19.471856
std 4.112568
min 1.000000
25% 17.000000
50% 20.000000
75% 23.000000
max 81.000000
Name: text_a, dtype: float64
# 可视化训练集文本长度分布
train['text_a'].astype(str).map(len).plot(kind='kde');
2.2 手动划分训练和验证集
# 考虑类别不均衡,此处选择根据label的具体类别按9:1的比例去划分训练和验证集,从而使训练和验证集尽量同分布。
from sklearn.utils import shuffle
new_train = pd.DataFrame() # 定义新训练集
new_valid = pd.DataFrame() # 定义新验证集
tags = list(train.label.unique()) # 总类别
# 根据类别进行抽样划分
for tag in tags:
data = train[(train['label'] == tag)]
# 抽样取0.1作为验证集
valid_sample = data.sample(int(0.1 * len(data)))
valid_index = valid_sample.index
# 将剩余0.9的数据作为训练集
all_index = data.index
residue_index = all_index.difference(valid_index)
residue = data.loc[residue_index]
# 对取的数据进行保存
new_valid = pd.concat([new_valid, valid_sample], ignore_index=True)
new_train = pd.concat([new_train, residue], ignore_index=True)
# 对划分后的数据进行随机打乱
new_train = shuffle(new_train)
new_valid = shuffle(new_valid)
# 保存训练和验证集文件
new_train.to_csv('train.csv', sep='\t', index=False) # 训练集
new_valid.to_csv('valid.csv', sep='\t', index=False) # 验证集
三.基于PaddleHub构建基线模型
PaddleHub可以便捷地获取PaddlePaddle生态下的预训练模型,完成模型的管理和一键预测。配合使用Fine-tune API,可以基于大规模预训练模型快速完成迁移学习,让预训练模型能更好地服务于用户特定场景的应用。
PaddleHub的github地址(有问题可以提issue):https://github.com/PaddlePaddle/PaddleHub
3.1 PaddleHub预训练模型微调流程:
PaddleHub预训练模型微调流程如下:
1)加载要使用的预训练模型
2)加载并处理数据为模型可接受的格式
3)设置finetune训练与优化策略
4)模型训练与验证
5)模型预测
以上流程每个步骤只需通过很少的代码即可完成,使得我们可以快速构建比赛基线方案。
3.2 前置环境准备
# 下载最新版本的PaddleHub
!pip install -U paddlehub -i https://pypi.tuna.tsinghua.edu.cn/simple
# 导入paddlehub
import paddlehub as hub
# 设置固定随机种子便于结果的复现
# ps: 无法100%复现结果,如需稳定结果建议5folds或多次结果取平均等尝试稳定下
seed = 1024
import random
import numpy as np
import paddle
random.seed(seed)
np.random.seed(seed)
paddle.seed(seed)
<paddle.fluid.core_avx.Generator at 0x7f8c8bf1adb0>
3.3 加载预训练模型及设置微调任务
# 设置要求进行文本分类的14个类别
label_list=list(train.label.unique())
print(label_list)
label_map = {
idx: label_text for idx, label_text in enumerate(label_list)
}
print(label_map)
['财经', '彩票', '房产', '股票', '家居', '教育', '科技', '社会', '时尚', '时政', '体育', '星座', '游戏', '娱乐']
{0: '财经', 1: '彩票', 2: '房产', 3: '股票', 4: '家居', 5: '教育', 6: '科技', 7: '社会', 8: '时尚', 9: '时政', 10: '体育', 11: '星座', 12: '游戏', 13: '娱乐'}
# 选择在中文领域效果较优的roberta-wwm-ext-large预训练模型并设置微调任务为14分类任务
model = hub.Module(name="roberta-wwm-ext-large", task='seq-cls', num_classes=14, label_map=label_map)
Download https://bj.bcebos.com/paddlehub/paddlehub_dev/roberta-wwm-ext-large_2.0.2.tar.gz
[##################################################] 100.00%
Decompress /home/aistudio/.paddlehub/tmp/tmp94h07ovo/roberta-wwm-ext-large_2.0.2.tar.gz
[##################################################] 100.00%
[2022-02-22 22:53:02,020] [ INFO] - Successfully installed roberta-wwm-ext-large-2.0.2
[2022-02-22 22:53:02,023] [ INFO] - Downloading https://paddlenlp.bj.bcebos.com/models/transformers/roberta_large/roberta_chn_large.pdparams and saved to /home/aistudio/.paddlenlp/models/roberta-wwm-ext-large
[2022-02-22 22:53:02,025] [ INFO] - Downloading roberta_chn_large.pdparams from https://paddlenlp.bj.bcebos.com/models/transformers/roberta_large/roberta_chn_large.pdparams
100%|██████████| 1271615/1271615 [00:31<00:00, 39982.66it/s]
W0222 22:53:33.922940 150 device_context.cc:447] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 10.1, Runtime API Version: 10.1
W0222 22:53:33.928656 150 device_context.cc:465] device: 0, cuDNN Version: 7.6.
hub.Module
的参数用法如下:
name
:模型名称,可以选择ernie
,ernie_tiny
,bert-base-cased
,bert-base-chinese
,roberta-wwm-ext
,roberta-wwm-ext-large
等。task
:fine-tune任务。此处为seq-cls
,表示文本分类任务。num_classes
:表示当前文本分类任务的类别数,根据具体使用的数据集确定,默认为2。
PaddleHub支持的更多模型可以访问:https://www.paddlepaddle.org.cn/hublist
PaddleHub当前支持文本分类任务的模型对应的加载示例如下:
模型名 | PaddleHub Module |
---|---|
ERNIE, Chinese | hub.Module(name='ernie') |
ERNIE 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') |
BERT-Base, English Cased | hub.Module(name='bert-base-cased') |
BERT-Base, English Uncased | hub.Module(name='bert-base-uncased') |
BERT-Large, English Cased | hub.Module(name='bert-large-cased') |
BERT-Large, English Uncased | hub.Module(name='bert-large-uncased') |
BERT-Base, Multilingual Cased | hub.Module(nane='bert-base-multilingual-cased') |
BERT-Base, Multilingual Uncased | hub.Module(nane='bert-base-multilingual-uncased') |
BERT-Base, Chinese | hub.Module(name='bert-base-chinese') |
BERT-wwm, Chinese | hub.Module(name='chinese-bert-wwm') |
BERT-wwm-ext, Chinese | hub.Module(name='chinese-bert-wwm-ext') |
RoBERTa-wwm-ext, Chinese | hub.Module(name='roberta-wwm-ext') |
RoBERTa-wwm-ext-large, Chinese | hub.Module(name='roberta-wwm-ext-large') |
RBT3, Chinese | hub.Module(name='rbt3') |
RBTL3, Chinese | hub.Module(name='rbtl3') |
ELECTRA-Small, English | hub.Module(name='electra-small') |
ELECTRA-Base, English | hub.Module(name='electra-base') |
ELECTRA-Large, English | hub.Module(name='electra-large') |
ELECTRA-Base, Chinese | hub.Module(name='chinese-electra-base') |
ELECTRA-Small, Chinese | hub.Module(name='chinese-electra-small') |
3.4 加载并处理数据为模型可接受的格式
import os, io, csv
from paddlehub.datasets.base_nlp_dataset import InputExample, TextClassificationDataset
# 设置数据集存放位置路径
DATA_DIR="/home/aistudio/data/data12701/"
# 对训练数据(训练集和验证集)进行格式处理,处理为模型可接受的格式
class News(TextClassificationDataset):
def __init__(self, tokenizer, mode='train', max_seq_len=128):
if mode == 'train':
data_file = 'train.csv'
elif mode == 'dev':
data_file = 'valid.csv'
super(News, self).__init__(
base_path=DATA_DIR,
data_file=data_file,
tokenizer=tokenizer,
max_seq_len=max_seq_len,
mode=mode,
is_file_with_header=True,
label_list=label_list
)
# 解析文本文件里的样本
def _read_file(self, input_file, is_file_with_header: bool = False):
if not os.path.exists(input_file):
raise RuntimeError("The file {} is not found.".format(input_file))
else:
with io.open(input_file, "r", encoding="UTF-8") as f:
reader = csv.reader(f, delimiter="\t") # ‘\t’分隔数据
examples = []
seq_id = 0
header = next(reader) if is_file_with_header else None
for line in reader:
example = InputExample(guid=seq_id, text_a=line[0], label=line[1])
seq_id += 1
examples.append(example)
return examples
# 最大序列长度max_seq_len是可调整的重要参数,默认值为128,需要根据具体文本长度调整该值,但最大建议不超过512。
# 由于此次任务为文本标题,文本长度普遍较短,故此处设置为了48
train_dataset = News(model.get_tokenizer(), mode='train', max_seq_len=48)
dev_dataset = News(model.get_tokenizer(), mode='dev', max_seq_len=48)
# 处理完后查看处理后的数据前3条
for e in train_dataset.examples[:3]:
print(e)
for e in dev_dataset.examples[:3]:
print(e)
[2022-02-22 22:53:57,261] [ INFO] - Downloading https://paddlenlp.bj.bcebos.com/models/transformers/roberta_large/vocab.txt and saved to /home/aistudio/.paddlenlp/models/roberta-wwm-ext-large
[2022-02-22 22:53:57,263] [ INFO] - Downloading vocab.txt from https://paddlenlp.bj.bcebos.com/models/transformers/roberta_large/vocab.txt
100%|██████████| 107/107 [00:00<00:00, 3921.79it/s]
[2022-02-22 22:55:57,506] [ INFO] - Already cached /home/aistudio/.paddlenlp/models/roberta-wwm-ext-large/vocab.txt
text=商务人士最爱 六款低价便携投影机一览 label=科技
text=九州OL新增双倍经验 享受升级快感 label=游戏
text=英雄联盟7月21日开放测试 明星送祝福 label=游戏
text=杨元庆:乐Pad平板3月底上市 不惧与iPad竞争 label=科技
text=港股挟升近六百点 57只熊仔就此遭殃 label=股票
text=上午期指低见19637后徘徊 收报19730 label=股票
3.5 选择优化策略和运行配置
# 优化器的选择
optimizer = paddle.optimizer.AdamW(learning_rate=2e-5, weight_decay=0.0, parameters=model.parameters())
# 训练运行配置:设置是否使用gpu及训练模型存放路径等
trainer = hub.Trainer(model, optimizer, checkpoint_dir='./ckpt', use_gpu=True, use_vdl=True) # fine-tune任务的执行者
[2022-02-22 22:56:10,161] [ WARNING] - PaddleHub model checkpoint not found, start from scratch...
3.6 模型训练与验证
trainer.train
主要控制具体的训练过程,包含以下可控制的参数:
train_dataset
: 训练时所用的数据集;epochs
: 训练轮数;batch_size
: 训练的批大小,如果使用GPU,请根据实际情况调整batch_size;num_workers
: works的数量,默认为0;eval_dataset
: 验证集;log_interval
: 打印日志的间隔, 单位为执行批训练的次数。save_interval
: 保存模型的间隔频次,单位为执行训练的轮数。
# 模型训练:配置训练参数,指定验证集,启动训练
# ps: 需要根据显存大小调整好batch_size值!否则容易爆显存。 此处默认使用了32G显存环境故设置其值较大。
trainer.train(train_dataset, epochs=4, batch_size=256, eval_dataset=dev_dataset, save_interval=1)
3.7 模型预测并生成结果文件
# 对测试集进行预测:
import numpy as np
# 将输入数据进行格式处理,处理为list格式
data_array = np.array(test)
data_list =data_array.tolist()
# 加载训练好的模型
model = hub.Module(
name="roberta-wwm-ext-large",
task='seq-cls',
load_checkpoint='./ckpt/best_model/model.pdparams', # 加载最优一轮的模型参数
num_classes=14,
label_map=label_map)
# 对测试集数据进行预测:
# ps:由于训练显存未释放,预测时的batchsize注意不要设置过大否则容易出现显存不足的情况
predictions = model.predict(data_list, max_seq_len=48, batch_size=8, use_gpu=True)
[2022-02-23 04:50:52,582] [ INFO] - Already cached /home/aistudio/.paddlenlp/models/roberta-wwm-ext-large/roberta_chn_large.pdparams
[2022-02-23 04:51:00,264] [ INFO] - Loaded parameters from /home/aistudio/data/data12701/ckpt/best_model/model.pdparams
[2022-02-23 04:51:00,276] [ INFO] - Already cached /home/aistudio/.paddlenlp/models/roberta-wwm-ext-large/vocab.txt
# 预测结果存储为要求格式 txt文件
def write_results(labels, file_path):
with open(file_path, "w", encoding="utf8") as f:
f.writelines("\n".join(labels))
write_results(predictions, "./result.txt")
# 移动提交结果文件至主目录下
!cp -r /home/aistudio/data/data12701/result.txt /home/aistudio/
3.8 结果提交
在主目录下找到生成的预测结果文件: result.txt文件后进入答题页面进行提交即可!
a.进入答题页面环境然后将result.txt文件上传至与work同级目录下后点击生成版本,生成版本时注意添加result.txt文件哦!
b.停止环境后点击提交试题选择要提交的版本及添加结果文件后进行提交即可通关,通关后可到学习地图页面领取通关奖励(算力+积分)哦!
感兴趣的也可以尝试在本基线模型上从模型优化、数据处理和结果融合等方向出发,进一步优化提升效果!
四.个人介绍
昵称:炼丹师233
主要方向:搞开发,主攻NLP和数据挖掘相关比赛或项目
https://aistudio.baidu.com/aistudio/personalcenter/thirdview/330406 关注我,下次带来更多精彩项目分享!
更多推荐
所有评论(0)