天然语言处理入门新手上路

天然语言处理 (Natural Language Processing,NLP)是一门融合了计算机科学、人工智能以及语言学的交叉学科,它们的关系如图 1-1 所示。这门学科研究的是如何经过机器学习等技术,让计算机学会处理人类语言,乃至实现终极目标——理解人类语言或人工智能①。html

图像说明文字

事实上,天然语言处理这个术语并无被普遍接受的定义②。注重语言学结构的学者喜欢使用 计算语言学 (Computational Linguistics,CL)这个表达,而强调最终目的的学者则更偏好 天然语言理解 (Natural Language Understanding,NLU)这个术语。因为 NLP 听上去含有更多工程意味,因此本书将一直使用该术语,而不去细究它们的异同。java

如同其自己的复杂性同样,天然语言处理一直是一个艰深的课题。虽然语言只是人工智能的一部分(人工智能还包括计算机视觉等),但它很是独特。这个星球上有许多生物拥有超过人类的视觉系统,但只有人类才拥有这么高级的语言。天然语言处理的目标是让计算机处理或 “理解”天然语言,以完成有意义的任务,好比订机票、购物或同声传译等。彻底理解和表达语言是极其困难的,完美的语言理解等价于实现人工智能。python

在这一章中,咱们将围绕天然语言处理的缩略图,了解一些基本概念。git

① 著名的图灵测试就是根据机器是否能像人类同样理解语言来判断它是否具有人工智能。
② Smith N. A. Linguistic structure prediction[J]. Synthesis lectures on human language technologies, 2011, 4(2): 1-274.复制代码

1.1 天然语言与编程语言

做为咱们将要处理的对象,天然语言具有高度灵活的特色。咱们太熟悉本身的语言,就像水对鱼来说是透明的同样,咱们很难体会到语言的复杂程度。不如拿天然语言与人工语言作一番比较,看看计算机理解咱们的语言是多么困难。程序员

1.1.1 词汇量

天然语言中的词汇比编程语言中的关键词丰富。在咱们熟悉的编程语言中,能使用的关键词数量是有限且肯定的。好比,C 语言一共有 32 个关键字,Java 语言则有 50 个。虽然咱们能够自由地取变量名、函数名和类名,但这些名称在编译器看来只是区别符号,不含语义信息,也不影响程序的运行结果。但在天然语言中,咱们能够使用的词汇量是无穷无尽的,几乎没有意义彻底相同的词语。以汉语为例,由国家语言文字工做委员会发布的《现代汉语经常使用词表(草案)》一共收录了 56 008 个词条。除此以外,咱们还能够随时创造各类类型的新词,而不只限于名词。github

1.1.2 结构化

天然语言是非结构化的,而编程语言是结构化的。所谓结构化,指的是信息具备明确的结构关系,好比编程语言中的类与成员、数据库中的表与字段,均可以经过明确的机制来读写。举个例子,咱们来看看两种语言对同一事实的表述,一些面向对象的编程语言能够如此书写:正则表达式

算法

class Company(object): def __init__(self, founder, logo) -> None: self.founder = founder self.logo = logo 复制代码apple = Company(founder='乔布斯', logo='apple')复制代码

因而,程序员能够经过 apple.founder和 apple.logo来获取苹果公司的创始人和标志。像这样,程序语言经过 class Company这个结构为信息提供了层次化的模板,而在天然语言中则不存在这样的显式结构。人类语言是线性的字符串,给定一句话“苹果的创始人是乔布斯,它的 logo 是苹果”,计算机须要分析出以下结论:数据库

●这句汉语转换为单词序列后,应该是“苹果 的 创始人 是 乔布斯 , 它 的 logo 是 苹果”;express

●第一个“苹果”指的是苹果公司,而第二个“苹果”指的是带缺口的苹果 logo ;

● “乔布斯”是一我的名;

● “它”指代的是苹果公司;

●苹果公司与乔布斯之间的关系是“的创始人是”,与带缺口的苹果 logo 之间的关系为“的logo 是”。

这些结论的得出分别涉及中文分词、命名实体识别、指代消解和关系抽取等天然语言处理任务。这些任务目前的准确率都达不到人类水平。可见,人类以为很简单的一句话,要让计算机理解起来并不简单。

1.1.3 歧义性

天然语言含有大量歧义,这些歧义根据语境的不一样而表现为特定的义项。好比汉语中的多义词,只有在特定的上下文中才能肯定其含义,甚至存在故意利用没法肯定的歧义营造幽默效果的用法。除了上文“苹果”的两种意思以外,“意思”这个词也有多种意义。好比,下面这则经典的笑话。

他说:“她这我的真有意思(funny)。”她说:“他这我的怪有意思的(funny)。”因而人们觉得他们有了意思(wish),并让他向她意思意思(express)。他火了:“我根本没有那个意思(thought)!”她也生气了:“大家这么说是什么意思(intention)?”过后有人说:“真有意思(funny)。”也有人说:“真没意思(nonsense)。”(原文见《生活报》1994.11.13. 第六版)[吴尉天,1999]①

这个例子中特意用英文注解“意思”的不一样义项,从侧面体现了处理中文比处理英文更难。

但在编程语言中,则不存在歧义性②。若是程序员无心中写了有歧义的代码,好比两个函数的签名同样,则会触发编译错误。

1.1.4 容错性

书刊中的语言即便通过编辑的屡次校对,也仍然没法彻底避免错误。而互联网上的文本则更加随性,错别字或病句、不规范的标点符号等随处可见。不过,哪怕一句话错得再离谱,人们仍是能够猜出它想表达的意思。而在编程语言中,程序员必须保证拼写绝对正确、语法绝对规范,不然要么获得编译器无情的警告,要么形成潜在的 bug。

事实上,区别于规范的新闻领域,如何处理不规范的社交媒体文本也成为了一个新的课题。

① 摘自宗成庆《统计天然语言处理》。
② 编程语言被特地设计为无歧义的肯定上下文无关文法,而且能在 O(n) 时间内分析完毕,其中 n 为文本长度。复制代码

1.1.5 易变性

任何语言都是不断发展变化的,不一样的是,编程语言的变化要缓慢温和得多,而天然语言则相对迅速嘈杂一些。

编程语言由某个我的或组织发明而且负责维护。以 C++ 为例,它的发明者是 Bjarne Stroustrup,它如今由 C++ 标准委员会维护。从 C++ 98 到 C++ 03,再到 C++ 11 和 C++ 14,语言标准的变化是以年为单位的迁越过程,且新版本大体作到了对旧版本的前向兼容,只有少数废弃掉的特性。

而天然语言不是由某个我的或组织发明或制定标准的。或者说,任何一门天然语言都是由全人类共同约定俗成的。虽然存在普通话、简体字等规范,但咱们每一个人均可以自由创造和传播新词汇和新用法,也在不停地赋予旧词汇以新含义,致使古代汉语和现代汉语相差巨大。此外,汉语不断吸取英语和日语等外语中的词汇,而且也在输出 niubility 等中式英语。这些变化是连续的,每时每刻都在进行,给天然语言处理带来了不小的挑战。这也是天然语言明明是人类发明的,却还要称做“天然”的缘由。

