吾爱NLP(3)—我对NLP的理解与学习建议

2018-09-12 10:58:31 浏览数 (1)

0、目录结构
  • 1、我理解的NLP
  • 2、如何开始学习NLP
  • 3、自然语言处理技术的发展历程
  • 4、文本分类小实例:垃圾短信分类(可运行代码)
  • 5、总结

深度认知人类语言的本质

1、我理解的NLP

简单来说,NLP = Nature Language Process = 自然语言处理 ≈ 语言信息(文本/语音) 机器学习 。

所以,在我看来,自然语言处理主要包括语言信息机器学习两部分知识,其中语言信息主要包括语音与文本两种,我主要接触的是文本信息,所以后面介绍的都是文本信息处理相关的。机器学习则可以大体分为传统的机器学习与深度学习两种。

下面从自己的认知水平上阐述对自然语言处理的一些见解与学习体会!如有不当之处,欢迎评论处指出探讨。

如今,解决NLP的问题,肯定离不开机器学习,那我简单从数学角度上来区分一下机器学习与深度学习: 1、传统的机器学习:一般都具有扎实的数学理论推导(分析、几何、代数,主要关注概率图模型),你可以知道结果产生的原因,为什么结果好?结果例如:逻辑回归、决策树、朴素贝叶斯、以及GBDT、XGBoost等集成模型。这也是求职时必问的推公式环节!!初步了解机器学习,推荐《机器学习实战》,想了解其中数学推导,推荐《统计学习方法》,如果还口渴的话,还可以再来本"西瓜书”,三本书都是经典,一遍遍看吧,不喜欢看也没关系,面试官虐你的时候你会怀念它们的! 2、深度学习:目前为止,暂没还有扎实数学理论基础,即在下面这棵树种找不到它的根基所在。这也就导致了深度学习最大的缺点:缺乏可解释性。无法解释为什么多层、参数冗余的深层神经网络在这个数据集上产生的结果。

数学理论体系

NLP作为一门交叉学科,研究的目标在于解决计算机与人类(自然)语言的交互问题。在很多优秀语言学家、数学家、计算机学家对语言处理的相关工作进行了系统、理论的分析与研究之后,我们可以在他们研究成果的基础上,进行相关的实践与研究工作。

如果想了解“信息-计算机-数学”之间是如何联系起来的,我推荐读一下《数学之美》这本书,在这本书中,也许能找到答案,

当然,作为计算机专业的学生,起初我也并不了解语言学与计算机有什么联系,我的大学数学也是学的比较烂,之所以选择NLP,是因为对数据挖掘相关的比赛比较感兴趣,经常参加一些数据挖掘的竞赛,也因此接触到一些传统的机器学习算法,进而接触到深度学习思想。在导师定研究方向的时候,我就选择了与机器学习更相关的NLP方向。

SEI-B519NLP小组

此后,我研究生阶段的研究方向就是自然与原处理,主要关注文本分类以及文本多标签分类相关的方向。我所在的B519NLP小组主要研究文本数据的处理工作,除了文本分类之外,还有摘要生成、文本聚类等方向。此外,因为我是一名专硕,觉得自己对学术研究没有啥发言权,所以,我的下面介绍都是偏向于应用实践的相关的。

首先,简单的了解一下,NLP都是用来干什么?

根据之前李航老师的总计,NLP主要解决5个基本问题:

  1. 分类:
  2. 匹配:
  3. 翻译:
  4. 结构化预测:
  5. 马氏决策过程: 而这5个基本的问题又可以在具体的应用场景下,被细化之后用于解决各种应用场景下的具体问题。

在我选择NLP作为研究方向之后,根据个人的学习喜好,喜欢通过解决某个特定问题而获得成就感的方式学习。在查阅资料的过程上,了解到了文本分类这个方向,感觉很适合动手去实践,语料集(各种竞赛、开放的)以及各种解决方案(GitHub)比较丰富,在工业界实际应用中也有比较大的应用价值,所以研究生阶段主要就在做文本分类相关的工作,在一些比赛中也有机会了解并学习了一下与对轮对话、查询相似度匹配等相关的知识。

