分类 深度学习 下的文章

NLTK工具集

数据集

  • WordNet : 包含同义词、释义、例句等
  • SentiWordNet : Senti=Sentiment
  • Wikipedia
  • Common Crawl
  • PB 级别,7 年爬虫我的妈,使用 Facebook 的 CC-Net 工具进行处理
  • Hugging Face Datasets

Wikipedia 数据集使用方法

语料处理方法

纯文本语料抽取

pip install wikiextractor
python -m wikiextractor.WikiExtractor
python -m wikiextractor.WikiExtractor -h

中文简繁体切换

我们使用 OpenCC : 甚至可以转换日本新体字等中文字体

pip install opencc
python convert_t2s.py input_file > output_file

数据清洗

包括:删除空的成对符号,删除除了 外残留 html 标签,删除不可见控制字符等

<span class="ne-text">python wikidata_cleaning.py input_file > output_file</span>

Hugging Face Datasets 使用方法

数据集获取

<span class="ne-text">pip install datasets</span>

调用dataset

from datasets import list_datasets, load_dataset
import pprint

# dataset loading
datasets_list = list_datasets()
print(len(datasets_list))  # num_datasets
dataset = load_dataset('sst', split='train')  # load SST (Stanford Sentiment Treebank)
print(len(dataset))  # num_samples
pprint(dataset[0])  # {'label':xxx, 'sentence':xxx, 'tokens':xxx, 'tree':xxx}

调用 metrics

from datasets import list_metrics, load_metric

# metrics
metrics_list = list_metrics()
print(len(metrics_list))  # num_metrics
accuracy_metric = load_metric('accuracy')
results = accuracy_metric.compute(references= [0, 1, 0], predictions= [1, 1, 0])
print(results)  # {'accuracy': 0.6666666}

书名:自然语言处理:基于预训练模型的方法

文本的表示

独热编码表示

独热编码,就是使用一个词表的大小的向量表示一个词的“语义”,然后第i个词用wi表示。词表中第i个词在第i维上被设置为1,其余维均为0。

词的分布式表示

由于用独热编码表示词汇导致数据过于稀疏和庞大。因此John RupertFirth于1957年提出了分布式语义假设:词的含义可由其上下文的分布进行表示。

我们将以词为单位的其它词语作为上下文,因此创建下列共现频次表。

除了词,上下文的选择有很多种方式,而选择不同的上下文得到的词向量表示性质会有所不同。例如,可以使用词在句子中的一个固定窗口内的词作为其上下文,也可以使用所在的文档本身作为上下文。前者得到的词表示将更多地反映词的局部性质:具有相似词法、句法属性的词将会具有相似的向量表示。而后者将更多地反映词代表的主题信息。

直接使用与上下文的共现频次作为词的向量表示,至少存在以下三个问题:

  • 高频词往往没有什么作用,反而会影响计算机国。如"我" "。"的共现频次很高,实际上可能它们并没有关系但由于共现过,从而产生了较高的相似度。
  • 共现频次无法反映词之前的高阶关系。假设词“A”与“B”共现过,“B”与“C”共现过,“C”与“D”共现过,通过共现频次,只能获知“A”与“C”都与“B”共现过,它们之间存在一定的关系,而“A”与“D”这种高阶的关系则无法知晓。
  • 仍然存在稀疏性的问题。即向量中仍有大量的值为0

解决高频词误导计算结果的问题

点互信息

由于共矩阵仍然存在稀疏性的问题。即向量中仍有大量的值为0。最直接的想法就是:如果一个词与很多词共现,则降低其权重;反之,如果一个词只与个别词共现,则提高其权重。信息论中的点互信息(Pointwise Mutual Information,PMI)恰好能够做到这一点。

对于词w和上下文c,其PMI为:

式中,P (w, c)、P (w)、P (c)分别是w与c的共现概率,以及w和c分别出现的概率。可见,通过PMI公式计算,如果w和c的共现概率(与频次正相关)较高,但是w或者c出现的概率也较高(高频词),则最终的PMI值会变小;反之,即便w和c的共现概率不高,但是w或者c出现的概率较低(低频词),则最终的PMI值也可能会比较大。从而较好地解决高频词误导计算结果的问题。

当某个词与上下文之间共现次数较低时,可能会得到负的PMI值。考虑到这种情况下的PMI不太稳定(具有较大的方差),在实际应用中通常采用PPMI (Positive PMI)的形式,即:

奇异值分解

解决共现频次无法反映词之间高阶关系的问题。相关的技术有很多,对共现矩阵M进行奇异值分解。

词的分布式表示取得了不错的效果,但是其仍然存在一些问题。

  • 当共现矩阵规模较大时,奇异值分解的运行速度非常慢;
  • 如果想在原来语料库的基础上增加更多的数据,则需要重新运行奇异值分解算法,代价非常高;
  • 分布式表示只能用于表示比较短的单元,如词或短语等,如果待表示的单元比较长,如段落、句子等,由于与其共现的上下文会非常少,则无法获得有效的分布式表示;
  • 最后,分布式表示一旦训练完成,则无法修改,也就是说,无法根据具体的任务调整其表示方式。为了解决这些问题,可引入一种新的词表示方式——词嵌入表示。

词嵌入表示(Word Embedding)

使用一个连续、低维、稠密的向量来表示词,经常直接简称为词向量

词向量中的向量值,是随着目标任务的优化过程自动调整的,也就是说,可以将词向量中的向量值看作模型的参数

词袋表示

所谓词袋表示,就是假设文本中的词语是没有顺序的集合,将文本中的全部词所对应的向量表示(既可以是独热表示,也可以是分布式表示或词向量)相加,即构成了文本的向量表示。如在使用独热表示时,文本向量表示的每一维恰好是相应的词在文本中出现的次数。

nlp任务

语言模型(统计语言模型)

N元语言模型

基本任务是在给定词序列w1w2··· wt−1的条件下,对下一时刻t可能出现的词wt的条件概率P (wt|w1w2···wt−1)进行估计。一般地,把w1w2··· wt−1称为wt的历史。

随着句子长度增加,w1:i−1出现的次数会越来越少,甚至从未出现过,那么P (wi|w1:i−1)则很可能为0,此时对于概率估计就没有意义了。为了解决该问题,可以假设“下一个词出现的概率只依赖于它前面n−1个词”。

马尔可夫假设

  1. N-gram :N 元语言模型
  • 马尔可夫假设 :
  • 满足该假设称为:N元语法或文法(gram)模型
  • n=1 的 unigram 独立于历史(之前的序列),因此语序无关
  • n=2 的 bigram 也被称为一阶马尔可夫链
  • w0 可以是 可以是
  1. 平滑: 解决未登录词 (OOV, Out-Of-Vocabulary, )的零概率问题
  • 折扣法 :高频补低频(频繁出现的N-gram中匀出一部分概率并分配给低频次(含零频次)的N-gram)
  • 加1平滑 :拉普拉斯平滑

对于unigram:

对于biggram:

也可以使用 +δ 平滑,尤其当训练数据较小时,加一太大了

关于 δ 选择,可以使用验证集对不同值的困惑度比较选择最优参数

  1. 模型评价

1.外部任务评价:计算代价高,实现的难度较大

2.内部评价方法: 基于困惑度 (Perplexity, PPL) ,越小越好

: 测试集到每个词的概率的几何平均值的倒数

测试集到每个词这里针对一个句子而言:我们的目标是使测试集中的所有句子 PPL 最小。

困惑度越低的语言模型并不总是能在外部任务上取得更好的性能指标,但是两者之间通常呈现出一定的正相关性。应用在下游任务之后,关键要看具体任务上的表现。

基础任务

中文分词

  • 正向最多匹配算法(FMM),找当前最长词
  • 可能会造成切分歧义问题:如“哈尔滨市”可以是一个词,也可以认为“哈尔滨”是一个词,“市”是一个词。
  • 未登录词的问题比例更高:未登录词指不在词典中,但是必须要分出来的词

字词切分:词形还原(Lemmatization)或者词干提取(Stemming)

词形还原指的是将变形的词语转换为原形,如将“computing”还原为“compute”;

词干提取则是将前缀、后缀等去掉,保留词干(Stem),如“computing”的词干为“comput”,可见,词干提取的结果可能不是一个完整的单词。

  • 解决数据稀疏问题和大词表问题
  • 传统方法需要大量规则,因此:基于统计的无监督方法(使用尽量长且频次高的子词)
  • 字节对编码 (BPE)生成子词词表,然后使用贪心算法;可以使用缓存算法加快速度
  • WordPiece: 比对BPE, 不过 BPE 选频次最高对,WordPiece 选提升语言模型概率最大对。
  • Unigram Language Model (ULM) : 比对WordPiece, 不同的是,它基于减量法

SentencePiece 开源工具用于子词切分,通过将句子看做 Unicode ,从而能够处理多种语言

词性标注

词性标注(POS Tagging)任务是指给定一个句子,输出句子中每个词相应的词性。

例如,当输入句子为:"他 喜欢 下 象棋"

输出:他/PN 喜欢/VV 下/VV 象棋/NN 。/PU

斜杠后面的PN、VV、NN和PU分别代表代词、动词、名词和标点符号

难点在于歧义性,即一个词在不同的上下文中可能有不同的词性。例如,上例中的“下”,既可以表示动词,也可以表示方位词。因此,需要结合上下文确定词在句子中的具体词性。

句法分析

句法分析(Syntactic Parsing)的主要目标是给定一个句子,分析句子的句法成分信息,例如主谓宾定状补等成分。

最终的目标是将词序列表示的句子转换成树状结构,从而有助于更准确地理解句子的含义,并辅助下游自然语言处理任务

  • 树状结构的主谓宾定状补等
  • 两种句法结构表示:不同点在于依托的文法规则不同

    • 短语结构句法表示:上下文无关文法,层次性的表示法
    • 依存结构句法表示 (DSP):依托依存文法规则

语义分析

词义消歧WSD

从词语的粒度考虑,一个词语可能具有多种语义(词义),例如“打”,含义即可能是“攻击”(如“打人”),还可能是“玩”(如“打篮球”),甚至“编织”(如“打毛衣”)等。根据词语出现的不同上下文,确定其具体含义的自然语言处理任务被称为词义消歧(Word SenseDisambiguation,WSD)。可以使用 WordNet 等语义词典

语义角色标注 SRL : 谓词论元结构

识别谓词后找到论元(语义角色)(施事 Agent 受事 Patient)

附加语义角色: 状语、副词等

语义依存分析SDP:通用图

  • 语义依存图:词作为节点,词词关系作为语义关系边
  • 概念语义图:首先将句子转化为虚拟的概念节点,然后建立语义关系边

专门任务:如自然语言转 SQL

应用任务

信息抽取(Information Extraction,IE)

信息抽取 ,定义:从非结构化的文本中自动提取结构化信息的过程,另外还可以将抽取的记过作为新的知识加入知识库中。

命名实体识别(Information Extraction,IE)

定义:在文本中抽取每个提及的命名实体并标注其类型,一般包括人名、地名和机构名等,也包括专有名称等,如书名、电影名和药物名等。然后往往需要将命名实体链接到知识库或者知识图谱中的具体实体,被称作 实体链接

如“华盛顿”既可以指美国首任总统,也可以指美国首都,需要根据上下文进行判断,这一过程类似于词义消歧任务。

关系抽取(Relation Extraction)

定义:用于识别和分类文本中提及的实体之间的语义关系,如夫妻、子女、工作单位和地理空间上的位置关系等二元关系。

事件抽取(Event Extraction)

从文本中识别人们感兴趣的事件以及事件所涉及的时间、地点和人物等关键元素。事件往往使用文本中提及的具体触发词(Trigger)定义,解析时间、地点、人物等关键因素。

时间表达式(Temporal Expression)

事件发生的时间往往比较关键,通常时间表达式识别被认为是重要的信息抽取子任务。

绝对时间:日期、星期、月份和节假日等

相对时间:明天、两年前等

~SRL : 谓词~Trigger, 论元~事件元素

假设下列句子进行信息抽取

信息抽取结果

情感分析

  1. 情感分类(识别文本中蕴含的情感类型或者情感强度,其中,文本既可以是句子,也可以是篇章)
  2. 情感信息抽取(抽取文本中的情感元素,如评价词语、评价对象和评价搭配等)

如图中用户评论

情感分析结果如下:

问答系统(Question Answering,QA)

系统接收用户以自然语言形式描述问题,并从异构数据中通过检索、匹配和推理等技术获得答案的自然语言处理系统。

根据数据来源的不同,问答系统可以分为4种主要的类型:

  • 检索式:答案来源于归哪个的文本预料库,系统查找相关文档抽取答案并完成回答
  • 知识库:问题→结构化查询语句 →结构化知识存储→推理→答案
  • 常见问题集:对历史积累的常见问题集检索,回答用户提出的类似问题
  • 阅读理解式:抽取给定文档中片段或生成

机器翻译(Machine Translation,MT)

  • 任意时间
  • 任意地点
  • 任意语言

对话系统

用户与计算机通过多轮交互的方式实现特定目标的智能系统。

  1. 任务型:垂直领域的自动业务经理,具有明确的任务目标,如完成机票预订、天气查询等特定的任务。

自然语言理解→对话管理→自然语言生成

NLU : 领域(什么东西)、意图(要干什么)、槽值(?=?)等

DM : 对话状态跟踪 DST 和对话策略优化 DPO,对话状态往往表示为槽值列表

NLG : 有了 DPO 后比较简单,只需要套用问题模板即可

  1. 开放域:聊天系统或者聊天机器人

基本问题

文本分类问题