1.1.6 简略性

因为说话速度和听话速度、书写速度和阅读速度的限制,人类语言每每简洁、干练。咱们常常省略大量背景知识或常识,好比咱们会对朋友说“老地方见”,而没必要指出“老地方”在哪里。对于机构名称,咱们常用简称,好比“工行”“地税局”,假定对方熟悉该简称。若是上文提出一个对象做为话题,则下文常用代词。在连续的新闻报道或者一本书的某一页中,并不须要重复前面的事实,而假定读者已经熟知。这些省略掉的常识,是交流双方共有而计算机不必定拥有的,这也给天然语言处理带来了障碍。

1.2 天然语言处理的层次

按照处理对象的颗粒度,天然语言处理大体能够分为图 1-2 所示的几个层次。

图像说明文字

本节逐一介绍这些天然语言处理任务的定义,为读者提供一个概览。

1.2.1 语音、图像和文本

天然语言处理系统的输入源一共有 3 个,即语音、图像与文本。其中,语音和图像虽然正引发愈来愈大的关注,但受制于存储容量和传输速度,它们的信息总量仍是没有文本多。另外,这两种形式通常通过识别后转化为文本,再进行接下来的处理,分别称为语音识别(Speech Recognition)和光学字符识别(Optical Character Recognition)。一旦转化为文本,就能够进行后续的 NLP 任务。因此,文本处理是重中之重。

1.2.2 中文分词、词性标注和命名实体识别

这 3 个任务都是围绕词语进行的分析,因此统称词法分析。词法分析的主要任务是将文本分隔为有意义的词语(中文分词),肯定每一个词语的类别和浅层的歧义消除(词性标注),而且识别出一些较长的专有名词(命名实体识别)。对中文而言,词法分析经常是后续高级任务的基础。在流水线式① 的系统中,若是词法分析出错,则会波及后续任务。所幸的是,中文词法分析已经比较成熟,基本达到了工业使用的水准。

① 指的是前一个系统的输出是后一个系统的输入,而且前一个系统不依赖于后续系统。复制代码

做为一个初级且资源丰富的任务,词法分析将在本书后续章节中详细阐述。另外,因为这是读者接触的第一个 NLP 任务,它将引出许多有趣的模型、算法和思想。所以,词法分析不只是天然语言处理的基础任务,它所属的章节也会成为读者知识体系的基础。

1.2.3 信息抽取

词法分析以后,文本已经呈现出部分结构化的趋势。至少,计算机看到的再也不是一个超长的字符串,而是有意义的单词列表,而且每一个单词还附有本身的词性以及其余标签。

根据这些单词与标签,咱们能够抽取出一部分有用的信息,从简单的高频词到高级算法提取出的关键词,从公司名称到专业术语,其中词语级别的信息已经能够抽取很多。咱们还能够根据词语之间的统计学信息抽取出关键短语乃至句子,更大颗粒度的文本对用户更加友好。

值得一提的是,一些信息抽取算法用到的统计量能够复用到其余任务中,会在相应章节中详细介绍。  

1.2.4 文本分类与文本聚类

将文本拆分为一系列词语以后,咱们还能够在文章级别作一系列分析。

有时咱们想知道一段话是褒义仍是贬义的,判断一封邮件是不是垃圾邮件,想把许多文档分门别类地整理一下,此时的 NLP 任务称做文本分类。

另外一些时候,咱们只想把类似的文本归档到一块儿,或者排除重复的文档,而不关心具体类别,此时进行的任务称做文本聚类。

这两类任务看上去挺类似,实际上分属两种大相径庭的算法流派,咱们会在单独的章节中分别讲解。

1.2.5 句法分析

词法分析只能获得零散的词汇信息,计算机不知道词语之间的关系。在一些问答系统中,须要获得句子的主谓宾结构。好比“查询刘医生主治的内科病人”这句话,用户真正想要查询的不是“刘医生”,也不是“内科”,而是“病人”。虽然这三个词语都是名词,甚至“刘医生” 离表示意图的动词“查询”最近,但只有“病人”才是“查询”的宾语。经过句法分析,能够获得如图 1-3 所示的语法信息。

图像说明文字

咱们发现图 1-3 中果真有根长长的箭头将“查询”与“病人”联系起来,而且注明了它们之间的动宾关系。后续章节会详细介绍上面这种树形结构,以及句法分析器的实现方法。

不只是问答系统或搜索引擎,句法分析还常常应用于基于短语的机器翻译,给译文的词语从新排序。好比,中文“我吃苹果”翻译为日文后则是“私は(我)林檎を(苹果)食べる(吃)”,二者词序不一样,但句法结构一致。

1.2.6 语义分析与篇章分析

相较于句法分析,语义分析侧重语义而非语法。它包括词义消歧(肯定一个词在语境中的含义,而不是简单的词性)、语义角色标注(标注句子中的谓语与其余成分的关系)乃至语义依存分析(分析句子中词语之间的语义关系)。

随着任务的递进,它们的难度也逐步上升,属于较为高级的课题。即使是最前沿的研究,也还没有达到可以实用的精确程度。另外,相应的研究资源比较稀缺,大众难以获取,因此本书不会涉及。

1.2.7 其余高级任务

除了上述“工具类”的任务外,还有许多综合性的任务,与终端应用级产品联系更紧密。好比:

● 自动问答,根据知识库或文本中的信息直接回答一个问题,好比微软的Cortana和苹果的Siri;

● 自动摘要,为一篇长文档生成简短的摘要;

● 机器翻译,将一句话从一种语言翻译到另外一种语言。

注意,通常认为信息检索(Information Retrieve,IR)是区别于天然语言处理的独立学科。虽然二者具备密切的联系,但 IR 的目标是查询信息,而 NLP 的目标是理解语言。此外,IR 检索的未必是语言,还能够是以图搜图、听曲搜曲、商品搜索乃至任何信息的搜索。现实中还存在大量不须要理解语言便可完成检索任务的场景,好比 SQL 中的 LIKE。

本书做为入门读物,不会讨论这些高级任务,但了解天然语言处理的整个宏观图景有助于咱们开拓视野,找准定位与方向。

1.3 天然语言处理的流派

上一节比较了天然语言与人工语言的异同,展现了天然语言处理的困难所在,介绍了一些常见的 NLP 任务。这一节简要介绍进行天然语言处理的几种不一样手法。

1.3.1 基于规则的专家系统

规则,指的是由专家手工制定的肯定性流程。小到程序员平常使用的正则表达式,大到飞机的自动驾驶仪①,都是固定的规则系统。