简单介绍一下文本分类: 文本分类是NLP中一个重要的研究方向之一,是指按照预先定义的主题类别,为每一个文档集合中的每一个文档指定属于一个类别(多分类)或多个类别(多标签分类)。

文本分类

2、如何开始NLP的学习?

根据现实情况,选定NLP领域的一个问题,然后开始研究如何利用NLP技术更好的解决它,注重动手实践,这是我推荐的一种学习NLP的方式。

目前NLP有很多的研究方向,例如:文本分类(情感分析)、摘要生成(文本生成)、多轮对话(智能客服)等。每一个研究方向都包含很多更基础的研究点,下面这张图总结了从词汇、语句、篇章到系统应用不同粒度上的NLP应用场景。

美团沙龙分享--NLP应用场景

工业界若干应用

初学者,可以根据个人的爱好与实际情况,选择不同粒度的问题作为自己学习NLP的切入点。

例如:分词技术是一种比较基础的模块,如果你感兴趣如何提高分词的准确率(一般是需要结合具体应用场景),也许你需要从研究分词技术的演变历史,从最初的基于字典、基于统计语言模型、基于序列标注的分词方法(基于HMM、CRF),再到基于深度学习方式的分词技术。不同的研究领域,深入的点也有一定的不同。

中文分词技术

目前工业界比较火热的,应该是自动问答(智能客服)吧,很多的初创公司都在做面向特定领域的自动问答系统,自动问答从上面的图可知是处于系统应用粒度的研究方向,要解决好这个问题,还要需要研究其它粒度的问题,例如从词性标注、命名体识别、语义消歧、语义匹配,再到系统应用粒度知识图谱、信息检索等,都是需要研究并解决的问题。所以,从系统应用粒度上来看,每一个系统都有一套贯穿各粒度层的研究切入点。

智能一点科技

在深度学习的学习背景下,我是比较建议首先从系统应用粒度上作为入自己研究的起点,比较容易取得阶段性的成果,而且研究的资料(语料&代码)也比较多。从一个应用系统入手,梳理解决这个问题需要的理论体系,找到目前较好的解决方案,自己着手实现它。作为一个学生党,我不建议为了为了提高智能客服的效果,而陷入提高分词效果的细节泥潭中,因为一般认为,中文分词是已经解决的问题,也许只有百度...那些有特殊需要的公司才会去研究这些偏底层应用的基础点。

当然,如果你所在实验室有NLP相关项目的,那么恭喜你,你的研究领域基本上你的导师已经帮你定好了,可能让你着手解决该项目中的某一个问题或者继承师兄师姐的研究工作继续深入的研究。

如果能够有一个在NLP方面有经验的师傅引导你学习的话,不论他是有成功的经历或者丰富的失败经历(例如我),对你的学习都是大有裨益的,毕竟某人初次踏入一个新的研究领域都会有一段迷茫期,在摸索中会踩很多坑、找不到应该深入的切入点。所以,一定要好好利用自己身边的资源奥!

最后,作为学生党,研究的终究目标是至少能够出一篇论文来毕业,对于学硕来说,还得多一篇小论文……对于如何努力出学术成果,作为一个觉得写论文比写代码还难的人,我是没有什么发言权了!反正,多出论文应该没有坏处吧!

如何通过项目实践的方式来解决感兴趣的问题: 首先,确定一个问题,然后找到解决该问题的一个开源项目,GitHub上一般都有,而且还不止一种(另一个有效的途径就是关注各大机器学习竞赛平台,不仅可以搜集企业处理好的数据,还能学习冠军的团队的代码思路...知道我为什么这么热衷参与竞赛了吧!)。比如机器翻译或者深度学习的项目。理解开源项目的任务,编译通过该项目发布的示范程序,得到与项目示范程序一致的结果。然后再深入理解开源项目示范程序的算法。自己编程实现一下这个示范程序的算法。再按照项目提供的标准测试集测试自己实现的程序。如果输出的结果与项目中出现的结果不一致,就要仔细查验自己的程序,反复修改,直到结果与示范程序基本一致。在此基础上,再看看自己能否进一步完善算法或者实现,取得比示范程序更好的结果。

