作者 | Mike Casale
编译 | VK
来源 | Towards Data Science
下图是文本到文本框架的示意图。每个任务都使用文本作为模型的输入,通过训练生成一些目标文本。
这允许在不同的任务中使用相同的模型、损失函数和超参数,包括翻译(绿色)、语言可接受性(红色)、句子相似性(黄色)和文档摘要(蓝色)。
在本文中,我们将演示如何使用Google T5对表格数据中的文本进行特征化。你可以使用这个存储库中的Jupyter笔记本:
https://github.com/mikewcasale/nlp_primitives
当试图在机器学习管道中利用真实世界的数据时,通常会遇到书面文本—例如,在预测房地产估价时,有许多数字特征,例如:
- “卧室数量”
- “浴室数量”
- “面积(平方英尺)”
- “纬度”
- “经度”
- 等等…
但同时,也有大量的书面文本,比如在Zillow等网站的房地产上市描述中。这些文本数据可以包括许多其他方面没有考虑到的有价值的信息,例如:
- 开放式厨房/平面图
- 花岗岩个数
- 硬木地板
- 不锈钢电器
- 最近的装修
- 等等…
然而,令人惊讶的是,许多AutoML工具完全忽略了这些信息,因为诸如XGBoost之类的流行表格算法不能直接使用书面文本。
这就是Featuretools基本函数的用武之地。Featuretools旨在为不同类型的数据(包括文本)自动创建特征,然后表格机器学习模型可以使用这些数据。
在本文中,我们将展示如何扩展nlp Primitive库,以便与Google最先进的T5模型一起使用,并在此过程中创建最重要的nlp特征,进而提高准确性。
关于T5
对于任何不熟悉T5的读者来说,T5模型出现在谷歌的论文中,题目是Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer。
使用Hugging Face T5的一个机器学习demo
在NLP的背景下,Hugging Face Transformers是一个自然语言处理库,对很多ML模型开放,并得到了像Flair、Asteroid、ESPnet、Pyannote等库的支持。
为了扩展NLP库以便与T5一起使用,我们将构建两个自定义TransformPrimitive类。出于实验目的,我们测试了两种方法:
- 微调Hugging Face T5-base
- Hugging Face T5-base的情感分析
首先,让我们加载基本模型。
代码语言:javascript复制from simpletransformers.t5
import T5Modelmodel_args = {
"max_seq_length": 196,
"train_batch_size": 8,
"eval_batch_size": 8,
"num_train_epochs": 1,
"evaluate_during_training": True,
"evaluate_during_training_steps": 15000,
"evaluate_during_training_verbose": True,
"use_multiprocessing": False,
"fp16": False,
"save_steps": -1,
"save_eval_checkpoints": False,
"save_model_every_epoch": False,
"reprocess_input_data": True,
"overwrite_output_dir": True,
"wandb_project": None,
}
model = T5Model("t5", "t5-base", args=model_args)
第二,让我们加载预训练模型。
代码语言:javascript复制model_pretuned_sentiment = T5Model('t5',
'mrm8488/t5-base-finetuned-imdb-sentiment',
use_cuda=True)
model_pretuned_sentiment.args
为了对t5模型进行微调,需要对训练数据进行重组和格式化。
从Kaggle数据集,我们将review_text
列映射到一个名为input_text
的新列,我们将review_rating
列映射到一个名为target_text
的新列,这意味着review_rating
就是我们试图预测的内容。
这些更改符合Simpletransformers库接口,用于微调t5,其中主要的附加要求是指定一个“前缀”,用于帮助进行多任务训练(注意:在本例中,我们将重点放在单个任务上,因此前缀不必使用,但是,我们无论如何都会定义它,以便于使用)。
代码语言:javascript复制dft5 = df[['review_text','review_rating']
].rename({
'review_text':'input_text',
'review_rating':'target_text'
},axis=1)
dft5['prefix'] = ['t5-encode' for x in range(len(dft5))]dft5['target_text'] =
dft5['target_text'].astype(str)
dft5
本例中的目标文本是消费者对给定餐厅的评分。我们可以通过以下方法轻松地微调T5模型
代码语言:javascript复制from sklearn.model_selection import train_test_split
train_df, eval_df = train_test_split(dft5)
model.train_model(train_df, eval_data=eval_df)
接下来,我们加载预训练模型。
代码语言:javascript复制test = ['Great drinks and food',
list(np.array(model.predict(test)).astype(float))
'Good food & beer',
Generating outputs: 0%| | 0/1 [00:00<?, ?it/s] Generating outputs: 100%|██████████| 1/1 [00:00<00:00, 3.17it/s] Generating outputs: 100%|██████████| 1/1 [00:00<00:00, 3.16it/s] Decoding outputs: 0%| | 0/3 [00:00<?, ?it/s] Decoding outputs: 33%|███▎ | 1/3 [00:00<00:01, 1.14it/s] Decoding outputs: 100%|██████████| 3/3 [00:00<00:00, 3.43it/s] Out[14]: [4.0, 4.0, 4.0]
'Pretty good beers']
我们可以看到,微调模型输出了review_rankings
列表[4.0,4.0,4.0],这是一个预测结果。
接下来,让我们使用预训练的模型进行测试。
代码语言:javascript复制test = ['Great drinks and food',
'Good food & beer',
'Pretty good beers']
list(np.where(np.array(model_pretuned_sentiment.predict(test))=='positive', 1.0, 0.0))
Generating outputs: 0%| | 0/1 [00:00<?, ?it/s] Generating outputs: 100%|██████████| 1/1 [00:00<00:00, 7.57it/s] Generating outputs: 100%|██████████| 1/1 [00:00<00:00, 7.56it/s] Decoding outputs: 0%| | 0/3 [00:00<?, ?it/s] Decoding outputs: 33%|███▎ | 1/3 [00:00<00:01, 1.17it/s] Decoding outputs: 100%|██████████| 3/3 [00:00<00:00, 3.50it/s] Out[15]: [1.0, 1.0, 1.0]
注意,预训练模型输出一个布尔真/假值列表,该列表指示语句是正还是负-我们将它们转换为浮点值,以便更好地与表格建模集成。在这种情况下,所有值都为true,因此输出变为[1.0、1.0、1.0]。
既然我们已经加载了两个版本的T5,我们可以构建TransformPrimitive
类,这些类将与NLP和Featuretools库集成。
from featuretools.primitives.base import TransformPrimitive
from featuretools.variable_types import Numeric, Text
class T5Encoder(TransformPrimitive):
name = "t5_encoder"
input_types = [Text]
return_type = Numeric
default_value = 0
def __init__(self, model=model):
self.model = model
def get_function(self):
def t5_encoder(x):
model.args.use_multiprocessing = True
return list(np.array(model.predict(x.tolist())).astype(float))
return t5_encoder
以上代码创建了一个名为T5编码器的新类,该类将使用微调的T5模型,下面的代码创建了一个名为T5SentimentEncoder的新类,该类将使用预训练的T5模型。
代码语言:javascript复制class T5SentimentEncoder(TransformPrimitive):
name = "t5_sentiment_encoder"
input_types = [Text]
return_type = Numeric
default_value = 0
def __init__(self, model=model_pretuned_sentiment):
self.model = model
def get_function(self):
def t5_sentiment_encoder(x):
model.args.use_multiprocessing = True
return list(np.where(np.array(model_pretuned_sentiment.predict(x.tolist()))=='positive',1.0,0.0))
return t5_sentiment_encoder
Featuretools现在知道如何使用T5来为文本列提供特征,它甚至会使用T5输出计算聚合
定义了这些新类之后,我们只需将它们与默认类一起以所需的Featuretools格式包起来,这将使它们可用于自动化特征工程
代码语言:javascript复制trans = [
T5Encoder,
T5SentimentEncoder,
DiversityScore,
LSA,
MeanCharactersPerWord,
PartOfSpeechCount,
PolarityScore,
PunctuationCount,
StopwordCount,
TitleWordCount,
UniversalSentenceEncoder,
UpperCaseCount
]
ignore = {'restaurants': ['rating'],
'reviews': ['review_rating']}
drop_contains = ['(reviews.UNIVERSAL']
features = ft.dfs(entityset=es,
target_entity='reviews',
trans_primitives=trans,
verbose=True,
features_only=True,
ignore_variables=ignore,
drop_contains=drop_contains,
max_depth=4)
正如你在下面的输出中看到的,Featuretools库非常强大!事实上,除了这里显示的T5特征之外,它还使用指定的所有其他NLP Primitive创建了数百个特征,非常酷!
代码语言:javascript复制feature_matrix = ft.calculate_feature_matrix(features=features,
entityset=es,
verbose=True)
features
机器学习
现在我们使用包含新创建的T5 Primitive的特征矩阵从sklearn创建和测试各种机器学习模型。
作为提醒,我们将比较T5增强的精确度和Alteryx博客《自动特征工程的自然语言处理》中演示的精确度:https://innovation.alteryx.com/natural-language-processing-featuretools/
使用逻辑回归:
请注意,上面的0.64逻辑回归分数显示了比Featuretools原生逻辑回归分数0.63有0.01的改进。
使用随机林分类器:
请注意,上面T5增强的0.65随机林分类器分数显示了比Featuretools本机随机林分类器分数0.64有0.01的改进。
随机森林分类器特征重要性
我们可以查看sklearn随机森林分类器的特征重要性,可以看到改进的分数归于新的T5特征。
从上表中我们可以看到,随机林模型的最高特征重要性是新创建的特征
T5情感编码器(标题)!
关键特征
- T5模型是一个健壮、灵活的文本到文本转换器,它可以增强几乎任何NLP任务的结果,包括处理文本数据时NLP Primitive库的结果。虽然额外的准确度在这里微不足道,但几乎可以肯定的是,除了情绪分析之外,通过实施额外的预训练模型,可以提高准确度。
此外,在这个例子中,我们微调的T5版本只在
review_text
上训练,而不是在review_title
数据上训练,这似乎与Featuretools创建的特征不一致。纠正这个问题很可能意味着更高的整体性能。 - 扩展Featuretools框架非常简单,可以使用Hugging Face transformers和Simpletransformers库。再加上几行代码,精确度就提高了,代码的复杂度也保持不变。