PyTorch自然语言处理入门与实战
上QQ阅读APP看书,第一时间看更新

第1章 自然语言处理概述

自然语言处理是指用计算机处理自然演化形成的人类语言。随着信息技术的发展,自然语言数据的积累和数据处理能力的提高促进了自然语言处理的发展。本章介绍自然语言处理的概念、基本任务、主要挑战与常用方法。

本章主要涉及的知识点如下。

自然语言处理的概念。

自然语言处理的任务。

自然语言处理的挑战。

自然语言处理中的常用方法和工具。

1.1 什么是自然语言处理

本节先介绍自然语言处理的定义,然后介绍自然语言处理的常用术语、任务和发展历程。

1.1.1 定义

自然语言指的是人类的语言,例如中文、英语等,处理特指使用计算机技术处理,所以自然语言处理就是指使用计算机处理人类的语言。自然语言处理的英语是Natural Language Processing,通常缩写为NLP。

自然语言处理是语言学、计算机科学、信息工程和人工智能的交叉领域,涉及的内容非常广泛。人类的语言本身是复杂的,所以自然语言处理的任务也是多种多样的。

注意:自然语言严格地说是指自然演化形成的语言,如中文等。非自然语言的例子有程序设计语言,如C语言、Python等。虽然世界语也是一种人类的语言,但它是人工设计而非自然演化而成的,严格地说并不算自然语言。

1.1.2 常用术语

自然语言处理中的常用术语如下。

语料:语言材料,如百科知识类网站的所有词条可以构成一个语料库。

自然语言:自然演化形成的人类语言。

形式化语言:用数学方法精确定义的语言,如计算机程序设计语言。

分词:把一个句子分解为多个词语。

词频:一个词在一定范围的语料中出现的次数。

机器学习(Machine Learning):通过特定算法和程序让计算机从数据中自主学习知识。

深度学习(Deep Learning):使用深度神经网络的机器学习方法。

人工神经网络(Artificial Neural Network):简称为神经网络,是一种模拟人脑神经元处理信息的过程的模型。

训练模型:在训练过程中模型使用学习型算法,根据训练数据更新自身参数,从而更好地解决问题。

监督学习(Supervised Learning):使用有标签的数据对模型进行训练,即训练过程中既给模型提供用于解决问题的信息和线索,也给模型提供问题的标准答案(就是数据的标签),模型可以根据标准答案修正自身参数。

无监督学习(Unsupervised Learning):使用没有标签的数据对模型进行训练,因为只有解决问题的信息,而没有标准答案,一般可以根据某些人为设定的规则评估模型效果的好坏。

1.1.3 自然语言处理的任务

广义地说,自然语言处理包含对各种形式的自然语言的处理,如语音识别、光学字符识别(即识别图像中的文字);还包括理解文字的含义,如自然语言理解;还可能需要让机器有自己组织语言的能力,即自然语言生成;甚至还要输出这些语言,例如语音合成等。

一些智能音箱可以根据用户语音指令执行特定的操作。首先用户发出指令,比如用户说:“今天出门需要带雨伞吗?”智能音箱的麦克风接收到声音信号后,先要找到语音对应的字,理解这些字的含义,然后要想如何回答用户的问题,最终知道问题的关键是确认今天的天气——虽然这句话里没有出现“天气”二字。

最后智能音箱查到今天没有雨雪,需要给用户回复,于是它生成一句话:“今天天气不错,不需要带伞。”接下来,它通过语音合成算法把这句话变成比较自然的声音传递给用户。

本书只会涉及从文字含义的理解到生成回复句子的过程。

笼统地说,本书中探讨的自然语言处理的任务有两个:语言理解和语言生成。

处理的对象可分为3种:词语/字、句子、篇章。

具体地说,比较常见的自然语言处理的任务有如下4类。

序列标注:给句子或者篇章中的每个词或字一个标签,如分词(把一句话分割成多个词语,相当于给序列中的每个字标记“是否是词的边界”)、词性标注(标出句子中每个词语的属性)等。

文本分类:给每个句子或篇章一个标签,如情感分析(区分正面评价和负面评价,区分讽刺语气和正常语气)等。

关系判断:判断多个词语、句子、篇章之间的关系,如选词填空等。

语言生成:产生自然语言的字、词、句子、篇章等,如问答系统、机器翻译等。

1.1.4 自然语言处理的发展历程