在竞赛中寻求问题,很可能收获一群志同道合的朋友

总之,发现问题,找到可能的解决方案,可以先从模仿开始,能跑起来、跑出理想结果、如何改进、移植到其它数据集用来解决类似的问题。

3、自然语言处理技术的发展历程

自然语言相关处理技术的发展,可以划分为基于规则的专家系统、基于统计的以及基于神经网络的三个阶段。

1950年代,基于规则的方式,简单理解就是基于语言学家、计算机学家根据语言学知识而人工构建的规则来解决问题,当时普遍认为首先要解决句法分析与语义分析,认为这两个是解决自然语言处理问题的基础。

1970年代,统计语言学的出现使得自然语言处理获得了新生,当时关键成是IBM华生实验室的语音识别系统,在采用了统计学的方法之后,语音识别率从70%提升到90%。(后面会补充介绍统计语言模型,它与传统的机器学习结合比较紧密)

2003年,Bengio提出神经网络语言模型(Neural Network Language Model,NNLM),网络结构属于一个前馈神经网络,包含三层:输入层、投影层、隐含层。前面我写的的文章吾爱NLP--我与自然语言处理中有介绍过,这里就不啰嗦了。

NNLM

NNLM 依赖的一个核心概念就是词向量(Word Embedding),词向量在整个神经概率语言模型中,是来帮助构造目标函数的辅助参数,训练完成之后,它也只是语言模型的一个副产品,但这个副产品的作用却非常重要!它的意义甚至超越了NNLM本身,后续牛人Tomas Mikolov在其基础上发明word2vec,而word2vec作为词分布式表示的一种方式,在NLP中具有非常重要的应用!word2vec的产生为深度学习能够被应用到NLP具有重大的意义。word2vec的思想在推荐领域也有比较实际的应用场景,所以我们需要深入的了解word2vec的理论推导,几乎面试必问。

​​​词向量是通过训练的方法,将语言词表中的词映射成一个长度固定的向量。词表中所有的词向量构成一个向量空间,每一个词都是这个词向量空间中的一个点,利用这种方法,实现文本的可计算。

word2vec词向量模型效果

伴随着深度学习技术不断被应用到NLP领域,不仅为解决NLP中的各种问题提供了新的解决方案,而且降低了新手进入NLP领域的门槛。

因为深度学习具有自动抽取低维特征组合为高级特征的能力,让我们不用再去关注基于领域知识的特征工程相关的工作,一个不懂语言学人同样可以基于大量语料数据,利用语言模型,很好的解决语言理解的相关问题。

传统机器学习VS深度学习

当然,我们也不能完全只停留在简单的利用各种深度学习模型来跑跑数据出个结果的初级应用使用上。熟悉细粒度的理论知识以及它们的数学推导,更加有利于我们对现有模型的改进产生自己的想法。至于理解的深度,还是根据特定的问题以及自身的时间成本来权衡。

4、文本分类小实例:垃圾短信分类

为了引出下面垃圾短信分类的小例子,先简单的介绍一下机器学习的一般知识。

首先,常见的机器学习算法分类如下图所示:

机器学习算法分类

我们日常使用中,常用的算法一般就是有监督学习与无监督学习,我这里简单从数据集上来对两者进行一下区分:

1. 有监督学习(supervised learning),它的训练集中的每一条数据一般包括特征与标签两个部分,这里我们把特征记为X,标签记为Y,则该训练集我们记为(X,Y)。其中,如果我们预测的标签Y是连续的,则又称为回归问题,若标签Y是离散的,则称为分类问题

2. 无监督学习(unsupervised learning),它的数据集中只有特征而没有标签,一般是通过对特征数据结构的分析来得出结论。

我理解的机器学习

下面是我从微信公众号中看到的一个中文垃圾短信分类的小例子,分类是一个有监督学习的过程,通过这个例子,熟悉一下NLP中文本分类的主要流程:

文本分类的一般流程