定义:针对一段文本输入,输出该文本所属的类别

  1. 文本匹配(Text Matching),即判断两段输入文本之间的匹配关系,包括复述关系(Paraphrasing:判断两个表述不同的文本语义是否相同)
  2. 蕴含关系(Entailment:根据一个前提文本,推断与假设文本之间的蕴含或矛盾关系)等。一种转换的方法是将两段文本直接拼接起来,然后按复述或非复述、蕴含或矛盾等关系分类。

结构预测问题

序列标注(Sqquence Labeling)

为输入文本序列中的每个词标注相应的标签,如词性标注是为每个词标注一个词性标签,包括名词、动词和形容词等。其中,输入词和输出标签数目相同且一一对应。

序列标注问题可以简单地看成多个独立的文本分类问题,即针对每个词提取特征,然后进行标签分类,并不考虑输出标签之间的关系。

  1. CRF模型:最广泛应用的序列标注模型,他不仅考虑每个词属于某一标签的概率(发射概率),还考虑标签之间的相互关系(转移概率)。

  1. RNN(循环神经网络)+CRF(条件随机场)

序列分割

  • 分词、NER 等
  • 也可以看成序列标注

NER : B-xxx 表示开始,I-xxx 表示中间,O-xxx 表示非实体

分词同理

图结构生成

  1. 基于图的算法:最小生成树,最小子图等
  2. 基于转移的算法:图→ 状态转移序列,状态→策略→动作等。

使用序列标注方法解决序列分割(分词和命名实体识别)

如用于 DSP 的 标准弧转移算法

转移状态由一个栈和队列组成, 栈存依存结构子树序列,队列存未处理的词

初始转移状态:栈为空

转移动作:

  • 移进 Shift (SH) : 将队列中的第一个元素移入栈顶,形成一个仅包含一个节点的依存子树
  • 左弧归约 Reduce Left (RL) : 将栈顶的两棵依存子树采用一个左弧S1↶S0进行合并,然后S1下栈;
  • 将栈顶的两棵依存子树采用一个右弧S1↷S0进行合并,然后S0下栈。
  • 完成 FIN

弧上的句法关系可以在生成弧的时候(即 RR 或 RL)采用额外的句法关系分类器加以预测

该算法也可以用于短语结构的句法分析方法

面向依存句法分析的标准弧转移算法中的三种动作

序列到序列问题

Encoder-Decoder架构

评价指标

准确率(Accuracy)

最简单、直观的评价指标,经常被应用于文本分类等问题。其计算公式为:

词性标注等序列标注问题也可以采用准确率进行评价,即:

并非全部的序列标注问题都可以采用准确率进行评价,如在将分词、命名实体识别等序列分割问题转化为序列标注问题后,就不应该使用准确率进行评价。

命名实体识别,序列标注的输出标签可以为一个实体的开始(B-XXX)、中间(I-XXX)或者非实体(O)等,其中B代表开始(Begin)、I代表中间(Inside),O代表其他(Other),XXX代表实体的类型,如人名(PER)、地名(LOC)和机构名(ORG)等

F -score

  1. Ner中:

  1. 在句法依存树中:
  • UAS :(unlabeled attachment score): 即准确率,父节点被正确识别的概率
  • LAS :父节点被正确识别且与父节点的关系也正确的概率
  1. 在 Semantic Dependency Graph :多个父节点不能用上述
  • F-score : 图中的弧为单位,计算识别的精确率和召回率
  • 可分为考虑和不考虑语义关系两种情况
  1. 在短语结构句法分析中:也不能用准确率
  • F-score : 句法结构中包含短语的 F 值进行评价
  • 包含短语:包括短语类型以及短语所覆盖的范围

