聊天机器人

摘要:制作个人聊天机器人笔记

1 聊天机器人简介

1.1 工作原理

1.1.1 核心模块

  1. 意图识别

    分类器(SVM,深度学习)

  2. 实体识别

    NER(命名实体识别)

  3. 对话管理系统

  4. 回复生成

机器人嗯流程

1.2 关键技术

  1. 海量文本知识表示:网络文本资源获取、机器学习方法、大规模语义计算和推理、知识表示体系、知识库构建;
  2. 问句解析:中文分词、词性标注、实体标注、概念类别标注、句法分析、语义分析、逻辑结构标注、指代消解、关联关系标注、问句分类(简单问句还是复杂问句、实体型还是段落型还是篇章级问题)、答案类别确定;
  3. 答案生成与过滤:候选答案抽取、关系推演(并列关系还是递进关系还是因果关系)、吻合程度判断、噪声过滤

1.3 技术方法

  1. 基于检索的技术(淘汰)
  2. 基于模式匹配的技术(淘汰)
  3. 基于意图识别的⽅法
  4. ⽣成式⽅法(i.e.,端到端)

端到端

2 词性标注和关键词提取

2.1 安装

PyNLPIR官网地址

1
pip install PyNLPIR

2.2 初始化NLPIR

1
2
3
import pynlpir
# 默认情况下,输入假定为unicode或UTF-8编码。如果您想使用不同的编码(例如GBK或BIG5)
pynlpir.open(encoding='gbk')

2.3 分词及词性标注

1
2
3
4
# 词性标注 pos_tagging=True;词性标注显示英文/中文 pos_english=True; 词性标记的显示方式 pos_names='parent/child/all'
# 返回的是tuple(token, pos)组成的列表,其中token就是切出来的词,pos就是语言属性
# 调用segment方法指定的pos_names参数可以是'all', 'child', 'parent',默认是parent, 表示获取该词性的最顶级词性,child表示获取该词性的最具体的信息,all表示获取该词性相关的所有词性信息,相当于从其顶级词性到该词性的一条路径
pynlpir.segment(s, pos_tagging=True, pos_names='parent', pos_english=True)
1
2
3
4
s = 'NLPIR分词系统前身为2000年发布的ICTCLAS词法分析系统,从2009年开始,为了和以前工作进行大的区隔,并推广NLPIR自然语言处理与信息检索共享平台,调整命名为NLPIR分词系统。'
pynlpir.segment(s)

# Sample output: [('NLPIR', 'noun'), ('分词', 'verb'), ('系统', 'noun'), ('前身', 'noun'), ('为', 'preposition'), ('2000年', 'time word'), ('发布', 'verb'), . . . ]

如果不想词性标注,设置post_tagging为false:

1
2
3
pynlpir.segment(s, pos_tagging=False)

# Sample output: ['NLPIR', '分词', '系统', '前身', '为', '2000年', '发布', . . . ]

2.4 关键字提取

1
2
3
4
# 获得多少个词:max_words=50; 显示关键字权重:weighted=True
pynlpir.get_key_words(s, max_words=50, weighted=True)
# 关闭API
pynlpir.close()

