自然语言极其复杂多样,计算机难以直接理解人类的语言。因此,我们需要让计算机学会理解和处理人类的语言。这一过程的第一步是对文本进行编码。然而,很多人可能会立刻想到使用ASCII编码,但这并不能满足我们的需求。ASCII编码只能处理单个字符,而不是完整的词语。实际上,词语才是自然语言处理的基础单元。那么,我们该如何表示词语,并处理词语之间的关系呢?此外,我们如何利用文本语料库(训练数据集)来训练我们的模型呢?这些问题构成了自然语言处理(NLP)的基础。
在机器学习系统中,我们可以通过两种主要方式表示词汇:One-hot 编码和特征表示(词嵌入)。One-hot 编码的基本思路是为词汇表中的每个单词分配一个唯一的索引。例如,假设词汇表包含10000个单词,“猫”在词汇表中的索引是3202,那么“猫”的表示方式就是[0,0,0,0,...,1,...,0],其中只有第3202位是1,其余位置均为0。这种表示方法非常稀疏,因为每个单词都需要一个与词汇表长度相同数量的元素,而且大多数元素都是0。此外,这种表示方法忽略了单词之间的关联性,所有单词之间的余弦相似度都为0,这显然不符合实际情况。例如,现实中“猫”和“狗”之间的关系通常比“猫”和“书”之间的关系更密切,但在One-hot 编码中,它们之间的余弦相似度相同。
词嵌入是NLP中最常用的技术之一。其核心思想是每个单词都有多个维度,具体维度数量由用户自行定义。这些维度确保相似的单词在多维空间中的数值相近。例如,我们可以用5维空间来表示一个词,“猫”可能是[1.0, 1.5, 0.0, 6.4, 0.0],“狗”可能是[0.95, 1.2, 0.11, 5.5, 0.0],“书”可能是[9.5, 0.0, 3.4, 0.3, 6.2]。从这些数值可以看出,“猫”和“狗”在五维空间中较为接近,而与“书”距离较远。这种表示方法更加符合实际认知。尽管具体维度的含义不需要明确,但可以通过特定算法计算词嵌入。例如,T-SNE算法可以将多维数据转换为二维数据,便于可视化。
一种计算词嵌入的方法是通过传统神经网络训练模型。其基本流程包括将文本序列化、从嵌入层提取数据、展平数据并输入到深度神经网络(DNN)中。在这个过程中,嵌入层既是输入数据的一部分,也是模型的参数,会随着训练不断更新。例如,用DNN计算嵌入时,上下文词的数量必须固定,以便数据可以输入到统一的神经网络中。此外,上下文词的选择由用户定义,但一旦选定,就必须一致。如果数据中的上下文词长度不足,可以通过填充补齐。
另一种常用的词嵌入算法是跳字模型(Skip-Gram)。跳字模型的基本思想是从训练数据中的句子中随机选择一个单词作为上下文词,然后在初始化的嵌入层中找到该单词的值,将其输入到softmax模型中计算所有词汇的概率,选择概率最高的单词作为目标词。跳字模型同样需要大量计算,每次梯度下降都需要计算所有词汇的值。这种模型的致命缺点是计算量巨大。
下面通过TensorFlow来演示如何使用词嵌入进行情感分析。情感分析是一种常见的NLP应用场景,用于判断一段文本的情感倾向。我们将使用IMDB电影评论数据集。
```python import tensorflow as tf import tensorflow_datasets as tfds import numpy as np
imdb, info = tfds.load("imdbreviews", withinfo=True, assupervised=True) traindata = imdb["train"] test_data = imdb["test"] ```
```python trainingsentences = [] traininglabels = [] testsentences = [] testlabels = []
for s, l in traindata: trainingsentences.append(str(s.numpy())) training_labels.append(l.numpy())
for s, l in testdata: testsentences.append(str(s.numpy())) test_labels.append(l.numpy()) ```
```python from tensorflow.keras.preprocessing.text import Tokenizer from tensorflow.keras.preprocessing.sequence import pad_sequences
maxlength = 120 trunctype = "post" oov_tok = ""
tokenizer = Tokenizer(numwords=vocabsize, oovtoken=oovtok) tokenizer.fitontexts(trainingsentences) wordindex = tokenizer.word_index
trainingsequences = tokenizer.textstosequences(trainingsentences) trainingpaddedsequences = padsequences(trainingsequences, maxlen=maxlength, truncating=trunctype)
testsequences = tokenizer.textstosequences(testsentences) testpaddedsequences = padsequences(testsequences, maxlen=maxlength, truncating=trunctype) ```
```python vocabsize = 10000 embeddingdim = 16
model = tf.keras.Sequential([ tf.keras.layers.Embedding(vocabsize, embeddingdim, inputlength=maxlength), tf.keras.layers.Flatten(), tf.keras.layers.Dense(64, activation="relu"), tf.keras.layers.Dense(1, activation="sigmoid") ])
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"]) model.summary() ```
python
model.fit(
training_padded_sequences,
training_labels,
epochs=10,
validation_data=(test_padded_sequences, test_labels)
)
以上五个步骤涵盖了从数据加载、预处理、模型定义到训练的完整流程。这些步骤是解决文本情感分析问题的主要步骤。