侧边栏倒计时

  <h5 class="widget-title m-t-none text-md">    
   <svg t="1629119495433" class="icon" viewbox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7053" width="30" height="30">
    <path d="M961.468008 336.875396l-8.529899-1.963525 1.969706-8.509296c12.698012-54.853022-33.927984-105.255662-88.723316-97.727098-44.483219 6.113095-77.504644 30.413006-107.305722 63.399404H480.282785V660.016419h139.296966c12.689771 55.143533 62.18173 112.170237 95.267026 142.941746 79.754559 74.18334 161.639533 20.475879 159.276297-47.029827l-0.304933-8.725634 8.750358-0.304933c86.809239-3.024612 132.423598-135.51208-38.883155-207.657723 45.888386-3.997103 91.81798-17.867461 122.105304-36.744499 18.43406-11.486519 33.482946-26.331429 44.852024-43.240821 30.77769-45.779187 5.878213-109.701924-49.174664-122.379332z" fill="#FFB5C0" p-id="7054"></path>
    <path d="M756.398101 129.489642c-24.361722-49.477537-98.285457-59.929755-136.81835-18.71633-38.532893-41.211364-112.456628-30.759147-136.818351 18.71633-22.258093 45.204346-17.490414 114.06371-2.480676 162.585239-29.801078-32.986398-62.824563-57.28631-107.305722-63.399404-54.795332-7.528563-101.421328 42.874076-88.723316 97.727098l1.969706 8.509296-8.529899 1.963525c-55.052877 12.675348-79.952354 76.598085-49.172604 122.377272 11.369078 16.909392 26.417964 31.754302 44.852024 43.240821 30.287324 18.877038 76.214857 32.747396 122.105304 36.744499-171.306753 72.143581-125.692394 204.633111-38.883155 207.657722l8.750359 0.304934-0.304934 8.725634c-2.363235 67.505706 79.521738 121.213167 159.276298 47.029827 33.085296-30.773569 82.577256-87.800274 95.267026-142.941747-3.805489-15.221956-3.490254-69.683509-5.157087-85.123863l81.400789-220.780169 63.053264-62.035445c15.009738-48.521529 19.775356-117.378833-2.480676-162.585239z" fill="#FF8E9E" p-id="7055"></path>
    <path d="M695.825513 354.110326h-82.463936l1.063147 220.780169c2.060362 0.103018-2.085087 0 0 0 68.274221 0 128.778817-55.190922 128.778817-123.467203-0.00206-39.503324-18.535018-74.681948-47.378028-97.312966z" fill="#FFDBE0" p-id="7056"></path>
    <path d="M619.579751 327.803622c-68.274221 0-123.62173 55.347509-123.621731 123.62173 0 66.189135 53.081111 120.226254 118.464644 123.467203 0-82.449513 19.622889-163.454712 81.400789-220.780169a123.077795 123.077795 0 0 0-76.243702-26.308764z" fill="#FFB5C0" p-id="7057"></path>
    <path d="M456.835863 451.425352a247.793577 247.793577 0 0 0-60.992901-7.588314c-107.734278 0-199.368885 68.855243-233.346318 164.952596v0.010302C73.950519 609.974342 0 682.309537 0 773.779316c0 91.111276 73.859863 164.969078 164.971139 164.969078h351.034205V510.594833z" fill="#D4D4FF" p-id="7058"></path>
    <path d="M643.265674 691.286535c-0.006181-115.870648-79.445505-212.728274-186.429811-239.861183-107.132652 27.200901-186.388604 124.276926-186.388603 239.871485 0 136.035412 109.765795 246.419316 245.558084 247.453618h127.629135c68.333972 0 123.728869-55.394897 123.728869-123.728869-0.00206-69.228169-56.579606-124.095614-124.097674-123.735051z" fill="#EFEDFF" p-id="7059"></path>
    <path d="M178.046197 749.17035a61.810865 44.297787 0 1 0 123.621731 0 61.810865 44.297787 0 1 0-123.621731 0Z" fill="#FF8E9E" p-id="7060"></path>
    <path d="M495.341972 749.17035a61.810865 44.297787 0 1 0 123.62173 0 61.810865 44.297787 0 1 0-123.62173 0Z" fill="#FF8E9E" p-id="7061"></path>
    <path d="M269.839453 666.003831a15.452716 15.452716 0 0 0-15.452717 15.452716v24.724346c0 8.53608 6.918696 15.452716 15.452717 15.452717s15.452716-6.916636 15.452716-15.452717v-24.724346a15.452716 15.452716 0 0 0-15.452716-15.452716zM527.172507 666.003831a15.452716 15.452716 0 0 0-15.452716 15.452716v24.724346c0 8.53608 6.918696 15.452716 15.452716 15.452717s15.452716-6.916636 15.452716-15.452717v-24.724346a15.452716 15.452716 0 0 0-15.452716-15.452716zM442.580217 693.796056a15.452716 15.452716 0 0 0-21.802752 1.497884 29.545594 29.545594 0 0 1-22.272515 10.153464 29.549714 29.549714 0 0 1-22.274576-10.153464 15.452716 15.452716 0 1 0-23.298575 20.304869c11.494761 13.188378 28.1054 20.751968 45.57109 20.751968s34.07633-7.56359 45.571091-20.751968a15.450656 15.450656 0 0 0-1.493763-21.802753z" fill="#313D40" p-id="7062"></path>
   </svg>2024年毕业时间:</h5>  
  <center>
   <img src="https://www.ilfishs.com/littlefish/sclool_logo.png" weight="130" height="60" />
  </center> 
  <style>  .gn_box{     border: none;     border-radius: 10px; }  .gn_box {     padding: 8px 10px;     margin: 8px;     margin-bottom: 15px;     text-align: center;     background-color: ; }  #t_d{     color: grey;     font-size: 18px; }  #t_h{     color: grey;     font-size: 18px; }  #t_m{     color: grey;     font-size: 18px; }  #t_s{     color: grey;     font-size: 18px; }  </style> 
  <div class="gn_box"> 
   <h3>距2024年毕业还有</h3>
   <center> 
    <div id="CountMsg" class="HotDate">
     <span id="t_d"> 天</span>
     <span id="t_h"> 时</span>
     <span id="t_m"> 分</span>
     <span id="t_s"> 秒</span>
    </div>
   </center> 
   <script type="text/javascript">  function getRTime() {        var EndTime = new Date('2024/07/01 00:09:00');       var NowTime = new Date();       var t = EndTime.getTime() - NowTime.getTime();              var d = Math.floor(t / 1000 / 60 / 60 / 24);              var h = Math.floor(t / 1000 / 60 / 60 % 24);              var m = Math.floor(t / 1000 / 60 % 60);              var s = Math.floor(t / 1000 % 60);      var day = document.getElementById("t_d");     if (day != null) {         day.innerHTML = d + " 天";        }     var hour = document.getElementById("t_h");     if (hour != null) {         hour.innerHTML = h + " 时";       }     var min = document.getElementById("t_m");     if (min != null) {         min.innerHTML = m + " 分";        }     var sec = document.getElementById("t_s");     if (sec != null) {         sec.innerHTML = s + " 秒";     } }      setInterval(getRTime, 1000);      </script> 
  </div> 

将代码上传至component/sidebar.php中下列代码之后

<div id="sidebar">
         <?php if (@!in_array('column', Utils::checkArray($this->options->sidebarSetting))): ?>

给handsome文章页添加版权信息

在handsome 主题后台提供 CSS 代码的编辑中,在 设置外观 -> 开发者设置 -> 自定义CSS 对话框中加入以下代码即可!

/*版权信息&正文结束分割线 CSS*/
.cutline {
    border-top: 1px dotted #ccc;
    height: 1px;
    margin: 20px 0;
    text-align: center;
    width: 100%;
}
.cutline span {
    background-color: rgb(236, 237, 238);
    border: 1px solid #d6d6d6;
    font: 12px Arial,Microsoft JhengHei;
    padding: 2px 4px;
    position: relative;
    top: -10px;
}
.post-copyright {
    font-size: 13px;
    margin: 8px 0;
    padding: 10px;
    border-left: 4px solid #ff5252;
    background-color: rgba(220, 220, 220, 0.1);
    list-style: none;
    word-break: break-all;
    position: relative;
    overflow: hidden;
}
.post-copyright li {
    display: list-item;
    text-align: -webkit-match-parent;
}
.post-copyright a {
    color: rgba(0, 120, 231, 1);
    text-decoration: none;
    transition: color .1s;
}

首页头像呼吸灯加自动旋转

/*首页头像呼吸灯自动旋转*/
.avatar {
    width: 100px;
    border-radius: 50%;
    animation: light 4s ease-in-out infinite;
    transition: 0.5s;
}

.avatar:hover {
    transform: scale(1.15) rotate(720deg);
}
@keyframes light {
    0% {
        box-shadow: 0 0 4px #f00;
    }

    25% {
        box-shadow: 0 0 16px #0f0;
    }

    50% {
        box-shadow: 0 0 4px #00f;
    }

    75% {
        box-shadow: 0 0 16px #0f0;
    }

    100% {
        box-shadow: 0 0 4px #f00;
    }
}

打赏图标浮动

.btn-pay {
    animation: star 0.5s ease-in-out infinite alternate;
}

@keyframes star {
    from {
        transform: scale(1);
    }

    to {
        transform: scale(1.1);
    }
}

创建 Field 对象

Field这个对象包含了我们打算如何预处理文本数据的信息。 下面定义了两个 **Field 对象。

TEXT = data.Field(sequential=True, # 是否把数据表示成序列,如果是False, 不能使用分词 默认值: True.
                  tokenize=rumor_tokenize,# 分词函数
                  fix_length=max_length,#截断的长度
                  use_vocab=True)

LABEL = data.Field(sequential=False,
                   use_vocab=False)

如果LABEL是整型,不需要numericalize, 就需要将use_vocab=False.Torchtext可能也会允许使用 text 作为 label,但是现在我还没有用到。

torch text实践过程图

加载语料库

然后我们可以通过 torchtext.data.Dataset 的类方法 splits 加载所有的语料库:(假设我们有三个语料库,train.tsv, val.tsv, test.tsv)