在天然语言处理的语境下,比较成功的案例有波特词干算法(Porter stemming algorithm),它由马丁•波特在 1980 年提出,普遍用于英文词干提取。该算法由多条规则构成,每一个规则都是一系列固定的 if then条件分支。当词语知足条件则执行固定的工序,输出固定的结果。摘录其中一部分规则为例,收录于表 1-1 中。

图像说明文字

专家系统要求设计者对所处理的问题具有深刻的理解,而且尽可能以人力全面考虑全部可能的状况。它最大的弱点是难以拓展。当规则数量增长或者多个专家维护同一个系统时,就容易出现冲突。好比表 1-1 这个仅有 3 条规则的简单系统,规则 1 和规则 2 其实有冲突,相似 feed这样的单词会同时知足这两个规则的条件,从而引发矛盾。此时,专家系统一般依靠规则的优先级来解决。好比定义规则 1 优先于规则 2,当知足规则 1 的条件时,则忽略其余规则。几十条规则尚可接受,随着规则数量与团队人数的增长,须要考虑的兼容问题也愈来愈多、愈来愈复杂,系统维护成本也愈来愈高,没法拓展。

大多数语言现象比英文词干复杂得多,咱们已经在上文了解了很多。这些语言现象没有必然遵循的规则,也在时刻变化,使得规则系统显得僵硬、死板与不稳定。

① 区别于汽车的无人驾驶技术,飞机的自动驾驶系统只能处理预约状况,在异常状况下会报警或切换到手动驾驶。 
② 下面的例子中,feed 为特殊状况,不是过去式,不执行替换。bled 是 bleed 的过去式,不该执行“去 ed”。sing 不是如今进行时,不该执行“去 ing”。复制代码

1.3.2 基于统计的学习方法

为了下降对专家的依赖,自适应灵活的语言问题,人们使用统计方法让计算机自动学习语言。所谓“统计”,指的是在语料库上进行的统计。所谓语料库,指的是人工标注的结构化文本,咱们会在接下来的小节中详细阐述。

因为天然语言灵活多变,即使是语言学专家,也没法总结出完整的规则。哪怕真的存在完美的规则集,也难以随着语言的不停发展而逐步升级。因为没法用程序语言描述天然语言,因此聪明的人们决定以举例子的方式让机器自动学习这些规律。而后机器将这些规律应用到新的、未知的例子上去。在天然语言处理的语境下,“举例子”就是“制做语料库”。

统计学习方法实际上是机器学习的别称,而机器学习则是当代实现人工智能的主流途径。机器学习在天然语言处理中的重要性很是之大,能够说天然语言处理只是机器学习的一种应用。此处咱们仅仅用“举例学习”来简单理解,后续章节将浓墨重彩地系统学习。

1.3.3 历史

既然天然语言处理是机器学习的应用层,那么如同人工智能的历史同样,天然语言处理也经历了从逻辑规则到统计模型的发展之路。图 1-4 列出了历史上几个重要的时间段。

图像说明文字

20 世纪 50 年代是人工智能与天然语言处理的萌芽期,出现了许多奠定性的工做。其中最具表明性的是数学家阿兰•图灵在论文 Computing Machinery and Intelligence 提出的人工智能的充分条件——图灵测试,以及语言学家乔姆斯基的《句法结构》——认为句子是按某种与语境无关的广泛语法规则生成的。有趣的是,先驱们的早期估计或理论都过于乐观。图灵曾预言在2014 年一台 1 GB 内存的计算机就能以 70% 的几率在 5 分钟内不被识破机器的身份,然而这个乐观的预言截至今日也没有实现。而乔姆斯基的“广泛语法”则由于对语义的忽视而备受争议,并在后续理论中作了相应修正。不管是人工智能仍是天然语言处理,都是任重道远的课题。

20 世纪 80 年代以前的主流方法都是规则系统,由专家手工编写领域相关的规则集。那时候计算机和计算机语言刚刚发明,从事编程的都是精英学者。他们雄心勃勃,认为只要经过编程就能赋予计算机智能。表明性工做有 MIT AI 实验室的 BASEBALL 以及 Sun 公司(2009 年被甲骨文公司收购)的 LUNAR,分别专门回答北美棒球赛事的问题和阿波罗探月带回来的岩石样本问题。这一时期还有不少相似的问答系统,都是主要依赖手写规则的专家系统。以BASEBALL 为例,其中的词性标注模块是这样判断 score 的词性的:“若是句子中不含其余动词,则 score 是一个动词,不然是名词。”接着该系统依靠词性上的规则合并名词短语、介词短语以及副词短语。语法模块则根据“若最后一个动词是主要动词并位于 to be 以后”之类的规则判断被动句、主语和谓语。而后该系统利用词典上的规则来将这些信息转化为“属性名 = 属性值”或“属性名 = ?”的键值对,用来表示知识库中的文档以及问句。最后利用相似“若除了问号以外全部属性名都匹配,则输出该文档中问句所求的属性”的规则匹配问句与答案。如此僵硬严格的规则致使该系统只能处理固定的问句,没法处理与或非逻辑、比较级与时间段。因而,这些规则系统被称为“玩具”。为了方便表述这样的规则逻辑,1972 年人们还特地发明了 Prolog(Programming in Logic)语言来构建知识库以及专家系统。

20 世纪 80 年代以后,统计模型给人工智能和天然语言处理领域带来了革命性的进展——人们开始标注语料库用于开发和测试 NLP 模块:1988 年隐马尔可夫模型被用于词性标注,1990年 IBM 公布了第一个统计机器翻译系统,1995 年出现第一个健壮的句法分析器(基于统计)。为了追求更高的准确率,人们继续标注更大的语料库(TREC 问答语料库、CoNLL 命名实体识别、语义角色标注与依存句法语料库)。而更大的语料库与硬件的发展又吸引人们应用更复杂的模型。到了 2000 年,大量机器学习模型被普遍使用,好比感知机和条件随机场。人们再也不依赖死板的规则系统,而是指望机器自动学习语言规律。要提升系统的准确率,要么换用更高级的模型,要么多标注一些语料。今后 NLP 系统能够健壮地拓展,而再也不依赖专家们手写的规则。但专家们依然有用武之地,根据语言学知识为统计模型设计特征模板(将语料表示为方便计算机理解的形式)成为立竿见影的方法,这道工序被称为“特征工程”。2010 年基于 SVM 的Turbo 依存句法分析器在英语宾州树库(Penn Treebank)上取得了 92.3% 的准确率①,是当时最早进的系统。本书将着重介绍一些实用的统计模型及实现,它们并不是遥不可及的技术,彻底能够实现,且在普通的硬件资源下运行起来。

