【导读】我们一直在关心深度学习模型的具体实现, 实际上,无论是什么实验, 数据的处理总是占大头的。如何将一个纯文本数据(比如一个 txt 文本), 变成一个模型可接受的数据(比如一个 embedding 序列)呢?
如果你是 pytorch 的用户,你可能已经非常熟悉 torchvision 了,因为它已经比较稳定,而且官方也为它出了教程。torchtext 跟 torchvision 一样,是为了处理特定的数据和数据集而存在的。正如 NLP和 CV的热度一样, torchtext的热度也较 torchvision 少了许多,至今还在积极开发中,甚至在使用过程中你可能会遇见一些 bug。但是, torchtext 的可用性是肯定的,它提供了一整套文本数据处理流程。
在本文中,我们将使用torchtext,来处理文本数据。其中,数据集采用kaggle的《有毒评论》数据集(https://www.kaggle.com/c/jigsaw-toxic-comment-classification-challenge)。
该数据集格式如下:
存储在一个 csv文件中。
一、预处理CSV文件
import pandas aspd
importnumpy as np
VAL_RATIO =0.2
defprepare_csv(seed=999):
# 加载训练数据
df_train = pd.read_csv("data/train.csv")
df_train["comment_text"] = df_train.comment_text.str.replace("\n", " ")
idx =np.arange(df_train.shape[0])
# 将训练数据分成训练集和验证集
np.random.seed(seed)
np.random.shuffle(idx)
val_size =int(len(idx) * VAL_RATIO)
df_train.iloc[idx[val_size:], :].to_csv("cache/dataset_train.csv", index=False)
df_train.iloc[idx[:val_size], :].to_csv("cache/dataset_val.csv", index=False)
# 加载测试数据
df_test = pd.read_csv("data/test.csv")
df_test["comment_text"] = df_test.comment_text.str.replace("\n", " ")
df_test.to_csv("cache/dataset_test.csv", index=False)
主要是为了将数据集分成训练,验证,测试三部分。
二、标记化(Tokenization)
mport re
importspacy
NLP = spacy.load('en')
MAX_CHARS =20000
deftokenizer(comment):
comment = re.sub(r"[\*\"“”\n\\…\+\-\/\=\(\)‘•:\[\]\|’\!;]", " ", str(comment))
comment = re.sub(r"[]+", " ",comment)
comment = re.sub(r"\!+", "!", comment)
comment = re.sub(r"\,+", ",", comment)
comment = re.sub(r"\?+", "?", comment)
# 如果数据太长,将被截断
if (len(comment) > MAX_CHARS):
comment = comment[:MAX_CHARS]
return[x.text for x in NLP.tokenizer(comment) if x.text !=" "]
这里使用正则表达式清洗一下数据,然后,直接调用 Spacy ,使用其中的 tokenizer函数,将文本标记化。
三、加载数据
import logging
importtorch
fromtorchtext
LOGGER = logging.getLogger("toxic_dataset")
defget_dataset(fix_length=100, lower=False, vectors=None):
ifvectors isnotNone:
lower =True
LOGGER.debug("预处理 csv...")
prepare_csv()
# 用 torchtext 的 data 类加载数据
comment = torchtext.data.Field(
sequential=True,
fix_length=fix_length,
tokenize=tokenizer,
pad_first=True,
tensor_type=torch.cuda.LongTensor,
lower=lower
)
LOGGER.debug("读 train csv...")
train=data.TabularDataset(
path='cache/dataset_train.csv',format='csv', skip_header=True,
fields=[
('id', None),
('comment_text', comment),
('toxic', data.Field(
use_vocab=False,sequential=False,tensor_type=torch.cuda.ByteTensor)),
('severe_toxic', data.Field(
use_vocab=False,sequential=False,tensor_type=torch.cuda.ByteTensor)),
('obscene', data.Field(
use_vocab=False,sequential=False,tensor_type=torch.cuda.ByteTensor)),
('threat', data.Field(
use_vocab=False,sequential=False,tensor_type=torch.cuda.ByteTensor)),
('insult', data.Field(
use_vocab=False,sequential=False,tensor_type=torch.cuda.ByteTensor)),
('identity_hate', data.Field(
use_vocab=False,sequential=False,tensor_type=torch.cuda.ByteTensor)),
])
LOGGER.debug("读 test csv file...")
test =torchtext.data.TabularDataset(
path='cache/dataset_test.csv',format='csv',
skip_header=True,
fields=[
('id', None),
('comment_text', comment)
])
LOGGER.debug("构建词表...")
comment.build_vocab(
train, val, test,
max_size=20000,
min_freq=50,
vectors=vectors
)
LOGGER.debug("预处理结束")
returntrain.examples, test.examples, comment
data.Field函数,定义了处理数据的pipline,然后返回给了comment,用于在data.TabularDataset中,针对csv 文件里的comment_text这一Field做处理。
其中:
comment =torchtext.data.Field(
sequential=True,# 该列数据是否是序列数据
fix_length=fix_length, #最大长度
tokenize=tokenizer, #标记化函数,上面定义过
pad_first=True,# 在句子前方 pad
tensor_type=torch.cuda.LongTensor, #数据转换后的类型
lower=lower# 是否小写
)
另外,.build_vocab也非常有用。
comment.build_vocab(
train, val, test,
max_size=20000, # 词典大小
min_freq=50, #词频率最小值
vectors=vectors #word embedding
)
它能够建立词汇表用于将token 或者词转化成数字,另外,它还能自动对齐word embedding (comment.vocab.vectors`)。
其他几个字段就是 label了,一共有6个:toxic, severe_toxic, obscene, threat, insult, identity_hate都是0-1变量.
data.TabularDataset.splits能够一次读取多个文件比如上面的代码中,我们就同时读取了训练集和验证集。另外,值得注意的是,在fields处理中,必须要按照顺序,一列一列的处理,不能跳过,所以,对一我们不要的那些列,需要显式的声明,比如:("id", None)。
四、分batch和迭代
def get_iterator(dataset, batch_size, train=True,
shuffle=True,repeat=False):
dataset_iter = torchtext.data.Iterator(
dataset, batch_size=batch_size, device=0,
train=train, shuffle=shuffle, repeat=repeat,
sort=False
)
return dataset_iter
创建迭代器非常简单,我们也可以自定义一些别的属性,不然 repeat 等等。
for examples inget_iterator(
train_dataset, batch_size, train=True,
shuffle=True,repeat=False
):
x =examples.comment_text #(fix_length, batch_size) Tensor
y =torch.stack([
examples.toxic,
examples.severe_toxic,
examples.obscene,
examples.threat,
examples.insult,
examples.identity_hate
],dim=1)
以及使用以训练的 word emebdding (假设你的 model 的 embedding 放在 word_em 下面,同时你的训练集叫 train_dataset)
model.word_em.weight.data = train_dataset.fields["comment_text"].vocab.vectors
至此,我们就完成了了数据从纯文本到纯 embedding 的转换了了。下一步就可以 Feed 进模型,比如 RNN等。
-END-
专 · 知
人工智能领域主题知识资料查看与加入专知人工智能服务群:
【专知AI服务计划】专知AI知识技术服务会员群加入与人工智能领域26个主题知识资料全集获取。欢迎微信扫一扫加入专知人工智能知识星球群,获取专业知识教程视频资料和与专家交流咨询!
请PC登录www.zhuanzhi.ai或者点击阅读原文,注册登录专知,获取更多AI知识资料!
请加专知小助手微信(扫一扫如下二维码添加),加入专知主题群(请备注主题类型:AI、NLP、CV、 KG等)交流~
请关注专知公众号,获取人工智能的专业知识!
点击“阅读原文”,使用专知