NLP就是人与机器沟通的"桥梁"。
NLP的基础概念
概念名词
词表/词库(Vocabulary)
文本数据集中出现的所有单词的集合。
语料库(Corpus)
用于NLP任务的文本数据集合。
词嵌入(Word Embedding)
将单词映射到低维连续向量空间的技术,用于捕捉单词的语义和语法信息。
分词(Tokenization)
将文本分割成一个个单词或标记的过程,为后续处理提供基本的单位。
停用词(Stop Words)
在文本处理中被忽略的常见单词,如"a"、"the"、"is"等
词频(Term Frequency)
在给定文档中,某个单词出现的次数。
词性标注(Part-of-Speech Tagging)
为每个词赋予正确的词法标记。
句法分析(Parsing)
分析句子的结构,确定词语间的语法关系。
词干提取(Stemming)与词形还原(Lemmatization)
词干提取:将词转换为词干或原型形式,去除变化或衍生部分。
词形还原:将词还原为词源或词典中的词目形式。
词向量化(Word Vector)
将词语表示为实数向量,以捕捉语言与实数间的关系。
TF-IDF(Term Frequency-Inverse Document Frequency)
一种常用的文本特征表示方法,综合考虑了词频和逆文档频率。
命名实体消歧(Named Entity Disambiguation)与识别(Named Entity Recognition)
命名实体消歧:确定文本中提到的实体的具体含义,如区分同名不同义的实体。
命名实体识别:识别文本中具有特定意义的实体,并分类为人名、机构名、日期等。
序列常见类型
字符序列
一个字符串就是一个字符序列,每个字符按顺序排列。 例子:"hello"
是一个由 h
、e
、l
、l
、o
组成的字符序列。
2.
单词序列
一句话可以看作是一个单词序列,每个单词按照一定顺序排列。 例子:"I love NLP"
是一个由 I
、love
、NLP
组成的单词序列。
3.
时序数据
在时间序列中,元素是按时间顺序排列的,常用于预测问题。 例子:股票价格数据可以看作是随时间变化的数值序列。
4.
语音序列
在语音处理任务中,语音信号可以被分解为按时间顺序排列的帧序列(特征向量序列)。
5.
其他序列
序列还可以表示一些更抽象的结构,比如DNA序列(由碱基组成的序列)、事件序列等。
基本流程
1.语料获取
利用已经建好的数据集或第三方语料库
获取网络数据
与第三方合作获取数据,通过购买的方式获取部分需求文本数据
2.语料预处理
去除数据中非文本内容
中文分词 jieba分词软件
词性标注。词性标注指给词语打上词类标签,如名词、动词、形容词等,常用的词性标注方法有基于规则的算法、基于统计的算法等。
去停用词。停用词就是句子中没必要存在的词,去掉停用词后对理解整个句子的语义没有影响。中文文本中存在大量的虚词、代词或者没有特定含义的动词、名词,在文本分析的时候需要去掉。
3.文本向量化(特征工程)
文本数据经过预处理去除数据中非文本内容、中文分词、词性标注和去停用词后,基本上是干净的文本了。但此时还是无法直接将文本用于任务计算,需要通过某些处理手段,预先将文本转化为特征向量。一般可以调用一些模型来对文本进行处理,常用的模型有词袋模型(Bag of Words Model)、独热表示、TF-IDF 表示、n元语法(n-gram)模型和 Word2Vec模型等。
4.模型构建
5.模型训练
6.模型评价
NLP中的特征工程
在自然语言处理(NLP)中,特征工程 是指将文本数据转换为适合机器学习模型使用的数值表示的过程。
传统NLP中的特征工程
独热编码 one - hot
独热编码(One-Hot Encoding) 是一种常见的特征表示方法,通常用于将离散的类别型数据转换为数值型表示,它的特点是将每个类别表示为一个向量,在该向量中,只有一个元素为1,其余元素全部为0。
例:在nlp中,构成词库{time, fruit, flies, like, a, an, arrow, banana},banana的one-hot表示就是:[0,0,0,0,0,0,0,1],"like a banana" 的one-hot表示就是:[0,0,0,1,1,0,0,1]。
词频-逆文档频率(TF-IDF)
词频
在计算词频(TF)时,分母是文档中的总词数 ,不考虑重复
例:"Fruit flies like time flies a fruit" ,TF("files")=2/7
逆文档频率**(Inverse Document Frequency, IDF)**
逆文档频率用来衡量一个词在整个文档集合(语料库)中的重要性。它的目的是降低那些在很多文档中频繁出现的词的权重,例如"the"、"is"这种常见词,或者低频罕见词tetrafluoroethylene(四氟乙烯)。
D表示文档集合,t是要计算的词。+1
是为了避免分母为 0 的情况。
math在文章中出现5次,文章有200个词,则IDF=log[200/(5+1)]
TF-IDF 计算
TF-IDF 是 TF 和 IDF 相乘
一个词在特定文档中出现的频率越高(TF高),并且在整个语料库中出现得越少(IDF高),它的 TF-IDF 值就越高。可以找出在文章中重点但不常见的词,比如一些专业名词等。
n-grams
n-grams 是特征工程中的一种技术,它通过将文本中的连续 n 个词(或字符)组合起来,形成一个短语来捕捉文本中的局部上下文信息。n 可以为 1、2、3 等,具体取决于希望捕捉的上下文范围。
-
1-gram(Unigram) :每个单独的词作为一个单位。例如,"I love NLP" 的 1-gram 是
["I", "love", "NLP"]
。 -
2-grams(Bigram) :相邻的两个词组合成一个短语。例如,"I love NLP" 的 2-grams 是
["I love", "love NLP"]
。 -
3-grams(Trigram) :相邻的三个词组合成一个短语。例如,"I love NLP" 的 3-grams 是
["I love NLP"]
。
深度学习中NLP的特征输入
稠密编码(特征嵌入)
稠密编码(Dense Encoding)
通常指的是将离散或高维稀疏数据转化为低维的连续、密集向量表示。
特征嵌入(Feature Embedding)
特征嵌入,也成为词嵌入,是稠密编码的一种表现形式,目的是将离散的类别、对象或其他类型的特征映射到一个连续的向量空间。
特点:
-
低维度:相比稀疏表示(如独热编码),稠密编码的维度更低,能够减少计算和存储成本。
-
语义相似性:嵌入向量之间的距离(如欧氏距离或余弦相似度)可以表示这些对象之间的语义相似性。
-
可微学习:嵌入表示通常通过神经网络进行学习,并且通过反向传播算法进行优化。
词嵌入算法
Embedding Layer
API
nn.Embedding(num_embeddings=10, embedding_dim=4)
-
num_embeddings 表示词的数量
-
embedding_dim 表示用多少维的向量来表示每个词
代码示例
python
import torch
import torch.nn as nn
import jieba
test="今天天气真好,好久没有这么好的天了"
#文本分词
words=jieba.lcut(test)
# print(words)
# 输出:
# ['今天天气', '真', '好', ',', '好久', '没有', '这么', '好', '的', '天', '了']
#构建词典
index_to_word={}
word_to_index={}
for i,word in enumerate(set(words)):
if word not in word_to_index:
index_to_word[i]=word
word_to_index[word]=i
# print(word_to_index)
# print(index_to_word)
#输出:
"""
{'今天天气': 0, '真': 1, '好': 2, ',': 3, '好久': 4, '没有': 5, '这么': 6, '
的': 8, '天': 9, '了': 10}
{0: '今天天气', 1: '真', 2: '好', 3: ',', 4: '好久', 5: '没有', 6: '这么', 8: '的', 9: '天', 10: '了'}
"""
#词嵌入层
#第一个参数:词表单词总数 第二个:词嵌入维度
embed=nn.Embedding(len(word_to_index),2)
#将文本转成词向量表示
print("-"*30)
for word in words:
i=word_to_index[word]
# 获取词向量
word_vector=embed(torch.tensor([i]))
print("%3s\t" % word_vector)
"""
------------------------------
tensor([[0.4638, 1.4010]], grad_fn=<EmbeddingBackward0>)
tensor([[0.2467, 0.5415]], grad_fn=<EmbeddingBackward0>)
tensor([[ 0.1601, -0.2102]], grad_fn=<EmbeddingBackward0>)
tensor([[-0.6121, -1.8269]], grad_fn=<EmbeddingBackward0>)
tensor([[ 0.4472, -0.0368]], grad_fn=<EmbeddingBackward0>)
tensor([[-1.0996, 0.1180]], grad_fn=<EmbeddingBackward0>)
tensor([[-1.0891, -0.2760]], grad_fn=<EmbeddingBackward0>)
tensor([[ 0.1601, -0.2102]], grad_fn=<EmbeddingBackward0>)
tensor([[ 0.3143, -0.9363]], grad_fn=<EmbeddingBackward0>)
tensor([[-0.2251, 0.9102]], grad_fn=<EmbeddingBackward0>)
tensor([[-0.5780, -0.8060]], grad_fn=<EmbeddingBackward0>)
"""
word2vec
Word2vec是一个用来产生词向量的模型。是一个将单词转换成向量形式的工具。
word2vec一般分为CBOW(Continuous Bag-of-Words)与 Skip-Gram 两种模型:
1、CBOW:根据中心词周围的词来预测中心词,有negative sample和Huffman两种加速算法,
CBOW对小型数据库比较合适。
2、Skip-Gram:根据中心词来预测周围词;
python
"""
假设现在有语料库sentences = ["i like dog", "i love coffee", "i hate milk", "i love milk"] 通过词嵌入层算法和NNLM模型得到以下结果
[['i', 'like'], ['i', 'love'], ['i', 'hate'], ['i', 'love']] -> ['dog', 'coffee', 'milk', 'milk']
"""
import torch
import torch.nn as nn
import numpy
import torch.optim as optim
sentences= ["i like dog", "i love coffee", "i hate milk","i love milk"]
#创建词表和对应的映射关系
word_list = " ".join(sentences).split()
# print(word_list)
"""
['i', 'like', 'dog', 'i', 'love', 'coffee', 'i', 'hate', 'milk','i', 'love', 'milk']
"""
word_list= list(set(word_list))
word_dict = {w: i for i, w in enumerate(word_list)}
number_dict = {i: w for i, w in enumerate(word_list)}
n_class = len(word_dict)#词表大小
#设置模型超参数
m_dim=2#嵌入向量的维度
n_hidden=2#神经元数量
n_step=2#输入步长数
#创建输入的样本和目标值
def make_batch(sentences):
input_batch = []
target_batch = []
for sen in sentences:
word = sen.split()
# print(word)
input = [word_dict[n] for n in word[:-1]]
target = word_dict[word[-1]]
input_batch.append(input)
target_batch.append(target)
return input_batch,target_batch
#创建模型
class NNLM(nn.Module):
def __init__(self,n_step,n_class,m_dim,n_hidden):
super (NNLM,self).__init__()
#定义嵌入层,单词索引映射为嵌入向量
self.embed=nn.Embedding(n_class,m_dim)
#第一层隐藏层
self.linear1=nn.Linear(m_dim*n_step,n_hidden)
#分类类别数就是词表大小
self.linear2=nn.Linear(n_hidden,n_class)
def forward(self,x):
x=self.embed(x)#通过嵌入层得到的形状是(batch_size,n_step,m_dim) ->(batch_size,n_step*m_dim)
x=x.view(-1,n_step*m_dim)#拉平为二维数据
h=torch.tanh(self.linear1(x))
output=self.linear2(h)
return output
#初始化模型
model=NNLM(n_step,n_class,m_dim,n_hidden)
#创建损失函数和优化器
criterion=nn.CrossEntropyLoss()#损失函数 交叉熵
optimizer=optim.Adam(model.parameters(),lr=0.001)#优化器 学习率
#准备输入和目标数据
input_batch,target_batch=make_batch(sentences)
input_batch=torch.LongTensor(input_batch)
target_batch=torch.LongTensor(target_batch)
for epoch in range(5000):
optimizer.zero_grad()#梯度清零
output=model(input_batch)
loss=criterion(output,target_batch)
if (epoch+1)%1000==0:
print(f'Epoch:, %04d % (epoch+1), cost=, {loss:.6f}.format(loss)')
loss.backward()#反向传播
optimizer.step()#更新参数
#使用训练好的模型进行预测
predict=model(input_batch).max(1,keepdim=True)[1]
#输出预测结果
print([sen.split()[:2] for sen in sentences],'->',[number_dict[n.item()] for n in predict.squeeze()])
"""
Epoch:, %04d % (epoch+1), cost=, 0.601257.format(loss)
Epoch:, %04d % (epoch+1), cost=, 0.511757.format(loss)
Epoch:, %04d % (epoch+1), cost=, 0.452694.format(loss)
Epoch:, %04d % (epoch+1), cost=, 0.412047.format(loss)
Epoch:, %04d % (epoch+1), cost=, 0.389134.format(loss)
[['i', 'like'], ['i', 'love'], ['i', 'hate'], ['i', 'love']] -> ['dog', 'milk', 'milk', 'milk']