最近打算学习一下NLP,在这里记录一下看到的知识。
n-gram是一种语言模型,作用就是为一句给定的单词的序列返回一个概率,表示这个序列出现的概率值。常见的有unigram,bigram,trigram等等。
n个单词的句子出现的概率:
unigram,假设单词之间相互独立,那么可以表示为:
unigram是不可取的,因为‘i have a dream’和'dream have a i'计算出来的概率是一样的,bigram就是根据条件概率计算:
当然trigram的结果就是:
n-gram能解决什么问题呢?,其中一个就是根据语料库的n-gram查看一个语句是不是合理的,比如"我喜欢吃西瓜"就比"西瓜喜欢吃我"出现的概率大。
import nltk
word_data = "The best performance can bring in sky high success."
nltk_tokens = nltk.word_tokenize(word_data)
print(list(nltk.bigrams(nltk_tokens)))
output:
[('The', 'best'), ('best', 'performance'), ('performance', 'can'), ('can', 'bring'),
('bring', 'in'), ('in', 'sky'), ('sky', 'high'), ('high', 'success'), ('success', '.')]
# encoding=utf8
from __future__ import print_function
import re
from nltk.util import ngrams
def generate_ngrams(s, n):
# Convert to lowercases
s = s.lower()
# Replace all none alphanumeric characters with spaces
s = re.sub(r'[^a-zA-Z0-9\s]', ' ', s)
# Break sentence in the token, remove empty tokens
tokens = [token for token in s.split(" ") if token != ""]
# Use the zip function to help us generate n-grams
# Concatentate the tokens into ngrams and return
ngrams = zip(*[tokens[i:] for i in range(n)])
return [" ".join(ngram) for ngram in ngrams]
if __name__ == "__main__":
s = """
Natural-language processing (NLP) is an area of
computer science and artificial intelligence
concerned with the interactions between computers
and human (natural) languages.
"""
# print (generate_ngrams(s, 2))
s = s.lower()
s = re.sub(r'[^a-zA-Z0-9\s]', ' ', s)
tokens = [token for token in s.split(" ") if token != ""]
output = list(ngrams(tokens, 2))
print (output)
RNN从理论上看是能够利用任意远的输入信息的,但是在实际应用中,使用RNN学习长序列问题的时候效果不好,这是因为梯度在传播的过程中发生了消失(或者爆炸)的情况。
colah在举了这样一个例子:
从梯度推导的角度看,RNN无法依赖长期信息的原因是梯度可能会出现消失或者爆炸的情况,详情见。
LSTM的结构包含了三个门,输入门,遗忘门和输出门,并且还引入了cell state这样的一个历史状态,结构如下:
那为什么LSTM能够解决长期依赖问题呢?这是因为RNN的状态S是根据St-1非线性变换的结果:
这样导致链式法则求导时引入了激活函数的导数和参数的乘积:
这样连乘就容易导致梯度的爆炸或者消失,而LSTM在更新状态的时候使用的是线性的相加:
The cell state is kind of like a conveyor belt. It runs straight down the entire chain, with only some minor linear interactions. It’s very easy for information to just flow along it unchanged.
因此状态求导之后结果就是各个门的结果,梯度不依赖w的取值,实际应用中相比RNN能够更好的传递梯度:
LSA:对基于tf-idf的词项-文档矩阵进行SVD分解 ,由于SVD很慢,基本不再使用
NMF:基于非负矩阵分解的NMF方法在求解上效率更高
LDA:
这篇文章介绍的word2vec源码解析写的很好,看了下上面word2vec的C源码,对于word2vec的理解更加深入了,发现其中hierachical softmax用哈夫曼树来实现真的很巧妙,其实最终的梯度更新和逻辑回归类似。