2010 年以后语料库规模、硬件计算力都获得了很大提高,为神经网络的复兴创造了条件。但随着标注数据的增长,传统模型的准确率提高愈来愈不明显,人们须要更复杂的模型,因而深层的神经网络从新回归研究者的视野。神经网络依然是统计模型的一种,其理论奠定于 20世纪 50 年代左右。 1951 年,Marvin Lee Minsky 设计了首台模拟神经网络的机器。1958 年, Rosenblatt 首次提出可以模拟人类感知能力的神经网络模型——著名的感知机。1989 年,Yann LeCun 在贝尔实验室利用美国邮政数据集训练了首个深度卷积神经网络,用于识别手写数字。只不过限于计算力和数据量,神经网络一直到 2010 年先后才被普遍应用,并被冠以“深度学习”的新术语,以区别于以前的浅层模型。深度学习的魅力在于,它再也不依赖专家制定特征模板,而可以自动学习原始数据的抽象表示,因此它主要用于表示学习。做为入门书,咱们仅仅在最后一章介绍一些概念与应用,做为衔接传统方法与深度学习的桥梁。

① 准确来说,是斯坦福标准下忽略标点符号的 Unlabeled Attachment Score,将会在第12 章中详细介绍。复制代码

1.3.4 规则与统计

纯粹的规则系统已经日渐式微,除了一些简单的任务外,专家系统已经落伍了。20 世纪 70年代,美国工程院院士贾里尼克在 IBM 实验室开发语音识别系统时,曾经评论道:“我每开除一名语言学家,个人语音识别系统的准确率就提升一点。”① 这句广为流传的快人快语未免有些刻薄,但公正地讲,随着机器学习的日渐成熟,领域专家的做用愈来愈小了。

实际工程中,语言学知识的做用有两方面:一是帮助咱们设计更简洁、高效的特征模板,二是在语料库建设中发挥做用。事实上,实际运行的系统在预处理和后处理的部分依然会用到一些手写规则。固然,也存在一些特殊案例更方便用规则特殊处理。

本书尊重工程实践,以统计为主、规则为辅的方式介绍实用型 NLP 系统的搭建。

1.3.5 传统方法与深度学习

虽然深度学习在计算机视觉领域取得了耀眼的成绩,但在天然语言处理领域中的基础任务上发力并不大。这个结论或许有点意外,做为数据科学从业者,用数听说明问题最合适。表 1-2收录了《华尔街日报》语料库上的词性标注任务的前沿准确率。

图像说明文字

① 原话是“Every time I fire a linguist, the performance of the speech recognizer goes up”。
② “做者姓 ( 年份 )”是一种常见的论文引用格式,可经过该信息(必要时加入主题关键词)搜索到论文。复制代码

截止 2015 年,除了 Bi-LSTM-CRF 之外,其余系统都是传统模型,最高准确率为 97.36%,而 Bi-LSTM-CRF 深度学习模型为 97.55%,仅仅提升了 0.19%。2016 年,传统系统 NLP4J 经过使用额外数据与动态特征提取算法,准确率能够达到 97.64%。

相似的情形也在句法分析任务上重演,以斯坦福标准下宾州树库的准确率为例,如表 1-3所示。

图像说明文字

2014 年首个神经网络驱动的句法分析器还不如传统系统 TurboParser 准确,通过几年的发展准确率终于达到 95.7%,比传统算法提升 3.4%。这个成绩在学术界是很是显著的,但在实际使用中并不明显。

另外一方面,深度学习涉及大量矩阵运算,须要特殊计算硬件(GPU、TPU 等)的加速。目前,一台入门级塔式服务器的价格在 3000 元左右,一台虚拟服务器每个月仅需 50 元左右,但仅一块入门级计算显卡就须要 5000 元。从性价比来看,反而是传统的机器学习方法更适合中小企业。

此外,从传统方法到深度学习的迁移不可能一蹴而就。二者是基础和进阶的关系,许多基础知识和基本概念用传统方法讲解会更简单、易懂,它们也会在深度学习中反复用到(好比 CRF与神经网络的结合)。不管是传统模型仍是神经网络,它们都属于机器学习的范畴。掌握传统方法,不只能够解决计算资源受限时的工程问题,还能够为未来挑战深度学习打下坚实的基础。

1.4 机器学习

在前面的小节中,咱们邂逅了一些机器学习的术语。按照递归学习的思路,如今咱们来递归了解一下机器学习的基本概念。

本书虽然主要面向天然语言处理,不会专门设立章节详谈机器学习,但仍然会在合适的时候介绍引擎盖下的机器学习算法。机器学习是天然语言处理的基石,一些基本概念依然须要预先掌握。熟练掌握这些术语,还方便咱们与其余人流畅交流。

1.4.1 什么是机器学习

人工智能领域的先驱 Arthur Samuel 在 1959 年给出的机器学习定义是:不直接编程却能赋予计算机提升能力的方法。

聪明的读者或许都曾经思考过,计算机是否只能执行人类设计好的步骤?机器学习给了这个问题积极的答复,机器能够经过学习提升自身能力,而不须要程序员硬编码该项能力。美国工程院院士 Tom Mitchell 给过一个更明确的定义,机器学习指的是计算机经过某项任务的经验数据提升了在该项任务上的能力。

简而言之,机器学习是让机器学会算法的算法。这个说法有些绕口,不如拿咱们熟悉的数据库作类比:数据库中的“元数据”指的是描述数据的数据(表名、字段等),而其中的一行则是普通数据。类比过来,机器学习算法则能够称做“元算法”,它指导机器自动学习出另外一个算法,这个算法被用来解决实际问题。为了不混淆,人们一般称被学习的算法为模型。

1.4.2 模型

模型是对现实问题的数学抽象,由一个假设函数以及一系列参数构成。举个简单的例子,咱们要预测中国人名对应的性别。假设中国人名由函数 f x()输出的符号决定,负数表示女性,非负数表示男性。

咱们选取的 f x()的定义以下:

图像说明文字

其中, w 和 b 是函数的参数,而 x 是函数的自变量。那么,模型指的就是包括参数在内的整个函数。不过模型并不包括具体的自变量 x ,由于自变量是由用户输入的。自变量 x 是一个特征向量,用来表示一个对象的特征。

读者能够将式 (1.1) 理解为初中的直线方程,也能够理解为高中的平面方程,或者高维空间中的超平面方程。总之,没必要担忧问题的抽象性,咱们将在第 5 章中用代码完整地实现这个案例。

1.4.3 特征

特征指的是事物的特色转化的数值,好比牛的特征是 4 条腿、0 双翅膀,而鸟的特征是 2条腿、1 双翅膀。那么在性别识别问题中,中国人名的特征是什么呢?

首先,对于一个中国人名,姓氏与性别无关,真正起做用的是名字。而计算机不知道哪部分是姓,哪部分是名。姓氏属于无用的特征,不该被提取。另外,有一些特殊的字(壮、雁、健、强)是男性经常使用的,而另外一些(丽、燕、冰、雪)则是女性经常使用的,还有一些(文、海、宝、玉)则是男女通用的。让咱们把人名表示为计算机能够理解的形式,一个名字是否含有这些字就成了最容易想到的特征。在专家系统中,咱们显式编程:

图像说明文字