train, dev, test = data.TabularDataset.splits(path=os.path.join(data_path,task_name),#数据集存放路径
                                              train=train_file,
                                              validation=valid_file,
                                              test=test_file,
                                              format='csv', #csv/json
                                              skip_header=True, # 跳过表头
                                              csv_reader_params={'delimiter':','}, #用/t分割
                                              fields=[("text",TEXT),('label',LABEL)])

然后构建语料库的 Vocabulary, 同时,加载预训练的 word-embedding

导入预训练词向量

# 导入预训练词向量
if load_embedding == "None":
    TEXT.build_vocab(train)
elif load_embedding == "w2v":
    cache = '.vector_cache'
    if not os.path.exists(cache):
        os.mkdir(cache)
    vectors = Vectors(name=w2v_file,cache=cache)
    TEXT.build_vocab(train, vectors=vectors)
elif load_embedding == "glove":
    cache = '.vector_cache'
    if not os.path.exists(cache):
        os.mkdir(cache)
    vectors = Vectors(name=glove_file, cache=cache)
    TEXT.build_vocab(train, vectors=vectors)
elif load_embedding == "weibo_biggram":
    cache = '.vector_cache'
    vectors = Vectors(name=weibo_file, cache=cache)
    TEXT.build_vocab(train,max_size=5000,vectors=vectors)
  
    #TEXT.bulid_vocab(train_data,max_size=10000) #将词汇表中频率前10000的单词取出来
    #TEXT.bulid_vocab(train_data,min_freq=10) #将词汇表中频率大于等于10的单词取出来
else:
    TEXT.build_vocab(train)

通过api来创建iterator

我们可以直接传一个 string,然后后端会下载 word vectors 并且加载她。我们也可以通过 vocab.Vectors 使用自定义的 vectors.

train_iter, val_iter, test_iter = data.Iterator.splits(
        (train, val, test), sort_key=lambda x: len(x.Text),
        batch_sizes=(32, 256, 256), device=-1)

batch = next(iter(train_iter))
print("batch text: ", batch.Text) # 对应 Fileld 的 name
print("batch label: ", batch.Label)
"""
BucketIterator为了使padding最少,会在batch之前先对整个dataset上的cases进行sort(按一定规则),
将相近长度的case放在一起,这样一个batch中的cases长度相当,使得padding的个数最小。
同时,为了每次能生成稍微不同的batch,在sort之前加入了noise进行长度的干扰。
"""
train_iter, val_iter, test_iter = data.BucketIterator.splits((train,dev,test),
                                                             batch_size = batch_size,
                                                             shuffle=True,
                                                             sort=False,
                                                             sort_within_batch=False,
                                                             repeat=False)
  • 如果您要运行在 CPU 上,需要设置 device=-1, 如果运行在GPU 上,需要设置device=0
  • torchtext 使用了动态 padding,意味着 batch内的所有句子会 padbatch 内最长的句子长度。
  • batch.Textbatch.Label 都是 torch.LongTensor 类型的值,保存的都是 index。

获得word vocab

我们使用 Pytorch 的 Embedding Layer 来解决 embedding lookup 问题。

Vocab = len(DataSet.getTEXT().vocab)
self.embed = nn.Embedding(Vocab, Dim)  ## 词向量,这里直接随机
# 指定嵌入矩阵的初始权重 ****
if load_embedding == "w2v":
    weight_matrix = DataSet.getTEXT().vocab.vectors
    self.embedding.weight.data.copy_(weight_matrix)
elif load_embedding == "glove":
    weight_matrix = DataSet.getTEXT().vocab.vectors
    self.embedding.weight.data.copy_(weight_matrix)
elif load_embedding == "weibo_biggram":
    weight_matrix = DataSet.getTEXT().vocab.vectors
    self.embedding.weight.data.copy_(weight_matrix)

为什么使用 Field 抽象

torchtext 认为一个样本是由多个字段(文本字段,标签字段)组成,不同的字段可能会有不同的处理方式,所以才会有 Field 抽象。

  • Field: 定义对应字段的处理操作
  • Vocab: 定义了 词汇表
  • Vectors: 用来保存预训练好的 word vectors

<span class="ne-text">TEXT.build_vocab(train, vectors="glove.6B.100d")</span>

上述代码的意思是从预训练的 vectors 中,将当前 corpus 词汇表的词向量抽取出来,构成当前 corpus 的 Vocab(词汇表)。

其它

希望迭代器返回固定长度的文本

  • 设置Fieldfix_length属性

在创建字典时, 希望仅仅保存出现频率最高的 k 个单词

  • .build_vocab时使用max_size参数指定

如何指定 Vector 缺失值的初始化方式

  • vector.unk_init = init.xavier_uniform 这种方式指定完再传入 build_vocab

参考链接

[1] https://blog.csdn.net/dendi_hust/article/details/101221922

[2] http://anie.me/On-Torchtext/

[3] https://www.yuque.com/cqustkg/lnznt6/ka69ua

一、为什么要有 Transformer?

为什么要有 Transformer? 首先需要知道在 Transformer 之前都有哪些技术,这些技术所存在的问题:

  • RNN:能够捕获长距离依赖信息,但是无法并行;
  • CNN: 能够并行,无法捕获长距离依赖信息(需要通过层叠 or 扩张卷积核 来 增大感受野);
  • 传统 Attention

    • 方法:基于源端和目标端的隐向量计算Attention,
    • 结果:源端每个词与目标端每个词间的依赖关系 【源端->目标端】
    • 问题:忽略了 远端或目标端 词与词间 的依赖关系

二、Transformer 作用是什么?

基于Transformer的架构主要用于建模语言理解任务,它避免了在神经网络中使用递归,而是完全依赖于self-attention机制来绘制输入和输出之间的全局依赖关系。

三、Transformer 整体结构怎么样?

  1. 整体结构
  • Transformer 整体结构:

    • encoder-decoder 结构
  • 具体介绍:

    • 左边是一个 Encoder;
    • 右边是一个 Decoder;

此次是图片,手机可能打不开

  1. 整体结构放大一点

从上一张 Transformer 结构图,可以知道 Transformer 是一个 encoder-decoder 结构,但是 encoder 和 decoder 又包含什么内容呢?

  • Encoder 结构:

    • 内部包含6层小encoder 每一层里面有2个子层;
  • Decoder 结构:

    • 内部也是包含6层小decoder ,每一层里面有3个子层

此次是图片,手机可能打不开

  1. 整体结构再放大一点

其中上图中每一层的内部结构如下图所求。

  • 上图左边的每一层encoder都是下图左边的结构;
  • 上图右边的每一层的decoder都是下图右边的结构;

具体内容,后面会逐一介绍。

此次是图片,手机可能打不开

四、Transformer-encoder 结构怎么样?