步骤说明:中文语料集——>利用Pandas库制作训练集(X,Y)--—>去除X中冗余信息(各种标点符号)—>去除X中停用词——>使用JieBa对X进行分词——>词的数值化(one-hot、BoW、Word2vec)—>划分数据集Train/Test—>训练模型(使用sklearn包中封装的LR模型)——>在模型效果评估——>调节参数、特征工程等继续优化模型…….——>模型的集成与融合(不讲但很重要)。

带标记的垃圾短信文本数据集,数据没法上传,有需要的评论里说吧(下面有彩蛋,仔细看哟!)。

垃圾短信数据

可运行示例代码:

代码语言:javascript复制
#coding: utf-8
import sys
import os
import collections
import itertools
import operator
import array
import argparse
import numpy as np
import jieba
import sklearn
import sklearn.linear_model as linear_model


def fetch_train_test(data_path, test_size=0.2):
    """读取数据,分词并拆分数据为训练集和测试集
    """
    y = list()
    text_list = list()
    for line in open(data_path, "r").xreadlines():
        # 拆分为(X,Y)形式,X代表特征数据,Y代表标记
        label, text = line[:-1].split('t', 1)
        # 使用jieba分词工具进行分词
        text_list.append(list(jieba.cut(text)))
        y.append(int(label))
    # 利用sklearn包划分数据集
    return sklearn.model_selection.train_test_split(
                text_list, y, test_size=test_size, random_state=1028)


def build_dict(text_list, min_freq=5):
    """根据传入的文本列表,创建一个最小频次为min_freq的字典,并返回字典word -> wordid
    """
    freq_dict = collections.Counter(itertools.chain(*text_list))
    freq_list = sorted(freq_dict.items(), key=operator.itemgetter(1), reverse=True)
    # 过滤低频词
    words, _ = zip(*filter(lambda wc: wc[1] >= min_freq, freq_list))
    return dict(zip(words, range(len(words))))


def text2vect(text_list, word2id):
    """将传入的文本转化为向量,返回向量大小为[n_samples, dict_size]
    """
    X = list()
    for text in text_list:
        vect = array.array('l', [0] * len(word2id))
        for word in text:
            if word not in word2id:
                continue
            vect[word2id[word]] = 1
        X.append(vect)
    return X


def evaluate(model, X, y):
    """评估数据集,并返回评估结果,包括:正确率、AUC值
    """
    accuracy = model.score(X, y)
    fpr, tpr, thresholds = sklearn.metrics.roc_curve(y, model.predict_proba(X)[:, 1], pos_label=1)
    return accuracy, sklearn.metrics.auc(fpr, tpr)
# 程序执行的入口!!
if __name__ == "__main__":
    
    # 原始数据集存放路径,这是一个有监督模型,数据中每一行的第一位为标记Y,Y=1代表该条是垃圾短信,Y=0则是正常短信
    data="train.txt"
    # step 1. 将原始数据构建训练集(X,Y),分词并拆分成训练集train和测试集test
    X_train, X_test, y_train, y_test = fetch_train_test(data)

    # step 2. 创建字典
    word2id = build_dict(X_train, min_freq=10)

    # step 3. 抽取特征,文本特征的数值化,这里使用了Bag-of-words模型(后面有介绍),常用的方式是还有TF-IDF、word2vec等
    X_train = text2vect(X_train, word2id)
    X_test = text2vect(X_test, word2id)

    # step 4. 训练模型,我们使用逻辑回归模型来解决这个二分类的问题,只用调用sklearn中封装好LR的模型,
    # 参数C控制了在正则化项L1/L2在最终的损失函数中所占的比重,详细说明自己查skilearn的官网API
    lr = linear_model.LogisticRegression(C=1)
    lr.fit(X_train, y_train)

    # step 5. 模型评估,至于模型的评估参数自己多查资料理解吧
    accuracy, auc = evaluate(lr, X_train, y_train)
    sys.stdout.write("训练集正确率:%.4f%%n" % (accuracy * 100))
    sys.stdout.write("训练集AUC值:%.6fn" % (auc))
    # 测试集上的评测结果
    accuracy, auc = evaluate(lr, X_test, y_test)
    sys.stdout.write("测试集正确率:%.4f%%n" % (accuracy * 100))
    sys.stdout.write("测试AUC值:%.6fn" % (auc))


