文本分类/文本聚类
文本分类
文本聚类
情感分析 Sentiment Classification
方法1,极简单的规则:
- step1:搜集一个褒义词/贬义词词典
- step2:计算一句话中褒义词的数量 $cnt_p$,贬义词的数量 $cnt_n$,然后情感评分为 $\dfrac{cnt_p}{cnt_p+cnt_n}$
- step3:另外,由于褒义词和贬义词的词典大小不一样,所以可以做个修正 $\dfrac{cnt_p/len_p}{cnt_p/len_p+cnt_n/len_n}$
方法2,使用分类模型
- 难点相对于单词数量来说,训练集太少,例如,你的训练集有10k,但涉及到的单词量也是10k
- 难点解决:利用其它模型训练好的 word embedding 进行转化。
- 模型。假设共有5个分数(label有5种)。对于某条评论,每个单词用 embedding matrix 转化为向量后(假设转化后的向量是$300\times 1$的),把向量求平均,输入 softmax 模型进行回归(weights 形状是$5\times 300$)。
方法3,RNN for sentiment classification
- 上面的方法有个缺陷,例如句子是 “Completely lacking in good taste, good service, and good ambience.”,这个句子会被判别为非常正向。
- 使用一种 Many-to-one 的RNN,这种模型可用性很好的原因是,你用近义词替换后,模型的输出结果会差不多。
机器翻译
信息检索
Information Retrieval(IR)
布尔检索:主要从数据结构/数据库的角度,探索如何提高关键词检索的性能。
向量空间模型:
- 把用户输入的查询也作为文档
- 统一用 tf-idf 转化为向量
- 按照余弦相似度,检索出结果
信息提取
NER
问答系统
分为2部分
- 对用户的问题做分类模型
- 一个高效的检索系统,给出最接近的文档。
主题建模
根据输入的语料,给出主题
主要模型是
- LDA(Latent Dirichlet Allocation)
- LSI(Latent Semantics Indexing)
信息摘要
目的:给定一个文档,返回摘要。
思路:有较多实体和名词的句子,往往重要性较高。因此只需要构建一个重要性评分标准,然后找出前n句。如此简单的算法即可获得不错的效果。
方案1 : 返回每个段落的第一句话。这是最简单但往往有效的方法。
方案2
step1:给定一个文档,其有 n 句话。
step2:对每个句子i,求出它与其它 n-1 个句子的相似度
step3:对每个句子i,求出 i 与其它 n-1 个句子的平均相似度
step4:返回相似度最大的 k 个句子。
注:如何定义相似度呢?求两个句子对应的单词之间的 杰卡德相似系数,如果 Jaccard。。。。
代码如下:
分句+分词,没什么好说的。
import numpy as np
sentences_raw = '卷积神经网络是优雅且有用的图像算法。卷积本身是一种传统的图像处理方法。相比之下,它的优雅之处在于它能够自动计算卷积。它被用于图像识别、人脸识别等图像算法中'
# 分句
sentences_raw = [i for i in sentences_raw.split('。') if len(i) > 1]
# 分词
import jieba
import re
sentences = [jieba.lcut(sentence, cut_all=False) for sentence in sentences_raw] # 拆词
regex = re.compile(u'[\u4e00-\u9fa5]')
sentences = [[word for word in sentence if regex.match(word) is not None] for sentence in
sentences] # jieba 拆开的词,一串数字也作为一个词返回,这里过滤一下
# sentences=[[word for word in sentence if word not in stops] for sentence in sentences] # 停词
sentences = [' '.join(sentence) for sentence in sentences]
摘要提取算法
def get_score(sent1, sent2):
if len(sent1) == 0 or len(sent2) == 0:
return 0
return len(sent1 & sent2) / len(sent1 | sent2)
def get_avg_score(sent1, sentences):
return np.average([get_score(sent1, sent2) for sent2 in sentences])
def get_summary_idx(sentences):
sentences_ = [set(sentence.split(' ')) for sentence in sentences]
return np.argmax([get_avg_score(sent1, sentences_) for sent1 in sentences_])
summary_idx = get_summary_idx(sentences)
summary = sentences_raw[summary_idx]
print(summary)
卷积神经网络是优雅且有用的图像算法
看起来效果还行
以上算法还可以用来 减少冗余,
改进:
- 动态调整分数。
- 根据所在位置调整分数,首句和尾句的权重加大
- 根据标点符号调整分数,陈述句、疑问句、感叹句的权重各有不同
- 根据关键词调整分数,出现“总而言之”,“总之”,“本文”,“综上所述”的,增加分数;出现“比如”,“例如”的,减少分数 用单词的 TF-IDF 评分。
语言检测
给出某个文本使用的是哪种语言
OCR
消除偏见
由于训练用的文本有偏见,embedding matrix 也会有偏见,例如性别偏见:
Man: computer programmers as woman :Homemaker
偏见会导致 embedding matrix 在使用时的问题。
做法(以sexual bias为例):
step1. Identify bias direction $avg (e_{he}-e_{she},e_{male}-e_{female},…)$,这就找到表示性别的轴
step2. Neutralize: For every word that is not definitional, project to get rid of bias.就是把那些性别无关的单词(如computer programmers),投影到轴上
step3. Equalize pairs. 使得与性别有关的单词(如gril和boy)词组到computer programmers的距离相等。
生成模型
(这个图里面,左边和右边是不同的RNN)
- 翻译,Many-to-Many RNN model.
- 读图讲故事。模型的输入是一张图,输出是一句话,描述图中的内容。
做法:一个训练好点的CNN,去除最后的 softmax 层,将这个输出作为RNN的输入。
2020年更新:
这个模型叫做Seq2Seq,有这几种类型
- 图中的输出和输入不是同时,这个叫做 Delayed Many2Many,左半部分的神经元都一样,叫做 Encoder,右半部分的神经元都一样,叫做 Decoder。另外如果输入输出同时的话,叫做 Many-to-Many,也是最原始的那个RNN
- 每一块可以是 LSTM,GRU等。GRU更常见
- 针对右半部分,每个节点输入的y可以是上一个节点的输出(叫做AR,例如DeepAR),也可以是真实值(叫做MQRNN)
DeepAR
DeepAR:(论文 https://arxiv.org/abs/1704.04110)
- 神经网络节点是GRU,
- 输出不是y,而是正态分布的$u,\sigma$,损失函数会相应调整。
MQRNN
(论文 https://arxiv.org/abs/1711.11053)
- encoder用的是GRU,decoder用的是DNN
- 输出的是分位数。并且有对应的损失函数。
WaveNet(https://arxiv.org/abs/1609.03499)
Attention(https://arxiv.org/abs/1706.03762)
Picking the most likely sentence
缺点一样,在生成过程中,单词是依概率选取的。
解决:Picking the most likely sentence
我们想要找到$\arg\max P(y^{<1>},…,y^{
- 不能用遍历,情况太多了。假设有$10k$个单词,要生成长度为10的句子,那么搜索空间是$10k^{10}$,非常巨大
- 不能用 greedy search (因为未必是全局最大)
- 用 beam search (未必能达到最优,但往往是最优)
- 有一个 hyperparameter ,B,下面以$B=3$为例
- 每一步生成 top 3 (top B)个单词,放到下一步
- 如果要生成长度为10的句子,那么搜索空间变成$3^10$
(如果B=1,等价于 greedy search)
beam search的改进
新问题,$\arg\max\limits_y P(y^{<1>},…,y^{
- 我们考虑用这个$\arg\max\limits_y \sum\limits_{t=1}^{T_y} \log P(y^{
}\mid x,y^{<1>},...,y^{ })$ - 进一步,为了将句子的长度也纳入最优化的考虑因素中,用这个,$\arg\max\limits_y \dfrac{1}{T_y^{\alpha}}\sum\limits_{t=1}^{T_y} \log P(y^{
}\mid x,y^{<1>},...,y^{ })$,这里,$\alpha$是一个 hyperparameter - $\alpha=0$,就是整个句子概率最大
- $\alpha=1$,就是平均到每个单词,概率最大
Error analysis in beam search
假设你有一个好的翻译(可能来自人的翻译),记为 $ y^* $
算法用 beam search 计算出的句子,记为$\hat y$
可以用算法计算 $P(y^* \mid x),P(\hat y \mid x)$
- case1:$P(y^* \mid x)>P(\hat y \mid x)$,需要调整 beam search 算法
- case2:$P(y^* \mid x)\leq P(\hat y \mid x)$,需要调整 RNN
Bleu Score (bilingual evaluation understudy)是一种给文本生成效果打分的方法。
假如我们有人工翻译的标准答案,和机器翻译的结果:
Reference 1: The cat is on the mat.
Reference 2: There is a cat on the mat.
MT output: The cat the cat on the mat.
step1:对于 MT output,用n-gram拆分,并计数
这里假设用 2-gram,计数结果是{‘the cat’:2, ‘cat the’:1, ‘cat on’:1, ‘on the’: 1, ‘the mat’: 1}
step2:对step1中拆分出的gram,找到标准答案的计数中最大的那个,结果是{‘the cat’:1, ‘cat the’:0, ‘cat on’:1, ‘on the’: 1, ‘the mat’: 1}
step3: sum(step2)/sum(step1) 就是 Bleu Score
- 可以是 n-gram
- 如果 MT output 与某个标准答案完全一样,得分为1
- 假设 $p_n=$ Bleu score on n-grams,用$BP * \exp (1/4 \sum\limits_{n=1}^4 p_n)$作为总分,其中,$BP=\exp(1-\max(MTOutputLength/ReferenceOutputLength))$
(BP 是 brevity penalty 的缩写)
Attention Model Intuition
https://www.coursera.org/learn/nlp-sequence-models/lecture/lSwVa/attention-model
语音识别
Speech recognition 解决的问题是,输入的音频,$T_x»T_y$
https://www.coursera.org/learn/nlp-sequence-models/lecture/sjiUm/speech-recognition
Trigger Word Detection
https://www.coursera.org/learn/nlp-sequence-models/lecture/Li4ts/trigger-word-detection
常见 NLP 任务
1、token-level task:token级别的任务. 如完形填空(Cloze), 预测句子中某个位置的单词; 或者实体识别; 或是词性标注; SQuAD等.
- 1.1 Cloze task :BERT模型预训练的两个任务之一, 完形填空任务。给出句子中其他的上下文token, 推测出当前位置应当是什么token. BERT在预训练时使用 masked language model, 即在与训练时, 将句子中的部分token用【masked】这个特殊的token进行替换,然后目标就是预测[masked]对应位置的单词.
- 1.2. SQuAD(Standford Question Answering Dataset) task:这是一个生成式的任务. 样本为语句对. 给出一个问题, 和一段来自于Wikipedia的文本, 其中这段文本之中, 包含这个问题的答案, 返回一短语句作为答案. 因为给出答案, 这是一个生成式的问题, 这个问题的特殊性在于最终的答案包含在语句对的文本内容之中, 是有范围的, 而且是连续分布在内容之中的.因此, 我们找出答案在文本语句的开始和结尾处, 就能找到最后的答案. 通过对文本语句序列中每个token对应的所有hidden vector做softmax判断是开始的概率和是结束的概率, 最大化这个概率就能进行训练, 并得到输出的结果.
- 1.3 Named Entity Recognition(NER)对每个token打标签, 判断每个token的类别.
- SpaCy:基于Python的NER系统
- Stanford NER:基于JAVA的NER系统
2、sequence-level (Segment-level) task:序列级别的任务(也叫做句子级别的任务). 如情感分类等各种句子分类问题; 推断两个句子的是否是同义等.
- 2.1 NLI(Natural Language Inference) task:自然语言推断任务, 即给出一对(a pair of)句子, 判断两个句子是entailment(相近), contradiction(矛盾)还是neutral(中立)的. 由于也是分类问题, 也被称为sentence pair classification tasks.
- 在智能问答, 智能客服, 多轮对话中有应用.
- 常用的数据集有:
- MNLI(Multi-Genre Natural Language Inference): 是GLUE Datasets(General Language Understanding Evaluation)中的一个数据集. 是一个大规模的来源众多的数据集, 目的就是推断两个句子是意思相近, 矛盾, 还是无关的.
- WNLI(Winograd NLI)
- 2.2. Sentence Pair Classification tasks. 两个句子相关性的分类问题, NLI task是其中的特殊情况. 经典的此类问题和对应的数据集有:
- QQP(Quora Question Pairs): 这是一个二分类数据集. 目的是判断两个来自于Quora的问题句子在语义上是否是等价的.
- QNLI(Question Natural Language Inference): 也是一个二分类问题, 两个句子是一个(question, answer)对. 正样本为answer是对应question的答案, 负样本则相反.
- STS-B(Semantic Textual Similarity Benchmark): 这是一个类似回归的问题. 给出一对句子, 使用1~5的评分评价两者在语义上的相似程度.
- MRPC(Microsoft Research Paraphrase Corpus): 句子对来源于对同一条新闻的评论. 判断这一对句子在语义上是否相同.
- RTE(Recognizing Textual Entailment): 是一个二分类问题, 类似于MNLI, 但是数据量少很多.
- 2.3. Single Sentence Classification tasks
- SST-2(Stanford Sentiment Treebank): 单句的二分类问题, 句子的来源于人们对一部电影的评价, 判断这个句子的情感.
- CoLA(Corpus of Linguistic Acceptability): 单句的二分类问题, 判断一个英文句子在语法上是不是可接受的.
- 2.4. SWAG(Situations With Adversarial Generations) 给出一个陈述句子和4个备选句子, 判断前者与后者中的哪一个最有逻辑的连续性, 相当于阅读理解问题.
常用 NLP 工具
spaCy
https://github.com/explosion/spaCy
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("This is a sentence.")
print([(w.text, w.pos_) for w in doc])
nlp = spacy.load("zh_core_web_sm")
doc = nlp("我叫郭飞,是一名算法工程师。")
print([(w.text, w.pos_) for w in doc])
# [('我', 'PRON'), ('叫', 'VERB'), ('郭飞', 'PROPN'), (',', 'PUNCT'), ('是', 'VERB'), ('一', 'NUM'), ('名', 'NUM'), ('算法', 'NOUN'), ('工程师', 'NOUN'), ('。', 'PUNCT')]
中文分词工具 jieba
中文转拼音工具 Pypinyin
# pip install pypinyin
from pypinyin import lazy_pinyin, Style
lazy_pinyin('我叫郭飞,是一名算法工程师', style=Style.TONE3)
# ['wo3', 'jiao4', 'guo1', 'fei1', ',', 'shi4', 'yi1', 'ming2', 'suan4', 'fa3', 'gong1', 'cheng2', 'shi1']