2.5 词性分类表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
POS_MAP = {
'n': ('名词', 'noun', {
'nr': ('人名', 'personal name', {
'nr1': ('汉语姓氏', 'Chinese surname'),
'nr2': ('汉语名字', 'Chinese given name'),
'nrj': ('日语人名', 'Japanese personal name'),
'nrf': ('音译人名', 'transcribed personal name')
}),
'ns': ('地名', 'toponym', {
'nsf': ('音译地名', 'transcribed toponym'),
}),
'nt': ('机构团体名', 'organization/group name'),
'nz': ('其它专名', 'other proper noun'),
'nl': ('名词性惯用语', 'noun phrase'),
'ng': ('名词性语素', 'noun morpheme'),
}),
't': ('时间词', 'time word', {
'tg': ('时间词性语素', 'time morpheme'),
}),
's': ('处所词', 'locative word'),
'f': ('方位词', 'noun of locality'),
'v': ('动词', 'verb', {
'vd': ('副动词', 'auxiliary verb'),
'vn': ('名动词', 'noun-verb'),
'vshi': ('动词"是"', 'verb 是'),
'vyou': ('动词"有"', 'verb 有'),
'vf': ('趋向动词', 'directional verb'),
'vx': ('行事动词', 'performative verb'),
'vi': ('不及物动词', 'intransitive verb'),
'vl': ('动词性惯用语', 'verb phrase'),
'vg': ('动词性语素', 'verb morpheme'),
}),
'a': ('形容词', 'adjective', {
'ad': ('副形词', 'auxiliary adjective'),
'an': ('名形词', 'noun-adjective'),
'ag': ('形容词性语素', 'adjective morpheme'),
'al': ('形容词性惯用语', 'adjective phrase'),
}),
'b': ('区别词', 'distinguishing word', {
'bl': ('区别词性惯用语', 'distinguishing phrase'),
}),
'z': ('状态词', 'status word'),
'r': ('代词', 'pronoun', {
'rr': ('人称代词', 'personal pronoun'),
'rz': ('指示代词', 'demonstrative pronoun', {
'rzt': ('时间指示代词', 'temporal demonstrative pronoun'),
'rzs': ('处所指示代词', 'locative demonstrative pronoun'),
'rzv': ('谓词性指示代词', 'predicate demonstrative pronoun'),
}),
'ry': ('疑问代词', 'interrogative pronoun', {
'ryt': ('时间疑问代词', 'temporal interrogative pronoun'),
'rys': ('处所疑问代词', 'locative interrogative pronoun'),
'ryv': ('谓词性疑问代词', 'predicate interrogative pronoun'),
}),
'rg': ('代词性语素', 'pronoun morpheme'),
}),
'm': ('数词', 'numeral', {
'mq': ('数量词', 'numeral-plus-classifier compound'),
}),
'q': ('量词', 'classifier', {
'qv': ('动量词', 'verbal classifier'),
'qt': ('时量词', 'temporal classifier'),
}),
'd': ('副词', 'adverb'),
'p': ('介词', 'preposition', {
'pba': ('介词“把”', 'preposition 把'),
'pbei': ('介词“被”', 'preposition 被'),
}),
'c': ('连词', 'conjunction', {
'cc': ('并列连词', 'coordinating conjunction'),
}),
'u': ('助词', 'particle', {
'uzhe': ('着', 'particle 着'),
'ule': ('了/喽', 'particle 了/喽'),
'uguo': ('过', 'particle 过'),
'ude1': ('的/底', 'particle 的/底'),
'ude2': ('地', 'particle 地'),
'ude3': ('得', 'particle 得'),
'usuo': ('所', 'particle 所'),
'udeng': ('等/等等/云云', 'particle 等/等等/云云'),
'uyy': ('一样/一般/似的/般', 'particle 一样/一般/似的/般'),
'udh': ('的话', 'particle 的话'),
'uls': ('来讲/来说/而言/说来', 'particle 来讲/来说/而言/说来'),
'uzhi': ('之', 'particle 之'),
'ulian': ('连', 'particle 连'),
}),
'e': ('叹词', 'interjection'),
'y': ('语气词', 'modal particle'),
'o': ('拟声词', 'onomatopoeia'),
'h': ('前缀', 'prefix'),
'k': ('后缀' 'suffix'),
'x': ('字符串', 'string', {
'xe': ('Email字符串', 'email address'),
'xs': ('微博会话分隔符', 'hashtag'),
'xm': ('表情符合', 'emoticon'),
'xu': ('网址URL', 'URL'),
'xx': ('非语素字', 'non-morpheme character'),
}),
'w': ('标点符号', 'punctuation mark', {
'wkz': ('左括号', 'left parenthesis/bracket'),
'wky': ('右括号', 'right parenthesis/bracket'),
'wyz': ('左引号', 'left quotation mark'),
'wyy': ('右引号', 'right quotation mark'),
'wj': ('句号', 'period'),
'ww': ('问号', 'question mark'),
'wt': ('叹号', 'exclamation mark'),
'wd': ('逗号', 'comma'),
'wf': ('分号', 'semicolon'),
'wn': ('顿号', 'enumeration comma'),
'wm': ('冒号', 'colon'),
'ws': ('省略号', 'ellipsis'),
'wp': ('破折号', 'dash'),
'wb': ('百分号千分号', 'percent/per mille sign'),
'wh': ('单位符号', 'unit of measure sign'),
}),
}

3 通过爬虫获取语料信息

通过上节得到了关键词,想获取预料信息,通过几大搜索引擎的调用接口获取。

3.1 Anaconda安装Scrapy

  1. 首先查看anaconda中是否装有scrapy工具包,具体方法如下:
    Anaconda Prompt / cmd命令中,输入 conda list,查看所有已经安装的工具包及版本号

    如果没有发现scrapy,则执行第2步。

  2. 输入 conda install -c scrapinghub scrapy ,等待片刻后,提示需要安装的相关工具包

  3. proceed下输入y,回车, 自动进行安装相关的库。

  4. 再一次通过conda list 查看,就可以看到scrapy已经在list中了。安装成功。