此次是图片,手机可能打不开

  • 特点:

    • 与 RNN,CNN 类似,可以当成一个特征提取器;
  • 组成结构介绍

    • embedding 层:将 input 转化为 embedding 向量 $X$;
    • Position encodding: input的位置与 input 的 embedding $X$ 相加 得到 向量 $X$;
    • self-attention : 将融合input的位置信息 与 input 的 embedding 信息的 $X$ 输入 Self-Attention 层得到 $Z$;
    • 残差网络:$Z$ 与 $X$ 相加后经过 layernorm 层;
    • 前馈网络:经过一层前馈网络以及 Add&Normalize,(线性转换+relu+线性转换 如下式)

此次是图片,手机可能打不开

  • 举例说明(假设序列长度固定,如100,如输入的序列是“我爱中国”):

    • 首先需要 encoding

      • 将词映射成一个数字,encoding后,由于序列不足固定长度,因此需要padding,
      • 然后输入 embedding层,假设embedding的维度是128,则输入的序列维度就是100*128;
    • 接着是 Position encodding ,论文中是直接将每个位置通过cos-sin函数进行映射;

      • 分析:这部分不需要在网络中进行训练,因为它是固定。但现在很多论文是将这块也embedding,如bert的模型,至于是encoding还是embedding可取决于语料的大小,语料足够大就用embedding。将位置信息也映射到128维与上一步的embedding相加,输出100*128
    • 经过 self-attention层

      • 操作:假设v的向量最后一维是64维(假设没有多头),该部分输出100*64;
    • 经过残差网络:

      • 操作:即序列的embedding向量与上一步self-attention的向量加总;
    • 经过 layer-norm

      • 原因:

        • 由于在self-attention里面更好操作而已;
        • 真实序列的长度一直在变化;
    • 经过 前馈网络

      • 目的:增加非线性的表达能力,毕竟之前的结构基本都是简单的矩阵乘法。若前馈网络的隐向量是512维,则结构最后输出100*512;

五、Transformer-decoder 结构怎么样?

此次是图片,手机可能打不开

  • 特点:与 encoder 类似
  • 组成结构介绍

    • masked 层:

      • 目的:确保了位置 i 的预测仅依赖于小于 i 的位置处的已知输出;
    • Linear layer:

      • 目的:将由解码器堆栈产生的向量投影到一个更大的向量中,称为对数向量。这个向量对应着模型的输出词汇表;向量中的每个值,对应着词汇表中每个单词的得分;
    • softmax层:

      • 操作:这些分数转换为概率(所有正数,都加起来为1.0)。选择具有最高概率的单元,并且将与其相关联的单词作为该时间步的输出

六、传统 attention 是什么?

此次是图片,手机可能打不开

  • 注意力机制是什么呢?

    • 就是将精力集中于某一个点上
    • 举个例子:

      • 你在超市买东西,突然一个美女从你身边走过,这个时候你会做什么呢?
      • 没错,就是将视线【也就是注意力】集中于这个美女身上,而周围环境怎么样,你都不关注。
  • 思路

    • 输入 给定 Target 中某个 query;
    • 计算权值 Score:

      • 计算 query 和 各个 Key 的相似度或相关性,得到每个 Key 对应 value 的权值系数;
    • 对 权值 Score 和 value 进行加权求和
  • 核心:

    • Attention 机制 是对 source 中各个元素 的 value 进行加权求和,而 query 和 key 用于计算 对应 value 的权值系数

此次是图片,手机可能打不开

$L_x=||Source||$代表Source的长度
  • 概念:

    • attention 的核心 就是从 大量信息中 筛选出少量的 重要信息;
    • 具体操作:每个 value 的 权值系数,代表 其 重要度;

此次是图片,手机可能打不开

  • 具体流程介绍

    • step 1:计算权值系数

      • 采用 不同的函数或计算方式,对 query 和 key 进行计算,求出相似度或相关性
      • 采用的计算方法:

        • 向量点积:

        • Cosine 相似度计算:

        • MLP 网络:

    • step 2: softmax 归一化

      • 原因:

        1. score 值分布过散,将原始计算分值整理成所有元素权重之和为1 的概率分布;
        2. 可以通过SoftMax的内在机制更加突出重要元素的权重;
      • 公式介绍

      此次是图片,手机可能打不开

    • step 3: 加权求和

      • 公式介绍:

        • 计算结果 $a_i$ 即为 $value_i$ 对应的权重系数,然后进行加权求和即可得到Attention数值

此次是图片,手机可能打不开

  • 存在问题

    • 忽略了 源端或目标端 词与词间 的依赖关系【以上面栗子为例,就是把注意力集中于美女身上,而没看自己周围环境,结果可能就扑街了!】

七、self-attention 长怎么样?

  • 动机

    • CNN 所存在的长距离依赖问题;
    • RNN 所存在的无法并行化问题【虽然能够在一定长度上缓解 长距离依赖问题】;
  • 传统 Attention

    • 方法:基于源端和目标端的隐向量计算Attention,
    • 结果:源端每个词与目标端每个词间的依赖关系 【源端->目标端】
    • 问题:忽略了 远端或目标端 词与词间 的依赖关系
  • 核心思想:self-attention的结构在计算每个token时,总是会考虑整个序列其他token的表达;

    • 举例:“我爱中国”这个序列,在计算"我"这个词的时候,不但会考虑词本身的embedding,也同时会考虑其他词对这个词的影响
  • 目的:学习句子内部的词依赖关系,捕获句子的内部结构。

此次是图片,手机可能打不开

此次是图片,手机可能打不开

  • 步骤

    • embedding层:

      • 目的:将词转化成embedding向量;
    • Q,K,V 向量计算:

      • 根据 embedding 和权重矩阵,得到Q,K,V;

        • Q:查询向量,目标字作为 Query;
        • K:键向量,其上下文的各个字作为 Key;
        • V:值向量,上下文各个字的 Value;
    • 权重 score 计算:

      • 查询向量 query 点乘 key;
      • 目的:计算其他词对这个词的重要性,也就是权值;
    • scale 操作:

      • 乘以 $\frac{1}{\sqrt{d_{k}}}$;
      • 目的:起到调节作用,使得内积不至于太大。实际上是Q,K,V的最后一个维度,当 $d_k$ 越大, $QK^T$ 就越大,可能会将 Softmax 函数推入梯度极小的区域;
    • Softmax 归一化:

      • 经过 Softmax 归一化;
    • Attention 的输出计算:

      • 权值 score 和各个上下文字的 V 向量 的加权求和
      • 目的:把上下文各个字的 V 融入目标字的原始 V 中
  • 举例

    • 答案就是文章中的Q,K,V,这三个向量都可以表示"我"这个词,但每个向量的作用并不一样,Q 代表 query,当计算"我"这个词时,它就能代表"我"去和其他词的 K 进行点乘计算其他词对这个词的重要性,所以此时其他词(包括自己)使用 K 也就是 key 代表自己,当计算完点乘后,我们只是得到了每个词对“我”这个词的权重,需要再乘以一个其他词(包括自己)的向量,也就是V(value),才完成"我"这个词的计算,同时也是完成了用其他词来表征"我"的一个过程
  • 优点

    • 捕获源端和目标端词与词间的依赖关系
    • 捕获源端或目标端自身词与词间的依赖关系