若是有人叫“沈雁冰”① 怎么办?“雁”听上去像男性,而“冰”听上去像女性,而这个名字实际上是男性用的。看来,每一个字与男女的相关程度是不同的,“雁”与男性的相关程度彷佛大于“冰”与女性的相关程度。这个冲突彷佛能够经过“优先级”解决,不过这种机械的工做交给机器好了。在机器学习中,“优先级”能够看做特征权重或模型参数。咱们只须要定义一系列特征,让算法根据数据自动决定它们的权重就好了。为了方便计算机处理,咱们将它们表示为数值类型的特征,这个过程称为特征提取。以“沈雁冰”的特征提取为例,如表 1-4 所示。

图像说明文字

特征的数量是因问题而定的,2 个特征显然不足以推断名字的性别,咱们能够增长到 4 个,如表 1-5 所示。

① 做家茅盾原名沈德鸿,字雁冰,以字行于世,所以“沈雁冰”一样为人熟知。复制代码

图像说明文字

有时候,咱们还能够将位置信息也加入特征中,好比“是否以雪字结尾”。咱们还能够组合两个特征获得新的特征,好比“是否以雪字结尾而且倒数第二个字是吹”,这样就可让“西门吹雪”这个特殊名字获得特殊处理,而不至于同“小雪”“陆雪琪”混为一谈。

工程上,咱们并不须要逐个字地写特征,而是定义一套模板来提取特征。好比姓名为 name的话,则定义特征模板为 name[1] + name[2]之类,只要咱们遍历一些姓名,则 name[1] + name[2]可能组合而成的特征就基本覆盖了。这种自动提取特征的模板称做特征模板。

如何挑选特征,如何设计特征模板,这称做特征工程。特征越多,参数就越多;参数越多,模型就越复杂。模型的复杂程度应当与数据集匹配,按照递归学习的思路,数据集的概念将在下一节中介绍。

1.4.4 数据集

如何让机器自动学习,以获得模型的参数呢?首先得有一本习题集。有许多问题没法直接编写算法(规则)解决(好比人名性别识别,咱们说不清楚什么样的名字是男性),因此咱们准备了大量例子(人名 x 及其对应的性别 y)做为习题集,但愿机器自动从习题集中学习中国人名的规律。其中,“例子”通常称做样本。

这本习题集在机器学习领域称做数据集,在天然语言处理领域称做语料库,会在 1.5 节详细介绍。数据集的种类很是多,根据任务的不一样而不一样。表 1-6 收录了一些经常使用的数据集。

图像说明文字

在使用数据集时,咱们不光要考虑它的规模、标注质量,还必须考虑它的受权。大部分数据集都不可商用,许多冷门领域的数据集也比较匮乏,此时咱们能够考虑自行标注。

1.4.5 监督学习

若是这本习题集附带标准答案 y ,则此时的学习算法称做监督学习。监督学习算法让机器先作一遍题,而后与标准答案做比较,最后根据偏差纠正模型的错误。大多数状况下,学习一遍偏差还不够小,须要反复学习、反复调整。此时的算法是一种迭代式的算法,每一遍学习都称做一次迭代。监督学习在日语中被称做“教師あり学習”,意思是“有老师的学习”。经过提供标准答案,人类指出了模型的错误,充当了老师的角色。

图像说明文字

这种在有标签的数据集上迭代学习的过程称为训练,训练用到的数据集称做训练集。训练的结果是一系列参数(特征权重)或模型。利用模型,咱们能够为任意一个姓名计算一个值,若是非负则给出男性的结论,不然给出女性的结论。这个过程称为预测。

总结一下,监督学习的流程如图 1-5 所示。

图像说明文字

在性别识别的例子中:

● 非结构化数据是许多个相似“沈雁冰”“丁玲”的人名;

● 通过人工标注后获得含有许多个相似“沈雁冰=男”“丁玲=女”样本的标注数据集;

● 而后经过训练算法获得一个模型;

● 最后利用这个模型,咱们能够预测任何名字(如“陆雪琪”)的性别。

待预测的名字不必定出如今数据集中,但只要样本数量充足且男女均衡、特征模板设计得当、算法实现正确,咱们依然能够预期一个较高的准确率。

另外,图 1-5 中的标注数据其实也是结构化数据。但因为它含有人工标注的成本,有时被称做“黄金数据”(gold data),与模型预测的、有必定偏差的结果仍是有很大区别的。

本书将从第 3 章开始详细介绍一些 NLP 中实用的监督学习方法。

1.4.6 无监督学习

若是咱们只给机器作题,却不告诉它参考答案,机器仍然能够学到知识吗?

能够,此时的学习称做无监督学习,而不含标准答案的习题集被称做无标注(unlabeled)的数据集。无监督学习在日语中被称做“教師なし学習”,意为“没有老师的学习”。没有老师的指导,机器只能说发现样本之间的联系,而没法学习样本与答案之间的关联。

无监督学习通常用于聚类和降维,二者都不须要标注数据。

聚类已经在 1.2 节中介绍过了,咱们再也不赘述。在性别识别的例子中,若是咱们选择将一系列人名聚成 2 个簇的话,“周树人”“周立人”极可能在一个簇里面,“陆雪琪”和“曹雪芹” 在另外一个簇里面。这是由样本之间的类似性和簇的颗粒度决定的,但咱们并不知道哪一个簇表明男性哪一个簇表明女性,它们也未必能经过肉眼区分。

降维指的是将样本点从高维空间变换到低维空间的过程。机器学习中的高维数据比比皆是,好比在性别识别的例子中,以经常使用汉字为特征的话,特征数量轻易就突破了 2000。若是样本具备 n 个特征,则样本对应着 n +1 维空间中的一个点,多出来的维度是给假设函数的因变量用的。若是咱们想要让这些样本点可视化,则必须将其降维到二维或三维空间。有一些降维算法的中心思想是,降维后尽可能不损失信息,或者说让样本在低维空间中每一个维度上的方差都尽可能大。试想一下这样的极端案例:平地上竖直地插着一些等长的钢管,将这些钢管的顶端降维到二维平面上,就是拔掉钢管后留下来的孔洞。垂直维度上钢管长度都是同样的,没有有用信息,因而被舍弃掉了。

有一些无监督方法也能够用来驱动中文分词、词性标注、句法分析等任务。因为互联网上存储了丰富的非结构化数据,因此无监督学习十分诱人。然而无监督学习时,模型与用户之间没有发生任何信息交换,这种缺少监督信号的学习致使模型没法捕捉用户的标准,最终预测的结果每每与用户心目中的理想答案相去甚远。目前,无监督学习的 NLP 任务的准确率总比监督学习低十几个到几十个百分点,没法达到生产要求。

本书将在第 10 章详细介绍聚类算法的原理和实现。

1.4.7 其余类型的机器学习算法

