如何用spaCy训练一个文本分类模型

编程入门 行业动态 更新时间:2024-10-23 17:36:39

<a href=https://www.elefans.com/category/jswz/34/1771443.html style=如何用spaCy训练一个文本分类模型"/>

如何用spaCy训练一个文本分类模型

如何用spaCy训练一个文本分类模型

文本分类是将文本分成不同类别的过程。SpaCy通过textcat组件能够方便地进行自定义文本结构化分类。
文本分类通常用于对影评、酒店服务评论、新闻数据、文本主题等进行分类,或根据投诉类型对客户支持电子邮件进行分类等情况。对于实际案例,训练自定义文本分类模型能够提高分类准确率。本文将向您展示如何使用spaCy库构建自定义文本分类器。

本文的案例是基于《火电厂辅机运行规程》中的小标题进行分类的。

  • 目录
  1. 什么是自定义文本分类器模型?
  2. spaCy自定义文本分类入门
  3. 如何准备所需格式的训练数据集?
  4. 如何编写评分函数?
  5. 训练模型并对结果进行评估打分
  6. 用新文本测试模型
  • 先来看一个文本分类的典型用例。

我们在从亚马逊买了一本书之后会填写一份评价反馈。这些评论会帮助商家分析问题并改进服务。我们来看看这个过程:有数百万条评论是由客户填写的,有没有可能手动浏览每一条评论,看看是赞赏还是否定?

当然,不!第一步是将所有审查分为积极和消极两类。然后,你可以很容易地分析有多少人不满意以及为什么不满意。将文本分类为不同 组/标签 的过程称为文本分类。

文本分类的实现方法多种多样。我们将使用spaCy对文本进行分类。spaCy是一个非常流行的NLP库,它提供了最先进(state-of-the-art)的组件。对于实际应用,最好使用经过训练的自定义模型进行分类。下一节将首先介绍什么是定制模型,以及为什么我们需要定制。

##1 什么是自定义文本分类器模型?

假设你有一大堆电影评论/客户评论。你希望把每一个评论都分为正面的或负面的。如果使用默认的spaCy分类器,结果可能不是很好。但是,如果自己收集电影/客户评论的标记数据集,并在此基础上培训自己的模型呢?

结果会更好更准确!你可以通过训练自定义文本分类器来实现。首先在标记好数据集上对它进行训练,并为我们在类似上下文中的使用它做好准备。这非常有用,尤其是在数据量大的情况下,效果更好。

在接下来的部分中,我们将逐步探索如何在spaCy中训练自定义文本分类模型。

2 spaCy自定义文本分类入门

spaCy是一个用于执行NLP任务(如分类)的高级库。spaCy之所以备受青睐,一个重要原因是它允许轻松地构建或扩展文本分类模型。我们将使用这个功能进行文本分类。

接下来,我将用一个真实的例子演示如何训练文本分类器。假设你有文本数据,其中包含文本和分类标记。我们的任务是使用这些数据并训练我们的模型。最后,模型应该能够将一个新的没见过的文本上给出正确的分类标记。

将数据集读入CSV并查看内容。对于我们的任务,我们只需要2列。包含文本和分类标签栏。让我们将这两列提取到一个Dataframe中。

# Import pandas & read csv file
import pandas as pd
cat_set=pd.read_csv("./data/cat_set.csv")# 提取列,并查看dataframe 
cat_set = cat_set[['TEXT','CAT']]
cat_set.head(10)
-TEXTCAT
0润滑油净化装置的停运S
1汽动给水泵组事故处理E
2启动锅炉运行调整的主要任务M
3湿式搅拌机的启动R
4一次风机并列O
5引风机启动R
6高压流化风机启动前的检查B
7主机冷油器切换O
8真空系统投运R
9一次风机停止(两台风机运行停止一台)S

CAT标记说明:

标记英文说明中文说明
AAfter启动前
BBefore停运后
CCommon通用规定
EEmergency事故处理
MMaintain运行维护
OOpertation操作
RRun启动
SStop停运

通过上面的数据可以看到每个文本对应相应的标签。我们需要训练自定义模型,让其新的在训练数据中未出现过的文本进行分类。

我们从训练集中得到的原始数据。当我们使用spaCy时,为了训练我们的模型,我们导入spaCy包。导入后,可以加载一个预先训练好的模型,如“zh_core_web_sm”。稍后我们将向这个模型添加/修改文本分类器。对于任何spaCy模型,都可以通过 pipe_names 方法查看当前管道中存在的管道组件。

import spacy
nlp = spacy.load('zh_core_web_sm')
nlp.pipe_names

输出:
[‘tagger’, ‘parser’, ‘ner’]

可以看出它没有文本分类器。所以,我们需要将spaCy的内置textcat管道组件添加到管道中,用于文本分类。使用add_pipe()方法

text_cat=nlp.create_pipe( "textcat", config={"exclusive_classes": True, "architecture": "simple_cnn"})
nlp.add_pipe(text_cat, last=True)
nlp.pipe_names

这样当前管道就变为:

[‘tagger’, ‘parser’, ‘ner’, ‘textcat’]