'''
控制台输出:
Building prefix dict from the default dictionary ...
Loading model from cache /var/folders/nm/vrcffrqs4c374kp3jjx77d680000gn/T/jieba.cache
Loading model cost 0.681 seconds.
Prefix dict has been built succesfully.
训练集正确率:99.1114%
训练集AUC值:0.999267
测试集正确率:96.3098%
测试AUC值:0.990265
[Finished in 26.9s]
'''

就问你,跑出实验结果的那一刻是不是有那么一丝成就感?

每当我看到能够解决现实问题的代码时,总是忍不住有Fork一份的冲动。

5、总结

机器学习界的牛人

原本打算写这篇博客的目的,是想给实验室研一的学妹、学弟传递一些自己对NLP的理解以及学习的建议,但是发现自己的写作的能力还有待提高,很难在一篇博客里把自己的想说的都表达清楚,很多细节的都未能展开说,但比较重要的知识应该大部分都提到了,掌握知识最终还是要靠自己去实践总结。当你看到上面的图片,能把一些大神的英雄事迹介绍的差不多的时候,应该算是已经入门了吧。最后总结一下吧,学习NLP先找到一个感兴趣的问题,然后努力利用NLP技术去实践解决它,不要忘记GitHub这个优质的代码仓库。最后记住,作为程序猿,不关你是做软件开发还是人工智能......你都要会Coding、要会Coding、会Coding!!!


补充两个基础内容点:

(1)统计语言模型:

使用计算机来处理自然语言处理的一个基本问题就是: 为自然语言这种上下文相关的特性建立数学模型。这个数学模型就是我们常说的统计语言模型,它是今天几乎所有自然语言处理的基础。

一个语言模型首要的功能:判断一句话是否能合理?这一句话是人话的可能性。

既然,说到可能性,那么就可以使用概率来描述,此时,数学就可以登场了!

举例:

一句话W=“我喜欢你”===>分词==>“我 喜欢 你”===>w1=我,w2=喜欢,w3=你===>P(W)=P(w1,w2,w3)

引入条件概率模型:P(w1,w2,w3)=P(w3|w2,w1)p(w2,w1)=P(w3|w2,w1)p(w2|w1)P(w1)

上面例子是一个只有三个词汇的短句,当我们遇到一个长句的时候,可想而知,计算P(W)的是比较麻烦的。

俄国数学家:马尔可夫===>提出马尔可夫假设:"任意一个词的出现的概率只与它前面的n个词有关。”

假设n=1:

则:P(w1,w2,w3)=P(w3|w2)p(w2|w1)P(w1)

常用的是n=2(二元模型,Bigarm Model)或者n=3(三元模型,trigram),实际应用一般最大就取到3。

(2)BoW模型

Bag-of-words model (BoW model) 最早出现在自然语言处理(Natural Language Processing)和信息检索(Information Retrieval)领域.。该模型忽略掉文本的语法和语序等要素,将其仅仅看作是若干个词汇的集合,文档中每个单词的出现都是独立的。BoW使用一组无序的单词(words)来表达一段文字或一个文档.。近年来,BoW模型被广泛应用于计算机视觉中。

基于文本的BoW模型的一个简单例子如下:

首先给出两个简单的文本文档如下:

代码语言:javascript复制
    John likes to watch movies. Mary likes too.

    John also likes to watch football games.

基于上述两个文档中出现的单词,构建如下一个词典 (dictionary):

代码语言:javascript复制
   {"John": 1, "likes": 2,"to": 3, "watch": 4, "movies": 5,"also": 6, "football": 7, "games": 8,"Mary": 9, "too": 10}

上面的词典中包含10个单词, 每个单词有唯一的索引, 那么每个文本我们可以使用一个10维的向量来表示。如下:

代码语言:javascript复制
   [1, 2, 1, 1, 1, 0, 0, 0, 1, 1]

   [1, 1,1, 1, 0, 1, 1, 1, 0, 0]

该向量与原来文本中单词出现的顺序没有关系,而是词典中每个单词在文本中出现的频率。

0 人点赞