1950年艾伦·图灵(Alan Turing,1912—1954)发表论文Computing Machinery and Intelligence(计算机器与智能),文中提出了判断机器是否有智能的试验——“图灵测试”。简单说,图灵测试就是测试者通过工具,如键盘,与他看不到的一个人和一个机器分别聊天,如果测试者无法通过聊天判断这两者哪个是机器,这个机器就通过了测试。

注意:图灵测试的要求超出了自然语言处理的范围,要想让计算机完成图灵测试,仅让其能理解自然语言是不够的,还需要让其了解人类的特点和各种常识性知识,例如测试者可能会提出多个复杂的数学问题,如果计算机快速给出了精准答案,那么虽然它完成了任务,却会因此被识破身份。

第12.3.6小节中介绍了文章Giving GPT-3 a Turing Test中提到的对GPT-3模型(2020年5月被提出)进行的图灵测试,GPT-3模型被认为拥有与人脑相同数量级规模的神经元,也拥有与人脑类似的表示能力。

GPT-3模型能使用自然语言准确回答很多不同种类的简单的常识性问题(甚至很多普通人也无法准确记忆的问题),但是对于一些人们一眼就能发现,并且可以灵活处理的明显不合理的问题,而GPT-3模型却给出了机械、刻板的答案。

1.基于规则的方法

早期自然语言处理依赖人工设定的规则,语言学家研究语言本身的规律,把归纳好的规则编写成程序,告诉计算机应该怎么做。1954年乔治城大学(又译为乔治敦大学)和IBM公司进行了一次试验,他们编写了一个有6条语法规则和包含250个词汇项的词典的翻译系统,把经过挑选的60多条俄语句子翻译成了英语。结果,他们的程序只能对特定的句子给出好的结果,因为简单的规则和有限的词汇无法适应多变的自然语言。

2.经验主义和理性主义

对于语言规则的研究,有经验主义和理性主义,可以笼统地认为经验主义主张通过观察得到规律,理性主义则主张要通过推理而不是观察得出规律。

经验主义的工作有:1913年马尔可夫(Markov,1856—1922)使用手动方法统计了普希金的作品《叶甫盖尼·奥涅金》中元音和辅音出现的频次,提出马尔可夫随机过程理论。1948年香农(Shannon,1916—2001)发表论文A Mathematical Theory of Communication,标志着信息论诞生。

理性主义的工作有:乔姆斯基(Chomsky,1928—)使用理性主义的方法研究语言学,也就是使用形式化规则而不是统计规律来定义语言模型。

3.机器学习方法

随着数据的积累和计算机性能的提高,基于概率与统计的机器学习和深度学习方法在自然语言处理领域的表现越来越好。

2013年谷歌(Google)公司的技术团队发表Word2vec模型,其可以从语料中自主学习得出每个词语的向量表示,也就是把每个词语表示成一个固定维度的向量,这样的向量不仅便于在计算机中存储和处理,还能通过向量间的数学关系反映词语之间的语义关系。

2014年Google公司发表论文提出Seq2seq模型,其在机器翻译领域的性能明显超过传统模型。

2018年Google公司发表BERT(Bidirectional Encoder Representations from Transformers)模型,其在多种自然语言处理的任务上刷新了最好成绩。

1.2 自然语言处理中的挑战

自然语言处理工作是困难的,因为自然语言灵活多样,没有明确的规则和边界,而且自然语言会随着时间而发生变化,新的词语和表达方式也可能不断出现。

1.2.1 歧义问题

自然语言中存在大量的歧义现象。同样的文字可能有不同的含义,反过来,同样的意思也可以用完全不同的文字来表达。歧义可以出现对词的不同的理解上,例如句子“他介绍了他们公司自动化所取得的成就”。这里对“自动化所”可以有不同的理解,可以把“自动化所”看成他们公司的一个部门,“所”是名词;或者“所”可以做介词,该句表示他们公司通过自动化取得了成就。单看这个句子,我们无法确定“自动化所”是一个词,还是两个词。

还有指代的歧义,如“小明做了好事,老师表扬了小明,他很高兴”,“他”可以指小明也可以指老师。

实际上人们在理解句子的时候会选择自己认为更合理的意思,有一些句子虽然可以有两种意思,但是根据经验我们可以判断其确切的含义。

1.2.2 语言的多样性

自然语言中,完全相同的意思可以用截然不同的方式表达,所以自然语言处理的方法不仅要能适应自然语言的多样性,还要使输出的内容多样而自然。