八、self-attention 如何解决长距离依赖问题?

  • 引言:

    • 在上一个问题中,我们提到 CNN 和 RNN 在处理长序列时,都存在 长距离依赖问题,那么你是否会有这样 几个问题:

      • 长距离依赖问题 是什么呢?
      • 为什么 CNN 和 RNN 无法解决长距离依赖问题?
      • 之前提出过哪些解决方法?
      • self-attention 是如何 解决 长距离依赖问题的呢?

下面,我们将会围绕着几个问题,进行一一解答。

  • 长距离依赖问题 是什么呢?

    • 介绍:对于序列问题,第 $t$ 时刻 的 输出 $y_t$ 依赖于 $t$ 之前的输入,也就是 说 依赖于 $x_{t-k}, k=1,...,t$,当间隔 $k$ 逐渐增大时,$x_{t-k}$ 的信息将难以被 $y_t$ 所学习到,也就是说,很难建立 这种 长距离依赖关系,这个也就是 长距离依赖问题(Long-Term Dependencies Problem)。
  • 为什么 CNN 和 RNN 无法解决长距离依赖问题?

    • CNN:

      • 捕获信息的方式:

        • CNN 主要采用 卷积核 的 方式捕获 句子内的局部信息,你可以把他理解为 基于 n-gram 的局部编码方式捕获局部信息
      • 问题:

        • 因为是 n-gram 的局部编码方式,那么当 $k$ 距离 大于 $n$ 时,那么 $y_t$ 将难以学习 $x_{t-k}$ 信息;
      • 举例:

        • 其实 n-gram 类似于 人的 视觉范围,人的视觉范围 在每一时刻 只能 捕获 一定 范围内 的信息,比如,你在看前面的时候,你是不可能注意到背后发生了什么,除非你转过身往后看。
    • RNN:

      • 捕获信息的方式:

        • RNN 主要 通过 循环 的方式学习(记忆) 之前的信息$x_{t}$;
      • 问题:

        • 但是随着时间 $t$ 的推移,你会出现梯度消失或梯度爆炸问题,这种问题使你只能建立短距离依赖信息。
      • 举例:

        • RNN 的学习模式好比于 人类 的记忆力,人类可能会对 短距离内发生的 事情特别清楚,但是随着时间的推移,人类开始 会对 好久之前所发生的事情变得印象模糊,比如,你对小时候发生的事情,印象模糊一样。
      • 解决方法:

        • 针对该问题,后期也提出了很多 RNN 变体,比如 LSTM、 GRU,这些变体 通过引入 门控的机制 来 有选择性 的记忆 一些 重要的信息,但是这种方法 也只能在 一定程度上缓解 长距离依赖问题,但是并不能 从根本上解决问题。

此次是图片,手机可能打不开

  • 之前提出过哪些解决方法?

    • 引言:

      • 那么 之前 主要采用 什么方法 解决问题呢?
    • 解决方法:

      • 增加网络的层数

        • 通过一个深层网络来获取远距离的信息交互
      • 使用全连接网络

        • 通过全连接的方法对 长距离 建模;
        • 问题:

          • 无法处理变长的输入序列;
          • 不同的输入长度,其连接权重的大小也是不同的;

此次是图片,手机可能打不开

  • self-attention 是如何 解决 长距离依赖问题的呢?

    • 解决方式:

      • 利用注意力机制来“动态”地生成不同连接的权重,从而处理变长的信息序列
    • 具体介绍:

      • 对于 当前query,你需要 与 句子中 所有 key 进行点乘后再 Softmax ,以获得 句子中 所有 key 对于 当前query 的 score(可以理解为 贡献度),然后与 所有词 的 value 向量进行加权融合之后,就能使 当前 $y_t$ 学习到句子中 其他词$x_{t-k}$的信息;

九、self-attention 如何并行化?

  • 引言:

    • 在上一个问题中,我们主要讨论了 CNN 和 RNN 在处理长序列时,都存在 长距离依赖问题,以及 Transformer 是 如何解决 长距离依赖问题,但是对于 RNN ,还存在另外一个问题:

      • 无法并行化问题
    • 那么,Transformer 是如何进行并行化的呢?
  • Transformer 如何进行并行化?

    • 核心:self-attention
    • 为什么 RNN 不能并行化:

      • 原因:RNN 在 计算 $x_i$ 的时候,需要考虑到 $x_1 ~ x_{i-1}$ 的 信息,使得 RNN 只能 从 $x_1$ 计算到 $x_i$;
    • 思路:

      • 在 self-attention 能够 并行的 计算 句子中不同 的 query,因为每个 query 之间并不存在 先后依赖关系,也使得 transformer 能够并行化;

十、multi-head attention 怎么解?

  • 思路:

    • 相当于 $h$ 个 不同的 self-attention 的集成
    • 就是把self-attention做 n 次,取决于 head 的个数;论文里面是做了8次。
  • 步骤:

    • step 1 : 初始化 N 组 $Q,K,V$矩阵(论文为 8组);

此次是图片,手机可能打不开

  • step 2 : 每组 分别 进行 self-attention;
  • step 3:

    • 问题:多个 self-attention 会得到 多个 矩阵,但是前馈神经网络没法输入8个矩阵;
    • 目标:把8个矩阵降为1个
    • 步骤:

      • 每次self-attention都会得到一个 Z 矩阵,把每个 Z 矩阵拼接起来,
      • 再乘以一个Wo矩阵,
      • 得到一个最终的矩阵,即 multi-head Attention 的结果;

此次是图片,手机可能打不开

最后,让我们来看一下完整的流程:

此次是图片,手机可能打不开

换一种表现方式:

此次是图片,手机可能打不开

  • 动图介绍

此次是图片,手机可能打不开

十一、为什么要 加入 position embedding ?

  • 问题:

    • 介绍:缺乏 一种 表示 输入序列中 单词顺序 的方法
    • 说明:因为模型不包括Recurrence/Convolution,因此是无法捕捉到序列顺序信息的,例如将K、V按行进行打乱,那么Attention之后的结果是一样的。但是序列信息非常重要,代表着全局的结构,因此必须将序列的分词相对或者绝对position信息利用起来
  • 目的:加入词序信息,使 Attention 能够分辨出不同位置的词
  • 思路:

    • 在 encoder 层和 decoder 层的输入添加了一个额外的向量Positional Encoding,维度和embedding的维度一样,让模型学习到这个值
  • 位置向量的作用:

    • 决定当前词的位置;
    • 计算在一个句子中不同的词之间的距离
  • 步骤:

    • 将每个位置编号,
    • 然后每个编号对应一个向量,
    • 通过将位置向量和词向量相加,就给每个词都引入了一定的位置信息。

此次是图片,手机可能打不开

  • 论文的位置编码是使用三角函数去计算的。好处:

    • 值域只有[-1,1]
    • 容易计算相对位置。

