词嵌入教程_单词_模子
当涉及到从给定的文本体中提取有用的特色时,所涉及的过程与连续整数向量(词袋)比较是根本不同的。这是由于句子或文本中的信息因此构造化的顺序编码的,单词的语义位置传达了文本的意思。
因此,在保持文本的高下文意义的同时,对数据进行适当表示的双主要求匆匆使我学习并实现了两种不同的NLP模型来实现文本分类的任务。
词嵌入是文本中单个单词的密集表示,考虑到高下文和其他与之干系的单词。
与大略的词袋模型比较,该实值向量可以更有效地选择维数,更有效地捕捉词与词之间的语义关系。
大略地说,具有相似含义或常常涌如今相似高下文中的词,将具有相似的向量表示,这取决于这些词在其含义中的“靠近”或“相距”有多远。
在本文中,我将磋商两个词的嵌入-
演习我们自己的嵌入预演习的GloVe 词嵌入数据集对付这个案例研究,我们将利用Kaggle的Stack Overflow 数据集(https://www.kaggle.com/imoore/60k-stack-overflow-questions-with-quality-rate)。这个数据集包含了6万个用户在网站上提出的问题,紧张任务是将问题分为3类。
现在让我们看看这个多分类NLP项目的实际模型本身。
但是,在开始之前,请确保你已经安装了这些包/库。
pip install gensim # 用于NLP预处理任务pip install keras # 嵌入层
1. 演习词嵌入
如果你希望跳过阐明,请访问第一个模型的完全代码:https://github.com/shraddha-an/nlp/blob/main/word_embedding_classification.ipynb
1) 数据预处理在第一个模型中,我们将演习一个神经网络来从我们的文本语料库中学习嵌入。详细地说,我们将利用Keras库为神经网络的嵌入层供应词标识及其索引。
在演习我们的网络之前,必须确定一些关键参数。这些包括词汇的大小或语料库中唯一单词的数量以及嵌入向量的维数。
以下链接是用于演习和测试的数据集。现在我们将导入它们,只保留问题和质量列以供剖析:https://www.kaggle.com/imoore/60k-stack-overflow-questions-with-quality-rate
我还变动了列名并定义了一个函数text_clean来清理问题。
# 导入库# 数据操作/处理import pandas as pd, numpy as np# 可视化import seaborn as sb, matplotlib.pyplot as plt# NLPimport refrom nltk.corpus import stopwordsfrom gensim.utils import simple_preprocessstop_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 = re.compile(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].values.reshape(-1, 1)X_test, y_test = ds.iloc[:, 0].values, ds.iloc[:, 1].values.reshape(-1, 1)# one-hot编码from sklearn.preprocessing import OneHotEncoder as ohefrom sklearn.compose import ColumnTransformerct = 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 = 2000sequence_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 keras.preprocessing.text import Tokenizertk = 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_sequencesX_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个演习不雅观察值足以有效地学习语料库并对问题的质量进行分类。我们将从指标中看到。
# 演习嵌入层和神经网络from keras.models import Sequentialfrom keras.layers import Embedding, Dense, Flattenmodel = 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'))model.compile(loss = 'categorical_crossentropy', optimizer = 'rmsprop', metrics = ['accuracy'])model.summary()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词嵌入
如果你只想运行模型,这里有完全的代码:https://github.com/shraddha-an/nlp/blob/main/pretrained_glove_classification.ipynb
代替演习你自己的嵌入,另一个选择是利用预演习好的词嵌入,比如GloVe或Word2Vec。在这一部分中,我们将利用在Wikipedia+gigaword5上演习的GloVe词嵌入;从这里***:https://nlp.stanford.edu/projects/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 = 2100glove_dim = 50sequence_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
构建和演习嵌入层和神经网络的代码该当稍作修正,以许可将嵌入矩阵用作权重。
# 神经网络from keras.models import Sequentialfrom keras.layers import Embedding, Dense, Flattenmodel = 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'))model.compile(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个样本的大型演习数据集为我们的嵌入层供应了一个很好的学习场景。
本文系作者个人观点,不代表本站立场,转载请注明出处!