若是咱们训练多个模型,而后对同一个实例执行预测,会获得多个结果。若是这些结果多数一致,则能够将该实例和结果放到一块儿做为新的训练样本,用来扩充训练集。这样的算法①被称为半监督学习。因为半监督学习能够综合利用标注数据和丰富的未标注数据,因此正在成为热门的研究课题。

现实世界中的事物之间每每有很长的因果链:咱们要正确地执行一系列彼此关联的决策,才能获得最终的成果。这类问题每每须要一边预测,一边根据环境的反馈规划下次决策。这类算法被称为强化学习。强化学习在一些涉及人机交互的问题上成果斐然,好比自动驾驶、电子竞技和问答系统。

本书做为入门读物,不会深刻这些前沿课题。但了解这些分支的存在,有助于构建完整的知识体系。

① 称做启发式半监督学习,是全部半监督学习方法中最容易理解的一种。复制代码

1.5 语料库

语料库做为天然语言处理领域中的数据集,是咱们教机器理解语言不可或缺的习题集。在这一节中,咱们来了解一下中文处理中的常见语料库,以及语料库建设的话题。

1.5.1 中文分词语料库

中文分词语料库指的是,由人工正确切分后的句子集合。

以著名的 1998 年《人民日报》语料库为例,该语料库由北京大学计算语言学研究所联合富士通研究开发中心有限公司,在人民日报社新闻信息中心的许可下,从 1999 年 4 月起到 2002年 4 月底,共同标注完成。语料规模达到 2600 万汉字,市售为 1998 年上半年的语料部分(约1300 万字=约 730 万词)。

在 2005 年的第二届国际中文分词比赛中,曾经公开过约 1 个月份的语料。其中的一句样例为:

先有通货膨胀干扰,后有通货紧缩叫板。

从这句简单的标注语料中,无须语言学知识,咱们也能发现一个问题:为什么“通货膨胀”是一个词,而“通货 紧缩”却分为两个词呢?这涉及语料标注规范和标注员内部一致性的问题。咱们将在后续章节中详细介绍这些话题,如今只需留个印象:语料规范很难制定,规范很难执行。

事实上,中文分词语料库虽然总量很少,但派别却很多。咱们将在第 3 章中了解这些语料的受权、下载与使用。

1.5.2 词性标注语料库

它指的是切分并为每一个词语指定一个词性的语料。总之,咱们要教机器干什么,咱们就得给机器示范什么。依然以《人民日报》语料库为例,1998 年的《人民日报》一共含有 43 种词性,这个集合称做词性标注集。这份语料库中的一句样例为:

迈向/v 充满/v 但愿/n 的/u 新/a 世纪/n ——/w 一九九八年/t 新年/t 讲话/n (/w 附/v 图片/n 1/m 张/q )/w复制代码

这里每一个单词后面用斜杠隔开的就是词性标签,关于每种词性的意思将会在第 7 章详细介绍。这句话中值得注意的是,“但愿”的词性是“名词”(n)。在另外一些句子中,“但愿”还能够做为动词。

1.5.3 命名实体识别语料库

这种语料库人工标注了文本内部制做者关心的实体名词以及实体类别。好比《人民日报》语料库中一共含有人名、地名和机构名 3 种命名实体:

萨哈夫/nr 说/v ,/w 伊拉克/ns 将/d 同/p [联合国/nt 销毁/v 伊拉克/ns 大规模/b 杀伤性/n 武器/n 特别/a 委员会/n] /nt 继续/v 保持/v 合做/v 。/w复制代码

这个句子中的加粗词语分别是人名、地名和机构名。中括号括起来的是复合词,咱们能够观察到:有时候机构名和地名复合起来会构成更长的机构名,这种构词法上的嵌套现象增长了命名实体识别的难度。

命名实体类型有什么取决于语料库制做者关心什么。在本书第 8 章中,咱们将演示如何标注一份语料库用来实现对战斗机名称的识别。

1.5.4 句法分析语料库

汉语中经常使用的句法分析语料库有 CTB(Chinese Treebank,中文树库),这份语料库的建设工做始于 1998 年,历经宾夕法尼亚大学、科罗拉多大学和布兰迪斯大学的贡献,一直在发布多个改进版本。以 CTB 8.0 版为例,一共含有来自新闻、广播和互联网的 3007 篇文章,共计 71 369个句子、1 620 561 个单词和 2 589 848 个字符。每一个句子都通过了分词、词性标注和句法标注。其中一个句子可视化后如图 1-6 所示。

图像说明文字

图 1-6 中,中文单词上面的英文标签表示词性,而箭头表示有语法联系的两个单词,具体是何种联系由箭头上的标签表示。关于句法分析语料库的可视化和利用,将会在第 12 章中介绍。

1.5.5 文本分类语料库

它指的是人工标注了所属分类的文章构成的语料库。相较于上面介绍的 4 种语料库,文本分类语料库的数据量明显要大不少。以著名的搜狗文本分类语料库为例,一共包含汽车、财经、 IT、健康、体育、旅游、教育、招聘、文化、军事 10 个类别,每一个类别下含有 8000 篇新闻,每篇新闻大约数百字。

另外,一些新闻网站上的栏目通过了编辑的手工整理,相互之间的区分度较高,也可做为文本分类语料库使用。情感分类语料库则是文本分类语料库的一个子集,无非是类别限定为 “正面”“负面”等而已。

若是这些语料库中的类目、规模不知足实际需求,咱们还能够按需自行标注。标注的过程实际上就是把许多文档整理后放到不一样的文件夹中。

1.5.6 语料库建设

语料库建设指的是构建一份语料库的过程,分为规范制定、人员培训与人工标注这 3 个阶段。

规范制定指的是由语言学专家分析并制定一套标注规范,这份规范包括标注集定义、样例和实施方法。在中文分词和词性标注领域,比较著名的规范有北京大学计算语言学研究所发布的《现代汉语语料库加工规范——词语切分与词性标注》和中国国家标准化管理委员会发布的《信息处理用现代汉语词类标记规范》。

人员培训指的是对标注员的培训。因为人力资源的限制,制定规范与执行规范的未必是同一批人。大型语料库每每须要多人协同标注,这些标注员对规范的理解必须达到一致,不然会致使标注员内部冲突,影响语料库的质量。

针对不一样类型的任务,人们开发出许多标注软件,其中比较成熟的一款是 brat(brat rapid annotation tool) ①,它支持词性标注、命名实体识别和句法分析等任务。brat 是典型的 B/S 架构,服务端用 Python 编写,客户端运行于浏览器。相较于其余标注软件,brat 最大的亮点是多人协同标注功能。此外,拖曳式的操做体验也为 brat 增色很多。

① 详见 http://brat.nlplab.org/。复制代码

1.6 开源工具

目前开源界贡献了许多优秀的 NLP 工具,它们为咱们提供了多种选择,好比教学经常使用的NLTK(Natural Language Toolkit)、斯坦福大学开发的 CoreNLP,以及国内哈工大开发的 LTP (Language Technology Platform)、我开发的 HanLP(Han Language Processing)。

