词嵌⼊教程
作者|Shraddha Anala
编译|VK
来源|Towards Data Science
⽆论我们是谁,阅读、理解、交流并最终产⽣新的内容是我们在职业⽣活中都要做的事情。
当涉及到从给定的⽂本体中提取有⽤的特征时,所涉及的过程与连续整数向量(词袋)相⽐是根本不同的。这是因为句⼦或⽂本中的信息是以结构化的顺序编码的,单词的语义位置传达了⽂本的意思。
因此,在保持⽂本的上下⽂意义的同时,对数据进⾏适当表⽰的双重要求促使我学习并实现了两种不同的NLP模型来实现⽂本分类的任务。
词嵌⼊是⽂本中单个单词的密集表⽰,考虑到上下⽂和其他与之相关的单词。
与简单的词袋模型相⽐,该实值向量可以更有效地选择维数,更有效地捕捉词与词之间的语义关系。
简单地说,具有相似含义或经常出现在相似上下⽂中的词,将具有相似的向量表⽰,这取决于这些词在其
含义中的“接近”或“相距”有多远。
在本⽂中,我将探讨两个词的嵌⼊-
1. 训练我们⾃⼰的嵌⼊
2. 预训练的GloVe 词嵌⼊
数据集
现在让我们看看这个多分类NLP项⽬的实际模型本⾝。
但是,在开始之前,请确保你已经安装了这些包/库。
pip install gensim            # ⽤于NLP预处理任务
pip install keras            # 嵌⼊层
1. 训练词嵌⼊
1)数据预处理
在第⼀个模型中,我们将训练⼀个神经⽹络来从我们的⽂本语料库中学习嵌⼊。具体地说,我们将使⽤Keras库为神经⽹络的嵌⼊层提供词标识及其索引。
在训练我们的⽹络之前,必须确定⼀些关键参数。这些包括词汇的⼤⼩或语料库中唯⼀单词的数量以及嵌⼊向量的维数。
我还更改了列名并定义了⼀个函数text_clean来清理问题。
# 导⼊库
# 数据操作/处理
import pandas as pd, numpy as np
# 可视化
import seaborn as sb, matplotlib.pyplot as plt
# NLP
import re
pus import stopwords
from gensim.utils import simple_preprocess
stop_words = set(stopwords.words('english'))
# 导⼊数据集
dataset = pd.read_csv('train.csv')[['Body', 'Y']].rename(columns = {'Body': 'question', 'Y': 'category'})
ds = pd.read_csv('valid.csv')[['Body', 'Y']].rename(columns = {'Body': 'question', 'Y': 'category'})
# 清理符号和HTML标签
symbols = repile(pattern = '[/<>(){}\[\]\|@,;]')
tags = ['href', 'http', 'https', 'www']
def text_clean(s: str) -> str:
s = symbols.sub(' ', s)
for i in tags:
s = s.replace(i, ' ')
return ' '.join(word for word in simple_preprocess(s) if not word in stop_words)
dataset.iloc[:, 0] = dataset.iloc[:, 0].apply(text_clean)
ds.iloc[:, 0] = ds.iloc[:, 0].apply(text_clean)
# 训练和测试集
X_train, y_train = dataset.iloc[:, 0].values, dataset.iloc[:, 1].shape(-1, 1)
X_test, y_test = ds.iloc[:, 0].values, ds.iloc[:, 1].shape(-1, 1)
# one-hot编码
from sklearn.preprocessing import OneHotEncoder as ohe
from sklearnpose import ColumnTransformer
ct = ColumnTransformer(transformers = [('one_hot_encoder', ohe(categories = 'auto'), [0])],
remainder = 'passthrough')
y_train = ct.fit_transform(y_train)
y_test = ct.transform(y_test)
# 设置参数
vocab_size = 2000
sequence_length = 100
如果你浏览原始数据集,你会发现HTML标记中包含的问题,例如,
…question
。此外,还有⼀些词,如href,https等,在整个⽂本中都有,所以我要确保从⽂本中删除这两组不需要的字符。
Gensim的simple_preprocess⽅法返回⼀个⼩写的标记列表,去掉重⾳符号。
在这⾥使⽤apply⽅法将通过预处理函数迭代运⾏每⼀⾏,并在继续下⼀⾏之前返回输出。对训练和测试数据集应⽤⽂本预处理功能。
因为在因变量向量中有3个类别,我们将应⽤one-hot编码并初始化⼀些参数以备以后使⽤。
2)标识化
接下来,我们将使⽤Keras Tokenizer类将单词组成的问题转换成⼀个数组,⽤它们的索引表⽰单词。
因此,我们⾸先必须使⽤fit_on_texts⽅法,从数据集中出现的单词构建索引词汇表。
在建⽴词汇表之后,我们使⽤text_to_sequences⽅法将句⼦转换成表⽰单词的数字列表。
pad_sequences函数确保所有观察值的长度相同,可以设置为任意数字或数据集中最长问题的长度。
我们先前初始化的vocab_size参数只是我们词汇表的⼤⼩(⽤于学习和索引)。
# Keras的标识器
from import Tokenizer
tk = Tokenizer(num_words = vocab_size)
tk.fit_on_texts(X_train)
X_train = tk.texts_to_sequences(X_train)
X_test = tk.texts_to_sequences(X_test)
# ⽤0填充所有
from keras.preprocessing.sequence import pad_sequences
X_train_seq = pad_sequences(X_train, maxlen = sequence_length, padding = 'post')
X_test_seq = pad_sequences(X_test, maxlen = sequence_length, padding = 'post')
3)训练嵌⼊层
最后,在这⼀部分中,我们将构建和训练我们的模型,它由两个主要层组成,⼀个嵌⼊层将学习上⾯准备的训练⽂档,以及⼀个密集的输出层来实现分类任务。
嵌⼊层将学习单词的表⽰,同时训练神经⽹络,需要⼤量的⽂本数据来提供准确的预测。在我们的例⼦中,45000个训练观察值⾜以有效地学习语料库并对问题的质量进⾏分类。我们将从指标中看到。
# 训练嵌⼊层和神经⽹络
dels import Sequential
from keras.layers import Embedding, Dense, Flatten
model = Sequential()
model.add(Embedding(input_dim = vocab_size, output_dim = 5, input_length = sequence_length))
model.add(Flatten())
model.add(Dense(units = 3, activation = 'softmax'))
modelpile(loss = 'categorical_crossentropy',
optimizer = 'rmsprop',
metrics = ['accuracy'])
model.summary()numpy教程 pdf
history = model.fit(X_train_seq, y_train, epochs = 20, batch_size = 512, verbose = 1)
# 完成训练后保存模型
#model.save("model.h5")
4)评估和度量图
剩下的就是评估我们的模型的性能,并绘制图来查看模型的准确性和损失指标是如何随时间变化的。
我们模型的性能指标显⽰在下⾯的屏幕截图中。
代码与下⾯显⽰的代码相同。
# 在测试集上评估模型的性能
loss, accuracy = model.evaluate(X_test_seq, y_test, verbose = 1)
print("\nAccuracy: {}\nLoss: {}".format(accuracy, loss))
# 画出准确度和损失
sb.set_style('darkgrid')
# 1) 准确度
plt.plot(history.history['accuracy'], label = 'training', color = '#003399')
plt.legend(shadow = True, loc = 'lower right')
plt.title('Accuracy Plot over Epochs')
plt.show()
# 2) 损失
plt.plot(history.history['loss'], label = 'training loss', color = '#FF0033')
plt.legend(shadow = True, loc = 'upper right')
plt.title('Loss Plot over Epochs')
plt.show()
以下是训练中准确度的提⾼
20个epoch的损失图
2.预训练的GloVe词嵌⼊
i)选择⼀个预训练的词嵌⼊,如果
你的数据集是由更“通⽤”的语⾔组成的,⼀般来说你没有那么⼤的数据集。
由于这些嵌⼊已经根据来⾃不同来源的⼤量单词进⾏了训练,如果你的数据也是通⽤的,那么预训练的模型可能会做得很好。此外,通过预训练的嵌⼊,你可以节省时间和计算资源。
ii)选择训练你⾃⼰的嵌⼊,如果
你的数据(和项⽬)是基于⼀个利基⾏业,如医药、⾦融或任何其他⾮通⽤和⾼度特定的领域。
在这种情况下,⼀般的词嵌⼊表⽰法可能不适合你,并且⼀些单词可能不在词汇表中。
需要⼤量的领域数据来确保所学的词嵌⼊能够正确地表⽰不同的单词以及它们之间的语义关系
此外,它需要⼤量的计算资源来浏览你的语料库和建⽴词嵌⼊。
最终,是根据已有的数据训练你⾃⼰的嵌⼊,还是使⽤预训练好的嵌⼊,将取决于你的项⽬。
显然,你仍然可以试验这两种模型,并选择⼀种精度更⾼的模型,但上⾯的教程只是⼀个简化的教程,可以帮助你做出决策。过程
前⾯的部分已经采取了所需的⼤部分步骤,只需进⾏⼀些调整。
我们只需要构建⼀个单词及其向量的嵌⼊矩阵,然后⽤它来设置嵌⼊层的权重。
所以,保持预处理、标识化和填充步骤不变。
⼀旦我们导⼊了原始数据集并运⾏了前⾯的⽂本清理步骤,我们将运⾏下⾯的代码来构建嵌⼊矩阵。以下决定要嵌⼊多少个维度(50、100、200),并将其名称包含在下⾯的路径变量中。
# # 导⼊嵌⼊
path = 'Full path to your glove file (with the dimensions)'
embeddings = dict()
with open(path, 'r', encoding = 'utf-8') as f:
for line in f:
# ⽂件中的每⼀⾏都是⼀个单词外加50个数(表⽰这个单词的向量)
values = line.split()
# 每⼀⾏的第⼀个元素是⼀个单词,其余的50个是它的向量
embeddings[values[0]] = np.array(values[1:], 'float32')
# 设置⼀些参数
vocab_size = 2100
glove_dim = 50
sequence_length = 200
# 从语料库中的单词构建嵌⼊矩阵
embedding_matrix = np.zeros((vocab_size, glove_dim))
for word, index in word_index.items():
if index < vocab_size:
try:
# 如果给定单词的嵌⼊存在,检索它并将其映射到单词。
embedding_matrix[index] = embeddings[word]
except:
pass
构建和训练嵌⼊层和神经⽹络的代码应该稍作修改,以允许将嵌⼊矩阵⽤作权重。
# 神经⽹络
dels import Sequential
from keras.layers import Embedding, Dense, Flatten
model = Sequential()
model.add(Embedding(input_dim = vocab_size,
output_dim = glove_dim,
input_length = sequence))
model.add(Flatten())
model.add(Dense(units = 3, activation = 'softmax'))
modelpile(optimizer = 'adam', metrics = ['accuracy'], loss = 'categorical_crossentropy')
# 加载我们预训练好的嵌⼊矩阵到嵌⼊层
model.layers[0].set_weights([embedding_matrix])
model.layers[0].trainable = False          # 训练时权重不会被更新
# 训练模型
history = model.fit(X_train_seq, y_train, epochs = 20, batch_size = 512, verbose = 1)
下⾯是我们预训练的模型在测试集中的性能指标。
结论
从两个模型的性能指标来看,训练嵌⼊层似乎更适合这个数据集。
⼀些原因可能是
1)关于堆栈溢出的⼤多数问题都与IT和编程有关,也就是说,这是⼀个特定领域的场景。
2) 45000个样本的⼤型训练数据集为我们的嵌⼊层提供了⼀个很好的学习场景。
希望本教程对你有帮助,谢谢你的阅读,下⼀篇⽂章再见。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。