2019-12-09 10:34:49 weixin_42137700 阅读数 11
  • 从零开始自然语言处理

    本课程隶属于自然语言处理(NLP)实战系列。自然语言处理(NLP) 是数据科学里的一个分支,它的主要覆盖的内容是:以一种智能与高效的方式,对文本数据进行系统化分析、理解与信息提取的过程。通过使用 NLP以及它的组件,我们可以管理非常大块的文本数据,或者执行大量的自动化任务,并且解决各式各样的问题,如自动摘要,机器翻译,命名实体识别,关系提取,情感分析,语音识别,以及主题分割等等。 一般情况下一个初级NLP工程师的工资从15万-35万不等,所以掌握NLP技术,对于人工智能学习者来讲是非常关键的一个环节。 课程从自然语言处理的基本概念与基本任务出发,对目前主流的自然语言处理应用进行全面细致的讲解, 包括文本分类,文本摘要提取,文本相似度,文本情感分析,文本特征提取等,同时算法方面包括经典算法与深度学习算法的结合,例如 LSTM,BiLSTM等,并结合京东电商评论分类、豆瓣电影摘要提取、今日头条舆情挖掘、饿了么情感分析等过个案例,帮助大家熟悉自然语言处理工程师在工作中会接触到的 常见应用的实施的基本实施流程,从0-1入门变成自然语言处理研发工程师。

    478 人正在学习 去看看 钱兴会

 2019-12-03 20:49:51

作者:Dipanjan (DJ) Sarkar

编译:ronghuaiyang

导读

今天接着昨天的内容,给大家介绍Glove模型和FastText模型,以及得到的词向量如何应用在机器学习任务里。

(书接上回)

GloVe模型

GloVe模型指的是全局向量模型,是一种无监督学习模型,可以获得类似于Word2Vec的dense词向量。然而,技术是不同的,训练是在一个聚合的全局词-词共现矩阵上做的,可以得到具有有意义的子结构的向量空间。这个方法是斯坦福大学的Pennington等人发明的。

我们不会在这里从头开始详细介绍模型的实现。我们在这里会保持简单,并试图理解GloVe模型背后的基本概念。我们已经讨论了基于计数的矩阵分解的方法,如LSA以及预测的方法,如Word2Vec。文章称,目前,这两个方法都存在明显的缺陷。像LSA这样的方法可以有效地利用统计信息,但在单词类比任务上,比如我们如何发现语义相似的单词,它们的表现相对较差。像skip-gram这样的方法可能在类比任务上做得更好,但是它们在全局水平上没有很好地利用语料库的统计数据。

GloVe模型的基本方法是首先创建一个由(单词,上下文)对组成的巨大单词上下文共现矩阵,这样的话,该矩阵中的每个元素表示的是这个单词与上下文一起出现的频率(可以是单词序列)。接下来的想法是应用矩阵分解来逼近这个矩阵,如下图所示。

基于深度学习的文本数据特征提取方法之Glove和FastText

 

考虑Word-Context (WC)矩阵、Word-Feature (WF)矩阵和Feature-Context (FC)矩阵,我们尝试对WC = WF x FC进行因式分解,将WFFC相乘,重构WC。为此,我们使用一些随机权重初始化WFFC,并尝试将它们相乘以得到WC'(WC的近似形式),并度量它与WC的距离。我们多次使用随机梯度下降(SGD)来降低误差。最后,单词特征矩阵(WF)为每个单词提供单词嵌入,其中F可以预先设置为特定数量的维度。需要记住的非常重要的一点是,Word2Vec和GloVe模型的工作原理非常相似。这两种方法的目的都是建立一个向量空间,在这个空间中,每个单词的位置都受到其相邻单词的上下文和语义的影响。Word2Vec以单词共现对的本地个别示例开始,GloVe以语料库中所有单词的全局聚合共现统计数据开始。

将Glove特征应用于机器学习任务

让我们尝试使用基于GloVe的嵌入式技术来完成文档聚类任务。非常流行的spacy框架具有利用基于不同语言模型来得到GloVe嵌入。你还可以获得预先训练好的词向量,并根据需要使用gensim或spacy加载它们。我们将首先安装spacy并使用en_vectors_web_lg模型,该模型由训练在Common Crawl上的300维单词向量组成。

 # Use the following command to install spaCy
 > pip install -U spacy
 OR
 > conda install -c conda-forge spacy
 # Download the following language model and store it in disk
 https://github.com/explosion/spacy-models/releases/tag/en_vectors_web_lg-2.0.0
 # Link the same to spacy
 > python -m spacy link ./spacymodels/en_vectors_web_lg-2.0.0/en_vectors_web_lg en_vecs
 Linking successful
 ./spacymodels/en_vectors_web_lg-2.0.0/en_vectors_web_lg --> ./Anaconda3/lib/site-packages/spacy/data/en_vecs
 You can now load the model via spacy.load('en_vecs')

在spacy中也有自动安装模型的方法。现在,我们将使用spacy加载语言模型。

 import spacy
 
 nlp = spacy.load('en_vecs')
 
 total_vectors = len(nlp.vocab.vectors)
 print('Total word vectors:', total_vectors)
 Total word vectors: 1070971

这验证了一切都在正常工作。现在让我们在玩具语料库中获取每个单词的GloVe嵌入。

 unique_words = list(set([word for sublist in [doc.split() for doc in norm_corpus] for word in sublist]))
 
 word_glove_vectors = np.array([nlp(word).vector for word in unique_words])
 pd.DataFrame(word_glove_vectors, index=unique_words)

基于深度学习的文本数据特征提取方法之Glove和FastText

 

现在我们可以使用t-SNE来可视化这些嵌入,类似于我们使用Word2Vec嵌入所做的。

 from sklearn.manifold import TSNE
 
 tsne = TSNE(n_components=2, random_state=0, n_iter=5000, perplexity=3)
 np.set_printoptions(suppress=True)
 T = tsne.fit_transform(word_glove_vectors)
 labels = unique_words
 
 plt.figure(figsize=(12, 6))
 plt.scatter(T[:, 0], T[:, 1], c='orange', edgecolors='r')
 for label, x, y in zip(labels, T[:, 0], T[:, 1]):
 plt.annotate(label, xy=(x+1, y+1), xytext=(0, 0), textcoords='offset points')

基于深度学习的文本数据特征提取方法之Glove和FastText

 

spacy的美妙之处在于,它将自动提供每个文档中单词的平均嵌入,而无需像我们在Word2Vec中那样实现函数。我们将利用相同的方法为语料库获取文档特征,并使用k-means聚类来对文档进行聚类。

 doc_glove_vectors = np.array([nlp(str(doc)).vector for doc in norm_corpus])
 
 km = KMeans(n_clusters=3, random_state=0)
 km.fit_transform(doc_glove_vectors)
 cluster_labels = km.labels_
 cluster_labels = pd.DataFrame(cluster_labels, columns=['ClusterLabel'])
 pd.concat([corpus_df, cluster_labels], axis=1)

基于深度学习的文本数据特征提取方法之Glove和FastText

 

我们看到一致的聚类,类似于我们从Word2Vec模型中得到的结果,这很好!GloVe模型声称在很多情况下都比Word2Vec模型表现得更好,如下图所示。

基于深度学习的文本数据特征提取方法之Glove和FastText

 

上述实验是通过在Wikipedia 2014 + Gigaword 5上训练300维向量,使用相同的40万个单词词汇表和一个大小为10的对称上下文窗口来完成的。

FastText模型

FastText模型于2016年首次由Facebook引入,作为普通Word2Vec模型的扩展和改进。基于Mikolov等人的原始论文' Subword Information Word Vectors with Subword Information',这是一本很好的读物,可以深入了解这个模型是如何工作的。总的来说,FastText是一个学习单词表示的框架,还可以执行健壮、快速和准确的文本分类。该框架由Facebook在GitHub上开源,拥有以下内容。

  • 最新最先进的英文词向量。
  • 在Wikipedia和crawl-vectors上训练了157种语言的词向量。
  • 用于语言识别和各种受监督的任务的模型。

虽然我并没有从零开始实现这个模型,但是根据我的研究论文,以下是我对这个模型是如何工作的了解。一般来说,像Word2Vec模型这样的预测模型通常将每个单词视为一个不同的实体(例如where),并为单词生成dense的嵌入。然而,这是一个严重的限制,语言有大量的词汇和许多罕见的词,可能不会出现在很多不同的语料库。Word2Vec模型通常忽略每个单词的形态学结构,而将单词视为单个实体。FastText模型认为每个单词都是由n个字符组成的包。这在论文中也称为子词模型。

我们在单词的开头和结尾添加了特殊的边界符号<>。这使我们能够从其他字符序列中区分前缀和后缀。我们还将单词w本身包含在它的n-gram集合中,以学习每个单词的表示(加上其字符的n-gram)。以单词wheren=3 (tri-grams)为例,它将由这些字符n-grams来表示:<wh, whe, her, ere, re>以及表示整个单词的特殊序列<where>来表示这个单词。注意,单词<her>与tri-grams中的her是不同的。

在实际应用中,本文建议提取n≥ 3n≤ 6。这是一种非常简单的方法,可以考虑不同的n-gram集合,例如取所有前缀和后缀。我们通常将向量表示(嵌入)与单词的每个n-gram关联起来。因此,我们可以用一个单词的n-gram的向量表示的和或者这些n-gram的嵌入的平均值来表示这个单词。因此,由于利用基于字符的单个单词的n-gram的这种效果,罕见单词获得良好表示的几率更高,因为它们基于字符的n-gram应该出现在语料库的其他单词中。