3.2 创建Scrapy项目

  1. 打开Anaconda Prompt,切换到想要创建的目录下面

    1
    2
    3
    4
    5
    cd D:\WorkSpace\Spider\
    # 执行下面语句创建scrapy工程
    scrapy startproject baidu_search
    # 将会自动生成了baidu_search目录和下面的文件
    创建baidu_search/baidu_search/spiders/baidu_search.py文件并对其进行配置,做好抓取器。

    参考资料

  2. 进入baidu_search/baidu_search/ 目录下,执行

    1
    scrapy crawl baidu_search

4 依存句法和语义依存分析

4.1 依存句法分析

依存句法就是这些成分之间有一种依赖关系。什么是依赖:没有你的话,我存在就是个错误。“北京是中国的首都”,如果没有“首都”,那么“中国的”存在就是个错误,因为“北京是中国的”表达的完全是另外一个意思了。

4.2 语义依存分析

“语义”就是说句子的含义,“张三昨天告诉李四一个秘密”,那么语义包括:谁告诉李四秘密的?张三。张三告诉谁一个秘密?李四。张三什么时候告诉的?昨天。张三告诉李四什么?秘密。

4.3 语义依存和依存句法的区别

依存句法强调介词、助词等的划分作用,语义依存注重实词之间的逻辑关系。

另外,依存句法随着字面词语变化而不同,语义依存不同字面词语可以表达同一个意思,句法结构不同的句子语义关系可能相同。

4.4 依存句法分析和语义依存分析对聊天机器人有什么意义呢?

依存句法分析和语义分析相结合使用,对对方说的话进行依存句法和语义分析后,一方面可以让计算机理解句子的含义,从而匹配到最合适的回答,另外如果有已经存在的依存句法、语义分析结果,还可以通过置信度匹配来实现聊天回答。

4.5 依存句法分析到底是怎么分析的呢?

依存句法分析的基本任务是确定句式的句法结构(短语结构)或句子中词汇之间的依存关系。依存句法分析最重要的两棵树:

依存树:子节点依存于父节点

依存投射树:实线表示依存联结关系,位置低的成分依存于位置高的成分,虚线为投射线

句法依存

4.6 依存关系的五条公理

  1. 一个句子中只有一个成分是独立的
  2. 其他成分直接依存于某一成分
  3. 任何一个成分都不能依存于两个或两个以上的成分
  4. 如果A成分直接依存于B成分,而C成分在句子中位于A和B之间,那么C或者直接依存于B,或者直接依存于A和B之间的某一成分
  5. 中心成分左右两面的其他成分相互不发生关系

    什么地方存在依存关系呢?比如合成词(如:国内)、短语(如:英雄联盟)很多地方都是

4.7 LTP依存关系标记

依存关系标记

4.8 那么依存关系是怎么计算出来的呢?

是通过机器学习和人工标注来完成的,机器学习依赖人工标注,那么都哪些需要我们做人工标注呢?分词词性、依存树库、语义角色都需要做人工标注,有了这写人工标注之后,就可以做机器学习来分析新的句子的依存句法了

4.9 LTP云平台怎么用?

首先注册用户,得到每月免费20G的流量,在http://www.ltp-cloud.com/注册一个账号,注册好后登陆并进入你的dashboard:http://www.ltp-cloud.com/dashboard/在dashboard里还可以查询自己流量使用情况。具体使用方法如下(参考http://www.ltp-cloud.com/document):

5 语言模型

业界目前比较认可而且有效的语言模型是n元语法模型(n-gram model),它本质上是马尔可夫模型,简单来描述就是:一句话中下一个词的出现和最近n个词有关(包括它自身)。详细解释一下:

如果这里的n=1时,那么最新一个词只和它自己有关,也就是它是独立的,和前面的词没关系,这叫做一元文法

如果这里的n=2时,那么最新一个词和它前面一个词有关,比如前面的词是“我”,那么最新的这个词是“是”的概率比较高,这叫做二元文法,也叫作一阶马尔科夫链

依次类推,工程上n=3用的是最多的,因为n越大约束信息越多,n越小可靠性更高

n元语法模型实际上是一个概率模型,也就是出现一个词的概率是多少,或者一个句子长这个样子的概率是多少。

这就又回到了之前文章里提到的自然语言处理研究的两大方向:基于规则、基于统计。n元语法模型显然是基于统计的方向。

5.1 语言模型的应用

这几乎就是自然语言处理的应用了,有:中文分词、机器翻译、拼写纠错、语音识别、音子转换、自动文摘、问答系统、OCR等