1.2.3 未登录词

自然语言中随时都可能有新词汇和新用法出现,很多自然语言处理的方法依赖预先定义或者在学习、训练中生成的词表。未登录词就是指此词表中不存在的词语,或者训练过程中未出现过的词语。因为缺乏这些词的信息,所以处理未登录词或原有词汇的新用法是困难的。

常见未登录词的来源有派生词、命名实体(人名、地名等)、新定义等。

1.2.4 数据稀疏

语料中,除了少数常用词汇出现的频次较高,还有很多不常用的词汇,虽然这些不常用的词汇的数量多,但是单个词汇出现的次数较少。

哈佛大学的乔治·金斯利·齐夫(George Kingsley Zipf,1902—1950)通过研究自然语言语料库中单词出现频率的规律提出了齐夫定律(Zipf's Law),说明了在自然语言的语料库中,单词出现的频率和它在词表中位次的关系。

我们统计了某一版本的鲁迅作品集中每个字出现的频率,该作品集中共有180万个字符,除去标点符号、空格、换行符等,共有6024个字,表1.1展示了其中出现次数排名前10的字。

表1.1 出现次数排名前10的字

从表1.1中可以看出,出现得最多的字是“的”,有近6万次;出现得第二多的“是”字,仅有不到3万次,大概是“的”字的一半。而出现频次最少的838个字都仅出现过1次,另外还有459个字只出现过2次,301个字只出现过3次。所以说实际上有大量的字出现的次数是极少的,在自然语言的语料库中,对于出现次数少的字我们只能获得较少的信息,但是这些字点体数量很多。图1.1展示了出现次数排名前100的字出现次数的分布。

图1.1 出现次数排名前100的字出现次数的分布(单位:次)

表1.1和图1.1是使用下面的代码得到的,该代码可以统计任意文本文件中字符出现的次数。

from collections import Counter  # Counter 可用来统计可迭代对象中元素的数量
f = open('corpus.txt', encoding='utf8')  # encoding 要使用和这个文件对应的编码
txt = f.read()  # 读取全部字符
f.close()

cnt = Counter(txt)  # 得到每个字符的出现次数
char_list = []  # 定义空的列表
for char in cnt:
   if char in "\u3000\n 。,:!!“?…”《》,;—()-:?^~`[]|":  # 过滤常见的标点符号、空格等
       continue
   char_list.append([cnt[char], char])  # 把字符和字符出现的次数加入列表

char_list.sort(reverse=True)  # 降序排列
# 输出出现次数排名前100的字符和出现次数
for char in char_list:
   print(char[0], char[1])
# 使用 Matplotlib 库绘制出现次数排名前100的字符的出现次数分布图,安装库的方法见第2章
from matplotlib import pyplot as plt
x = []
y = []
for i, char_cnt in enumerate(char_list):
   x.append(i)
   y.append(char_cnt[0])
plt.axis((0,100, 0, 60000))
plt.bar(x[:100], y[:100], width=1)
plt.show()

注意:这段代码中的Matplotlib库用于绘图,需要手动安装,安装和配置环境的方法见第2章。

1.3 自然语言处理中的常用技术

本节将简要介绍一些自然语言处理中常用的技术,包括一些经典方法,其中一些方法的具体实现和使用将在后面章节中详细介绍。

1.TF-IDF

词频-逆文本频率(Term Frequency-Inverse Document Frequency TF-IDF)用于评估一个词在一定范围的语料中的重要程度。

词频指一个词在一定范围的语料中出现的次数,这个词在某语料中出现的次数越多说明它越重要,但是这个词有可能是“的”“了”这样的在所有语料中出现次数都很多的词。所以又出现了逆文本频率,就是这个词在某个语料里出现了,但是在整个语料库中出现得很少,就能说明这个词在这个语料中重要。

2.词嵌入

词嵌入(Word Embedding)就是用向量表示词语。在文字处理软件中,字符往往用一个数字编码表示,如ASCII中大写字母A用65表示、B用66表示。做自然语言处理任务时我们需要用计算机能理解的符号表示字或词,但问题是词语的数量很多,而且词语之间是有语义关系的,单纯地用数字编号难以表达这种复杂的语义关系。

词嵌入就是使用多维向量表示一个词语,这样词语间的关系可以用向量间的关系来反映。词嵌入需要用特定的算法,可在语料库上训练得到。第8章将介绍多种词嵌入的方法。

3.分词

分词是指把句子划分为词语序列,如句子“今天天气不错”可划分为“今天/天气/不错”,共3个词语。

英文的分词很简单,因为英文的单词本身就是用空格隔开的。但中文分词比较困难,甚至不同分词方案可以让句子表现出不同的含义,还有的句子有不止一种分词方法,但是可以表达相同的意思。第6章将介绍分词问题。

4.循环神经网络

循环神经网络(Recurrent Neural Network,RNN)模型是用于处理序列数据的神经网络,它可以处理不定长度的数据。因为自然语言处理过程中我们常常把句子经过分词变成一个序列,而实际中的句子长短各异,所以适合用RNN模型处理。

RNN模型也可以用于生成不定长或定长数据。第7章将介绍RNN模型。

5.Seq2seq

Seq2seq(Sequence to sequence),即序列到序列,是一种输入和输出都是不定长序列的模型,可以用于机器翻译、问答系统等。第9章将介绍Seq2seq模型。

6.注意力机制

注意力机制(Attention Mechanism)是自然语言处理领域乃至深度学习领域中十分重要的技术。

注意力机制源于人们对人类视觉机制的研究。人类观察事物时,会把注意力分配到关键的地方,而相对忽视其他细节。在自然语言处理中可以认为,如果使用了注意力机制,模型会给重要的词语分配更高的权重,或者把句子中某些关系密切的词语关联起来共同考虑。图1.2展示的是一种可能的注意力分配的可视化效果,字的背景颜色越深说明其权重越高。

图1.2 一种可能的注意力分配的可视化效果[1]


[1] 实现该可视化效果的代码来自开源项目:Text-Attention-Heatmap-Visualization。

第10章将介绍注意力机制。

7.预训练

预训练是一种迁移学习方法。如BERT模型就是预训练模型,BERT会先在一个大规模的语料库(例如维基百科语料库)上训练,训练时使用的任务是特别设定的,一般是一些比较通用的任务,以得到一个预训练权重,这个权重也是比较通用的。BERT在实际中可以应用于不同的场景和任务,既可以用于文本分类,也可以用于序列标注,但是在实际应用之前要在预训练的基础上,使用相应场景的数据和任务进行第二次训练。

这样做的好处是预训练使用了较大规模的语料,模型可以对当前语言有更全面的学习,在特定场景和进行特定数据训练时,可以使用更小的数据集和进行更少的训练得到相对好的结果。第12章将介绍预训练语言模型。

8.多模态学习

多模态(Multimodal)学习指模型可以同时处理相关的不同形式的信息,常见的有视觉信息和文字信息,如同时处理图片和图片的描述的模型。多模态学习有很长的历史,近年来随着深度学习和预训练模型的发展,多模态学习取得了很大的进步。

很多问题单靠文字一种信息比较难解决,但如果能结合其他信息,如视觉信息等,可以帮助模型很好地解决问题。另外,结合不同来源的信息可以设计出有多种功能的模型,如根据文字描述检索视频图片的模型等。这不仅需要模型能够掌握每个模态的特征,还需要建立它们之间的联系。

早期的多模态学习主要应用在视听语音识别领域,可以提高语音识别的准确率;后来应用在多媒体内容的检索方面,如根据文字内容在图片集中搜索符合文字描述的图片。对于视频和文本对齐,如提出“BookCorpus”数据集的论文Aligning Books and Movies: Towards Story-like Visual Explanations by Watching Movies and Reading Books中的模型,则实现了将书中的文字内容和电影对齐的工作,该模型既要理解电影中的视觉内容,又要理解书中的文字描述,最后还要把二者对应起来。

还有看图回答问题数据集,如“Visual QA”数据集;结合图文信息判断作者立场数据集,如“多模态反讽检测数据集”,可以应用于公开社交网络的舆情检测。

1.4 机器学习中的常见问题

本节介绍机器学习中的常见问题,因为目前自然语言处理中广泛应用了机器学习,所以这些问题在自然语言的实践中十分关键。

1.4.1 Batch和Epoch

Batch指每次更新模型参数时所使用或依据的一批数据。训练模型使用的方法被称为梯度下降(Gradient Descent),即把一批数据输入模型求出损失,计算参数的导数,然后根据学习率朝梯度下降的方向整体更新参数,这一批数据就是Batch。

训练模型时常常要考虑Batch Size,即每次使用多少数据更新模型参数。传统机器学习使用Batch Gradient Descent(BGD)方法,每次使用全部数据集上的数据计算梯度。这种方法可以参考第4.6节中的逻辑回归的例子,就是每次遍历全部数据再更新参数。

深度学习中常用的是随机梯度下降(Stochastic Gradient Descent, SGD)方法,每次随机选取一部分数据训练模型。本书中的许多例子使用了该方法。

Epoch则指一个训练的轮次,一般每个轮次都会遍历整个数据集。每个轮次可能会使用多个Batch进行训练。

1.4.2 Batch Size的选择

Batch Size不能太小,否则会导致有的模型无法收敛,而且选择大的Batch Size可以提高模型训练时的并行性能,前提是系统拥有足够的并行资源。

但Batch Size不是越大越好。论文Revisiting Small Batch Training for Deep Neural Networks指出,在很多问题上,能得到最佳效果的Batch Size在2到32之间。但最佳的Batch Size并不总是固定的,有时候可能需要通过尝试和对比来获得。

设置大的Batch Size需要系统资源充足。系统的计算能力达到上限后继续增加Batch Size无助于提高并行性能。在GPU上训练时,需要把同一个Batch的数据同时载入显存,如果GPU剩余显存不足可能导致无法训练。

如果显存资源不够,但又需要使用较大的Batch Size,可以使用梯度累积,即每执行N次模型后更新一次模型参数,这相当于实际上的Batch Size是设定的N倍,但无法提高并行性能。

1.4.3 数据集不平衡问题

很多时候我们可能会遇到数据集中的数据分布不均匀的问题。比如分类问题,有的类别的数据可能出现得很少,另一些类别却出现得很多。数据不平衡的情况下模型可能会更倾向于数据中出现次数多的类别。

解决的方案有很多,比如可以通过采样的方法从数据上改善这个问题,把出现得少的数据复制多份以补充这些类别;或者可以从出现次数多的类别中随机抽取部分数据进行训练。

另外可以通过focal loss、weighted cross、entropy loss等特殊的损失函数帮助模型更“平等”地对待各个类别。

针对二分类问题,如果数据分布极不均衡,可以把出现得少的一个类别视为异常数据,通过异常检测的算法处理。

1.4.4 预训练模型与数据安全

2020年12月在arXiv.org上预发表的论文Extracting Training Data from Large Language Models提出了关于预训练模型泄露预训练数据的问题。很多预训练模型的训练数据集是私有的,这些数据可能是通过爬虫爬取的互联网上的信息,也可能是某些系统内部的数据,均可能包含一些隐私信息。上述论文证明了在某些情况下,用特定的方式可以还原出一些预训练时使用的数据。

该论文中实现了从GPT-2模型中提取出几百个原始的文本序列,其中包括姓名、电话号码、电子邮件等内容。

该论文给出的一些例子也提出了降低这些问题影响的建议。

1.4.5 通过开源代码学习

GitHub上有大量与自然语言处理(NLP)相关的开源代码。本书也会介绍到很多开源项目,很多常见工具甚至PyTorch本身也是开源的。

一些组织的GitHub开源如下。

OpenAI

Microsoft

Google Research

PyTorch

Hugging Face

清华大学NLP实验室

北京大学语言计算与机器学习组

一些有用的开源项目如下。

funNLP:自然语言处理工具和数据集的整理,包括中/英文敏感词、语言检测、多种词库、繁简转换等多种功能。

HanLP:提供中文的分词、词性标注、句法分析等多种功能。

中文词向量:提供在多个不同语料库中(如百度百科、维基百科、知乎、微博、《人民日报》等)使用多种方法训练的词向量。

中文GPT-2。

UER-py:通用编码表示(Universal Encoder Representations,UER)是一套用于预训练和Fine-tuning(将在12.1.2节中介绍)的工具。

1.5 小结

本章主要介绍了自然语言处理的概念、任务、挑战和常用方法与工具,让读者对自然语言处理有一个大致的认识。本章中提到的很多经典方法此处了解即可,而很多机器学习尤其是深度学习的方法,后面的章节将结合PyTorch详细介绍其基本原理、实现和应用。

读者服务:

微信扫码关注【异步社区】微信公众号,回复“e59525”获取本书配套资源以及异步社区15天VIP会员卡,近千本电子书免费畅读。