将FastText特征应用于机器学习任务

gensim包封装了很好的接口,为我们提供了gensim.models.fasttext下可用的FastText模型的接口。让我们再次把这个应用到我们的圣经语料库上,看看我们感兴趣的单词和它们最相似的单词。

 from gensim.models.fasttext import FastText
 
 wpt = nltk.WordPunctTokenizer()
 tokenized_corpus = [wpt.tokenize(document) for document in norm_bible]
 
 # Set values for various parameters
 feature_size = 100 # Word vector dimensionality 
 window_context = 50 # Context window size 
 min_word_count = 5 # Minimum word count 
 sample = 1e-3 # Downsample setting for frequent words
 
 # sg decides whether to use the skip-gram model (1) or CBOW (0)
 ft_model = FastText(tokenized_corpus, size=feature_size, window=window_context,
 min_count=min_word_count,sample=sample, sg=1, iter=50)
 
 
 # view similar words based on gensim's FastText model
 similar_words = {search_term: [item[0] for item in ft_model.wv.most_similar([search_term], topn=5)]
 for search_term in ['god', 'jesus', 'noah', 'egypt', 'john', 'gospel', 'moses','famine']}
 similar_words 

基于深度学习的文本数据特征提取方法之Glove和FastText

 

可以在我们的Word2Vec模型的结果中看到许多相似之处,其中每个感兴趣的单词都有相关的相似单词。你注意到有什么有趣的关联和相似之处吗?

基于深度学习的文本数据特征提取方法之Glove和FastText

 

注意:运行此模型的计算开销较大,而且与skip-gram模型相比,通常需要更多的时间,因为它考虑了每个单词的n-gram。如果使用GPU或好的CPU进行训练,可以更好地工作。我在AWS的p2上训练过这个。例如,我花了大约10分钟,而在一个普通的系统上需要花2-3个小时。

现在让我们使用Principal Component Analysis (PCA)将单词嵌入维数减少到二维,然后将其可视化。

 from sklearn.decomposition import PCA
 
 words = sum([[k] + v for k, v in similar_words.items()], [])
 wvs = ft_model.wv[words]
 
 pca = PCA(n_components=2)
 np.set_printoptions(suppress=True)
 P = pca.fit_transform(wvs)
 labels = words
 
 plt.figure(figsize=(18, 10))
 plt.scatter(P[:, 0], P[:, 1], c='lightgreen', edgecolors='g')
 for label, x, y in zip(labels, P[:, 0], P[:, 1]):
 plt.annotate(label, xy=(x+0.06, y+0.03), xytext=(0, 0), textcoords='offset points')

基于深度学习的文本数据特征提取方法之Glove和FastText

 

我们可以看到很多有趣的模式!诺亚、他的儿子闪和祖父玛土撒拉是非常接近的。我们还看到上帝与摩西和埃及有联系,埃及在那里忍受了圣经中的瘟疫,包括饥荒和瘟疫。此外,耶稣和他的一些门徒关系密切。

要访问任何单词embeddings,你可以使用以下的代码用单词为模型建立索引。

 ft_model.wv['jesus']
 array([-0.23493268, 0.14237943, 0.35635167, 0.34680951, 
 0.09342121,..., -0.15021783, -0.08518736, -0.28278247, 
 -0.19060139], dtype=float32)

有了这些嵌入,我们可以执行一些有趣的自然语言任务。其中之一是找出不同单词(实体)之间的相似性。

 print(ft_model.wv.similarity(w1='god', w2='satan'))
 print(ft_model.wv.similarity(w1='god', w2='jesus'))
 Output
 ------
 0.333260876685
 0.698824900473

根据我们的圣经语料库中的文本,我们可以看到“上帝”“耶稣”联系更紧密,而不是“撒旦”

考虑到单词嵌入的存在,我们甚至可以从一堆单词中找出一些奇怪的单词,如下所示。

 st1 = "god jesus satan john"
 print('Odd one out for [',st1, ']:', 
 ft_model.wv.doesnt_match(st1.split()))
 st2 = "john peter james judas"
 print('Odd one out for [',st2, ']:',
 ft_model.wv.doesnt_match(st2.split()))
 Output
 ------
 Odd one out for [ god jesus satan john ]: satan
 Odd one out for [ john peter james judas ]: judas

总结

这些示例应该让你对利用深度学习语言模型从文本数据中提取特征,以及解决诸如单词语义、上下文和数据稀疏等问题的新策略有一个很好的了解。

英文原文:https://towardsdatascience.com/understanding-feature-engineering-part-4-deep-learning-methods-for-text-data-96c44370bbfa

2019-10-10 11:05:44 yee_0217 阅读数 157
  • 从零开始自然语言处理

    本课程隶属于自然语言处理(NLP)实战系列。自然语言处理(NLP) 是数据科学里的一个分支,它的主要覆盖的内容是:以一种智能与高效的方式,对文本数据进行系统化分析、理解与信息提取的过程。通过使用 NLP以及它的组件,我们可以管理非常大块的文本数据,或者执行大量的自动化任务,并且解决各式各样的问题,如自动摘要,机器翻译,命名实体识别,关系提取,情感分析,语音识别,以及主题分割等等。 一般情况下一个初级NLP工程师的工资从15万-35万不等,所以掌握NLP技术,对于人工智能学习者来讲是非常关键的一个环节。 课程从自然语言处理的基本概念与基本任务出发,对目前主流的自然语言处理应用进行全面细致的讲解, 包括文本分类,文本摘要提取,文本相似度,文本情感分析,文本特征提取等,同时算法方面包括经典算法与深度学习算法的结合,例如 LSTM,BiLSTM等,并结合京东电商评论分类、豆瓣电影摘要提取、今日头条舆情挖掘、饿了么情感分析等过个案例,帮助大家熟悉自然语言处理工程师在工作中会接触到的 常见应用的实施的基本实施流程,从0-1入门变成自然语言处理研发工程师。

    478 人正在学习 去看看 钱兴会

我搜集了两种方法来实现,一种方法基于theano,另一种方法基于tensorflow。

方法一参考:

【1】https://github.com/ryankiros/skip-thoughts

【2】https://blog.csdn.net/qq_33373858/article/details/83928249

方法二参考:

【3】https://github.com/tensorflow/models/tree/master/research/skip_thoughts#encoding-sentences

方法一详解:

  1. 从github【1】上下载skip-thoughts的代码。
  2. 根据【1】中要求安装依赖库。(theano不用必须是Theano 0.7,我的1.0.4也可以)
  3. 在下好的文件目录下添加data文件夹。
  4. 根据作者提供的链接,下载所需文件,并全部存放到data目录下。注意这里的pkl文件下载地址发生了一些错误,只能下载txt文件,可以在作者github的issue中找新的link.
  5. 修改skipthoughts.py文件内的路径:
  6. 在data同目录下新建文件测试:(encoder.py),得到4800维向量。

 

使用上述方法可以提取个别sentence的特征,但是如果需要提取大量文本特征时,上述方法使用的cpu太费时间了,而且theano使用GPU加速有些麻烦,我还没有实现。

 

方法二详情:

1.首先,在【3】中下载skip-thoughts的代码。

2.然后,安装必需的依赖库:

3.下载的skip-thoughts可以放在tensorflow的模型文件examples下面,也可以直接使用,接下来介绍直接使用的方法。

4.新建自己的工程,将下载的skip-thoughts-master更名为skip-thoughts之后放在工程文件夹下。在skip-thoughts文件夹下新建pre-trained文件夹用于保存预训练模型,将下载的skip-thoughts的预训练模型(需要下单向和双向的两个文件)解压缩之后放在该目录下。

5.写自己的测试文件:

这里需要注意的是,checkpoint的路径文件只写到500008.

6.在encoder_manager.py的前面添加使用的GPU:

 

 

7.如果使用的是单向的,则只需要在测试文件中加入单向预训练模型:

如果使用的是双向的,则需要加入两个预训练模型,也需要调用两次load_model:

 

8.run测试文件。

 

2020-02-26 23:21:31 zimiao552147572 阅读数 146
  • 从零开始自然语言处理

    本课程隶属于自然语言处理(NLP)实战系列。自然语言处理(NLP) 是数据科学里的一个分支,它的主要覆盖的内容是:以一种智能与高效的方式,对文本数据进行系统化分析、理解与信息提取的过程。通过使用 NLP以及它的组件,我们可以管理非常大块的文本数据,或者执行大量的自动化任务,并且解决各式各样的问题,如自动摘要,机器翻译,命名实体识别,关系提取,情感分析,语音识别,以及主题分割等等。 一般情况下一个初级NLP工程师的工资从15万-35万不等,所以掌握NLP技术,对于人工智能学习者来讲是非常关键的一个环节。 课程从自然语言处理的基本概念与基本任务出发,对目前主流的自然语言处理应用进行全面细致的讲解, 包括文本分类,文本摘要提取,文本相似度,文本情感分析,文本特征提取等,同时算法方面包括经典算法与深度学习算法的结合,例如 LSTM,BiLSTM等,并结合京东电商评论分类、豆瓣电影摘要提取、今日头条舆情挖掘、饿了么情感分析等过个案例,帮助大家熟悉自然语言处理工程师在工作中会接触到的 常见应用的实施的基本实施流程,从0-1入门变成自然语言处理研发工程师。

    478 人正在学习 去看看 钱兴会