1.6.1 主流 NLP 工具比较

选择一个工具包,咱们须要考虑的问题有:功能、精度、运行效率、内存效率、可拓展性、商业受权和社区活跃程度。表 1-7 比较了 4 款主流的开源 NLP 工具包。

图像说明文字

关于这些开源工具的发展速度,根据 GitHub 上 Star 数量的趋势,HanLP 是发展最迅猛的,如图 1-7 所示。

图像说明文字

① 关于 HanLP 与 LTP 的具体性能对比,请参考 @zongwu233 的第三方开源评测:https://github.com/zongwu233/ HanLPvsLTP。关于 HanLP 与包括结巴、IK、Stanford、Ansj、word 在内的其余 Java 开源分词器的性能对比,可参考阿里巴巴架构师杨尚川的第三方开源评测:https://github.com/ysc/cws_evaluation。我不保证第三方开源评测的准确与公正,更不采信任何闭源评测。本书将在相关章节中详细介绍如何规范地评估常见 NLP 任务的精度。 复制代码② 截至 2019 年 8 月份在 GitHub 上的 Star 数量。复制代码

另外,我也研究过其余开源项目的原理,借鉴了其中优秀的设计。但毕竟仍是本身写的代码讲得最清楚,因此综合以上各类考虑,最后选取了 HanLP 做为本书的实现。

1.6.2 Python 接口

得益于 Python 简洁的设计,使用这门动态语言调用 HanLP 会省下很多时间。不管用户是否经常使用 Python,都推荐一试。

HanLP 的 Python 接口由 pyhanlp 包提供,其安装只需一句命令:

$ pip install pyhanlp复制代码

这个包依赖 Java 和 JPype。Windows 用户若是遇到以下错误:

building '_jpype' extension
error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual
C++ Build Tools": http://visualstudio.microsoft.com/visual-cpp-build-tools/复制代码

既能够按提示安装 Visual C++,也能够安装更轻量级的 Miniconda。Miniconda 是 Python 语言的开源发行版,提供更方便的包管理。安装时请勾选如图 1-8 所示的两个复选框。

图像说明文字

而后执行以下命令:

$ conda install -c conda-forge jpype1
$ pip install pyhanlp复制代码

若是遇到 Java 相关的问题:

jpype._jvmfinder.JVMNotFoundException: No JVM shared library file (jvm.dll) found. Try setting up the JAVA_HOME environment variable properly.复制代码

请安装 Java 运行环境①。HanLP 主项目采用 Java 开发,因此须要 JDK 或 JRE。若是发生其余错误,欢迎前往项目讨论区② 汇报问题。

一切顺利的话,在命令行中键入以下命令,能够验证安装结果:

图像说明文字

若是 Linux 用户遇到权限问题,则须要执行 sudo hanlp。由于在第一次运行时,pyhanlp 会自动下载 HanLP 的 jar 包(包含许多算法)和数据包(包含许多模型)到 pyhanlp 的系统路径。

经过命令行,咱们能够在不写代码的前提下轻松调用 HanLP 提供的常见功能。