此次是图片,手机可能打不开

注:

$pos$ 表示当前词在句子中的位置

$i$ 表示向量中每个值 的 index

在偶数位置:使用 正弦编码 $sin()$;

在奇数位置:使用 余弦编码 $cos()$;

十二、为什么要 加入 残差模块?

  • 动机:因为 transformer 堆叠了 很多层,容易 梯度消失或者梯度爆炸

十三、Layer normalization。Normalization 是什么?

  • 动机:因为 transformer 堆叠了 很多层,容易 梯度消失或者梯度爆炸;
  • 原因:

    • 数据经过该网络层的作用后,不再是归一化,偏差会越来越大,所以需要将 数据 重新 做归一化处理;
  • 目的:

    • 在数据送入激活函数之前进行normalization(归一化)之前,需要将输入的信息利用 normalization 转化成均值为0方差为1的数据,避免因输入数据落在激活函数的饱和区而出现 梯度消失或者梯度爆炸 问题
  • 介绍:

    • 归一化的一种方式
    • 对每一个样本介绍均值和方差【这个与 BN 有所不同,因为他是在 批方向上 计算均值和方差】
  • 公式
BN 计算公式

此次是图片,手机可能打不开

LN 计算公式

此次是图片,手机可能打不开

十四、什么是 Mask?

  • 介绍:掩盖某些值的信息,让模型信息不到该信息;
  • 类别:padding mask and sequence mask

    • padding mask

      • 作用域:每一个 scaled dot-product attention 中
      • 动机:

        • 输入句子的长度不一问题
      • 方法:

        • 短句子:后面 采用 0 填充
        • 长句子:只截取 左边 部分内容,其他的丢弃
      • 原因:

        • 对于 填充 的位置,其所包含的信息量 对于 模型学习 作用不大,所以 self-attention 应该 抛弃对这些位置 进行学习;
      • 做法:

        • 在这些位置上加上 一个 非常大 的负数(负无穷),使 该位置的值经过 Softmax 后,值近似 0,利用 padding mask 标记哪些值需要做处理;
    • sequence mask

      • 作用域:只作用于 decoder 的 self-attention 中
      • 动机:不可预测性;
      • 目标:sequence mask 是为了使得 decoder 不能看见未来的信息。也就是对于一个序列,在 time_step 为 t 的时刻,我们的解码输出应该只能依赖于 t 时刻之前的输出,而不能依赖 t 之后的输出。因此我们需要想一个办法,把 t 之后的信息给隐藏起来。
      • 做法:

        • 产生一个下三角矩阵,上三角的值全为0,下三角全是 1。把这个矩阵作用在每一个序列上,就可以达到我们的目的

sequence mask 公式

注意力矩阵, 每个元素 $a_{ij}$ 代表 第 i 个词和第 j 个词的内积相似度

下三角矩阵,上三角的值全为0,下三角全是 1

注:

在 decoder 的 scaled dot-product attention 中,里面的 attn_mask = padding mask + sequence mask

在 encoder 的 scaled dot-product attention 中,里面的 attn_mask = padding mask

十五、Transformer 存在问题?

  • 引言

    • 居然 Transformer 怎么厉害,那么 是否也存在不足呢?
    • 答案: 有的
  • 问题一:不能很好的处理超长输入问题?

    • 介绍:Transformer 固定了句子长度;
    • 举例:

      • 例如 在 Bert 里面,输入句子的默认长度 为 512;
    • 对于长度长短问题,做了以下处理:

      • 短于 512:填充句子方式;
      • 长于 512:

        • 处理方式一:截断句子方式(Transformer 处理方式);
        • 处理方式二:将句子划分为 多个 seg (Vanilla Transformer 处理方式);

          • 思路:

            • 将文本划分为多个segments;
            • 训练的时候,对每个segment单独处理;
          • 问题:

            • 因为 segments 之间独立训练,所以不同的token之间,最长的依赖关系,就取决于segment的长度 (如图(a));
            • 出于效率的考虑,在划分segments的时候,不考虑句子的自然边界,而是根据固定的长度来划分序列,导致分割出来的segments在语义上是不完整的 (如图(a));
            • 在预测的时候,会对固定长度的 segment 做计算,一般取最后一个位置的隐向量作为输出。为了充分利用上下文关系,在每做完一次预测之后,就对整个序列向右移动一个位置,再做一次计算,这导致计算效率非常低 (如图(b));

        此次是图片,手机可能打不开

        • 处理方式三:Segment-Level Recurrenc ( Transformer-XL 处理方式);

          • 思路:

            • 在对当前segment进行处理的时候,缓存并利用上一个segment中所有layer的隐向量序列;
            • 上一个segment的所有隐向量序列只参与前向计算,不再进行反向传播;

此次是图片,手机可能打不开

  • 问题二:方向信息以及相对位置 的 缺失 问题?

    • 动机:

      • 方向信息和位置信息的缺失,导致 Transformer 在 NLP 中表现性能较差,例如在 命名实体识别任务中;

        • 举例:

          • 如下图,“Inc”单词之前的词很有可能就是机构组织(ORG),“in”单词之后的词,很有可能是时间地点(TIME);并且一个实体应该是连续的单词组成,标红的“Louis Vuitton”不会和标蓝的“Inc”组成一个实体。但是原始的Transformer无法捕获这些信息。

此次是图片,手机可能打不开

  • 解决方法:

  • 问题三:缺少Recurrent Inductive Bias

    • 动机:

      • 学习算法中Inductive Bias可以用来预测从未遇到的输入的输出(参考[10])。对于很多序列建模任务(如需要对输入的层次结构进行建模时,或者在训练和推理期间输入长度的分布不同时),Recurrent Inductive Bias至关重要【可以看论文The Importance of Being Recurrent for Modeling Hierarchical Structure
  • 问题四:Transformer是非图灵完备的: 非图灵完备通俗的理解,就是无法解决所有的问题

    • 动机:

      • 在Transformer中,单层中sequential operation (context two symbols需要的操作数)是$O(1)$ time,独立于输入序列的长度。那么总的sequenctial operation仅由层数$T$决定。这意味着transformer不能在计算上通用,即无法处理某些输入。如:输入是一个需要对每个输入元素进行顺序处理的函数,在这种情况下,对于任意给定的深度$T$的transformer,都可以构造一个长度为 $N>T$;
  • 问题五:transformer缺少conditional computation

    • 动机:

      • transformer在encoder的过程中,所有输入元素都有相同的计算量,比如对于“I arrived at the bank after crossing the river", 和"river"相比,需要更多的背景知识来推断单词"bank"的含义,然而transformer在编码这个句子的时候,无条件对于每个单词应用相同的计算量,这样的过程显然是低效的。
  • 问题六:transformer 时间复杂度 和 空间复杂度 过大问题

    • 动机:

      • Transformer 中用到的自注意力与长度n呈现出$O(n^2)$的时间和空间复杂度
    • 解决方法:

十六、Transformer 怎么 Coding?