日萌社

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)


 

什么是特征提取呢?

 

1 特征提取

1.1 定义

将任意数据(如文本或图像)转换为可用于机器学习的数字特征

注:特征值化是为了计算机更好的去理解数据

  • 特征提取分类:
    • 字典特征提取(特征离散化)
    • 文本特征提取
    • 图像特征提取(深度学习将介绍)

1.2 特征提取API

sklearn.feature_extraction

2 字典特征提取

作用:对字典数据进行特征值化

  • sklearn.feature_extraction.DictVectorizer(sparse=True,…)
    • DictVectorizer.fit_transform(X)
      • X:字典或者包含字典的迭代器返回值
      • 返回sparse矩阵
    • DictVectorizer.get_feature_names() 返回类别名称

2.1 应用

我们对以下数据进行特征提取

[{'city': '北京','temperature':100},
{'city': '上海','temperature':60},
{'city': '深圳','temperature':30}]

2.2 流程分析

  • 实例化类DictVectorizer
  • 调用fit_transform方法输入数据并转换(注意返回格式)
from sklearn.feature_extraction import DictVectorizer

def dict_demo():
    """
    对字典类型的数据进行特征抽取
    :return: None
    """
    data = [{'city': '北京','temperature':100}, {'city': '上海','temperature':60}, {'city': '深圳','temperature':30}]
    # 1、实例化一个转换器类
    transfer = DictVectorizer(sparse=False)
    # 2、调用fit_transform
    data = transfer.fit_transform(data)
    print("返回的结果:\n", data)
    # 打印特征名字
    print("特征名字:\n", transfer.get_feature_names())

    return None

注意观察没有加上sparse=False参数的结果

返回的结果:
   (0, 1)    1.0
  (0, 3)    100.0
  (1, 0)    1.0
  (1, 3)    60.0
  (2, 2)    1.0
  (2, 3)    30.0
特征名字:
 ['city=上海', 'city=北京', 'city=深圳', 'temperature']

这个结果并不是我们想要看到的,所以加上参数,得到想要的结果:

返回的结果:
 [[   0.    1.    0.  100.]
 [   1.    0.    0.   60.]
 [   0.    0.    1.   30.]]
特征名字:
 ['city=上海', 'city=北京', 'city=深圳', 'temperature']

之前在学习pandas中的离散化的时候,也实现了类似的效果。我们把这个处理数据的技巧叫做”one-hot“编码

2.3 总结

对于特征当中存在类别信息的我们都会做one-hot编码处理

3 文本特征提取

作用:对文本数据进行特征值化

  • sklearn.feature_extraction.text.CountVectorizer(stop_words=[])

    • 返回词频矩阵
    • CountVectorizer.fit_transform(X)
      • X:文本或者包含文本字符串的可迭代对象
      • 返回值:返回sparse矩阵
    • CountVectorizer.get_feature_names() 返回值:单词列表
  • sklearn.feature_extraction.text.TfidfVectorizer

3.1 应用

我们对以下数据进行特征提取

["life is short,i like python",
"life is too long,i dislike python"]

3.2 流程分析

  • 实例化类CountVectorizer
  • 调用fit_transform方法输入数据并转换 (注意返回格式,利用toarray()进行sparse矩阵转换array数组)
from sklearn.feature_extraction.text import CountVectorizer

def text_count_demo():
    """
    对文本进行特征抽取,countvetorizer
    :return: None
    """
    data = ["life is short,i like like python", "life is too long,i dislike python"]
    # 1、实例化一个转换器类
    # transfer = CountVectorizer(sparse=False) # 注意,没有sparse这个参数
    transfer = CountVectorizer()
    # 2、调用fit_transform
    data = transfer.fit_transform(data)
    print("文本特征抽取的结果:\n", data.toarray())
    print("返回特征名字:\n", transfer.get_feature_names())

    return None

返回结果:

文本特征抽取的结果:
 [[0 1 1 2 0 1 1 0]
 [1 1 1 0 1 1 0 1]]
返回特征名字:
 ['dislike', 'is', 'life', 'like', 'long', 'python', 'short', 'too']

问题:如果我们将数据替换成中文?

"人生苦短,我喜欢Python","生活太长久,我不喜欢Python"

那么最终得到的结果是

为什么会得到这样的结果呢,仔细分析之后会发现英文默认是以空格分开的。其实就达到了一个分词的效果,所以我们要对中文进行分词处理

3.3 jieba分词处理

  • jieba.cut()
    • 返回词语组成的生成器

需要安装下jieba库

pip3 install jieba

3.4 案例分析

对以下三句话进行特征值化

今天很残酷,明天更残酷,后天很美好,
但绝对大部分是死在明天晚上,所以每个人不要放弃今天。

我们看到的从很远星系来的光是在几百万年之前发出的,
这样当我们看到宇宙时,我们是在看它的过去。

如果只用一种方式了解某样事物,你就不会真正了解它。
了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。
  • 分析
    • 准备句子,利用jieba.cut进行分词
    • 实例化CountVectorizer
    • 将分词结果变成字符串当作fit_transform的输入值

from sklearn.feature_extraction.text import CountVectorizer
import jieba

def cut_word(text):
    """
    对中文进行分词
    "我爱北京天安门"————>"我 爱 北京 天安门"
    :param text:
    :return: text
    """
    # 用结巴对中文字符串进行分词
    text = " ".join(list(jieba.cut(text)))

    return text