① 官网(http://www.oracle.com/technetwork/java/javase/downloads/index.html)推荐选择 JDK 8 以上版本。 复制代码② 详见 github.com/hankcs/HanL…复制代码

使用命令 hanlp segment进入交互分词模式;输入一个句子并回车,HanLP 会输出分词结果:

$ hanlp segment
商品和服务
商品/n 和/cc 服务/vn
当下雨天地面积水分外严重
当/p 下雨天/n 地面/n 积水/n 分外/d 严重/a王总和小丽结婚了
王总/nr 和/cc 小丽/nr 结婚/vi 了/ule复制代码

在 Linux 下还能够重定向字符串做为输入:

$ hanlp segment <<< '欢迎新老师生前来就餐'
欢迎/v 新/a 老/a 师生/n 前来/vi 就餐/vi复制代码

注意 Windows 不支持字符串的 <<< 定向,只能手动输入。

这里默认执行了词性标注,咱们能够禁用它:

$ hanlp segment --no-tag <<< ' 欢迎新老师生前来就餐'
欢迎 新 老 师生 前来 就餐复制代码

任何平台都支持重定向文件输入 / 输出,好比咱们将一本小说存储为 input.txt :

$ head input.txt 
第一章 隐忧
张小凡看着前方那个中年文士,也就是当今正道的心腹大患“鬼王”,脑海中一片混乱。
这些日子以来,他在深心处不时对本身往日的信仰有小小的疑惑,其实都根源于当日空桑山下茶摊里的一番对话。现在,又见故人,这份心情当真复杂,几乎让他一时间忘了此时此地的处境。
不过就算他忘了,旁边的人可不会忘。
小周伸手擦去了嘴边的鲜血,勉强站了起来,低声对张小凡、田灵儿二人道:“此人道行过高,不可力敌,我来拖住他,大家二人快走!”
说罢,他伸手一招,倒插在岩壁中到如今兀自在轻微振动的“七星剑”,似受他召唤,“铮”的一声破壁而出,飞回到他手上。
鬼王看了看小周,点了点头,脸上依然带着一丝微笑,道:“以你的道行,看来青云门门下年轻弟子一辈里,要以你为首。
想不到青云门除了这个张小凡,竟然还有你这样的人才,不错,不错!”
张小凡吓了一跳,却发觉师姐田灵儿与那小周的眼光都瞄了过来,一时脸上有些发热,殊不知道该说什么才好。复制代码

经过重定向,只需一条命令就能够给小说分词:

$ hanlp segment < input.txt > output.txt -a crf --no-tag复制代码

此处经过 -a参数指定分词算法为 CRF。关于该算法,咱们会在第 6 章中详细介绍。如今,咱们先来感性观察一下 CRF 分词的效果:

$ head output.txt 
第一 章   隐忧
张小凡 看着 前方 那个 中年 文士 , 也 就是 当今 正道 的 心腹大患 “ 鬼王 ” , 脑海中 一片 混乱。这些 日子 以来 , 他 在 深心 处 不时 对 本身 往日 的 信仰 有 小小 的 疑惑 , 其实 都 根源 于 当日 空桑山 下 茶摊 里 的 一番 对话 。
现在 , 又 见 故人 , 这 份 心情 当真 复杂 , 几乎 让 他 一 时间 忘 了 此时此地 的 处境 。不过 就算 他 忘 了 , 旁边 的 人 可 不会 忘 。
小周 伸手 擦去 了 嘴边 的 鲜血 , 勉强 站 了 起来 , 低声 对 张小凡 、 田灵儿 二 人 道 :
“ 此人 道行 太 高 , 不可力敌 , 我 来 拖住 他 , 大家 二 人 快走 !”
说罢 , 他 伸手 一 招 , 倒 插 在 岩壁 中 到 如今 兀自 在 轻微 振动 的 “ 七星剑 ” , 似 受 他 召唤 , “ 铮 ” 的 一 声 破壁 而 出 , 飞 回到 他 手上 。
鬼王 看 了 看 小周 , 点 了 点头 , 脸上 依然 带 着 一 丝 微笑 , 道 : “ 以 你 的 道行 , 看来 青云门 门下 年轻 弟子 一 辈 里 , 要以 你 为首 。
想不到 青云门 除了 这个 张小凡 , 竟然 还有 你 这样 的 人才 , 不错 , 不错 ! ”
张小凡 吓了一跳 , 却 发觉 师姐 田灵儿 与 那 小周 的 眼光 都 瞄 了 过来 , 一时 脸上 有些 发热 , 却 不 知道 该 说 什么 才 好 。复制代码

效果彷佛还行,“鬼王”“空桑山”“七星剑”“青云门”等词语都正确切分出来了。但仍然有不尽如人意的地方。好比“此时此地”“吓了一跳”为何被看成一个词?这些分词标准是由分词器做者定的吗?这些问题咱们将会在后续章节中逐个讨论。

句法分析功能也是同样的道理,一句命令便可:

图像说明文字

这些命令还支持许多其余参数,这能够经过 --help参数来查看最新的帮助手册:

图像说明文字

在初步体验 HanLP 后,来看看如何在 Python 中调用 HanLP 的经常使用接口。这里给出一个大而不全的例子:

图像说明文字

HanLP 的经常使用功能能够经过工具类 HanLP来调用,而不须要建立实例。对于其余更全面的功能介绍,可参考 GitHub 上的 demos 目录:https://github.com/hankcs/pyhanlp/tree/master/tests/demos。

1.6.3 Java 接口

Java 用户能够经过 Maven 方便地引入 HanLP 库,只需在项目的 pom.xml 中添加以下依赖项便可:

图像说明文字

此外,能够访问发布页https://github.com/hankcs/HanLP/releases 获取其最新的版本号。

而后就能够用一句话调用HanLP 了:

System.out.println(HanLP.segment("你好,欢迎使用HanLP汉语处理包!"));复制代码

经常使用的 API 依然封装在工具类 HanLP中,你可经过 https://github.com/hankcs/HanLP 了解接口的用法。固然,你也能够随着本书的讲解,逐步熟悉这些功能。

HanLP 的数据与程序是分离的。为了减少 jar 包的体积,portable 版只含有少许数据。对于一些高级功能(CRF 分词、句法分析等),则须要下载额外的数据包,并经过配置文件将数据包的位置告诉给 HanLP。

若是读者安装过 pyhanlp 的话,则数据包和配置文件已经安装就绪。咱们能够经过以下命令获取它们的路径:

图像说明文字

最后一行 hanlp.properties 就是所需的配置文件,咱们只需将它复制到项目的资源目录src/main/resources 便可(没有该目录的话,手动建立一个)。此时 HanLP 就会从 /usr/local/lib/python3.6/site-packages/pyhanlp/static 加载 data,也就是说与 pyhanlp 共用同一套数据包。

若是读者没有安装过 pyhanlp,或者但愿使用独立的 data,也并不困难。只需访问项目主页https://github.com/hankcs/HanLP,下载 data.zip 并将其解压到一个目录,好比 D:/hanlp。而后下载并解压 hanlp-1.7.5-release.zip,将获得的 hanlp.properties 中的第一行 root 设为 data 文件夹的父目录:

root=D:/hanlp复制代码

注意 Windows 用户请注意,路径分隔符统一使用斜杠“/”。Windows 默认的“\”与绝大多数编程语言的转义符冲突,好比“D:\nlp”中的“\n”实际上会被Java 和Python 理解为换行符,引起问题。

最后,将 hanlp.properties 移动到项目的 resources 目录中便可。

因为本书将深刻讲解 HanLP 的内部实现,因此还推荐读者去 GitHub 上建立分支(fork)并克隆(clone)一份源码。版本库中的文件结构以下:

图像说明文字

限于文件体积,版本库中依然不含完整的 model 文件夹,须要用户下载数据包和配置文件。下载方式有自动与手动两种,本书 Java 配套代码在运行时会自动下载并解压,另外用户也能够自行下载解压。按照前面提到的方法,建立 resources 目录并将 hanlp.properties 放入其中。而后将下载到的 data/model 放入版本库的相应目录便可。完成后的路径示意图以下:

图像说明文字

接下来,咱们就能够运行本书配套的代码了(配套代码位于 src/test/java/com/hankcs/book)。如今咱们来运行一个 Hello Word(详见 ch01/HelloWord.java):

HanLP.Config.enableDebug(); // 为了不你等得无聊,开启调试模式说点什么
System.out.println(HanLP.segment("王国维和服务员"));复制代码

运行一下,会获得相似以下的输出:

图像说明文字

相较于上一个例子,它们有如下两个区别。

● 咱们打开了调试模式,此时会将运行过程的中间结果输出到控制台。

● 咱们运行的是GitHub仓库版,该版本中的词典和模型都是文本形式。HanLP中的词典通常有文本和二进制两种形式,它们的关系相似于源码和程序。当二进制不存在时,HanLP会加载文本词典并自动缓存为同名的二进制。二进制的加载比文本要快不少,一般是5 倍的加速比。好比在上面的例子中,加载文本花了341 ms,但再次运行时加载相应的二进制只花了64 ms。经过缓存机制和内部重写的IO 接口,HanLP 能够将系统的冷启动控制在几百毫秒内。这为程序员反复调试提供了极大的便利。

再来看看调试输出,里面分为两个过程:粗分过程和细分过程。粗分过程的结果是 [王国 /n, 维和 /vn, 服务员 /nnt],这显然是不合理① 的,这个句子不该该这样理解。因而在细分过程当中,算法进行了人名识别,召回了“王国维”这个词语。接着算法以为 [王国维 /nr, 和 /cc, 服务员 /nnt]通顺多了,因而将其做为最终结果。

算法内部还有许多细节,但咱们已经有了趁手的武器。具体武器的基本骨架、锻造过程和使用场景,将以递归的形式逐步讲解。

1.7 总结

本章给出了人工智能、机器学习与天然语言处理的宏观缩略图与发展时间线。机器学习是人工智能的子集,而天然语言处理则是人工智能与语言学、计算机科学的交集。这个交集虽然小,它的难度却很大。为了实现理解天然语言这个宏伟目标,人们尝试了规则系统,并最终发展到基于大规模语料库的统计学习系统。

在接下来的章节中,就让咱们按照这种由易到难的发展规律去解决第一个 NLP 问题——中文分词。咱们将先从规则系统入手,介绍一些快而不许的算法,而后逐步进化到更加准确的统计模型。

① 称其“不合理”而非“不正确”的缘由是,咱们没法排除在某个奇幻世界里存在一个特立独行的王国,里面养着一只维和部队,部队的成员却不是战士而是服务员。但这种可能性很是低,几乎不可能发生。

本文摘自《天然语言处理入门》

相关文章
相关标签/搜索