常用于挖掘文本关键词:
import jieba
import numpy as np
texts=[
'...',
'...',
'...',
'...'
]
# sklearn
# 对于中文文档,需要提前使用jieba进行分词
x_train = [" ".join(jieba.cut(text)) for text in texts[:3]]
x_test = [" ".join(jieba.cut(text)) for text in texts[3:]]
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
vectorizer = CountVectorizer()
tf_idf_transformer = TfidfTransformer()
x_train_tf_idf = tf_idf_transformer.fit_transform(vectorizer.fit_transform(x_train))
x_test_tf_idf = tf_idf_transformer.transform(vectorizer.transform(x_test))
x_train_weight = x_train_tf_idf.toarray()
x_test_weight = x_test_tf_idf.toarray()
words = vectorizer.get_feature_names()
for w in x_train_weight:
loc = np.argsort(-w)
for i in range(5):
print('{}: {} {}'.format(str(i + 1), words[loc[i]], w[loc[i]]))
print('\n')
# gensim
x_train = [jieba.lcut(text) for text in texts[:3]]
x_test = [jieba.lcut(text) for text in texts[3:]]
from gensim import corpora
from gensim import models
# 建立词表
dic = corpora.Dictionary(x_train)
# 建立id2count
x_train_bow = [dic.doc2bow(sentence) for sentence in x_train]
tfidf = models.TfidfModel(x_train_bow)
tfidf_vec = []
for sentence in x_test:
word_bow = dic.doc2bow(sentence.lower())
word_tfidf = tfidf[word_bow]
tfidf_vec.append(word_tfidf)
# 输出 词语id与词语tfidf值
print(tfidf_vec)
# jieba
import jieba.analyse
# idf使用jieba默认的,也可以自行指定
keywords = jieba.analyse.extract_tags(texts[0], topK=5)
对于大规模文本,还可使用spark实现tf-idf:Spark MLlib TF-IDF – Example
常用于本文主题分析。
词汇的分布来表达主题,主题的分布来表达文章。
进行LDA的参数估计时,常用变分EM算法(MAP)或gibbs采样(贝叶斯估计)
from gensim import corpora, models, similarities
import jieba
docs = [
'...',
'...',
...,
'...'
]
documents = [' '.join(jieba.lcut(i)) for i in docs]
with open('stop_words.txt',encoding='UTF-8')) as f:
stoplist = [i.strip() for i in f.readlines()]
texts = [[word for word in doc.lower().split() if word not in stoplist] for doc in documents]
dictionary = corpora.Dictionary(texts)
corpus = [dictionary.doc2bow(text) for text in texts]
num_topics = 10
# model = models.LsiModel(corpus, id2word = dictionary, num_topics = num_topics)
model = models.LdaModel(corpus, id2word = dictionary, num_topics = num_topics)
# model = models.RpModel(corpus, num_topics = num_topics)
# model = models.HdpModel(corpus, id2word = dictionary)
doc = "..."
vec_bow = dictionary.doc2bow(jieba.lcut(doc))
vec_lsi = model[vec_bow]
index = similarities.MatrixSimilarity(model[corpus])
# index = similarities.Similarity(output_prefix='Similarity',corpus=model[corpus],num_features=500)
sims = index[vec_lsi]
# sims = sorted(enumerate(sims),key=lambda item:-item[1])
# print(sims)
result = [(docs[i[0]],i[1]) for i in enumerate(sims)]
result = sorted(result ,key = lambda x: -x[1])
print(result)
同样地,Spark MLlib也提供了LDA的支持,Topic modelling using Latent Dirichlet Condition in Apache Spark MLlib
GitHub - UKPLab/sentence-transformers
GitHub - MaartenGr/BERTopic
BERTopic是一个基于sentence-BERT实现的主题模型工具,可以实现主题的抽取、计算,同时可以替换不同的预训练模型。
sbert.net - Pretrained Models
Sentence-BERT使用了孪生神经网络结构,将两个不同的句子输入BERT,然后进行pooling,得到输出向量,最后计算向量相似度,得到句子相似度。
而BERT需要参考如下的学习路线
Seq2Seq -> Attention -> Transformer -> BERT
有一些NLP任务的输入输出序列都是长度可变的,例如机器翻译、对话机器人等,为了解决这类问题,常见的解决方案是使用编码器-解码器架构,利用编码器将不定长的输入序列编码成一个向量,称为context,解码器对context进行解码,得到输出序列。
编码器、解码器常用多层循环神经网络来实现。
DIVE INTO DEEPLEARNING - 9.7. 序列到序列学习(seq2seq)给出了一个Seq2Seq的TensorFlow Keras实现。
Seq2Seq常用的训练技巧有;
编码器-解码器架构存在一些问题:
因此一个可行的优化就是利用编码器所有的隐藏层状态:Bahdanau与Luong等人分别提出了在Seq2Seq中使用注意力机制,来利用编码器所有输出的方法。注意力的本质是加权平均,在Seq2Seq中,编码器每个时间步的输出同时作为键和值,通过计算向量与编码器输入序列每个位置之间的“相关度”,从而利用编码器所有输出计算出解码器当前时间步的输出。
其中:
Luong注意力在对齐上更符合语言习惯,因此后续的Transformer也使用了Luong的模式。
在Seq2Seq中的实现如下:
# https://github.com/wavewangyue/tensorflow_seq2seq/blob/master/model_seq2seq.py
# Luong Attention Mechanism
def attn(self, hidden, encoder_outputs):
attn_weights = tf.matmul(encoder_outputs, tf.expand_dims(hidden, 2))
attn_weights = tf.nn.softmax(attn_weights, axis=1)
context = tf.squeeze(tf.matmul(tf.transpose(encoder_outputs, [0,2,1]), attn_weights))
return context
# ...
if useAttention:
input = tf.concat([input, self.attn(previous_state, encoder_outputs)], 1)
# ...
基于编码器-解码器架构与注意力机制,Google提出了Transformer,用于解决机器翻译问题。
编码器-解码器架构:
自注意力:输入的所有单词进行注意力操作,一个句子内的单词,互相看其他单词对自己的影响力有多大,句子内各单词的注意力,应该关注在该句子内其他单词中的哪些单词上
Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text{Attention}(Q,K,V) = \text{softmax}(\frac{QK^T}{\sqrt{d_k}})V Attention(Q,K,V)=softmax(dkQKT)V
当 d k d_k dk很大时, Q K T QK^T QKT的方差就很大,分布会趋于陡峭(分布的方差大,分布就会集中在绝对值大的区域),就会使得softmax之后使得值出现两极分化的状态
————————————————
原文链接:https://blog.csdn.net/panxin801/article/details/120758904
多头注意力:使用多个不同的Q,K,V,将向量映射到不同的语义空间内,学习embedding之间的联系,类似CNN中通道的概念
MultiHead(Q,K,V) = Concat ( h e a d 1 , . . . , h e a d n ) W O \text{MultiHead(Q,K,V)} = \text{Concat}(head_1,...,head_n)W^O MultiHead(Q,K,V)=Concat(head1,...,headn)WO
位置编码:由于Transformer并行输入,没有使用序列的位置信息,因此采用了位置编码进行补偿
残差连接,LayerNorm:
GitHub - tensorflow/docs-l10n - 理解语言的 Transformer 模型给出了一个Transformer的TensorFlow Keras实现
BERT采用了两阶段模型:语言模型预训练,随后微调解决下游任务
from bertopic import BERTopic
from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd
import jieba
def tokenize_zh(text):
words = jieba.lcut(text)
return words
docs = [
'...',
'...',
...,
'...'
]
vectorizer = CountVectorizer(tokenizer=tokenize_zh)
# 初始化Bertopic模型
model = BERTopic(language='chinese (simplified)', vectorizer_model=vectorizer)
topics, probs = model.fit_transform(docs)
topic2doc = pd.DataFrame({'topic': topics, 'doc': docs})
print(model.get_topic_info())
print(topic2doc)
Bahdanau et.al (2014) Neural Machine Translation by Jointly Learning to Align and Translate
Luong et.al (2015) Effective Approaches to Attention-based Neural Machine Translation
Attention Is All You Need
BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
Spark MLlib TF-IDF – Example
Topic modelling using Latent Dirichlet Condition in Apache Spark MLlib
DIVE INTO DEEPLEARNING - 9.7. 序列到序列学习(seq2seq)
GitHub - CLUEbenchmark/CLUE
GitHub - MaartenGr/BERTopic
GitHub - tensorflow/docs-l10n - 理解语言的 Transformer 模型
GitHub - google-research/bert
通俗理解LDA主题模型
Tensorflow中的Seq2Seq全家桶
Attention Variants
Self-Attention和Transformer
Self-attention中为什么softmax要除d_k