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
组成的字符序列。 -
单词序列
一句话可以看作是一个单词序列,每个单词按照一定顺序排列。 例子:"I love NLP"
是一个由I
、love
、NLP
组成的单词序列。 -
时序数据
在时间序列中,元素是按时间顺序排列的,常用于预测问题。 例子:股票价格数据可以看作是随时间变化的数值序列。 -
语音序列
在语音处理任务中,语音信号可以被分解为按时间顺序排列的帧序列(特征向量序列)。 -
其他序列
序列还可以表示一些更抽象的结构,比如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 表示用多少维的向量来表示每个词
代码示例
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>)
"""
"""
假设现在有语料库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']
word2vec
Word2vec是一个用来产生词向量的模型。是一个将单词转换成向量形式的工具。
word2vec一般分为CBOW(Continuous Bag-of-Words)与 Skip-Gram 两种模型:
1.CBOW
根据中心词周围的词来预测中心词,有negative sample和Huffman两种加速算法,
CBOW对小型数据库比较合适。
连续词袋模型(CBOW)是一种根据上下文单词来预测目标单词的模型。具体来说,给定一个窗口大小为 n 的上下文单词序列,连续词袋模型的任务是预测中间的目标单词。
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
#定义数据类型为浮点数
dtype=torch.FloatTensor
# 语料库,包含训练模型的句子
sentences = ["i like dog", "i like cat", "i like animal",
"dog cat animal", "apple cat dog like", "cat like fish",
"dog like meat", "i like apple", "i hate apple",
"i like movie book music apple", "dog like bark", "dog friend cat"]
# 建立词表
word_sentences = " ".join(sentences).split()
word_list = list(set(word_sentences))# 去重
word_index = {w: i for i, w in enumerate(word_list)}
#创建CBOW的训练数据集
cbow_inputs=[]
for i in range(1,len(word_sentences)-1):
context=[word_index[word_sentences[i-1]],word_index[word_sentences[i+1]]]
target=word_index[word_sentences[i]]
cbow_inputs.append([context, target]) # 上下文和目标加入训练集
#词嵌入维度
emb_dim=2
#词表大小
vocab_size=len(word_index)
#训练批次
batch_size=2
#定义CBOW模型
class CBOW(nn.Module):
def __init__(self):
super(CBOW,self).__init__()
#映射矩阵
self.embed=nn.Embedding(vocab_size,emb_dim)
self.linear=nn.Linear(emb_dim,vocab_size)
#输出矩阵
#前向传播
def forward(self,x):
embeds=self.embed(x)#映射矩阵
avg_embeds=torch.mean(embeds,dim=1)#上下文词向量取平均,dim是指在n_stepps维度上取平均
output=self.linear(avg_embeds)
return output
#初始化模型
model=CBOW()
#创建损失函数和优化器
criterion=nn.CrossEntropyLoss()#损失函数 交叉熵
optimizer=optim.Adam(model.parameters(),lr=0.001)#优化器 学习率
#定义随机批量生成函数
def random_batch(data,size):
random_inputs=[]
random_labels=[]
random_index=np.random.choice(range(len(data)),size,replace=False)
#根据随机索引生成输入和目标数据
for i in random_index:
#目标词one_hot编码
random_inputs.append(data[i][0])
#上下文词的索引作为标签
random_labels.append(data[i][1])
return random_inputs,random_labels
#训练模型
for epoch in range(10000):
inputs,labels=random_batch(cbow_inputs,batch_size)
# print(inputs)
# print(labels)
#转为张量
input_batch=torch.LongTensor(inputs)
label_batch=torch.LongTensor(labels)
optimizer.zero_grad()#梯度清零
output=model(input_batch)
loss=criterion(output,label_batch)
if (epoch+1)%1000==0:
print("Epoch:",epoch+1,"loss:",loss.item())
loss.backward()#反向传播
optimizer.step()#更新参数
#可视化词嵌入
for i,label in enumerate(word_list):
W=model.embed.weight.data.numpy()#获取参数
x,y=float(W[i][0]),float(W[i][1])
plt.scatter(x,y)
plt.annotate(label,xy=(x,y),xytext=(5,2),textcoords='offset points',ha='right',va='bottom')
plt.show()
"""
Epoch: 1000 loss: 1.9663656949996948
Epoch: 2000 loss: 2.3870277404785156
Epoch: 3000 loss: 1.9677610397338867
Epoch: 4000 loss: 1.111128330230713
Epoch: 5000 loss: 0.8203855752944946
Epoch: 6000 loss: 2.0697202682495117
Epoch: 7000 loss: 1.6513001918792725
Epoch: 8000 loss: 1.0836256742477417
Epoch: 9000 loss: 0.2905329167842865
Epoch: 10000 loss: 1.4150944948196411
"""
2.Skip-Gram
根据中心词来预测周围词;
Skip-gram 模型是一种根据目标单词来预测上下文单词的模型。具体来说,给定一个中心单词,Skip-gram 模型的任务是预测在它周围窗口大小为 n 内的上下文单词。
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
#定义数据类型为浮点数
dtype=torch.FloatTensor
# 语料库,包含训练模型的句子
sentences = ["i like dog", "i like cat", "i like animal",
"dog cat animal", "apple cat dog like", "cat like fish",
"dog like meat", "i like apple", "i hate apple",
"i like movie book music apple", "dog like bark", "dog friend cat"]
# 建立词表
word_sentences = " ".join(sentences).split()
word_list = list(set(word_sentences))# 去重
word_index = {w: i for i, w in enumerate(word_list)}
#创建skip的训练数据集
skip_grams=[]
for i in range(1,len(word_sentences)-1):
#当前词对应的id
center=word_index[word_sentences[i]]
#获取当前词的前后两个上下文词对应的id
context=[word_index[word_sentences[i-1]],word_index[word_sentences[i+1]]]
#将当前词和上下文词组合成skip-gram对
for w in context:
skip_grams.append([center,w])
#定义超参数
#词嵌入维度
emb_dim=2
#词表大小
vocab_size=len(word_list)
#训练批次
batch_size=5
#定义skip模型
class Word2Vec(nn.Module):
def __init__(self):
super(Word2Vec,self).__init__()
#词嵌入层
self.W=nn.Parameter(torch.rand(vocab_size,emb_dim))
#定义输出层矩阵W2
self.WT=nn.Parameter(torch.rand(emb_dim,vocab_size))
self.logsoftmax=nn.LogSoftmax(dim=1)
#前向传播
def forward(self,x):
#映射层
weights=torch.matmul(x,self.W)
#输出层
out_put=torch.matmul(weights,self.WT)
return out_put
#初始化模型
model=Word2Vec()
#创建损失函数和优化器
criterion=nn.CrossEntropyLoss()#损失函数 交叉熵
optimizer=optim.Adam(model.parameters(),lr=0.001)#优化器 学习率
#准备输入和目标数据
def random_batch(data,size):
random_inputs=[]
random_labels=[]
#从数据中随机选取size个索引值
random_index=np.random.choice(range(len(skip_grams)),size,replace=False)
#根据随机索引生成输入和目标数据
for i in random_index:
#目标词one_hot编码
random_inputs.append(np.eye(vocab_size)[data[i][0]])
#上下文词的索引作为标签
random_labels.append(data[i][1])
return random_inputs,random_labels
#训练模型
for epoch in range(10000):
inputs,labels=random_batch(skip_grams,batch_size)
#转为张量
input_batch=torch.Tensor(inputs)
label_batch=torch.LongTensor(labels)
optimizer.zero_grad()#梯度清零
output=model(input_batch)
loss=criterion(output,label_batch)
if (epoch+1)%1000==0:
print("Epoch:",epoch+1,"loss:",loss.item())
loss.backward()#反向传播
optimizer.step()#更新参数
#可视化词嵌入
for i,label in enumerate(word_list):
W,WT=model.parameters()#获取参数
x,y=float(W[i][0]),float(W[i][1])
plt.scatter(x,y)
plt.annotate(label,xy=(x,y),xytext=(5,2),textcoords='offset points',ha='right',va='bottom')
plt.show()
"""
input_batch=torch.Tensor(inputs)
Epoch: 1000 loss: 2.0359740257263184
Epoch: 2000 loss: 1.9298549890518188
Epoch: 3000 loss: 2.2617080211639404
Epoch: 4000 loss: 1.4156063795089722
Epoch: 5000 loss: 1.850890874862671
Epoch: 6000 loss: 1.5289673805236816
Epoch: 7000 loss: 1.8529554605484009
Epoch: 8000 loss: 1.8329124450683594
Epoch: 9000 loss: 1.6333214044570923
Epoch: 10000 loss: 1.8766262531280518
"""
3.gensim API调用
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
from gensim.models import Word2Vec
# 语料库,包含训练模型的句子
sentences = ["i like dog", "i like cat", "i like animal",
"dog cat animal", "apple cat dog like", "cat like fish",
"dog like meat", "i like apple", "i hate apple",
"i like movie book music apple", "dog like bark", "dog friend cat"]
# 将语料库转换为列表
token_list=[sentences.split() for sentences in sentences]
print(token_list)
#定义模型
model=Word2Vec(token_list,vector_size=2,window=1,min_count=0,sg=0)
#获取词汇表
word_list=list(model.wv.index_to_key)
# print(word_list)
#可视化嵌入结果
for i,word in enumerate(word_list):
w=model.wv[word]#获取模型参数
x,y=float(w[0]),float(w[1])
plt.scatter(x,y)
plt.annotate(word,xy=(x,y),xytext=(5,2),textcoords='offset points',ha='right',va='bottom')
print(model.wv.most_similar("like"))
print(model.wv.similarity("i","cat"))
plt.show()
"""
[['i', 'like', 'dog'], ['i', 'like', 'cat'], ['i', 'like', 'animal'], ['dog', 'cat', 'animal'], ['apple', 'cat', 'dog', 'like'], ['cat', 'like', 'fish'], ['dog', 'like', 'meat'], ['i', 'like', 'apple'], ['i', 'hate', 'apple'], ['i', 'like', 'movie', 'book', 'music', 'apple'], ['dog', 'like', 'bark'], ['dog', 'friend', 'cat']]
[('friend', 0.846409797668457), ('bark', 0.7237492203712463), ('fish', 0.5371317267417908), ('apple', 0.4996943771839142), ('i', 0.49164748191833496), ('book', 0.31097015738487244), ('dog', -0.11141161620616913), ('cat', -0.21838019788265228), ('movie', -0.5319129824638367), ('music', -0.7415058016777039)]
-0.9571427
"""
该api主要的参数有:
sentences 可以是一个list,对于大语料集,建议使用BrownCorpus,Text8Corpus或lineSentence构建。
vector_size word向量的维度,默认为100。大的size需要更多的训练数据,但是效果会更好。推荐值为几十到几百。
window 表示当前词与预测词在一个句子中的最大距离是多少。
min_count 可以对字典做截断。词频少于min_count次数的单词会被丢弃掉,默认值为5。
sg 用于设置训练算法,默认为0,对应CBOW算法;sg=1则采用skip-gram算法。
标签:NLP,word,like,loss,处理,torch,batch,dog,自然语言 From: https://blog.csdn.net/m0_68153457/article/details/142463462