def text_chinese_count_demo2():
    """
    对中文进行特征抽取
    :return: None
    """
    data = ["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
            "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
            "如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]
    # 将原始数据转换成分好词的形式
    text_list = []
    for sent in data:
        text_list.append(cut_word(sent))
    print(text_list)

    # 1、实例化一个转换器类
    # transfer = CountVectorizer(sparse=False)
    transfer = CountVectorizer()
    # 2、调用fit_transform
    data = transfer.fit_transform(text_list)
    print("文本特征抽取的结果:\n", data.toarray())
    print("返回特征名字:\n", transfer.get_feature_names())

    return None

返回结果:

Building prefix dict from the default dictionary ...
Dumping model to file cache /var/folders/mz/tzf2l3sx4rgg6qpglfb035_r0000gn/T/jieba.cache
Loading model cost 1.032 seconds.
['一种 还是 一种 今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝对 大部分 是 死 在 明天 晚上 , 所以 每个 人 不要 放弃 今天 。', '我们 看到 的 从 很 远 星系 来 的 光是在 几百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去 。', '如果 只用 一种 方式 了解 某样 事物 , 你 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 取决于 如何 将 其 与 我们 所 了解 的 事物 相 联系 。']
Prefix dict has been built succesfully.
文本特征抽取的结果:
 [[2 0 1 0 0 0 2 0 0 0 0 0 1 0 1 0 0 0 0 1 1 0 2 0 1 0 2 1 0 0 0 1 1 0 0 1 0]
 [0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 1 3 0 0 0 0 1 0 0 0 0 2 0 0 0 0 0 1 0 1]
 [1 1 0 0 4 3 0 0 0 0 1 1 0 1 0 1 1 0 1 0 0 1 0 0 0 1 0 0 0 2 1 0 0 1 0 0 0]]
返回特征名字:
 ['一种', '不会', '不要', '之前', '了解', '事物', '今天', '光是在', '几百万年', '发出', '取决于', '只用', '后天', '含义', '大部分', '如何', '如果', '宇宙', '我们', '所以', '放弃', '方式', '明天', '星系', '晚上', '某样', '残酷', '每个', '看到', '真正', '秘密', '绝对', '美好', '联系', '过去', '还是', '这样']

但如果把这样的词语特征用于分类,会出现什么问题?

请看问题:

该如何处理某个词或短语在多篇文章中出现的次数高这种情况

3.5 Tf-idf文本特征提取

  • TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。
  • TF-IDF作用:用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。

3.5.1 公式

  • 词频(term frequency,tf)指的是某一个给定的词语在该文件中出现的频率
  • 逆向文档频率(inverse document frequency,idf)是一个词语普遍重要性的度量。某一特定词语的idf,可以由总文件数目除以包含该词语之文件的数目,再将得到的商取以10为底的对数得到

最终得出结果可以理解为重要程度。

举例:
假如一篇文章的总词语数是100个,而词语"非常"出现了5次,那么"非常"一词在该文件中的词频就是5/100=0.05。
而计算文件频率(IDF)的方法是以文件集的文件总数,除以出现"非常"一词的文件数。
所以,如果"非常"一词在1,0000份文件出现过,而文件总数是10,000,000份的话,
其逆向文件频率就是lg(10,000,000 / 1,0000)=3。
最后"非常"对于这篇文档的tf-idf的分数为0.05 * 3=0.15

3.5.2 案例

from sklearn.feature_extraction.text import TfidfVectorizer
import jieba

def cut_word(text):
    """
    对中文进行分词
    "我爱北京天安门"————>"我 爱 北京 天安门"
    :param text:
    :return: text
    """
    # 用结巴对中文字符串进行分词
    text = " ".join(list(jieba.cut(text)))

    return text

def text_chinese_tfidf_demo():
    """
    对中文进行特征抽取
    :return: None
    """
    data = ["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
            "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
            "如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]
    # 将原始数据转换成分好词的形式
    text_list = []
    for sent in data:
        text_list.append(cut_word(sent))
    print(text_list)

    # 1、实例化一个转换器类
    # transfer = CountVectorizer(sparse=False)
    transfer = TfidfVectorizer(stop_words=['一种', '不会', '不要'])
    # 2、调用fit_transform
    data = transfer.fit_transform(text_list)
    print("文本特征抽取的结果:\n", data.toarray())
    print("返回特征名字:\n", transfer.get_feature_names())

    return None

返回结果:

Building prefix dict from the default dictionary ...
Loading model from cache /var/folders/mz/tzf2l3sx4rgg6qpglfb035_r0000gn/T/jieba.cache
Loading model cost 0.856 seconds.
Prefix dict has been built succesfully.
['一种 还是 一种 今天 很 残酷 , 明天 更 残酷 , 后天 很 美好 , 但 绝对 大部分 是 死 在 明天 晚上 , 所以 每个 人 不要 放弃 今天 。', '我们 看到 的 从 很 远 星系 来 的 光是在 几百万年 之前 发出 的 , 这样 当 我们 看到 宇宙 时 , 我们 是 在 看 它 的 过去 。', '如果 只用 一种 方式 了解 某样 事物 , 你 就 不会 真正 了解 它 。 了解 事物 真正 含义 的 秘密 取决于 如何 将 其 与 我们 所 了解 的 事物 相 联系 。']
文本特征抽取的结果:
 [[ 0.          0.          0.          0.43643578  0.          0.          0.
   0.          0.          0.21821789  0.          0.21821789  0.          0.
   0.          0.          0.21821789  0.21821789  0.          0.43643578
   0.          0.21821789  0.          0.43643578  0.21821789  0.          0.
   0.          0.21821789  0.21821789  0.          0.          0.21821789
   0.        ]
 [ 0.2410822   0.          0.          0.          0.2410822   0.2410822
   0.2410822   0.          0.          0.          0.          0.          0.
   0.          0.2410822   0.55004769  0.          0.          0.          0.
   0.2410822   0.          0.          0.          0.          0.48216441
   0.          0.          0.          0.          0.          0.2410822
   0.          0.2410822 ]
 [ 0.          0.644003    0.48300225  0.          0.          0.          0.
   0.16100075  0.16100075  0.          0.16100075  0.          0.16100075
   0.16100075  0.          0.12244522  0.          0.          0.16100075
   0.          0.          0.          0.16100075  0.          0.          0.
   0.3220015   0.16100075  0.          0.          0.16100075  0.          0.
   0.        ]]
返回特征名字:
 ['之前', '了解', '事物', '今天', '光是在', '几百万年', '发出', '取决于', '只用', '后天', '含义', '大部分', '如何', '如果', '宇宙', '我们', '所以', '放弃', '方式', '明天', '星系', '晚上', '某样', '残酷', '每个', '看到', '真正', '秘密', '绝对', '美好', '联系', '过去', '还是', '这样']

3.6 Tf-idf的重要性

分类机器学习算法进行文章分类中前期数据处理方式


4 小结

  • 特征提取【了解】
    • 将任意数据(如文本或图像)转换为可用于机器学习的数字特征
  • 特征提取分类:【了解】
    • 字典特征提取(特征离散化)
    • 文本特征提取
    • 图像特征提取
  • 字典特征提取【知道】
    • 字典特征提取就是对类别型数据进行转换
    • api:sklearn.feature_extraction.DictVectorizer(sparse=True,…)
      • aparse矩阵
        • 1.节省内容
        • 2.提高读取效率
      • 注意:
        • 对于特征当中存在类别信息的我们都会做one-hot编码处理
  • 文本特征提取(英文)【知道】
    • api:sklearn.feature_extraction.text.CountVectorizer(stop_words=[])
      • stop_words -- 停用词
      • 注意:没有sparse这个参数
      • 单个字母,标点符号不做统计
  • 文本特征提取(中文)【知道】
    • 注意:
      • 1.在中文文本特征提取之前,需要对句子(文章)进行分词(jieba)
      • 2.里面依旧可以使用停用词,进行词语的限制
  • tfidf【知道】
    • 主要思想:
      • 如果某个词或短语在一篇文章中出现的概率高,并且在其他文章中很少出现,则认为此词或者短语具有很好的
      • 类别区分能力,适合用来分类
    • tfidf
      • tf -- 词频
      • idf -- 逆向文档频率
    • api:sklearn.feature_extraction.text.TfidfVectorizer
    • 注意:
      • 分类机器学习算法进行文章分类中前期数据处理方式

feature_extraction_demo.py 

# coding:utf-8

from sklearn.feature_extraction import DictVectorizer
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
import jieba


def dict_demo():
    """
    字典特征提取
    :return: None
    """
    # 1.获取数据
    data = [{'city': '北京', 'temperature': 100},
            {'city': '上海', 'temperature': 60},
            {'city': '深圳', 'temperature': 30}]

    # 2.字典特征提取
    # 2.1 实例化
    transfer = DictVectorizer(sparse=True)

    # 2.2 转换
    new_data = transfer.fit_transform(data)
    print(new_data)

    # 2.3 获取具体属性名
    names = transfer.get_feature_names()
    print("属性名字是:\n", names)


def english_count_demo():
    """
    文本特征提取-英文
    :return: None
    """
    # 获取数据
    data = ["life is is short,i like python",
            "life is too long,i dislike python"]

    # 文本特征转换
    # transfer = CountVectorizer(sparse=True)  # 注意:没有sparse这个参数
    transfer = CountVectorizer(stop_words=["dislike"])
    new_data = transfer.fit_transform(data)

    # 查看特征名字
    names = transfer.get_feature_names()

    print("特征名字是:\n", names)
    print(new_data.toarray())
    print(new_data)


def chinese_count_demo1():
    """
    文本特征提取-中文
    :return: None
    """
    # 获取数据
    data = ["人生 苦短,我 喜欢 Python", "生活 太长久,我 不喜欢 Python"]

    # 文本特征转换
    transfer = CountVectorizer()
    new_data = transfer.fit_transform(data)

    # 查看特征名字
    names = transfer.get_feature_names()

    print("特征名字是:\n", names)
    print(new_data.toarray())
    print(new_data)


def cut_word(text):
    """
    中文分词
    :param text:
    :return:
    """
    # ret = " ".join(list(jieba.cut(text)))
    # print(ret)
    return " ".join(list(jieba.cut(text)))


def chinese_count_demo2():
    """
    文本特征提取-中文
    :return: None
    """
    # 1.获取数据
    data = ["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
            "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
            "如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]

    # 2.文章分割
    list = []
    for temp in data:
        list.append(cut_word(temp))
    print(list)

    # 3.文本特征转换
    # 3.1 实例化+转化
    transfer = CountVectorizer(stop_words=["一种", "今天"])
    new_data = transfer.fit_transform(list)

    # 3.2 查看特征名字
    names = transfer.get_feature_names()

    print("特征名字是:\n", names)
    print(new_data.toarray())
    print(new_data)


def tfidf_demo():
    """
    文本特征提取-中文
    :return: None
    """
    # 1.获取数据
    data = ["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
            "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
            "如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]

    # 2.文章分割
    list = []
    for temp in data:
        list.append(cut_word(temp))
    print(list)

    # 3.文本特征转换
    # 3.1 实例化+转化
    transfer = TfidfVectorizer()
    new_data = transfer.fit_transform(list)

    # 3.2 查看特征名字
    names = transfer.get_feature_names()

    print("特征名字是:\n", names)
    print(new_data.toarray())
    print(new_data)


if __name__ == '__main__':
    dict_demo()
    english_count_demo()
    chinese_count_demo1()
    cut_word("我爱你python, 人生苦读,我用python")
    chinese_count_demo2()
    tfidf_demo()

 

2019-09-23 07:33:00 u011984148 阅读数 396
  • 从零开始自然语言处理

    本课程隶属于自然语言处理(NLP)实战系列。自然语言处理(NLP) 是数据科学里的一个分支,它的主要覆盖的内容是:以一种智能与高效的方式,对文本数据进行系统化分析、理解与信息提取的过程。通过使用 NLP以及它的组件,我们可以管理非常大块的文本数据,或者执行大量的自动化任务,并且解决各式各样的问题,如自动摘要,机器翻译,命名实体识别,关系提取,情感分析,语音识别,以及主题分割等等。 一般情况下一个初级NLP工程师的工资从15万-35万不等,所以掌握NLP技术,对于人工智能学习者来讲是非常关键的一个环节。 课程从自然语言处理的基本概念与基本任务出发,对目前主流的自然语言处理应用进行全面细致的讲解, 包括文本分类,文本摘要提取,文本相似度,文本情感分析,文本特征提取等,同时算法方面包括经典算法与深度学习算法的结合,例如 LSTM,BiLSTM等,并结合京东电商评论分类、豆瓣电影摘要提取、今日头条舆情挖掘、饿了么情感分析等过个案例,帮助大家熟悉自然语言处理工程师在工作中会接触到的 常见应用的实施的基本实施流程,从0-1入门变成自然语言处理研发工程师。

    478 人正在学习 去看看 钱兴会

点击上方“AI公园”,关注公众号,选择加“星标“或“置顶”


作者:Dipanjan (DJ) Sarkar

编译:ronghuaiyang

导读

介绍了基于深度学习的文本数据特征提取方法,一步一步动手代码实践,非常清楚,包括了Word2Vec,后面还会有Glove和FastText。

640?wx_fmt=jpeg

介绍

处理非结构化文本数据非常困难,尤其是试图构建一个可以像人类一样解释和理解自由流动的自然语言的智能系统时。你需要能够处理和转换嘈杂的、非结构化的文本数据,并将其转换为可由任何机器学习算法理解的结构化、向量化格式。自然语言处理、机器学习或深度学习都属于人工智能的范畴,它们都是该行业的有效工具。根据我之前的文章,需要记住的一点是,任何机器学习算法都是基于统计、数学和优化原理的。因此,他们没有足够的智能来开始处理原始的、原生的文本。上一篇文章中,我们介绍了一些从文本数据中提取有意义的特征的传统的策略。在本文中,我们将研究更高级的特征工程策略,这些策略通常利用深度学习模型。更具体地说,我们将介绍Word2VecGloVeFastText模型。

动机

我们已经多次讨论过,特征工程是创建性能更好的机器学习模型的秘诀。请始终记住,即使出现了自动化特征工程,你仍然需要理解应用这些技术背后的核心概念。否则它们就只是黑盒子,你就不知道如何对你试图解决的问题进行调整。

传统模型的缺点

传统的(基于计数的)文本数据特征工程策略包括了一大类的模型,这些模型通常称为词袋模型。包括词频、TF-IDF(词频逆文档频率)、N-grams等等。虽然它们是从文本中提取特征的有效方法,但是由于模型本身就是一袋非结构化的单词,我们丢失了额外的信息,比如每个文本文档中围绕邻近单词的语义、结构、序列和上下文。这为我们探索更复杂的模型提供了足够的动力,这些模型可以捕捉这些信息,并为我们提供单词的向量特征表示,即通常所说的嵌入。

词嵌入的需求

虽然这有一定的道理,但是我们到底是哪来的动力去学习和构建这些词嵌呢?在语音或图像识别系统中,所有的信息都已经以丰富密集的特征向量的形式存在于高维数据集中,如声谱和图像像素强度。然而,当涉及到原始文本数据时,尤其是基于计数的模型(如词袋),我们处理的是单独的单词,这些单词可能有自己的标识符,但是不能捕获单词之间的语义关系。这就导致了文本数据中的巨大稀疏的词向量,因此,如果我们没有足够的数据,我们可能会得到糟糕的模型,甚至由于维数诅咒而过度拟合。

640?wx_fmt=png

音频,图像和文本的特征表示的对比

为了克服词袋模型没有语义以及特征稀疏的缺点,我们需要利用向量空间模型(VMS),这样,我们就可以把单词嵌入到基于语义和上下文的连续向量空间中。事实上,语义分布领域的分布假设告诉我们,在相同上下文中出现的单词语义上是相似的,具有相似的意义。简单地说,“一个词的特征取决于和它一起出现的词”。有一篇著名的论文详细讨论了这些各种类型的语义词向量,这个文章是‘Don’t count, predict! A systematic comparison of context-counting vs. context-predicting semantic vectors’。这篇文章我们不会深入讨论,但简而言之,上下文词向量有两种主要的方法。基于计数的方法,比如Latent Semantic Analysis (LSA)可以用于计算某些词和它的相邻的词一起出现频率的统计度量,然后基于这些度量构建dense的向量。基于神经网络的语言模型的预测方法试着从相邻的单词中预测单词,观察语料库中的单词序列,在这个过程中,它学习分布表示,给我们dense的词嵌入。我们将在本文中重点介绍这些预测方法。

特征工程策略

让我们来看看处理文本数据并从中提取有意义的特征的一些高级策略,这些策略可用于下游的机器学习系统。我们将从加载一些基本的依赖项和设置开始。

 import pandas as pd
 import numpy as np
 import re
 import nltk
 import matplotlib.pyplot as plt
 pd.options.display.max_colwidth = 200
 %matplotlib inline

现在,我们将获取一些文档语料库,在这些文档语料库上执行所有的分析。对于其中一个语料库,我们将重用上一篇文章中的语料库。为了便于理解,我们将代码重新写一下。

 corpus = ['The sky is blue and beautiful.',
           'Love this blue and beautiful sky!',
           'The quick brown fox jumps over the lazy dog.',
           "A king's breakfast has sausages, ham, bacon, eggs, toast and beans",
           'I love green eggs, ham, sausages and bacon!',
           'The brown fox is quick and the blue dog is lazy!',
           'The sky is very blue and the sky is very beautiful today',
           'The dog is lazy but the brown fox is quick!'    
 ]
 labels = ['weather', 'weather', 'animals', 'food', 'food', 'animals', 'weather', 'animals']
 
 corpus = np.array(corpus)
 corpus_df = pd.DataFrame({'Document': corpus,
                           'Category': labels})
 corpus_df = corpus_df[['Document', 'Category']]

640?wx_fmt=png

我们的玩具语料库由几个类别的文档组成。我们将在本文中使用的另一个语料库是The King James Version of the Bible,可以从Project Gutenberg通过nltk中的corpus模块免费获得。我们将在下一节中加载它。在讨论特征工程之前,我们需要对本文进行预处理和规范化。

文本预处理

可以有多种方法来清理和预处理文本数据。在上一篇文章中已经讲过了。由于本文的重点是特征工程,就像前面的文章一样,我们将重用简单的文本预处理程序,它的重点是删除特殊字符、额外的空格、数字、停止词和把语料库的大写转换为小写。

 wpt = nltk.WordPunctTokenizer()
 stop_words = nltk.corpus.stopwords.words('english')
 
 def normalize_document(doc):
     # lower case and remove special characters\whitespaces
     doc = re.sub(r'[^a-zA-Z\s]', '', doc, re.I|re.A)
     doc = doc.lower()
     doc = doc.strip()
     # tokenize document
     tokens = wpt.tokenize(doc)
     # filter stopwords out of document
     filtered_tokens = [token for token in tokens if token not in stop_words]
     # re-create document from filtered tokens
     doc = ' '.join(filtered_tokens)
     return doc
 
 normalize_corpus = np.vectorize(normalize_document)

我们准备好了基本的预处理pipeline,让我们首先将其应用于我们的玩具语料库。

 norm_corpus = normalize_corpus(corpus)
 norm_corpus
 Output
 ------
 array(['sky blue beautiful', 'love blue beautiful sky',
        'quick brown fox jumps lazy dog',
        'kings breakfast sausages ham bacon eggs toast beans',
        'love green eggs ham sausages bacon',
        'brown fox quick blue dog lazy',
        'sky blue sky beautiful today',
        'dog lazy brown fox quick'],
       dtype='<U51')

现在让我们使用nltk加载基于The King James Version of the Bible的其他语料库,并对文本进行预处理。

 from nltk.corpus import gutenberg
 from string import punctuation
 
 bible = gutenberg.sents('bible-kjv.txt')
 remove_terms = punctuation + '0123456789'
 
 norm_bible = [[word.lower() for word in sent if word not in remove_terms] for sent in bible]
 norm_bible = [' '.join(tok_sent) for tok_sent in norm_bible]
 norm_bible = filter(None, normalize_corpus(norm_bible))
 norm_bible = [tok_sent for tok_sent in norm_bible if len(tok_sent.split()) > 2]
 
 print('Total lines:', len(bible))
 print('\nSample line:', bible[10])
 print('\nProcessed line:', norm_bible[10])

下面的输出显示了语料库中的总行数以及预处理如何处理文本内容。

 Output
 ------
 Total lines: 30103
 
 Sample line: ['1', ':', '6', 'And', 'God', 'said', ',', 'Let', 'there', 'be', 'a', 'firmament', 'in', 'the', 'midst', 'of', 'the', 'waters', ',', 'and', 'let', 'it', 'divide', 'the', 'waters', 'from', 'the', 'waters', '.']
 
 Processed line: god said let firmament midst waters let divide waters waters

现在让我们来看看一些流行的词嵌入模型和对我们的语料库做的特征工程!

Word2Vec模型

该模型由谷歌于2013年创建,是一种基于预测的深度学习模型,用于计算和生成高质量的、连续的dense的单词向量表示,并捕捉上下文和语义相似性。本质上,这些是无监督的模型,可以接收大量的文本语料库,创建可能的单词的词汇表,并为表示该词汇表的向量空间中的每个单词生成dense的单词嵌入。通常可以指定单词的嵌入向量的大小,向量的总数本质上就是词汇表的大小。这使得该向量空间的维度大大低于传统的词袋模型构建出的高维稀疏的向量空间。

Word2Vec可以利用两种不同的模型结构来创建这些单词嵌入表示。

  • Continuous Bag of Words(CBOW)模型

  • Skip-gram模型

Continuous Bag of Words (CBOW) 模型

CBOW模型体系结构试图基于上下文单词(周围单词)预测当前目标单词(中心单词)。考虑一个简单的句子,“the quick brown fox jumps over the lazy dog”,这可以是(context_window, target_word)对,如果我们考虑一个大小为2的上下文窗口,我们有([quick, fox], brown)、([the, brown], quick)、(([the, dog], lazy))等例子。因此,该模型试图基于context_window单词预测target_word

640?wx_fmt=png

虽然Word2Vec系列模型是无监督的,这意味着可以给它一个没有附加标签或信息的语料库,它可以从语料库构建密集的单词嵌入。但是,一旦你拥有了这个语料库,你仍然需要利用一个监督的分类方法来实现这些嵌入。但是我们将在没有任何辅助信息的情况下,从语料库本身来做。我们现在可以将CBOW结构建模为一个深度学习分类模型,这样我们就可以将上下文单词作为输入X,并尝试预测目标单词Y。实际上,构建这个结构比skip-gram模型更简单,在skip-gram模型中,我们试图从源目标单词预测一大堆上下文单词。

实现Continuous Bag of Words (CBOW)模型

虽然使用像gensim这样具有Word2Vec模型的框架非常好用,但是现在让我们从头开始实现它,以了解幕后的工作原理。我们将利用norm_bible变量中包含的Bible语料库来训练模型。实现将集中于四个部分:

  • 构建语料库词汇表

  • 建立一个CBOW(上下文,目标)生成器

  • 构建CBOW模型架构

  • 训练模型

  • 获取Word Embeddings

构建语料库词汇表

首先,我们将构建语料库词汇表,从词汇表中提取每个惟一的单词,并将一个惟一的数字标识符映射到它。

 from keras.preprocessing import text
 from keras.utils import np_utils
 from keras.preprocessing import sequence
 
 tokenizer = text.Tokenizer()
 tokenizer.fit_on_texts(norm_bible)
 word2id = tokenizer.word_index
 
 # build vocabulary of unique words
 word2id['PAD'] = 0
 id2word = {v:k for k, v in word2id.items()}
 wids = [[word2id[w] for w in text.text_to_word_sequence(doc)] for doc in norm_bible]
 
 vocab_size = len(word2id)
 embed_size = 100
 window_size = 2 # context window size
 
 print('Vocabulary Size:', vocab_size)
 print('Vocabulary Sample:', list(word2id.items())[:10])
 Output
 ------
 Vocabulary Size: 12425
 Vocabulary Sample: [('perceived', 1460), ('flagon', 7287), ('gardener', 11641), ('named', 973), ('remain', 732), ('sticketh', 10622), ('abstinence', 11848), ('rufus', 8190), ('adversary', 2018), ('jehoiachin', 3189)]

可以看到,我们已经在语料库中创建了一个包含惟一单词的词汇表,以及将单词映射到其惟一标识符的方法,反之亦然。“PAD”通常用于在需要时将上下文单词填充为固定长度。

建立一个CBOW(上下文,目标)生成器

我们需要由目标中心词和及其上下文词组成的对。在我们的实现中,目标单词的长度为' 1 ',周围的上下文的长度为' 2 x window_size ',其中我们在语料库中的目标单词前后分别取' window_size '个单词。

 def generate_context_word_pairs(corpus, window_size, vocab_size):
     context_length = window_size*2
     for words in corpus:
         sentence_length = len(words)
         for index, word in enumerate(words):
             context_words = []
             label_word   = []            
             start = index - window_size
             end = index + window_size + 1
             
             context_words.append([words[i]
                                  for i in range(start, end)
                                  if 0 <= i < sentence_length
                                  and i != index])
             label_word.append(word)
 
             x = sequence.pad_sequences(context_words, maxlen=context_length)
             y = np_utils.to_categorical(label_word, vocab_size)
             yield (x, y)
             
             
 # Test this out for some samples
 i = 0
 for x, y in generate_context_word_pairs(corpus=wids, window_size=window_size, vocab_size=vocab_size):
     if 0 not in x[0]:
         print('Context (X):', [id2word[w] for w in x[0]], '-> Target (Y):', id2word[np.argwhere(y[0])[0][0]])
     
         if i == 10:
             break
         i += 1
 Context (X): ['old','testament','james','bible'] -> Target (Y): king
 Context (X): ['first','book','called','genesis'] -> Target(Y): moses
 Context(X):['beginning','god','heaven','earth'] -> Target(Y):created
 Context (X):['earth','without','void','darkness'] -> Target(Y): form
 Context (X): ['without','form','darkness','upon'] -> Target(Y): void
 Context (X): ['form', 'void', 'upon', 'face'] -> Target(Y): darkness
 Context (X): ['void', 'darkness', 'face', 'deep'] -> Target(Y): upon
 Context (X): ['spirit', 'god', 'upon', 'face'] -> Target (Y): moved
 Context (X): ['god', 'moved', 'face', 'waters'] -> Target (Y): upon
 Context (X): ['god', 'said', 'light', 'light'] -> Target (Y): let
 Context (X): ['god', 'saw', 'good', 'god'] -> Target (Y): light

前面的输出应该让你对X如何形成我们的上下文单词有更多的了解,我们正试图根据这个上下文预测目标中心单词Y。例如,如果原始文本是“in the beginning god created heaven and earth”,经过预处理和删除停止词后,就变成了‘beginning god created heaven earth’ ,而对于我们来说,我们正在努力实现的就是这个目标。给定[beginning, god, heaven, earth] 作为上下文,预测目标中心词是什么,在本例中是' created '

构建CBOW模型架构

我们现在利用keras构建CBOW模型的深度学习架构。为此,我们的输入是传递给嵌入层(用随机权重初始化)的上下文单词。词嵌入被传播到λ层,做词嵌入的平均 (叫CBOW是因为在做平均的时候我们真的不考虑上下文词的顺序),我们把平均后的向量送到一个dense的softmax层去预测我们的目标词。我们将其与实际的目标字匹配,通过利用categorical_crossentropy损失计算损失,并对每个epoch执行反向传播来更新嵌入层。下面的代码向我们展示了我们的模型架构。

 import keras.backend as K
 from keras.models import Sequential
 from keras.layers import Dense, Embedding, Lambda
 
 # build CBOW architecture
 cbow = Sequential()
 cbow.add(Embedding(input_dim=vocab_size, output_dim=embed_size, input_length=window_size*2))
 cbow.add(Lambda(lambda x: K.mean(x, axis=1), output_shape=(embed_size,)))
 cbow.add(Dense(vocab_size, activation='softmax'))
 cbow.compile(loss='categorical_crossentropy', optimizer='rmsprop')
 
 # view model summary
 print(cbow.summary())
 
 # visualize model structure
 from IPython.display import SVG
 from keras.utils.vis_utils import model_to_dot
 
 SVG(model_to_dot(cbow, show_shapes=True, show_layer_names=False,
                  rankdir='TB').create(prog='dot', format='svg'))

640?wx_fmt=png

如果你对上述深度学习模型的形象化仍有困难。可以看看下图:

640?wx_fmt=png

训练模型

在完整的语料库上运行这个模型需要相当多的时间,所以我只运行了5个epochs。你可以利用以下代码,并在必要时训练更多的时间。

 for epoch in range(1, 6):
     loss = 0.
     i = 0
     for x, y in generate_context_word_pairs(corpus=wids, window_size=window_size, vocab_size=vocab_size):
         i += 1
         loss += cbow.train_on_batch(x, y)
         if i % 100000 == 0:
             print('Processed {} (context, word) pairs'.format(i))
 
     print('Epoch:', epoch, '\tLoss:', loss)
     print()
 Epoch: 1    Loss: 4257900.60084
 Epoch: 2 Loss: 4256209.59646
 Epoch: 3 Loss: 4247990.90456
 Epoch: 4 Loss: 4225663.18927
 Epoch: 5 Loss: 4104501.48929

注意:运行这个模型是计算量很大的,如果使用GPU训练,会好一点。我在AWS的**p2上训练过这个。用的是Tesla K80 GPU,它花了我近1.5小时,只有5个epochs!

一旦这个模型被训练好,相似的单词应该就有相似的基于嵌入的权值,我们可以测试一下相似性。

获取词嵌入

要为整个词汇表获取词嵌入,可以利用下面的代码从嵌入层提取。我们不接受位置为0的嵌入,因为它属于  (PAD) ,这并不是一个真正的单词。

 weights = cbow.get_weights()[0]
 weights = weights[1:]
 print(weights.shape)
 
 pd.DataFrame(weights, index=list(id2word.values())[1:]).head()

640?wx_fmt=png

可以清楚地看到,正如前面的输出所描述的,每个单词都有一个dense的大小为“(1x100)”的嵌入。让我们尝试根据这些嵌入为感兴趣的特定单词找到一些上下文相似的单词。为此,我们基于dense的嵌入向量,在我们的词汇表中建立一个成对的距离矩阵,然后根据最短的欧氏距离找出感兴趣的每个单词的n个最近邻。

 from sklearn.metrics.pairwise import euclidean_distances
 
 # compute pairwise distance matrix
 distance_matrix = euclidean_distances(weights)
 print(distance_matrix.shape)
 
 # view contextually similar words
 similar_words = {search_term: [id2word[idx] for idx in distance_matrix[word2id[search_term]-1].argsort()[1:6]+1]
                    for search_term in ['god', 'jesus', 'noah', 'egypt', 'john', 'gospel', 'moses','famine']}
 
 similar_words
 (12424, 12424)
 {'egypt': ['destroy', 'none', 'whole', 'jacob', 'sea'],
  'famine': ['wickedness', 'sore', 'countries', 'cease', 'portion'],
  'god': ['therefore', 'heard', 'may', 'behold', 'heaven'],
  'gospel': ['church', 'fowls', 'churches', 'preached', 'doctrine'],
  'jesus': ['law', 'heard', 'world', 'many', 'dead'],
  'john': ['dream', 'bones', 'held', 'present', 'alive'],
  'moses': ['pharaoh', 'gate', 'jews', 'departed', 'lifted'],
  'noah': ['abram', 'plagues', 'hananiah', 'korah', 'sarah']}

您可以清楚地看到,其中一些在上下文上是有意义的 (god, heaven), (gospel, church) 等等,而有些可能没有意义。训练时间越长,效果往往越好。现在,我们将探讨与CBOW相比通常给出更好结果的skip-gram架构。

Skip-gram模型

Skip-gram模型体系结构实现与CBOW模型相反的功能。它预测给定目标单词(中心单词)的源上下文单词(周围单词)。考虑到我们前面简单的句子,“the quick brown fox jumps over the lazy dog”。如果我们使用CBOW模型,就会得到一对(context_window, target_word),其中如果我们考虑一个大小为2的上下文窗口,就会得到([quick, fox], brown), ([the, brown], quick), ([the, dog], lazy),等等。现在考虑到Skip-gram模型的目标是根据目标单词预测上下文,该模型通常将上下文和目标颠倒过来,并尝试根据目标单词预测每个上下文单词。因此,任务变成了预测给定目标单词[quick, fox]的上下文'brown'[the, brown]给定目标单词'quick',以此类推。因此,该模型是基于target_word预测context_window单词。

640?wx_fmt=png

正如我们在CBOW模型中所讨论的,我们现在需要将这个Skip-gram架构建模为一个深度学习分类模型,这样我们就可以将目标单词作为输入并预测上下文单词。这变得有点复杂,因为我们在上下文中有多个单词。我们将每个(target, context_words)对分解为多个(target, context)对,这样每个上下文只包含一个单词,从而进一步简化了这个过程。因此,我们前面的数据集被转换成成对的,比如(brown,quick),(brown,fox), (quick, the), (quick, brown)等等。但是,如何监督或训练模型,使其知道什么是上下文相关的,什么不是?

为此,我们对Skip-gram模型输入(X, Y),其中X是我们的输入Y是我们的标签。我们使用[(target, context), 1]对作为输入正样本,其中target是我们感兴趣的单词,context是发生在目标单词附近的上下文单词,正样本标签1 表示这是上下文相关的一对。我们还输入[(target, random), 0]对作为输入负样本,其中target仍然是我们感兴趣的单词,但是random只是从我们的词汇表中随机选择的一个单词,它与我们的目标单词没有上下文关系。因此,负样本标签0表示这是上下文无关的一对。我们这样做是为了让模型能够了解哪些词对与上下文相关,哪些不相关,并为语义相似的词生成类似的嵌入。

实现Skip-gram模型

现在让我们从头开始实现这个模型,以了解幕后的工作原理,并将其与CBOW模型的实现进行比较。我们将像往常一样利用包含在 norm_bible 变量中的圣经语料库来训练我们的模型。工作将集中于五个部分:

  • 构建语料库词汇表

  • 构建skip-gram[(target, context), relevancy]生成器

  • 构建skip-gram模型结构

  • 训练模型

  • 得到词嵌入

构建语料库词汇表

这个和CBOW是一样的。

构建skip-gram[(target, context), relevancy]生成器

现在开始构建我们的skip-gram生成器了,它将像我们前面讨论的那样给我们一对单词和它们的相关性。幸运的是,keras有一个漂亮的skipgrams函数,我们不需要像在CBOW中那样手动实现这个生成器。

注意:函数skipgrams(…)出现在keras.preprocessing.sequence中。

该函数将一个单词索引序列(整数列表)转换为以下形式的单词元组:

- (word, 在同一个窗口中的word),标签1(正样本)。

- (word,词汇表中的random word),标签0(负样本)。

 from keras.preprocessing.sequence import skipgrams
 
 # generate skip-grams
 skip_grams = [skipgrams(wid, vocabulary_size=vocab_size, window_size=10) for wid in wids]
 
 # view sample skip-grams
 pairs, labels = skip_grams[0][0], skip_grams[0][1]
 for i in range(10):
     print("({:s} ({:d}), {:s} ({:d})) -> {:d}".format(
           id2word[pairs[i][0]], pairs[i][0],
           id2word[pairs[i][1]], pairs[i][1],
           labels[i]))
 (james (1154), king (13)) -> 1
 (king (13), james (1154)) -> 1
 (james (1154), perform (1249)) -> 0
 (bible (5766), dismissed (6274)) -> 0
 (king (13), alter (5275)) -> 0
 (james (1154), bible (5766)) -> 1
 (king (13), bible (5766)) -> 1
 (bible (5766), king (13)) -> 1
 (king (13), compassion (1279)) -> 0
 (james (1154), foreskins (4844)) -> 0

可以看到我们已经成功地生成了所需的skip-grams,还可以根据标签(0或1)清楚地看到哪些是相关的,哪些是不相关的。

构建skip-gram模型结构

现在,我们在利用keras来为skip-gram模型构建我们的深度学习架构。为此,我们的输入将是我们的目标单词和上下文或随机单词对。然后传递到一个嵌入层(用随机权重初始化)。一旦我们获得了目标词和上下文词的词嵌入,我们将它传递到一个合并层,在那里我们计算这两个向量的点积。然后我们将这个点积值传递给一个dense的sigmoid层,该层根据这对单词是上下文相关的还是随机的单词(Y)来预测是1还是0。我们将其与实际的关联标签(Y)匹配,通过mean_squared_error计算损失,并对每个epoch反向传播来更新嵌入层。下面的代码向我们展示了我们的模型架构。

 from keras.layers import Merge
 from keras.layers.core import Dense, Reshape
 from keras.layers.embeddings import Embedding
 from keras.models import Sequential
 
 # build skip-gram architecture
 word_model = Sequential()
 word_model.add(Embedding(vocab_size, embed_size,
                          embeddings_initializer="glorot_uniform",
                          input_length=1))
 word_model.add(Reshape((embed_size, )))
 
 context_model = Sequential()
 context_model.add(Embedding(vocab_size, embed_size,
                   embeddings_initializer="glorot_uniform",
                   input_length=1))
 context_model.add(Reshape((embed_size,)))
 
 model = Sequential()
 model.add(Merge([word_model, context_model], mode="dot"))
 model.add(Dense(1, kernel_initializer="glorot_uniform", activation="sigmoid"))
 model.compile(loss="mean_squared_error", optimizer="rmsprop")
 
 # view model summary
 print(model.summary())
 
 # visualize model structure
 from IPython.display import SVG
 from keras.utils.vis_utils import model_to_dot
 
 SVG(model_to_dot(model, show_shapes=True, show_layer_names=False,
                  rankdir='TB').create(prog='dot', format='svg'))

640?wx_fmt=png

skip-gram模型的可视化:

640?wx_fmt=png

训练模型

在我们的完整语料库上运行模型需要相当多的时间,但比CBOW模型要少。所以我只运行了5个epochs。你可以利用以下代码,并在必要时训练更长的时间。

 for epoch in range(1, 6):
     loss = 0
     for i, elem in enumerate(skip_grams):
         pair_first_elem = np.array(list(zip(*elem[0]))[0], dtype='int32')
         pair_second_elem = np.array(list(zip(*elem[0]))[1], dtype='int32')
         labels = np.array(elem[1], dtype='int32')
         X = [pair_first_elem, pair_second_elem]
         Y = labels
         if i % 10000 == 0:
             print('Processed {} (skip_first, skip_second, relevance) pairs'.format(i))
         loss += model.train_on_batch(X,Y)  
 
     print('Epoch:', epoch, 'Loss:', loss)
 Epoch: 1 Loss: 4529.63803683
 Epoch: 2 Loss: 3750.71884749
 Epoch: 3 Loss: 3752.47489296
 Epoch: 4 Loss: 3793.9177565
 Epoch: 5 Loss: 3716.07605051

模型训练好之后,相似的单词应该有相似的基于嵌入的权重。

得到词嵌入

要为整个词汇表获取单词嵌入,可以利用下面的代码从嵌入层提取相同的单词。请注意,我们只对目标单词嵌入感兴趣,因此我们将从 word_model嵌入层提取嵌入。我们没有在位置0处进行嵌入,因为词汇表中没有一个单词的数字标识符为0,我们忽略了它。

 merge_layer = model.layers[0]
 word_model = merge_layer.layers[0]
 word_embed_layer = word_model.layers[0]
 weights = word_embed_layer.get_weights()[0][1:]
 
 print(weights.shape)
 pd.DataFrame(weights, index=id2word.values()).head()

640?wx_fmt=png

可以清楚地看到,正如前面的输出所描述的,每个单词都有一个dense的大小为(1x100)的嵌入,类似于我们从CBOW模型中得到的结果。现在让我们对这些dense的嵌入向量使用欧氏距离度量来为词汇表中的每个单词生成成对的距离度量。然后,我们可以根据最短的欧氏距离找到感兴趣的每个单词的n个最近邻,这与我们在CBOW模型的嵌入中所做的类似。

 from sklearn.metrics.pairwise import euclidean_distances
 
 distance_matrix = euclidean_distances(weights)
 print(distance_matrix.shape)
 
 similar_words = {search_term: [id2word[idx] for idx in distance_matrix[word2id[search_term]-1].argsort()[1:6]+1]
                    for search_term in ['god', 'jesus', 'noah', 'egypt', 'john', 'gospel', 'moses','famine']}
 
 similar_words
 (12424, 12424)
 {'egypt': ['pharaoh', 'mighty', 'houses', 'kept', 'possess'],
  'famine': ['rivers', 'foot', 'pestilence', 'wash', 'sabbaths'],
  'god': ['evil', 'iniquity', 'none', 'mighty', 'mercy'],
  'gospel': ['grace', 'shame', 'believed', 'verily', 'everlasting'],
  'jesus': ['christ', 'faith', 'disciples', 'dead', 'say'],
  'john': ['ghost', 'knew', 'peter', 'alone', 'master'],
  'moses': ['commanded', 'offerings', 'kept', 'presence', 'lamb'],
  'noah': ['flood', 'shem', 'peleg', 'abram', 'chose']}

从结果中可以清楚地看到,对于感兴趣的每个单词,许多相似的单词都是有意义的,并且与我们的CBOW模型相比,我们获得了更好的结果。现在我们用t-SNE来可视化一下。

 from sklearn.manifold import TSNE
 
 words = sum([[k] + v for k, v in similar_words.items()], [])
 words_ids = [word2id[w] for w in words]
 word_vectors = np.array([weights[idx] for idx in words_ids])
 print('Total words:', len(words), '\tWord Embedding shapes:', word_vectors.shape)
 
 tsne = TSNE(n_components=2, random_state=0, n_iter=10000, perplexity=3)
 np.set_printoptions(suppress=True)
 T = tsne.fit_transform(word_vectors)
 labels = words
 
 plt.figure(figsize=(14, 8))
 plt.scatter(T[:, 0], T[:, 1], c='steelblue', edgecolors='k')
 for label, x, y in zip(labels, T[:, 0], T[:, 1]):
     plt.annotate(label, xy=(x+1, y+1), xytext=(0, 0), textcoords='offset points')

640?wx_fmt=png

我用红色标记了一些圆圈,它们似乎显示了在向量空间中位置相近的上下文相似的不同单词。

(未完待续)

640?wx_fmt=png
END

英文原文:https://towardsdatascience.com/understanding-feature-engineering-part-4-deep-learning-methods-for-text-data-96c44370bbfa

640?wx_fmt=jpeg

请长按或扫描二维码关注本公众号

喜欢的话,请给我个好看吧640?wx_fmt=gif

2018-08-31 20:30:00 weixin_30692143 阅读数 11
  • 从零开始自然语言处理

    本课程隶属于自然语言处理(NLP)实战系列。自然语言处理(NLP) 是数据科学里的一个分支,它的主要覆盖的内容是:以一种智能与高效的方式,对文本数据进行系统化分析、理解与信息提取的过程。通过使用 NLP以及它的组件,我们可以管理非常大块的文本数据,或者执行大量的自动化任务,并且解决各式各样的问题,如自动摘要,机器翻译,命名实体识别,关系提取,情感分析,语音识别,以及主题分割等等。 一般情况下一个初级NLP工程师的工资从15万-35万不等,所以掌握NLP技术,对于人工智能学习者来讲是非常关键的一个环节。 课程从自然语言处理的基本概念与基本任务出发,对目前主流的自然语言处理应用进行全面细致的讲解, 包括文本分类,文本摘要提取,文本相似度,文本情感分析,文本特征提取等,同时算法方面包括经典算法与深度学习算法的结合,例如 LSTM,BiLSTM等,并结合京东电商评论分类、豆瓣电影摘要提取、今日头条舆情挖掘、饿了么情感分析等过个案例,帮助大家熟悉自然语言处理工程师在工作中会接触到的 常见应用的实施的基本实施流程,从0-1入门变成自然语言处理研发工程师。

    478 人正在学习 去看看 钱兴会

文本深度特征提取

注:本文内容摘自《深度学习算法实践》

 

为何要研究文本深度特征?

——因为文本深度特征无论对于文本分类还是文本预测,都是非常重要的。

 

文本特征的提取说白了就是将自然语言理解的问题转化成机器学习的问题。第一步肯定是找一种合适的方法,把语言表达数学化,即用可量化的方式来表示文本的特征。

下面将简单介绍一下文本的深度特征是如何量化的。

 

  1. 词特征表示

    文本的深度特征有四种表示方法:

  2. 词表法

    顾名思义,就是把词进行剔重、排序,和相对应的序号一一对应,形成字典。

    举个例子:

    "今天天气甚好"

    (今天,1)

    (天气,2)

    (甚好,3)

    那么,今天天气甚好,用向量表达就是[1,2,3],这样就方便扔到模型中进行计算了。

     

     

    一般来说,对于Embedding层的输入基本上都使用词表示法处理后的向量表达。

    Embedding层是什么?

    是将词表中的单词在字典中的位置(索引)映射为固定维度的稠密的向量。

    在Embedding这种结构出现之前,一般先用word2vec计算词向量,然后将词向量作为模型的输入层,计算词向量部分和模型是两个部分,而embedding出现后,就将这两个部分合并在一个模型中,输入层数据不是词向量,而是词在字典中的位置。Embedding主要不是作为降维使用,而是作为一种特征表示使用。

     

     

     

  3. One-Hot表示

    原理很简单,就是将每个词表示为一个向量,向量的长度就是句子的长度。在向量中,该词出现的位置填1,其他位置填0,那么这个向量就代表了当前的词。

    缺点:存储空间浪费巨大,矩阵稀疏问题明显。不利于存储和处理,也就是我们常说的维度灾难。

     

     

     

  4. n-gram模型

    n-gram模型也叫N元模型,是自然语言处理中一个重要的概念。它突出的是一个组的思想。1gram可以是一个单词或者是一个中文汉字。对于字符串s,n-gram就是按长度N切分原词得到的词段。通常在NLP中,可以基于一定的语料库,利用n-gram来预计或者表示一个句子,另一方面,可以用n-gram来评估两个字符串之间的差异程度。

    Unigram指的是单字;Bigram指的是双字;Trigram指的是三个字。

    举个例子:

    鲁迅老师生前是一位革命家,死后仍然是。

    首先分词:

    分词结果:

    鲁迅/老师/生前/是/一位/革命家,死后/仍然/是。

    调用ngram函数,定义n=3时的输出结果为:

    鲁迅/老师/生前

    老师/生前/是/

    生前/是/一位/

    /是/一位/革命家

    。。。

    skip-gram,"skip"就是指需要跳过多少个字符,其参数也多了一个K来决定输入值需要跳过几个词。

     

    模糊匹配算法的关键在于如何衡量两个相似单词之间的差异,这个差异用书面语言称为"距离"。这种基于距离的衡量有很多种方法,而n-gram就是其中的一种。

    有学者提出下面的公式来表示这种距离。

    假设我们要比较字符串s和字符串t,要算出这两句话的距离,可以应用下面的公式:

    |s中的n-gram数| + |t中的n-gram数| - N*|s和t共有的n-gram数|

    字符串s=" 鲁迅/老师/生前/是/一位/革命家,死后/仍然/是。"

    字符串t="鲁迅/老师/生前/是/一位/革命家/和/作家/,有/很多/伟大/的/作品"

    s 的3-gram数为9,t的3-gram数为11。共有4,根据公式(9+11)-3*4 = 8。

    则这两句话的距离为8。

     

    利用n-gram可以衡量词和词之间的距离,进而能衡量词与词之间的关系???

    --------------------------这里不应该是衡量的是句子和句子之间的距离吗?

     

    除了用n-gram直接提取特征外,还有什么方法能更进一步,用一组固定向量来表示一个词呢?词嵌入(Word Embedding)给了我们答案。

     

     

     

     

  5. 分布表示和词嵌入特征表示

    Distributed Representation(分布表示)最早由Hinton在1986年提出。它是一种低维实数向量,这种向量一般长成下面的样子。

    [1.2,3,23,3434,-5435,3242,…]

     

    维度以50维和100维比较常见,当然了,这种向量的表示不是唯一的。

     

    一段文本的语义分散在一个低维空间的不同维度上,相当于将不同的文本分散到空间中不同的区域。分布表示是文本的一种表现形式,具体维稠密、低维、连续的向量。向量的每一维都表示文本的某种潜在的语法或语义特征。

     

    2003年Bengio提出NPLM的时候,在模型中去学习每个词的一个连续向量表示,并经过Tmoas Mikolov等人的发展,发展出Word Embedding(词嵌入)。

    词嵌入就是将每个词映射为一个向量。

     

    Word Embedding 使寻找相关或者相似的词成为可能。向量的距离可以用最传统的欧式距离来衡量,也可以用cos夹角来衡量。用这种方式表示的向量,"明天"和"今天"的距离会远远小于"明天"和"你"的距离,甚至在可能的理想情况下,"明天"和"今天"的表示应该是基本一致的。

     

    这样两个词之间就可以进行比较了。当然,在这个方法下相似度高的两个词,并不具有相同的语义,它只能反映出两者经常在相近的上下文环境中出现。

     

    前文提到在Embedding这种结构出现之前,一般先用word2vec计算词向量,word2vec也是词嵌入的一种实现方式。它目前使用的神经网络模型有两种:CBOW和skip-gram。

    这两种模型都很简单粗暴。

     

     

 

 

在CBOW方法里,训练目标是给定一个word的context,预测word的概率;

在skip-gram方法里,训练目标则是给定一个word,预测word的context的概率。

skip-gram的输入是当前词的词向量,而输出是周围词的词向量。也就是说,通过当前词来预测周围的词,而cbow模型正好是将输入输出调转。

转载于:https://www.cnblogs.com/xmd-home/p/9568138.html

没有更多推荐了,返回首页