现在,我们将用我们的数据集训练textcat。

首先,需要向管道组件添加所需的标签。使用add_label函数将这些标签添加到textcat。

for label in ["A","B","C","E","M","O","R","S"]:textcat.add_label(label)

3 如何准备所需格式的训练数据集?

默认textcat模型已经就绪,接下来只需要准备所需格式的数据。

可以编写一个load_data()函数,它将元组列表作为输入。每个元组包含文本和标签值。下面的代码演示了如何将我们的训练数据集转换成所需的格式:

将dataframe转换成一个tuples列表

cat_set['tuples'] = cat_set.apply(lambda row: (row['TEXT'],row['CAT']), axis=1)
train =cat_set['tuples'].tolist()
train[:10]

结果:

[(‘配料’, ‘O’), (‘当锅筒压力到0.3~0.4MPa时,进行如下工作:’, ‘O’), (‘扇区冷却三角手动充水’, ‘O’), (‘转速自动控制方式’, ‘O’), (‘扇区冷却三角程控充水步序:’, ‘O’), (‘尿素溶液输送和储存’, ‘O’), (‘扇区冷却三角程控充水’, ‘O’), (‘油罐油温控制’, ‘O’), (‘空预器事故停机’, ‘O’), (‘小机抽真空与主机同时进行,小机冲转前送轴封:’, ‘O’)]

接下来,您可以将train数据作为输入传递给load_data()函数。

load_data()函数执行以下函数:

  • 使用随机。随机()此函数防止任何基于示例顺序的训练。

  • 对于输入数据中的每个元组,根据标签值指定相应类别,并存储在cats中

  • 80%的输入数据将用于培训,20%用于评估。可以使用split参数更改此比例。

定义函数后,将元组列表传递给上述函数。该函数将返回文本和CAT,用于训练和评估。可以使用load_data()函数来获得最终的训练数据,如下面的代码所示。

def load_data(train, split=0.8):import randomimport pandas as pdtrain_data =cat_set['tuples'].tolist()    # Shuffle the datarandom.shuffle(train_data)texts, labels = zip(*train_data)# get the categories for each reviewcategories = ["A","B","C","E","M","O","R","S"]cats = []for y in labels:cat = {category: 0 for category in categories}cat[y] = 1cats.append(cat)# Splitting the training and evaluation datasplit = int(len(train_data) * split)return (texts[:split], cats[:split]), (texts[split:], cats[split:])# Calling the load_data() function 
(train_texts, train_cats), (dev_texts, dev_cats) = load_data(train)# Processing the final format of training data
train_data = list(zip(train_texts,[{'cats': cats} for cats in train_cats]))
train_data[:2]

我们得到最终期望的训练数据格式:

[(‘冲转、升速注意事项:’, {‘cats’: {‘A’: 0, ‘B’: 0, ‘C’: 1, ‘E’: 0, ‘M’: 0, ‘O’: 0, ‘R’: 0, ‘S’: 0}}), (‘炉前燃油系统启动’, {‘cats’: {‘A’: 0, ‘B’: 0, ‘C’: 0, ‘E’: 0, ‘M’: 0, ‘O’: 0, ‘R’: 1, ‘S’: 0}})]

4 如何编写评分函数?

至此,我们已经准备好了所需格式的训练数据,并将其存储在train_data变量中。同时,我们在textcat中得到了模型的文本分类器组件。所以,可以继续在我们的train_data上训练textcat。但是,是不是还少点什么?

对于我们要训练的模型,检查其是否符合我们的预期是很重要的。这一步即是评估模型。这是一个可选的步骤,但强烈建议为选择这一步。load_data()函数会将原始数据的大约20%分割出来进行模型评估。我们将用这个来测试模型的训练效果。

所以,让我们来编写一个函数evaluate(),它可以执行这个评估过程。稍后我们将在模型训练中调用这个evaluate()函数来查看模型的性能。

此函数以textcat和评估数据作为输入。对于评估数据中的每个文本,它从模型预测结果中读取score。代码如下:

def evaluate(tokenizer, textcat, texts, cats):docs = (tokenizer(text) for text in texts)tp = 0for i, doc in enumerate(textcat.pipe(docs)):#获取最大值对应的keygold = max(cats[i], key=cats[i].get)ds =  doc.cats.items()h = {}[h.update({k:v}) for k,v in ds]predict = max(h, key=h.get)if gold == predict:tp += 1precision = tp / len(texts)return precision

5 训练模型

训练数据存储在train_data变量中,组件存储在 texcat 中。

在开始训练之前,需要禁用除 textcat 之外的其他管道组件。这是为了防止其他组件在训练时受到影响。通过disable_pipes()方法完成。接下来,使用begin_training()函数返回优化器。

使用n_iter参数定义在训练数据上迭代模型的次数。在每一次迭代中,我们循环训练数据,并使用spaCy的minibatch和composition helpers将数据划分为多个batch。

spaCy的minibatch()函数将批量返回训练数据。它使用size参数来表示批量大小。您可以使用函数composition()生成size。

