FastText 快速启动指南(二)
原文:
annas-archive.org/md5/edb0de43f18c2f8ccf389e03f95e34fb译者:飞龙
第九章:机器学习和深度学习模型
在我们到目前为止讨论的几乎所有应用中,都隐含着一个假设,那就是你正在创建一个新的机器学习 NLP 流水线。现在,情况不一定总是如此。如果你已经在一个成熟的平台上工作,fastText 可能也是一个很好的补充,可以使流水线更强大。
本章将为你提供一些使用流行框架(如 scikit-learn、Keras、TensorFlow 和 PyTorch)实现 fastText 的方法和示例。我们将讨论如何利用其他深度神经网络架构,如卷积神经网络(CNN)或注意力网络,来增强 fastText 词嵌入的能力,解决各种 NLP 问题。
本章涵盖的主题如下:
-
Scikit-learn 和 fastText
-
嵌入层
-
Keras
-
Keras 中的嵌入层
-
卷积神经网络架构
-
TensorFlow
-
PyTorch
-
Torchtext
Scikit-learn 和 fastText
在本节中,我们将讨论如何将 fastText 集成到统计模型中。最常用和流行的统计机器学习库是 scikit-learn,因此我们将重点关注它。
scikit-learn 是最流行的机器学习工具之一,原因是其 API 非常简单且统一。流程如下:
-
你基本上是将数据转换为矩阵格式。
-
然后,你创建预测类的实例。
-
使用实例,你在数据上运行
fit方法。 -
一旦模型创建完成,你可以在其上运行
predict。
这意味着你可以通过定义 fit 和 predict 方法来创建一个自定义分类器。
fastText 的自定义分类器
由于我们有兴趣将 fastText 词向量与线性分类器结合使用,你不能直接传递整个向量,而是需要一种方法来定义一个单一的向量。在这种情况下,我们选择使用均值:
class MeanEmbeddingVectorizer(object):
def __init__(self, ft_wv):
self.ft_wv = ft_wv
if len(ft_wv)>0:
self.dim = ft_wv[next(iter(all_words))].shape[0]
else:
self.dim=0
def fit(self, X, y):
return self
def transform(self, X):
return np.array([
np.mean([self.ft_wv[w] for w in words if w in self.ft_wv]
or [np.zeros(self.dim)], axis=0)
for words in X
])
现在,你需要将令牌字典传递给模型,该字典可以通过 fastText 库构建:
f = load_model(FT_MODEL)
all_words = set([x for tokens in data['tokens'].values for x in tokens])
wv_dictionary = {w: f.get_word_vector(w) for w in all_words}
将整个过程整合在一起
你可以使用 scikit-learn 的 Pipeline 来将整个流程组合在一起,如下所示:
etree_w2v = Pipeline([("fasttext word-vector vectorizer", MeanEmbeddingVectorizer(wv_dictionary)),
("extra trees", ExtraTreesClassifier(n_estimators=200))])
整个代码显示在统计机器学习笔记本中。为了进一步提高模型的效果,如果你能找到更好的方法来减少词向量,TF-IDF 已在共享笔记本中展示。另一种减少词向量的方法是使用哈希转换器。
在接下来的几节中,我们将探讨如何在深度学习模型中嵌入 fastText 向量。
嵌入层
正如你所看到的,当你需要在机器学习中处理文本时,你需要将文本转换为数值。神经网络架构中也有相同的逻辑。在神经网络中,你通过实现嵌入层来做到这一点。所有现代深度学习库都提供了嵌入 API 供使用。
嵌入层是一个有用且多功能的层,用于各种目的:
-
它可以用于学习词嵌入,以便稍后在应用中使用
-
它可以与更大的模型一起使用,在该模型中,嵌入也会作为模型的一部分进行调优
-
它可以用来加载预训练的词嵌入
本节的重点是第三点。我们的想法是利用 fastText 创建更优的词嵌入,然后通过这个嵌入层将其注入到你的模型中。通常,嵌入层会使用随机权重进行初始化,但在这种情况下,我们将通过 fastText 模型的词嵌入来初始化它。
Keras
Keras 是一个广泛流行的高级神经网络 API。它支持 TensorFlow、CNTK 和 Theano 作为后端。由于 Keras 具有用户友好的 API,许多人使用它代替基础库。
Keras 中的嵌入层
嵌入层将是 Keras 网络的第一个隐藏层,你需要指定三个参数:输入维度、输出维度和输入长度。由于我们将使用 fastText 来改善模型,因此还需要传递带有嵌入矩阵的权重参数,并将训练矩阵设置为不可训练:
embedding_layer = Embedding(num_words,
EMBEDDING_DIM,
weights=[embedding_matrix],
input_length=MAX_SEQUENCE_LENGTH,
trainable=False)
另外,我们需要注意的是,我们需要将词映射到整数,并将整数映射回词。在 Keras 中,你可以使用Tokenizer类来实现这一点。
让我们在卷积神经网络(CNN)中看看这一过程的实际应用。
卷积神经网络
当我们讨论将词嵌入和神经网络结合时,卷积神经网络是取得良好成果的一种方法。CNN 是通过在结果上应用多个卷积层和非线性激活函数(如 ReLu 或tanh)创建的。
让我们稍微谈一下什么是卷积。一个函数与另一个函数的卷积是一个积分,表示一个函数在经过另一个函数时的重叠量。你可以把它理解为将一个函数融合到另一个函数中。在信号理论中,专家是这样理解卷积的:输出信号是输入信号与环境冲击响应的卷积。任何环境的冲击响应本质上识别并区分该环境。
在传统的前馈神经网络中,我们将每个输入神经元连接到下一层中的每个输出神经元。而在 CNN 中,我们则使用卷积来计算输出。在训练阶段,CNN 会自动学习过滤器的值。
CNN 通常与词嵌入一起使用,在这里,fastText 就发挥了作用,它能够通过提供更好的词表示来在分类精度上带来巨大的提升。因此,架构由三个关键部分组成:
如果你在分类管道中已经有了这三个架构组件,你可以识别出词嵌入部分,看看是否将其更换为 fastText 能改善预测效果。
在这个示例中,我们将回顾之前的 Yelp 评论示例,并尝试使用卷积神经网络对其进行分类。为了简便起见,我们将使用一个已经发布的预训练数据集,但你可能会处理一个特定领域的用例,因此你应该按照前一章中的示范,整合模型的创建。如你所见,你可以使用 fastText 库或 Gensim 库。
从高层次来看,步骤如下:
-
数据集中的文本样本会被转换为单词索引序列。单词索引 仅仅是一个整数 ID,表示某个单词。我们将只考虑数据集中最常见的 20,000 个单词,并将序列截断至最多 1,000 个单词。这么做是为了计算的方便。你可以尝试这种方法,并找到最能带来通用性的做法。
-
准备一个嵌入矩阵,它将在索引
i处包含单词索引中单词i的嵌入向量。 -
然后将嵌入矩阵加载到 Keras 嵌入层,并将该层设置为冻结状态,以确保在训练过程中不会被更新。
-
紧接其后的层将是卷积网络。最后将有一个 softmax 层,将输出收敛到我们的五个类别。
在这种情况下,我们可以使用 pandas 库来创建输入文本的列表和输出标签的列表:
>>> df = pd.read_csv('yelp_review.csv')
>>> texts = df.text.values
>>> labels = df.stars.values
>>> texts = texts[:20000]
>>> labels = labels[:20000]
>>> print('Found %s texts.' % len(texts))
Found 20000 texts.
现在,我们需要将文本样本和标签格式化为可以输入神经网络的张量。在这一部分,我们将使用Tokenizer类。我们还需要对序列进行填充,以保证所有矩阵的长度相等:
>>> # finally, vectorize the text samples into a 2D integer tensor
>>> tokenizer = Tokenizer(num_words=MAX_NUM_WORDS)
>>> tokenizer.fit_on_texts(texts)
>>> sequences = tokenizer.texts_to_sequences(texts)
>>> word_index = tokenizer.word_index
>>> print('Found %s unique tokens.' % len(word_index))
Found 45611 unique tokens.
>>> data = pad_sequences(sequences, maxlen=MAX_SEQUENCE_LENGTH)
>>> labels = to_categorical(np.asarray(labels))
>>> print('Shape of data tensor:', data.shape)
>>> print('Shape of label tensor:', labels.shape)
Shape of data tensor: (20000, 1000)
Shape of label tensor: (20000, 6)
>>> # split the data into a training set and a validation set
>>> indices = np.arange(data.shape[0])
>>> np.random.shuffle(indices)
>>> data = data[indices]
>>> labels = labels[indices]
>>> num_validation_samples = int(VALIDATION_SPLIT * data.shape[0])
>>> x_train = data[:-num_validation_samples]
>>> y_train = labels[:-num_validation_samples]
>>> x_val = data[-num_validation_samples:]
>>> y_val = labels[-num_validation_samples:]
现在我们将使用我们的 fastText 嵌入。在这个案例中,我们使用的是预训练嵌入,但你也可以在训练过程中动态地训练自己的嵌入。你可以选择从.vec文件加载,但由于这是 fastText,我们将从 BIN 文件加载。使用 BIN 文件的优势在于,它可以在很大程度上避免词汇表外的情况。我们将使用 fastText 模型并生成一个嵌入矩阵:
>>> print('Preparing embedding matrix.')
>>># load the fasttext model
>>> f = load_model(FT_MODEL)
>>> # prepare embedding matrix
>>> num_words = min(MAX_NUM_WORDS, len(word_index) + 1)
>>> embedding_matrix = np.zeros((num_words, EMBEDDING_DIM))
>>> for word, i in word_index.items():
... if i >= MAX_NUM_WORDS:
... continue
... embedding_vector = f.get_word_vector(word)
... if embedding_vector is not None:
... # words not found in embedding index will be all-zeros.
... embedding_matrix[i] = embedding_vector
我们将其加载到嵌入层。需要注意的是,trainable参数应该设置为False,以防止在训练过程中更新权重,如下所示:
>>> # load pre-trained word embeddings into an Embedding layer
>>> embedding_layer = Embedding(num_words,
... EMBEDDING_DIM,
... weights=[embedding_matrix],
... input_length=MAX_SEQUENCE_LENGTH,
... trainable=False)
现在,我们可以构建一个 1D 卷积网络来应用于我们的 Yelp 分类问题:
>>> # train a 1D convnet with global maxpooling
>>> sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')
>>> embedded_sequences = embedding_layer(sequence_input)
>>> x = Conv1D(128, 5, activation='relu')(embedded_sequences)
>>> x = MaxPooling1D(5)(x)
>>> x = Conv1D(128, 5, activation='relu')(x)
>>> x = MaxPooling1D(5)(x)
>>> x = Conv1D(128, 5, activation='relu')(x)
>>> x = GlobalMaxPooling1D()(x)
>>> x = Dense(128, activation='relu')(x)
>>> preds = Dense(6, activation='softmax')(x)
该模型的摘要如下所示:
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) (None, 1000) 0
_______________________________________________________________
embedding_1 (Embedding) (None, 1000, 300) 6000000 _______________________________________________________________
conv1d_1 (Conv1D) (None, 996, 128) 192128
_______________________________________________________________
max_pooling1d_1 (MaxPooling1 (None, 199, 128) 0 _______________________________________________________________
conv1d_2 (Conv1D) (None, 195, 128) 82048
_______________________________________________________________
max_pooling1d_2 (MaxPooling1 (None, 39, 128) 0 _______________________________________________________________
conv1d_3 (Conv1D) (None, 35, 128) 82048
_______________________________________________________________
global_max_pooling1d_1 (Glob (None, 128) 0
_______________________________________________________________
dense_1 (Dense) (None, 128) 16512
_______________________________________________________________
dense_2 (Dense) (None, 6) 774
=================================================================
Total params: 6,373,510
Trainable params: 373,510
Non-trainable params: 6,000,000
_________________________________________________________________
现在,你可以尝试一些其他的超参数,看看能否提高准确度。
在本节中,你了解了如何将 fastText 词嵌入作为更大 CNN Keras 分类器的一部分。使用类似的方法,你可以在 Keras 中使用 fastText 嵌入与任何受益于词嵌入的神经网络架构。
TensorFlow
TensorFlow 是由 Google 开发的一个计算库。它现在非常流行,许多公司使用它来创建他们的神经网络模型。在你在 Keras 中看到的内容之后,使用 fastText 增强 TensorFlow 模型的逻辑是相同的。
TensorFlow 中的词嵌入
要在 TensorFlow 中创建词嵌入,你需要创建一个嵌入矩阵,其中所有文档列表中的标记都有唯一的 ID,因此每个文档都是这些 ID 的向量。现在,假设你有一个 NumPy 数组叫做word_embedding,它有vocab_size行和embedding_dim列,并且你想要创建一个张量W。以一个具体的例子,“I have a cat.”可以分解为["I", "have", "a", "cat", "." ],对应的word_ids张量的形状将是 5。为了将这些单词 ID 映射到向量中,创建词嵌入变量并使用tf.nn.embedding_lookup函数:
word_embeddings = tf.get_variable(“word_embeddings”,
[vocabulary_size, embedding_size])
embedded_word_ids = tf.nn.embedding_lookup(word_embeddings, word_ids)
之后,embedded_word_ids张量将在我们的示例中具有shape [5, embedding_size],并包含五个单词的嵌入(密集向量)。
为了能够使用带有预训练向量的词嵌入,创建W作为tf.Variable,并通过tf.placeholder()从 NumPy 数组初始化它:
with tf.name_scope("embedding"):
W = tf.Variable(tf.constant(0.0,
shape=[doc_vocab_size,
embedding_dim]),
trainable=False,
name="W")
embedding_placeholder = tf.placeholder(tf.float32,
[doc_vocab_size, embedding_dim])
embedding_init = W.assign(embedding_placeholder)
embedded_chars = tf.nn.embedding_lookup(W,x)
然后,你可以在 TensorFlow 会话中传递实际的嵌入:
sess = tf.Session()
sess.run(embedding_init, feed_dict={embedding_placeholder: embedding})
这样可以避免在图中存储嵌入的副本,但它确实需要足够的内存来同时保留矩阵的两个副本(一个用于 NumPy 数组,一个用于tf.Variable)。你希望在训练过程中保持词嵌入不变,因此如前所述,词嵌入的可训练参数需要设置为False。
RNN 架构
自然语言处理(NLP)一直被认为是 LSTM 和 RNN 类型神经网络架构的一个绝佳应用案例。LSTM 和 RNN 使用顺序处理。NLP 一直被认为是最大应用案例之一,因为任何句子的意义都是基于上下文的。一个单词的意义可以被认为是基于它之前的所有单词来确定的:
现在,当你运行 LSTM 网络时,你需要将单词转换成嵌入层。通常在这种情况下,会使用随机初始化器。但你可能应该能够通过使用 fastText 模型来提高模型的性能。让我们来看看在这种情况下如何使用 fastText 模型。
在这个例子中,由 Facebook 发布的爬取向量被加载到内存中。在你的使用案例中,你可能需要在你的文本语料库上训练一个 fastText 模型并加载该模型。我们在这里使用 VEC 文件来创建嵌入,但你也可以选择从.bin文件加载,如 Keras 示例中所示:
#Load fasttext vectors
filepath_glove = 'crawl-300d-2M.vec'
glove_vocab = []
glove_embd=[]
embedding_dict = {}
with open(filepath_glove) as file:
for index, line in enumerate(file):
values = line.strip().split() # Word and weights separated by space
if index == 0:
glove_vocab_size = int(values[0])
embedding_dim = int(values[1])
else:
row = line.strip().split(' ')
vocab_word = row[0]
glove_vocab.append(vocab_word)
embed_vector = [float(i) for i in row[1:]] # convert to list of float
embedding_dict[vocab_word]=embed_vector
调用你感兴趣的文本块,然后执行正常的清理步骤。类似于 Keras 中的示例,接下来你将需要一个机制,将标记映射到唯一的整数,并能通过整数获取回标记。因此,我们需要创建一个字典和一个反向字典来存储单词:
#Create dictionary and reverse dictionary with word ids
def build_dictionaries(words):
count = collections.Counter(words).most_common() #creates list of word/count pairs;
dictionary = dict()
for word, _ in count:
dictionary[word] = len(dictionary) #len(dictionary) increases each iteration
reverse_dictionary = dict(zip(dictionary.values(), dictionary.keys()))
return dictionary, reverse_dictionary
dictionary, reverse_dictionary = build_dictionaries(training_data)
我们使用 fastText 模型创建的字典来创建嵌入数组:
#Create embedding array
doc_vocab_size = len(dictionary)
dict_as_list = sorted(dictionary.items(), key = lambda x : x[1])
embeddings_tmp=[]
for i in range(doc_vocab_size):
item = dict_as_list[i][0]
if item in glove_vocab:
embeddings_tmp.append(embedding_dict[item])
else:
rand_num = np.random.uniform(low=-0.2, high=0.2,size=embedding_dim)
embeddings_tmp.append(rand_num)
# final embedding array corresponds to dictionary of words in the document
embedding = np.asarray(embeddings_tmp)
# create tree so that we can later search for closest vector to prediction
tree = spatial.KDTree(embedding)
接下来,我们设置 RNN 模型。我们将每次读取三个单词,因此我们的 x 是一个行数不确定、宽度为三列的矩阵。另一个需要注意的输入是 embedding_placeholder,它每个单词有一行,宽度为 300 维,对应输入词向量的维度数。
然后,TensorFlow 的 tf.nn.embedding_lookup() 函数可以用于从矩阵 W 中查找每个来自 x 的输入,从而生成 3D 张量 embedded_chars。接着,可以将其输入到 RNN 中:
# create input placeholders
x = tf.placeholder(tf.int32, [None, n_input])
y = tf.placeholder(tf.float32, [None, embedding_dim])
# RNN output node weights and biases
weights = { 'out': tf.Variable(tf.random_normal([n_hidden, embedding_dim])) }
biases = { 'out': tf.Variable(tf.random_normal([embedding_dim])) }
with tf.name_scope("embedding"):
W = tf.Variable(tf.constant(0.0, shape=[doc_vocab_size, embedding_dim]), trainable=False, name="W")
embedding_placeholder = tf.placeholder(tf.float32, [doc_vocab_size, embedding_dim])
embedding_init = W.assign(embedding_placeholder)
embedded_chars = tf.nn.embedding_lookup(W,x)
# reshape input data
x_unstack = tf.unstack(embedded_chars, n_input, 1)
# create RNN cells
rnn_cell = rnn.MultiRNNCell([rnn.BasicLSTMCell(n_hidden),rnn.BasicLSTMCell(n_hidden)])
outputs, states = rnn.static_rnn(rnn_cell, x_unstack, dtype=tf.float32)
# capture only the last output
pred = tf.matmul(outputs[-1], weights['out']) + biases['out']
既然我们已经有了 RNN,接下来需要弄清楚如何训练它以及可以使用什么样的代价函数。FastText 内部使用 softmax 函数。softmax 函数在这里可能不适合作为代价函数,因为按照定义,softmax 会在比较之前对向量进行归一化。因此,实际的向量可能会以任意的方式变大或变小。也许有必要让最终的向量与训练集中的向量具有相同的大小,从而与预训练向量的大小相同。在这个例子中,重点是 L2 损失:
cost = tf.reduce_mean(tf.nn.l2_loss(pred-y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
chapter6 folder: https://github.com/PacktPublishing/Learn-fastText/blob/master/chapter6/TensorFlow%20rnn.ipynb.
PyTorch
按照与前两个库相同的逻辑,你可以使用 torch.nn.EmbeddingBag 类来注入预训练的嵌入。虽然有一个小缺点。Keras 和 TensorFlow 假设你的张量实际上是作为 NumPy 数组实现的,而在 PyTorch 中并非如此。PyTorch 实现了 torch 张量。通常这不是问题,但这意味着你需要编写自己的文本转换和分词管道。为了避免重写和重新发明轮子,你可以使用 torchtext 库。
torchtext 库
torchtext 是一个出色的库,能够处理你构建 NLP 模型所需的大部分预处理步骤。基本上,可以将 torchtext 看作是以一种松散的方式充当 配置即代码 的工具。因此,理解 torchtext 数据范式是有意义的,学习大约需要三小时,而不是编写定制代码,虽然看起来可能更简单,但会涉及无数的困惑和调试。而且,torchtext 还能构建预构建的模型,包括 fastText。
现在,让我们来看看是如何实现的。
torchtext 中的数据类
我们将首先调用所有必要的库。请注意,你正在调用包含我们使用所需数据类的数据:
from torchtext import data
import spacy
...
我们将使用 spacy 进行分词步骤,torchtext 在这方面有很好的支持。torchtext 提供了对调用和加载 fastText 库的优异支持:
from torchtext.vocab import FastText
vectors = FastText('simple')
这将下载 wiki.simple.bin 模型。如果你提供名称 en,它将下载并加载 wiki.en.bin。如果加载 fr,它将加载 wiki.fr.bin,以此类推。
你可能会从 CSV 文件或文本文件中加载数据。在这种情况下,你需要打开文件,可能在 pandas 中提取相关字段,然后将其保存到单独的文件中。torchtext 无法区分训练集和验证集,因此你可能还需要将这些文件分开:
def clean_str(string):
string = re.sub(r"[^A-Za-z0-9(),!?\'\`]", " ", string)
string = re.sub(r"\'s", " \'s", string)
string = re.sub(r"\'ve", " \'ve", string)
string = re.sub(r"n\'t", " n\'t", string)
string = re.sub(r"\'re", " \'re", string)
string = re.sub(r"\'d", " \'d", string)
string = re.sub(r"\'ll", " \'ll", string)
string = re.sub(r",", " , ", string)
string = re.sub(r"!", " ! ", string)
string = re.sub(r"\(", " \( ", string)
string = re.sub(r"\)", " \) ", string)
string = re.sub(r"\?", " \? ", string)
string = re.sub(r"\s{2,}", " ", string)
return string.strip().lower()
def prepare_csv(df, seed=999):
df['text'] = df['text'].apply(clean_str)
df_train, df_test = train_test_split(df, test_size=0.2)
df_train.to_csv("yelp_tmp/dataset_train.csv", index=False)
df_test.to_csv("yelp_tmp/dataset_val.csv", index=False)
现在你需要定义数据并构建词汇表。你可以使用数据模块来实现这一点。该模块有数据类来定义管道步骤并运行批处理、填充和数字化。首先,你需要使用 data.Fields 定义字段类型。此类定义了可以用来创建所需张量的常见数据类型。你还可以定义一些常见指令来定义张量应如何创建。一旦字段创建完成,你可以调用 TabularDataset 来使用字段中定义的指令创建数据集。常见的指令作为参数传递:
# Define all the types of fields
# pip install spacy for the tokenizer to work (or remove to use default)
TEXT = data.Field(lower=True, include_lengths=True, fix_length=150, tokenize='spacy')
LABEL = data.Field(sequential=True, use_vocab=False)
# we use the index field to re-sort test data after processing
INDEX = data.Field(sequential=False)
train_fields=[
(text_label, TEXT),
(stars_label, LABEL)
]
train_fields=[
(text_label, TEXT),
(stars_label, LABEL)
]
train = data.TabularDataset(
path='yelp_tmp/dataset_train.csv', format='csv', skip_header=True,
fields=train_fields)
test_fields=[
(id_label, INDEX),
(text_label, TEXT),
(stars_label, LABEL)
]
test = data.TabularDataset(
path='yelp_tmp/dataset_val.csv', format='csv', skip_header=True,
fields=test_fields)
-
sequential=True表示该列包含序列。对于标签,我们可能希望保持这种设置,因为示例基本上是一个比较,但在不是这种情况的情况下,可以将其设置为 false。 -
我们在此指定使用 spacy 作为分词器,但你可以指定自定义函数。
-
fix_length将所有序列填充或裁剪到固定长度,这里是 150。 -
lower指定我们将所有英文字母设置为小写。
一旦数据集创建完成,你需要创建词汇表,以便稍后将标记转换为整数。在这里,我们将从之前加载的 fastText 向量构建词汇表:
max_size = 30000
TEXT.build_vocab(train, test, vectors=vectors, max_size=max_size)
INDEX.build_vocab(test)
使用迭代器
现在你可以使用迭代器来遍历数据集。在这种情况下,我们使用 BucketIterator,它的额外优势是将相似长度的示例聚集在一起批处理。这减少了所需的填充量:
train = data.BucketIterator(train, batch_size=32,
sort_key=lambda x: len(x.text),
sort_within_batch=True, repeat=False)
test = data.BucketIterator(test, batch_size=128,
sort_key=lambda x: len(x.text),
sort_within_batch=True, train=False,
repeat=False)
所以,你将能够在这些迭代器上运行简单的 for 循环,并根据批次提供输入。
将所有步骤结合起来
最后,一旦完成所有这些步骤,你可以初始化你的 PyTorch 模型,并需要将预训练的向量作为模型的权重。在示例中,创建了一个 RNN 模型,并且词向量是从之前的字段向量初始化的。这将处理 PyTorch 中的 lookup_table:
model = RNNModel('GRU', ntokens, emsize, nhidden, 6,
nlayers, dropemb=dropemb, droprnn=droprnn,
bidirectional=True)
model.encoder.weight.data.copy_(TEXT.vocab.vectors)
这里展示的代码仅包括你可能不熟悉的部分。完整的代码可以查看仓库中的 pytorch torchtext rnn.ipynb 笔记本。
总结
在本章中,我们探讨了如何将 fastText 词向量集成到线性机器学习模型或在 Keras、TensorFlow 和 PyTorch 中创建的深度学习模型中。你还看到如何将词向量轻松地融入到你可能在业务应用中使用的现有神经网络架构中。如果你是通过随机值初始化嵌入,我强烈建议你尝试使用 fastText 值进行初始化,然后观察模型的性能是否有所提升。
第十章:部署模型到 Web 和移动端
对于依赖机器学习的公司来说,以可扩展的方式部署模型非常重要。模型应该以创建时的方式运行。无论是监督学习还是无监督学习,fastText 模型的部署可以通过多种方式实现。选择方法将取决于你个人的需求。
在本章中,我们将重点讨论如何在 Web 和移动场景中部署 fastText 模型。涉及的主题包括:
-
部署到 Web
-
Flask
-
FastText 函数
-
Flask 端点
-
部署到更小的设备
-
前提条件 – 完成 Google 教程
-
应用考虑事项
-
添加 fastText 模型
-
Java 中的 FastText
-
向 Android 添加库依赖
-
在 Android 中使用库依赖
-
最终,应用
部署到 Web
现在你已经掌握了创建自己 fastText 模型的方法,你可能需要将它们部署到生产环境,以便可以利用这些模型来创建应用和端点。Python 中有许多框架可以用来创建这样的 Web 应用。Flask、Django 和 Pyramid 是一些流行的 Python Web 框架。在本节中,我们将以 Flask 为例,构建一个简单的 Web 最近邻搜索应用。
Flask
Flask 是一个流行的 Web 框架,被归类为微框架,因为它不需要任何外部工具或库。Flask 内部没有数据库抽象层、表单验证或其他组件。其优点是,你可以用最少的代码行构建一个简单的 Web 应用。这有助于快速原型设计,并让你专注于应用本身的代码。
对于本节讨论的代码,可以查看仓库中的 chapter 7 文件夹。你将找到两个文件,ft_server.py 和 ft_utils.py。ft_utils.py 模块包含与 fastText 服务器相关的代码,而 ft_server.py 包含与 Flask 端点相关的代码。
fastText 函数
如果你查看代码,我们是通过 FT_MODEL 环境变量加载 fastText 模块的。这个模型被作为全局变量加载,以便可以在函数中使用。另一个好处是,当 Flask 应用初始化时,模型也会被加载到内存中。将模型加载到内存中是一个计算密集型操作,因此如果我们将此操作延迟到初始化阶段,将能提高响应时间:
print('loading the model')
FT_MODEL = os.environ.get('FT_MODEL')
if not FT_MODEL:
raise ValueError('No fasttext model has been linked.')
FT_MODEL = fastText.load_model(FT_MODEL)
print('model is loaded')
现在,我们还将基于一个阈值获取词汇表中最常见的词汇,并将其保存在内存中。我们将词向量作为全局变量保存,这样词向量的计算就会在应用初始化时完成,类似于之前的方式:
# Gets words with associated frequency sorted by default by descending order
words, freq = FT_MODEL.get_words(include_freq=True)
words = words[:threshold]
vectors = np.zeros((len(words), FT_MODEL.get_dimension()), dtype=float)
for i in range(len(words)):
wv = FT_MODEL.get_word_vector(words[i])
wv = wv / np.linalg.norm(wv)
vectors[i] = wv
# For efficiency preallocate the memory to calculate cosine similarities
cossims = np.zeros(len(words), dtype=float)
接下来的两个函数基本上是如何根据问题词的词向量与其他词的词向量之间的距离来获取最接近的词。这些函数在第五章,Python 中的 FastText中也有讨论。
你应该能够单独运行这个模块。同时,注意运行整个模块所需的时间。
在我的笔记本上,运行整个代码大约需要 10 秒钟。
Flask 端点
为了简洁起见,本文中只讨论了一个端点。基本上,它用于获取传入的问题词,使用 ft_utils.py 文件中定义的 nn 函数获取答案,然后以 JSON 格式提供答案:
@app.route('/nn/<question_word>')
def nearest_neighbours(question_word):
answers = [a for a in nn(FT_MODEL, question_word, k=5)]
return jsonify(dict(question=question_word, answers=answers))
现在,以开发模式运行应用,这样你就可以调试它:
$ export FLASK_APP=ft_server.py
$ export FLASK_ENV=development
$ export FT_MODEL=wiki.simple.bin
$ flask run
打开一个新的终端并发送一个 curl 请求;你应该能在终端看到响应。你可以看到响应也很快:
$ time curl http://127.0.0.1:5000/nn/dog
{
"answers": [
"dogs",
"catdog",
"sheepdog",
"sheepdogs",
"breed"
],
"question": "dog"
}
$ curl http://127.0.0.1:5000/nn/dog 0.01s user 0.00s system 9% cpu 0.105 total
我们能够在 Flask 应用中获得非常快速的响应,因为我们尽可能将计算开销大的部分代码移至应用初始化阶段。这通常是一个不错的做法。作为 Web 应用的一部分,只做绝对必要的事情,并将请求处理过程中的计算量保持在最低限度。这将确保你构建出高效且实用的 Web 应用,适合部署 fastText 模型和机器学习应用。
部署到较小的设备
正如你在第二章中看到的,使用 FastText 命令行创建模型,你可以使用类似下面的命令从完整模型创建一个压缩的 fastText 模型:
$ ./fasttext quantize -output <model prefix> -input <training file> -qnorm -retrain -epoch <number of epochs> -cutoff <number of words to consider>
在第四章,FastText 中的句子分类,我们也重新讨论了压缩模型的概念,以及如何在性能几乎不丢失的情况下实现压缩。
这使得你也可以在较小的设备上部署机器。首先想到的一个问题是,文件是否可以与 Android 应用打包并部署在 Android 应用中。
在本节中,我将展示所有应该能帮助你部署 Android fastText 应用所需的要求和依赖项。
前提条件 – 完成 Google 教程
一个值得参考的最佳示例是 Google 教程中的 Android 应用示例。如果你是 Android 新手,请访问developer.android.com/training/basics/firstapp/并完成那里的教程。我们在这里不再详细介绍,所以总结起来,步骤是:
-
安装 Android Studio
-
创建一些简单的用户界面
-
创建活动并定义意图
-
构建并创建 APK 文件
对于我们的应用程序,我们将沿着类似的思路进行。我们项目的名称是 Fasttext application。因此,下载最新版本的 Android Studio 并启动它:
继续点击“Next”,选择空活动并点击“Finish”。你应该会进入一个新的项目窗口,其中已经为你完成了大量 Android 的模板代码。现在,打开 Google 的教程并按照教程中的所有步骤进行操作。如果你已经是经验丰富的 Android 开发者,你可以从 GitHub 仓库中打开项目。首先,执行 git fetch 并切换到 android_starting 分支:
git fetch
git checkout android_starting
现在,如果你编译应用并创建 APK,你应该能够看到以下界面。或者,如果你已经设置了 ADB,你可以选择运行并在模拟器中查看应用。
要构建 APK,你可以在 Android Studio 中点击“Build APK(s)”按钮:
请按照 Google Android 教程中“构建简单用户界面”部分的步骤操作,以便最终运行一个类似于这个的简单应用:
现在,按照“开始另一个活动”教程进行操作,完成另一个活动的创建。这个教程的目的是让你能够从第一个活动触发另一个单独的活动:
=>
应用程序考虑事项
现在你已经有了两个活动,你可能已经猜到了我们 fastText 应用的目标。我们将在第一个活动中输入文本标签,并且它应该在第二个活动中给出标签。
要实现这一点,你需要做两件事:
-
将预构建的 fastText 模型添加到 Android 应用中
-
添加一个库来解析 fastText 模型并提供预测结果
有几点我想在这里提一下。我们将在这里使用 fastText FTZ 模型。你可以争辩说,正如我们所见,fastText 模型是通过产品量化方法构建的,使用了像最近邻中心估计、词汇修剪和哈希等方法。这会导致信息丢失,尽管有争议称这种丢失对性能没有显著影响。但如果你不信服,你可以选择按照前面章节讨论的那样,创建一个 Web 应用并通过 Android 应用访问结果,这意味着将 Android 应用作为只读视图,所有计算都由服务器完成。这是一个合理的方案,但更多的是一个工程挑战,并不在本书的范围内。在本节中,我们更感兴趣的是能否利用 fastText 的能力创建非常小的模型,将其部署到移动设备,并在我们的应用程序中使用它们。
现在,在继续之前,先构建 APK 并注意当前应用程序的大小,因为大小对于用户来说是一个重要问题。如果你希望用户下载并使用应用程序,大小问题不容忽视。你肯定不希望因为内存已满而让用户卸载应用程序,或者用户处在互联网非常慢的地方,下载应用程序会非常耗时。因此,在为小型设备设计应用时,始终要记得考虑应用程序的大小。
目前,构建仅占用 1.5 MB 的内存:
$ du -sh app-debug.apk
1.6M app-debug.apk
添加 fastText 模型
接下来,你需要将 fastText 模型添加到应用程序中。Android 有一个资产管理系统,可以用来实现这一点。
首先,下载或创建一个 FTZ 模型。我从 fastText 网站的监督模型部分下载了dbpedia.ftz文件。该文件大约 1.6 MB,因此不应该增加最终构建的 APK 大小。
Android 有一个资源管理系统,你可以用它来实现这一目的。在主文件夹下创建一个 assets 文件夹,并将你的 FTZ 文件复制/粘贴到其中:
你应该能够看到文件,如下所示:
完成后,添加代码以使用资源管理器访问文件。由于我们在第二个活动中进行预测,让我们在DisplayMessageActivity.java文件中访问该文件。
在onCreate方法中,创建一个AssetManager实例以访问资产文件,并创建一个InputStream实例,以便文件可以转换为流。数据将从这个流中读取和操作,代码如下:
public class DisplayMessageActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_message);
// Get the Intent that started this activity and extract the string
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
// Get the assets from the asset manager.
AssetManager assetManager = getAssets();
InputStream inputStream = null;
try {
inputStream = assetManager.open("dbpedia.ftz");
} catch (IOException e) {
e.printStackTrace();
}
// Capture the layout's TextView and set the string as its text
TextView textView = findViewById(R.id.textView);
textView.setText(message);
}
按下Alt + Enter(在 Mac 上是Option + Enter)来导入缺失的类。你的导入应该如下所示:
import android.content.Intent;
import android.content.res.AssetManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
Java 中的 FastText
现在你已经在 Android 应用中部署了 fastText 模型,你需要一种方法来访问文件并提供预测。你可以通过编写 Java 自定义代码来实现这一点,参考 fastText 的 GitHub 库。这样做的优势在于你对代码有更多的控制,且如果你在编写企业级应用时,可能是唯一的选择,因为 fastText 的代码是 BSD 许可下发布的。另一种选择是将 fastText 代码编译成 Android 库的一部分,但服务原生代码存在很多问题,且可能在所有设备上无法正常工作。对我来说,添加外部依赖的最佳方法是找到能够为你完成工作的核心 Java 库。
幸运的是,在这种情况下,我们有一个符合要求的库。fastText4j是一个由linkfluence在 GitHub 上发布的优秀 Java 库,包含所有 Java 代码,并且能够加载和解析 Java 库。除了能够读取 bin 和 FTZ 文件,我们还能够读取和创建 Java 内存映射文件,尽管在这里我们不会使用它。使用以下仓库克隆这个库,它是原始linkfluence库的克隆:
$ git clone https://github.com/infinite-Joy/fastText4j.git
$ cd fastText4j
$ mvn clean
还需要将包编译为应用程序,因为我们将需要它进行测试和编译。解压生成的文件:
$ mvn install -Papp
$ unzip app/fasttext4j-app.zip
$ cp target/fasttext4j-0.2.1-SNAPSHOT.jar lib/fasttext4j-0.2.1-SNAPSHOT.jar
这将把lib/文件夹和fasttext-mmap.sh文件复制到当前目录。最后的复制步骤现在并非必须,但这样做是为了向你展示,当你对这个仓库做出更改并重新编译 JAR 时,这一步是需要的。现在,文件将包含稍有不同的命令行。修改src/main/java/fasttext/FastText.java中的main方法:
public static void main(String[] args) throws Exception {
Options options = new Options();
Option input = new Option("i", "input", true, "input model path");
input.setRequired(true);
options.addOption(input);
CommandLineParser parser = new DefaultParser();
HelpFormatter formatter = new HelpFormatter();
CommandLine cmd;
try {
cmd = parser.parse(options, args);
} catch (ParseException e) {
System.out.println(e.getMessage());
formatter.printHelp("fasttext.FastText", options);
System.exit(1);
return;
}
String inputModelPath = cmd.getOptionValue("input");
logger.info("Loading fastText model to convert...");
FastText model = FastText.loadModel(inputModelPath);
FastTextPrediction label = model.predict("Good restaurant");
System.out.println(label.label());
}
输出参数已被移除,我们现在将模型作为输入并获取参数。编译此代码并复制我们下载的 FTZ 模型路径。现在我们来测试这个库:
$ mvn clean package
$ cp target/fasttext4j-0.2.1-SNAPSHOT.jar lib/fasttext4j-0.2.1-SNAPSHOT.jar
$ time bash fasttext-mmap.sh -i <path to>/dbpedia.ftz
__label__7
bash fasttext-mmap.sh -i 0.64s user 0.11s system 168% cpu 0.444 total
输出命令将会有大量日志。我们现在不会展示这些日志。只需检查日志中是否有任何错误消息,可能会标记缺少的依赖库。此外,正如你所见,在我的本地机器上加载并提供 FTZ 文件的预测非常快。假设在低性能的 Android 应用中,它也应该表现得很高效。
既然我们已经确认库可以工作并且能够给出预测,移除main方法,因为我们在 Android 应用中不需要它。编译 JAR 并将其放置在lib文件夹中:
$ mvn clean package
$ mvn install -Papp
$ unzip app/fasttext4j-app.zip
$ cp target/fasttext4j-0.2.1-SNAPSHOT.jar lib/fasttext4j-0.2.1-SNAPSHOT.jar
将库依赖添加到 Android 中
检查lib文件夹。所有作为此项目依赖的库都会放在这里。如果我们希望在 Android 应用中使用这个库,必须将这些依赖添加到应用中。
打开 文件 | 新建 | 新建模块...:
导入 JAR/AAR 包:
现在,将lib文件夹中的所有库添加为依赖项。现在,项目结构应该列出这些库作为依赖项。然后,点击应用 | 依赖项,将它们也作为应用的依赖项添加。将库文件作为模块依赖添加:
现在依赖已经添加,我们可以开始在我们的活动中使用这个库了。
在 Android 中使用库依赖
要在 Android 中使用这个库,修改DisplayMessageActivity.java并编写你在库测试阶段看到的相同代码。
在编译之前,在gradle.build文件中添加guava依赖,因为guava库中的UnsignedLong依赖:
compile 'com.google.guava:guava:21.0'
同时,添加编译版本,以便能够编译 Java 代码:
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
...
}
buildTypes {
...
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
...
compile 'com.google.guava:guava:21.0'
}
最终的应用
现在,编译应用并在你的手机上运行。你应该能够看到这些变化:
=>
让我们也来看一下创建的 APK 文件。在我的机器上,应用的大小已变为 4.6 MB。够小了吗?我将把这个问题留给你自己判断:
$du -sh app-debug.apk
4.6M app-debug.apk
总结
在本章中,我们研究了如何在网页和移动环境中实现 fastText 的方法,特别是针对 Android 平台。我们还探讨了在部署到网页或移动设备时需要考虑的不同因素。这将帮助你创建出色的应用,并将 fastText 集成到你的移动应用中。
第十一章:给读者的注意事项
Windows 和 Linux
我们建议您使用 PowerShell 作为 Windows 命令行工具,因为它比简单的 cmd 更强大。
| 任务 | Windows | Linux/macOS |
|---|---|---|
| 创建目录 | mkdir | mkdir |
| 切换目录 | cd | cd |
| 移动文件 | move | mv |
| 解压文件 | 图形界面并双击 | unzip |
| 文件顶部 | get-content | head |
| 文件内容 | type | cat |
| 管道 | this pipes objects | this pipes text |
| 文件底部 | 带有 get-content 的 -wait 参数 | tail |
python 和 perl 命令在 Windows 中的工作方式与在 bash 中相同,因此您可以以类似方式使用这些文件,特别是 perl 单行命令。
Python 2 和 Python 3
fastText 适用于 Python 2 和 Python 3。尽管如此,您应该注意特定 Python 版本之间的一些差异。
-
print在 Python 2 中是一个语句,而在 Python 3 中是一个函数。这意味着,如果您在 Jupyter Notebook 中查看变量的变化,您需要根据对应的 Python 版本使用适当的print语句。 -
fastText 处理文本时使用 Unicode 编码。Python 3 也处理文本为 Unicode,因此如果您使用 Python 3 编写代码,不会增加额外的开销。但如果您使用 Python 2 开发模型,数据不能是字符串实例。您需要将数据作为 Unicode 处理。以下是一个在 Python 2 中,
str类和unicode类的文本实例示例。
>>> text1 = "some text" # this will not work for fastText
>>> type(text1)
<type 'str'>
>>> text2 = unicode("some text") # in fastText you will need to use this.
>>> type(text2)
<type 'unicode'>
>>>
fastText 命令行
以下是您可以与 fastText 命令行一起使用的参数列表:
$ ./fasttext
usage: fasttext <command> <args>
The commands supported by fasttext are:
supervised train a supervised classifier
quantize quantize a model to reduce the memory usage
test evaluate a supervised classifier
predict predict most likely labels
predict-prob predict most likely labels with probabilities
skipgram train a skipgram model
cbow train a cbow model
print-word-vectors print word vectors given a trained model
print-sentence-vectors print sentence vectors given a trained model
print-ngrams print ngrams given a trained model and word
nn query for nearest neighbors
analogies query for analogies
dump dump arguments,dictionary,input/output vectors
supervised、skipgram 和 cbow 命令用于训练模型。predict、predict-prob 用于在有监督模型上进行预测。test、print-word-vectors、print-sentence-vectors、print-ngrams、nn、analogies 可用于评估模型。dump 命令基本上是用来查找模型的超参数,quantize 用于压缩模型。
您可以用于训练的超参数列表稍后会列出。
fastText 有监督
$ ./fasttext supervised
Empty input or output path.
The following arguments are mandatory:
-input training file path
-output output file path
The following arguments are optional:
-verbose verbosity level [2]
The following arguments for the dictionary are optional:
-minCount minimal number of word occurences [1]
-minCountLabel minimal number of label occurences [0]
-wordNgrams max length of word ngram [1]
-bucket number of buckets [2000000]
-minn min length of char ngram [0]
-maxn max length of char ngram [0]
-t sampling threshold [0.0001]
-label labels prefix [__label__]
The following arguments for training are optional:
-lr learning rate [0.1]
-lrUpdateRate change the rate of updates for the learning rate [100]
-dim size of word vectors [100]
-ws size of the context window [5]
-epoch number of epochs [5]
-neg number of negatives sampled [5]
-loss loss function {ns, hs, softmax} [softmax]
-thread number of threads [12]
-pretrainedVectors pretrained word vectors for supervised learning []
-saveOutput whether output params should be saved [false]
The following arguments for quantization are optional:
-cutoff number of words and ngrams to retain [0]
-retrain whether embeddings are finetuned if a cutoff is applied [false]
-qnorm whether the norm is quantized separately [false]
-qout whether the classifier is quantized [false]
-dsub size of each sub-vector [2]
fastText skipgram
$ ./fasttext skipgram
Empty input or output path.
The following arguments are mandatory:
-input training file path
-output output file path
The following arguments are optional:
-verbose verbosity level [2]
The following arguments for the dictionary are optional:
-minCount minimal number of word occurences [5]
-minCountLabel minimal number of label occurences [0]
-wordNgrams max length of word ngram [1]
-bucket number of buckets [2000000]
-minn min length of char ngram [3]
-maxn max length of char ngram [6]
-t sampling threshold [0.0001]
-label labels prefix [__label__]
The following arguments for training are optional:
-lr learning rate [0.05]
-lrUpdateRate change the rate of updates for the learning rate [100]
-dim size of word vectors [100]
-ws size of the context window [5]
-epoch number of epochs [5]
-neg number of negatives sampled [5]
-loss loss function {ns, hs, softmax} [ns]
-thread number of threads [12]
-pretrainedVectors pretrained word vectors for supervised learning []
-saveOutput whether output params should be saved [false]
The following arguments for quantization are optional:
-cutoff number of words and ngrams to retain [0]
-retrain whether embeddings are finetuned if a cutoff is applied [false]
-qnorm whether the norm is quantized separately [false]
-qout whether the classifier is quantized [false]
-dsub size of each sub-vector [2]
fastText cbow
$ ./fasttext cbow
Empty input or output path.
The following arguments are mandatory:
-input training file path
-output output file path
The following arguments are optional:
-verbose verbosity level [2]
The following arguments for the dictionary are optional:
-minCount minimal number of word occurences [5]
-minCountLabel minimal number of label occurences [0]
-wordNgrams max length of word ngram [1]
-bucket number of buckets [2000000]
-minn min length of char ngram [3]
-maxn max length of char ngram [6]
-t sampling threshold [0.0001]
-label labels prefix [__label__]
The following arguments for training are optional:
-lr learning rate [0.05]
-lrUpdateRate change the rate of updates for the learning rate [100]
-dim size of word vectors [100]
-ws size of the context window [5]
-epoch number of epochs [5]
-neg number of negatives sampled [5]
-loss loss function {ns, hs, softmax} [ns]
-thread number of threads [12]
-pretrainedVectors pretrained word vectors for supervised learning []
-saveOutput whether output params should be saved [false]
The following arguments for quantization are optional:
-cutoff number of words and ngrams to retain [0]
-retrain whether embeddings are finetuned if a cutoff is applied [false]
-qnorm whether the norm is quantized separately [false]
-qout whether the classifier is quantized [false]
-dsub size of each sub-vector [2]
Gensim fastText 参数
Gensim 支持与 fastText 本地实现相同的超参数。您应该能够按如下方式设置它们:
-
sentences:这可以是一个包含标记的列表的列表。一般来说,建议使用标记流,如之前提到的 word2vec 模块中的LineSentence。在 Facebook fastText 库中,这由文件路径提供,并通过-input参数传递。 -
sg:可以是 1 或 0。1 表示训练 skip-gram 模型,0 表示训练 CBOW 模型。在 Facebook fastText 库中,等效操作是传递skipgram和cbow参数。 -
size:词向量的维度,因此必须是整数。与原始实现一致,默认选择 100。这与 Facebook fastText 实现中的-dim参数类似。 -
window:围绕一个词语考虑的窗口大小。这与原始实现中的-ws参数相同。 -
alpha:这是初始学习率,类型为浮动数。它与第二章中看到的-lr参数相同,使用 FastText 命令行创建模型。 -
min_alpha:这是训练过程中学习率降至的最小值。 -
seed:这是为了可复现性。为了让种子生效,线程数也需要设置为 1。 -
min_count:文档中单词的最小频率,低于此频率的单词将被丢弃。类似于命令行中的-minCount参数。 -
max_vocab_size:用于限制 RAM 大小。如果词汇表中有更多的唯一单词,那么会修剪掉频率较低的单词。这个值需要根据你拥有的 RAM 大小来决定。例如,如果你有 2GB 内存,则max_vocab_size需要为 10M * 2 = 2000 万(20 000 000)。 -
sample:用于对单词进行下采样。类似于 fasttext 命令行中的"-t"参数。 -
workers:训练的线程数,类似于 fastText 命令中的-thread参数。 -
hs:可以是 0 或 1。如果是 1,则会使用层次化 softmax 作为损失函数。 -
negative:如果你想使用负采样作为损失函数,则将hs设置为 0,并将 negative 设为非零正数。请注意,损失函数仅支持两种功能:层次化 softmax 和负采样。简单的 softmax 不被支持。这个参数和hs一起,等同于fasttext命令中的-loss参数。 -
cbow_mean:这里与 fastText 命令有些不同。在原始实现中,对于cbow会取向量的均值。但在这种情况下,你可以选择通过传递 0 来使用和 1 来尝试均值。 -
hashfxn:用于随机初始化权重的哈希函数。 -
iter:样本的迭代次数或周期数。这与命令行中的-epoch参数相同。 -
trim_rule:用于指定是否应保留某些词汇或将其修剪掉的函数。 -
sorted_vocab:接受的值为 1 或 0。如果为 1,则词汇表将在索引之前进行排序。 -
batch_words:这是传递的批次的目标大小。默认值为 10000。这与命令行中的-lrUpdateRate有些相似,因为批次数决定了权重何时更新。 -
min_n和max_n:字符 n-grams 的最小和最大长度。 -
word_ngrams:丰富子词信息,以便在训练过程中使用。 -
bucket:字符 n-gram 被哈希到一个固定大小的向量上。默认情况下使用 200 万词的桶大小。
-
callbacks:在训练过程中特定阶段执行的回调函数列表。
第十二章:参考文献
第三章
-
独热编码:
machinelearningmastery.com/how-to-one-hot-encode-sequence-data-in-python/ -
表示学习:
github.com/anujgupta82/Representation-Learning-for-NLP -
N-gram 模型:
citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.53.9367 -
TF-IDF:
nlp.stanford.edu/IR-book/html/htmledition/inverse-document-frequency-1.html -
Mikolov 等 2013:
arxiv.org/abs/1310.4546 -
Maas 和 cgpotts 论文:
web.stanford.edu/~cgpotts/papers/wvSent_acl2011.pdf -
scikit-learn 中的词袋模型:
scikit-learn.org/stable/modules/feature_extraction.html#the-bag-of-words-representation -
Kaggle 上的 word2vec
www.kaggle.com/c/word2vec-nlp-tutorial -
Heap 法则:
en.wikipedia.org/wiki/Heaps%27_law -
句子和文档的分布式表示,Mikolov 等:
cs.stanford.edu/~quocle/paragraph_vector.pdf -
Skip-gram: McCormick, C. (2016, April 19), Word2Vec 教程 - Skip-Gram 模型
mccormickml.com/2016/04/19/word2vec-tutorial-the-skip-gram-model/ -
TensorFlow 中的 word2vec 实现:
github.com/tensorflow/tensorflow/blob/r1.1/tensorflow/examples/tutorials/word2vec/word2vec_basic.py -
Word2vec 详解:
arxiv.org/abs/1411.2738 -
推导负采样:
arxiv.org/abs/1402.3722 -
组合分布式语义学:
youtu.be/hTmKoHJw3Mg -
fastText 和 skipgram:
debajyotidatta.github.io/nlp/deep/learning/word-embeddings/2016/09/28/fast-text-and-skip-gram/ -
skip-gram 和 CBOW:
iksinc.online/tag/continuous-bag-of-words-cbow/ -
斯坦福大学关于 CBOW 和 skip-gram 的讲座:
cs224d.stanford.edu/lecture_notes/notes1.pdf -
fasttext PyTorch:
github.com/PetrochukM/PyTorch-NLP -
Levy,Omer 和 Goldberg Yoav(2014),基于依赖关系的词嵌入,第 52 届计算语言学协会年会,ACL 2014——会议论文集,2. 302-308. 10.3115/v1/P14-2050
-
噪声对比估计与负采样的笔记:
arxiv.org/abs/1410.8251 -
Sebastian Ruder,关于词嵌入 - 第二部分:逼近 Softmax,
ruder.io/word-embeddings-softmax,2016。 -
可扩展的层次分布式语言模型。
papers.nips.cc/paper/3583-a-scalable-hierarchical-distributed-language-model.pdf -
Softmax 函数及其导数。
eli.thegreenplace.net/2016/the-softmax-function-and-its-derivative/ -
什么是 Softmax 回归,它与逻辑回归有什么关系?,Sebastian Raschka。
www.kdnuggets.com/2016/07/softmax-regression-related-logistic-regression.html -
Softmax 回归,
ufldl.stanford.edu/tutorial/supervised/SoftmaxRegression/ -
Google Allo:
research.googleblog.com/2016/05/chat-smarter-with-allo.html -
层次化概率神经网络语言模型,Morin 和 Bengio,2005,
www.iro.umontreal.ca/~lisa/pointeurs/hierarchical-nnlm-aistats05.pdf -
可扩展的层次分布式语言模型。Mnih,Andriy 和 Hinton,Geoffrey E. 2009,
papers.nips.cc/paper/3583-a-scalable-hierarchical-distributed-language-model -
自组织层次 Softmax,arXiv:1707.08588v1 [cs.CL] 2017 年 7 月 26 日
-
基于哈夫曼编码算法的有效文本聚类方法, Nikhil Pawar, 2012 年,
www.ijsr.net/archive/v3i12/U1VCMTQ1NjE=.pdf -
Tomas Mikolov, Ilya Sutskever, Kai Chen, Gregory S. Corrado 和 Jeffrey Dean, 词和短语的分布式表示及其组合性, 载于《神经信息处理系统进展》第 26 卷:第 27 届神经信息处理系统年会,2013 年,会议论文集,2013 年 12 月 5-8 日,美国内华达州湖塔霍,页 3111-3119。
-
debajyotidatta.github.io/nlp/deep/learning/word-embeddings/2016/09/28/fast-text-and-skip-gram/ -
github.com/nzw0301/keras-examples/blob/master/Skip-gram-with-NS.ipynb
第四章
-
Vladimir Zolotov 和 David Kung 2017 年,fastText 线性文本分类器的分析与优化,
arxiv.org/abs/1702.05531 -
线性模型的文本分类,
www.cs.umd.edu/class/fall2017/cmsc723/slides/slides_03.pdf -
什么是文本分类,斯坦福,
nlp.stanford.edu/IR-book/html/htmledition/the-text-classification-problem-1.html#sec:classificationproblem -
nlp.stanford.edu/IR-book/html/htmledition/text-classification-and-naive-bayes-1.html -
Joseph Turian, Lev Ratinov, 和 Yoshua Bengio, 2010 年,词表示:一种简单而通用的半监督学习方法, 载于 第 48 届计算语言学协会年会论文集 (ACL '10), 计算语言学协会,斯特劳兹堡,美国,384-394。
-
[Weinberger 等, 2009] Kilian Weinberger, Anirban Dasgupta, John Langford, Alex Smola 和 Josh Attenberg, 2009 年, 特征哈希用于大规模多任务学习. 载于 ICML 会议
-
developers.googleblog.com/2018/04/text-embedding-models-contain-bias.html -
PyTorch 中的 Softmax 分类器:
www.youtube.com/watch?v=lvNdl7yg4Pg -
分类的层次损失:arXiv:1709.01062v1 [cs.LG],2017 年 9 月 1 日
-
Svenstrup,Dan & Meinertz Hansen,Jonas & Winther,Ole. (2017),哈希嵌入用于高效的词表示
-
极快的文本特征提取用于分类和索引,乔治·福尔曼和埃文·基尔申鲍姆著
-
阿曼德·朱林, 等人. FastText.zip: 压缩文本分类模型,2016,
arxiv.org/abs/1612.03651 -
shodhganga.inflibnet.ac.in/bitstream/10603/132782/14/12_chapter%204.pdf -
基于 Voronoi 投影的快速最近邻搜索算法:盒子搜索和映射表搜索技术,V. 拉马苏布拉马尼安,K.K. 皮利瓦尔。1997 年,
www.sciencedirect.com/science/article/pii/S1051200497903006 -
如何用 Python 从零实现学习向量量化。杰森·布朗尼,2016,
machinelearningmastery.com/implement-learning-vector-quantization-scratch-python/ -
赫尔维·热戈、马蒂斯·杜兹和科尔德莉亚·施密德,用于最近邻搜索的产品量化,IEEE Trans. PAMI,2011 年 1 月。
-
韩松、毛会子和威廉·J·达利。深度压缩:通过修剪、训练量化和霍夫曼编码压缩深度神经网络,在 ICLR 中,2016 年
-
孙捷、何凯明、柯启发和孙剑,优化的产品量化用于近似最近邻搜索。 在 CVPR 中,2013 年 6 月
-
期望最大化,乔伊迪普·巴塔查尔吉。
medium.com/technology-nineleaps/expectation-maximization-4bb203841757 -
陈文林、詹姆斯·T·威尔逊、史蒂芬·泰瑞、基利安·Q·温伯格和陈逸欣,利用哈希技巧压缩神经网络, arXiv:1504.04788, 2015
-
Kai Zeng, Kun She, 和 Xinzheng Niu, 基于邻域熵的合作博弈理论特征选择, 计算智能与神经科学, vol. 2014, 文章 ID 479289, 10 页, 2014,
doi.org/10.1155/2014/479289.
第五章
-
大规模语料主题建模软件框架, Radim, 2010
-
Gensim fastText 教程:
github.com/RaRe-Technologies/gensim/blob/develop/docs/notebooks/FastText_Tutorial.ipynb -
P. Bojanowski, E. Grave, A. Joulin, T. Mikolov, 用子词信息丰富词向量,
arxiv.org/abs/1607.04606 -
Tomas Mikolov, Quoc V Le, Ilya Sutskever, 2013, (利用语言间相似性进行机器翻译) (
arxiv.org/pdf/1309.4168.pdf) -
Georgiana Dinu, Angelikie Lazaridou, 和 Marco Baroni. 2014, 通过缓解中心性问题改善零-shot 学习 (
arxiv.org/pdf/1412.6568.pdf) -
fastText 标准化,
www.kaggle.com/mschumacher/using-fasttext-models-for-robust-embeddings/notebook -
Luong, Minh-Thang 和 Socher, Richard 和 Manning, Christopher D. 2013, (通过递归神经网络改善形态学词表示) (
nlp.stanford.edu/~lmthang/morphoNLM/)
第六章
-
Yoav Goldberg (2015), 神经网络模型入门:自然语言处理
语言处理, (
arxiv.org/abs/1510.00726) -
www.wildml.com/2015/11/understanding-convolutional-neural-networksfor-nlp/ -
machinelearningmastery.com/best-practices-document-classification-deep-learning/ -
pytorch.org/tutorials/beginner/nlp/word_embeddings_tutorial.html