「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战」
快速安装 simpletransformers
simpletransformers 项目地址:hub.fastgit.org/ThilinaRaja…
simpletransformers 文档地址:
快速安装方式:
- 使用Conda安装
1)新建虚拟环境
conda create -n st python pandas tqdm
conda activate st
2)安装cuda环境
conda install pytorch>=1.6 cudatoolkit=11.0 -c pytorch
3)安装 simpletransformers
pip install simpletransformers
- 安装 wandb
wandb 用于在web浏览器中追踪和可视化Weights和Biases(wandb)
pip install wandb
目前支持的任务:
| 任务 | 模型 |
|---|---|
| 二元和多类文本分类 | ClassificationModel |
| 对话式人工智能(聊天机器人训练) | ConvAIModel |
| 语言生成 | LanguageGenerationModel |
| 语言模型训练/微调 | LanguageModelingModel |
| 多标签文本分类 | MultiLabelClassificationModel |
| 多模态分类(文本和图像数据结合) | MultiModalClassificationModel |
| 命名实体识别 | NERModel |
| 问答 | QuestionAnsweringModel |
| 回归 | ClassificationModel |
| 句子对分类 | ClassificationModel |
| 文本表示生成 | RepresentationModel |
预训练模型去哪里下载?
有关预训练模型,请参阅Hugging Face 文档。
根据文档中给出的model_type,只要在args中正确设置model_name的字典值就是可以加载预训练模型
【实践01】文本分类
数据集
笔者选用CLUE的作为benchmark数据集
选取数据集:IFLYTEK' 长文本分类
中文语言理解测评基准(CLUE)
www.cluebenchmarks.com/dataSet_sea…
为更好的服务中文语言理解、任务和产业界,做为通用语言模型测评的补充,通过搜集整理发布中文任务及标准化测评等方式完善基础设施,最终促进中文NLP的发展。
Update: CLUE论文被计算语言学国际会议 COLING2020高分录用
- IFLYTEK' 长文本分类
该数据集共有1.7万多条关于app应用描述的长文本标注数据,包含和日常生活相关的各类应用主题,共119个类别:"打车":0,"地图导航":1,"免费WIFI":2,"租车":3,….,"女性":115,"经营":116,"收款":117,"其他":118(分别用0-118表示)。每一条数据有三个属性,从前往后分别是 类别ID,类别名称,文本内容。
数据量:训练集(12,133),验证集(2,599),测试集(2,600)
{"label": "110",
"label_des": "社区超市",
"sentence": "朴朴快送超市创立于2016年,专注于打造移动端30分钟即时配送一站式购物平台,商品品类包含水果、蔬菜、肉禽蛋奶、海鲜水产、粮油调味、酒水饮料、休闲食品、日用品、外卖等。朴朴公司希望能以全新的商业模式,更高效快捷的仓储配送模式,致力于成为更快、更好、更多、更省的在线零售平台,带给消费者更好的消费体验,同时推动中国食品安全进程,成为一家让社会尊敬的互联网公司。,朴朴一下,又好又快,1.配送时间提示更加清晰友好2.保障用户隐私的一些优化3.其他提高使用体验的调整4.修复了一些已知bug"}
数据处理
Simple Transformers要求数据必须包含在至少两列的Pandas DataFrames中。 只需为列的文本和标签命名,SimpleTransformers就会处理数据。
第一列包含文本,类型为str。
第二列包含标签,类型为int。
对于多类分类,标签应该是从0开始的整数。
import json
import pandas as pd
def load_clue_iflytek(path,mode=None):
"""适应simpletransformer的加载方式"""
data = []
with open(path, "r", encoding="utf-8") as fp:
if mode == 'train' or mode =='dev':
for idx, line in enumerate(fp):
line = json.loads(line.strip())
label = int(line["label"])
text = line['sentence']
data.append([text, label])
data_df = pd.DataFrame(data, columns=["text", "labels"])
return data_df
elif mode == 'test':
for idx, line in enumerate(fp):
line = json.loads(line.strip())
text = line['sentence']
data.append([text])
data_df = pd.DataFrame(data, columns=["text"])
return data_df
模型搭建和训练
先进行参数配置,Simple Transformers具有dict args, 有关每个args的详细说明,可有参考:simpletransformers.ai/docs/tips-a…
1)参数配置
# 配置config
import argparse
def data_config(parser):
parser.add_argument("--trainset_path", type=str, default="data/Chinese_Spam_Message/train.json",
help="训练集路径")
parser.add_argument("--testset_path", type=str, default="data/Chinese_Spam_Message/test.txt",
help="测试集路径")
parser.add_argument("--reprocess_input_data", type=bool, default=True,
help="如果为True,则即使cache_dir中存在输入数据的缓存文件,也将重新处理输入数据")
parser.add_argument("--overwrite_output_dir", type=bool, default=True,
help="如果为True,则训练后的模型将保存到ouput_dir,并将覆盖同一目录中的现有已保存模型")
parser.add_argument("--use_cached_eval_features", type=bool, default=True,
help="训练期间的评估使用缓存特征,将此设置为False将导致在每个评估步骤中重新计算特征")
parser.add_argument("--output_dir", type=str, default="outputs/",
help="存储所有输出,包括模型checkpoints和评估结果")
parser.add_argument("--best_model_dir", type=str, default="outputs/best_model/",
help="保存评估过程中的最好模型")
return parser
def model_config(parser):
parser.add_argument("--max_seq_length", type=int, default=64,
help="模型支持的最大序列长度")
parser.add_argument("--model_type", type=str, default="bert",
help="模型类型bert/roberta")
# 要加载以前保存的模型而不是默认模型的模型,可以将model_name更改为包含已保存模型的目录的路径。
parser.add_argument("--model_name", type=str, default="./outputs/bert",
help="选择使用哪个预训练模型")
parser.add_argument("--manual_seed", type=int, default=0,
help="为了产生可重现的结果,需要设置随机种子")
parser.add_argument("--learning_rate", type=int, default=4e-5,
help="学习率")
return parser
def train_config(parser):
parser.add_argument("--num_train_epochs", type=int, default=3,
help="模型训练迭代数")
parser.add_argument("--wandb_kwargs", type=dict, default={"name": "bert"},
help="")
parser.add_argument("--n_gpu", type=int, default=1,
help="训练时使用的GPU个数")
parser.add_argument("--train_batch_size", type=int, default=64)
parser.add_argument("--eval_batch_size", type=int, default=32)
return parser
def set_args():
parser = argparse.ArgumentParser()
parser = data_config(parser)
parser = model_config(parser)
parser = train_config(parser)
args,_ = parser.parse_known_args()
return args
2)模型搭建和训练
from simpletransformers.classification import ClassificationModel
from sklearn.metrics import f1_score, accuracy_score
import logging
def f1_multiclass(labels, preds):
return f1_score(labels, preds, average='micro')
# 创建分类模型
model = ClassificationModel(args.model_type, args.model_name, num_labels=num_labels, args=vars(args))
# 训练模型,并在训练时评估
model.train_model(train,eval_df=dev)
# 模型预测
result, model_outputs, wrong_predictions = model.eval_model(dev, f1=f1_multiclass)
# 模型预测
predictions, raw_outputs = model.predict(test["text"][0])
print(predictions)
print(raw_outputs)
预测结果
笔记本电脑性能有限,为了保证能跑动,maxlen只用了64,也只训练了3轮,F1值的效果并不是很好 除了F1值也可以添加其他评价指标,如准确率、精确率、召回率等
{"eval_loss" = 1.8086365330510024,"f1" = 0.5917660638707195,"mcc" = 0.5727319886339782}
完整代码
import json
import pandas as pd
from simpletransformers.classification import ClassificationModel
from sklearn.metrics import f1_score, accuracy_score
import logging
def load_clue_iflytek(path,mode=None):
"""适应simpletransformer的加载方式"""
data = []
with open(path, "r", encoding="utf-8") as fp:
if mode == 'train' or mode =='dev':
for idx, line in enumerate(fp):
line = json.loads(line.strip())
label = int(line["label"])
text = line['sentence']
data.append([text, label])
data_df = pd.DataFrame(data, columns=["text", "labels"])
return data_df
elif mode == 'test':
for idx, line in enumerate(fp):
line = json.loads(line.strip())
text = line['sentence']
data.append([text])
data_df = pd.DataFrame(data, columns=["text"])
return data_df
# 配置config
import argparse
def data_config(parser):
parser.add_argument("--trainset_path", type=str, default="data/Chinese_Spam_Message/train.json",
help="训练集路径")
parser.add_argument("--testset_path", type=str, default="data/Chinese_Spam_Message/test.txt",
help="测试集路径")
parser.add_argument("--reprocess_input_data", type=bool, default=True,
help="如果为True,则即使cache_dir中存在输入数据的缓存文件,也将重新处理输入数据")
parser.add_argument("--overwrite_output_dir", type=bool, default=True,
help="如果为True,则训练后的模型将保存到ouput_dir,并将覆盖同一目录中的现有已保存模型")
parser.add_argument("--use_cached_eval_features", type=bool, default=True,
help="训练期间的评估使用缓存特征,将此设置为False将导致在每个评估步骤中重新计算特征")
parser.add_argument("--output_dir", type=str, default="outputs/",
help="存储所有输出,包括模型checkpoints和评估结果")
parser.add_argument("--best_model_dir", type=str, default="outputs/best_model/",
help="保存评估过程中的最好模型")
return parser
def model_config(parser):
parser.add_argument("--max_seq_length", type=int, default=64,
help="模型支持的最大序列长度")
parser.add_argument("--model_type", type=str, default="bert",
help="模型类型bert/roberta")
# 要加载以前保存的模型而不是默认模型的模型,可以将model_name更改为包含已保存模型的目录的路径。
parser.add_argument("--model_name", type=str, default="./outputs/bert",
help="选择使用哪个预训练模型")
parser.add_argument("--manual_seed", type=int, default=0,
help="为了产生可重现的结果,需要设置随机种子")
parser.add_argument("--learning_rate", type=int, default=4e-5,
help="学习率")
return parser
def train_config(parser):
parser.add_argument("--num_train_epochs", type=int, default=3,
help="模型训练迭代数")
parser.add_argument("--wandb_kwargs", type=dict, default={"name": "bert"},
help="")
parser.add_argument("--n_gpu", type=int, default=1,
help="训练时使用的GPU个数")
parser.add_argument("--train_batch_size", type=int, default=64)
parser.add_argument("--eval_batch_size", type=int, default=32)
return parser
def set_args():
parser = argparse.ArgumentParser()
parser = data_config(parser)
parser = model_config(parser)
parser = train_config(parser)
args,_ = parser.parse_known_args()
return args
def f1_multiclass(labels, preds):
return f1_score(labels, preds, average='micro')
if __name__ == "__main__":
args = set_args()
logging.basicConfig(level=logging.INFO)
transformers_logger = logging.getLogger("transformers")
transformers_logger.setLevel(logging.WARNING)
# 模型训练
train = load_clue_iflytek("./data/iflytek/train.json", mode='train')
dev = load_clue_iflytek("./data/iflytek/dev.json", mode='dev')
test = load_clue_iflytek("./data/iflytek/test.json", mode='test')
num_labels = len(train["labels"].unique())
print(train.shape)
print(dev.shape)
# 创建分类模型
model = ClassificationModel(args.model_type, args.model_name, num_labels=num_labels, args=vars(args))
# 训练模型,并在训练时评估
model.train_model(train,eval_df=dev)
# 模型预测
result, model_outputs, wrong_predictions = model.eval_model(dev, f1=f1_multiclass)
Simpletransformers上手快,但只偏向于快速应用或者写baseline,需要更改模型结构灵活组合方法还是需要掌握transformer等自由度高的python库
NLP萌新,才疏学浅,有错误或者不完善的地方,请批评指正!!