函数接受三个输入,分别是start(起始值)、stop(可以生成的最大值)和增长率。size会随着调用次数从start–>stop。

对于每个迭代,通过nlp.update()命令更新。参数如下:

  • docs:使用一个batch文本作为输入。将每个batch传递给zip方法,该方法将返回一个batch的文本和分类。

  • drop:这表示drop out率。

  • losses:字典,保存每个管道组件的损失。创建一个空字典并传递给它。

模型训练完成后,您可以通过调用我们在上一节中定义的evaluate()函数来评估模型所做的预测。

# coding=utf-8def load_data(split=0.8):import randomimport pandas as pdcat_set=pd.read_csv("./data/cat_set.csv")cat_set['tuples'] = cat_set.apply(lambda row: (row['TEXT'],row['CAT']), axis=1)train_data =cat_set['tuples'].tolist()    random.shuffle(train_data)texts, labels = zip(*train_data)# 为每个样本格式化分类字典categories = ["A","B","C","E","M","O","R","S"]cats = []for y in labels:cat = {category: 0 for category in categories}cat[y] = 1cats.append(cat)# 划分数据集split = int(len(train_data) * split)return (texts[:split], cats[:split]), (texts[split:], cats[split:])# 装载数据 
(train_texts, train_cats), (dev_texts, dev_cats) = load_data()
train_data = list(zip(train_texts,[{'cats': cats} for cats in train_cats]))from spacy.util import minibatch, compounding
import spacynlp = spacy.load('zh_core_web_sm')
text_cat=nlp.create_pipe( "textcat", config={"exclusive_classes": True, "architecture": "simple_cnn"})
nlp.add_pipe(text_cat, last=True)
for label in ["A","B","C","E","M","O","R","S"]:text_cat.add_label(label)n_iter = 10
# 禁用其他组件
other_pipes = [pipe for pipe in nlp.pipe_names if pipe != 'textcat']
with nlp.disable_pipes(*other_pipes):  # 只训练 textcatoptimizer = nlp.begin_training()print("Training the model...")print('{:^5}\t{:^5}'.format('LOSS', 'PRECISION'))# 开始训练for i in range(n_iter):losses = {}batches = minibatch(train_data, size=compounding(4., 32., 1.001))for batch in batches:texts, annotations = zip(*batch)nlp.update(texts, annotations, sgd=optimizer, drop=0.2,losses=losses)with text_cat.model.use_params(optimizer.averages):score = evaluate(nlp.tokenizer, text_cat, dev_texts, dev_cats)			   print('{0:.3f}\t{1:.3f}'.format(losses['textcat'], score))

结果如下:

Training the model...
LOSS 	PRECISION
3.979	0.800
1.143	0.832
0.618	0.853
0.424	0.842
0.293	0.863
0.186	0.842
0.226	0.863
0.187	0.842
0.139	0.832
0.101	0.842

6 用新文本测试模型

最终这个模型现在可以使用了。

我们来为全新未见过的文本创建一个spaCy doc。它的分类或预测结果将存储在Doc.cats属性。这个Doc.cats属性存储将标签映射到文本类别的评分字典。

#测试模型texts = ['变频装置操作原则','变频装置送电启动前检查项目','凝泵变频器检修转热备用']
docs = nlp.pipe(texts)
for doc in docs:print(doc.text)print(doc.cats)

测试结果:

变频装置操作原则
{'A': 1.4584960581487394e-06, 'B': 4.261386834514269e-07, 'C': 0.9997310042381287, 'E': 1.8897288782682153e-06, 'M': 1.6282596959626972e-07, 'O': 0.00022265917505137622, 'R': 5.221944476829776e-08, 'S': 4.2241339542670175e-05}
变频装置送电启动前检查项目
{'A': 9.86464146990329e-05, 'B': 0.9877699613571167, 'C': 0.009538334794342518, 'E': 0.0017646290361881256, 'M': 1.1881843420269433e-05, 'O': 5.8820318372454494e-05, 'R': 0.0003737462102435529, 'S': 0.0003839542914647609}
凝泵变频器检修转热备用
{'A': 0.568670928478241, 'B': 0.07395660877227783, 'C': 0.0025626164861023426, 'E': 0.21869421005249023, 'M': 0.003099241992458701, 'O': 0.11320023983716965, 'R': 0.0005361264338716865, 'S': 0.019280044361948967}

这三个句子对应的标记模型给出的结果:‘C’, ‘B’ , ‘A’
我们期望的是:‘C’ , ‘B’ , ‘O’

结语

希望通过上述一个简单的例子,你已经了解了如何使用spaCy训练自定义文本分类模型。使用spaCy训练模型在各个领域都有广泛的应用。与此类似,spaCy还可以训练自定义NER模型,这部分将另开新贴进行论述,敬请关注!

P.s.
很遗憾,这个例子是在spaCy 2.3.0下运行的。如果可能,将来我会将其移植到spaCy V3.0下。

更多推荐

如何用spaCy训练一个文本分类模型

本文发布于:2024-02-25 13:58:55,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1699200.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:如何用   模型   文本   spaCy

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!