Jiahong的个人博客

凡事预则立不预则废


  • Home

  • Tags

  • Archives

  • Search

Linux——rpm和deb包的区别

Posted on 2019-02-17

Linux系统管理之rpm命令的使用


帮助信息

  • 执行man rpm可获取rpm命令的详细帮助信息

Centos

  • yum是用于安装和管理RPM包的
  • RPM包是一种预先在linux机器上被打包好的文件,文件后缀为.rpm,类似于Ubuntu上的deb

yum和rpm的区别

  • yum和rpm都是管理RPM包的
  • yum可以联网下载需要的RPM包
  • yum自己可以处理依赖

Centos安装deb包

  • 安装alien

    1
    2
    3
    4
    5
    6
    7
    # download alien source code
    # uncompress source code
    tar -zxvf alien_x.xx.tar.gz
    cd alien
    # compile
    make
    make install
  • 转换deb包为rpm包

    1
    2
    # generate a rpm package with name xxx.rpm
    alien -r xxx.deb
  • 安装rpm包

    1
    rpm -ivh xxx.rpm

Ubuntu

  • apt-get是用于管理deb包的

Ubuntu上安装rpm包

  • 安装alien

    1
    sudo apt-get install alien
  • 转换

    1
    2
    # generate a deb package with name xxx.deb
    sudo alien xxx.rpm
  • 安装包

    1
    sudo dpkg -i xxx.deb
  • 说明

    • 不是所有的RPM包都能通过alien成功转换成deb包并成功安装的,能找到deb包的最好使用deb包安装

总结

  • Ubuntu使用deb包(apt-get, dpkg),Centos使用RPM包(yum, rpm)
  • deb包和RPM包可互相转换(使用alien包转换即可)

DL——BERT

Posted on 2019-02-09
  • 参考博客:
    • 从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史
    • BERT详解
  • BERT论文: BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding

BERT之前

Word2Vec的缺点

  • 多义词问题: 传统的Word Embedding无法识别多义词
    • 确切的说是所有词的固定表征的方式(静态方式)的缺点
    • 所谓静态指的是训练好之后每个单词的表达就固定住了

从Word Embedding到ELMo

ELMo, Embedding from Language Models
根据当前上下文对Word Embedding动态调整的思路

  • ELMo 论文原文: NAACL 2018 Best Paper, Deep contextualized word representations
  • ELMo的本质思想:
    • 事先用语言模型学好一个单词的Word Embedding,此时多义词无法区分
    • 实际使用Word Embedding的时候,单词已经具备了特定的上下文了,这个时候我可以根据上下文单词的语义去调整单词的Word Embedding表示
    • 这样经过调整后的Word Embedding更能表达在这个上下文中的具体含义,自然也就解决了多义词的问题了
  • ELMo是典型的两阶段训练过程: 预训练 + 特征融合?
    • 第一个阶段是利用语言模型进行预训练
    • 第二阶段通过基于特征融合的方式训练
  • ELMo预训练过程示意图
  • ELMo预训练后如何处理下游任务?
    • 预训练训练完成后, 模型训练时使用在线特征抽取,和特征集成的方式对词向量在不同的上下文中进行不同的修正,从而区分多义词
补充知识: 下游任务

下游任务包括很多, 整体上可以分为四大类

序列标注
  • 分词
  • POS Tag
  • NER
  • 语义标注
  • …
分类任务
  • 文本分类
  • 情感计算
  • …
句子关系判断
  • Entailment
  • QA
  • 自然语言推理
  • …
机器翻译
  • 机器翻译
  • 文本摘要
  • …
预训练模型
  • 预训练模型是什么?
    • 预训练模型是指在训练结束是结果比较好的一组权重值,研究人员分享出来供他人使用,基于这些预训练好的权重可以提升我们的模型训练速度和精度
    • 预训练模型能够成功的本质是我们假设预训练模型足够好, 能学到句子的所有信息(包括序列信息等)
  • 两阶段预训练模型如何处理下游任务?
    • 预训练与下游任务无关
      • 预训练阶段是预训练模型自己选择相应的NLP任务,然后让模型在学习处理这些任务的途中实现参数的训练
      • 比如BERT选择的就是MLM(屏蔽语言模型)和NSP(Next Sentence Predition, 下一个句子预测)两个任务来做预训练
    • 不同的下游任务往往需要修改第二阶段中的模型结构等
    • 为适应不同的下游任务, 第二阶段可能使用不同结构, 比如添加Softmax层等方式
ELMo的优缺点
  • 优点:
    • 很好的解决了多义词问题,而且效果非常好
    • 采用上下文来训练词(从上下文预测单词, 上文称为Context-before, 下文称为Context-after)
  • 缺点:
    • 特征提取器没有使用新贵Transformer, 而是传统的LSTM, 特征抽取能力不足

从Word Embedding到GPT

GPT, Generative Pre-Training

  • ELMo的训练方法和图像领域的预训练方法对比,模式不同, ELMo使用的是基于特征融合的预训练方法
  • GPT使用的预训练方法则是在NLP领域开创了和图像领域一致的预训练方法基于Fine-tuning的模式
  • GPT也采用两阶段过程: 预训练 + Fine-tuning
    • 第一个阶段是利用语言模型进行预训练
    • 第二阶段通过Fine-tuning的模式训练
  • GPT预训练后如何处理下游任务?
  • 一些下游任务的Fine-tuning结构

GPT的优缺点

  • 优点:
    • 特征提取器是Transformer,不是RNN, 所以特征提取效果好
  • 缺点
    • GPT使用的是单向语言模型: 也就是说只用到了上文来预测词
    • 词嵌入时没有单词的下文, 失去了很多信息

BERT结构和原理

下面的讲解都将按照原论文的思路讲解

  • BERT(Bidirectional Encoder Representations from Transformers), 原文 BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
  • 下图是BERT与GPT和ELMo对比的结构图
    • 图中的每个 Trm 组件就是一个 Transformer 的Encoder部分,也就是下图中的左半部分

BERT的特点

  • 一体化特征融合的双向(Bidirectional)语言模型
    • 利用语言的双向信息
    • GPT是单向语言模型, 只能利用一个方向的信息
    • ELMo也是双向语言模型,但是 ELMo实际上是两个方向相反的单向语言模型的拼接, 融合特征的能力比BERT那种一体化的融合特征方式弱
  • 特征提取器:
    • 使用Transformer(实际上使用的是Transformer的Encoder部分, 图中每个)
  • 预训练任务:
    • 屏蔽语言模型(MLM, Masked Language Model) + 相邻句子判断(NSP, Next Sentence Prediction)两个任务的多任务训练目标
  • 训练数据量:
    • 超大规模的数据训练使得BERT结果达到了全新的高度
    • 可以使用BERT作为词嵌入(Word2Vec)的转换矩阵, 实现比其他词嵌入模型更好的结果

输入表示

  • 输入结构图
  • BERT输入是一个512维的编码向量, 是三个嵌入特征的单位和
WordPiece嵌入
  • 对应图中的Token Embedding
  • WordPiece是指将单词划分成一组有限的公共子词单元,能在单词的有效性和字符的灵活性之间取得一个折中的平衡
  • 举例: 原文中 “playing” 被拆分成了 “play” 和 “##ing” 两部分
Segment Embedding

分割嵌入

  • 对应图中的Segment Embedding
  • 用于区分两个句子,例如B是否是A的下文(对话场景,问答场景等)
  • 对于句子对,第一个句子的特征值是0,第二个句子的特征值是1, 从而模型可以表达出词出现在前一个句子还是后一个句子
Position Embedding

位置嵌入

  • 对应图中的 Position Embedding
  • 位置嵌入是指将单词的位置信息编码成特征向量
  • 这是继承自论文Google Brain, NIPS 2017: Attention Is All You Need中, 文章中的Transformer架构没有使用RNN,不能编码位置信息,就是在进入Attention前使用了 词嵌入 + 位置嵌入 的方式让模型能够表达位置信息的

预训练

  • 通常预训练是指在训练阶段让模型去解决自然语言任务, 从而训练完成后得到可移植到其他模型(或者当前模型)使用的参数(包括词向量等)
  • BERT的预训练使用了两个NLP任务: MLM + NSP
  • BERT预训练和使用概览:
    • 从上图可以看出, BERT的预训练包含了两方面的任务, NSP和 MLM
    • 实验证明, MLM 优于标准的 LTR(left-to-right)语言模型(OpenAI GPT 使用的就是这个)
屏蔽语言模型(MLM)

Masked Language Model

  • Masked Language Model(MLM)核心思想取自Wilson Taylor在1953年发表的一篇论文“Cloze Procedure”: A New Tool for Measuring Readability
  • 在训练的时候随机从输入预料上屏蔽(Mask)掉一些单词,然后通过的上下文预测该单词(“完形填空”)
  • 传统的语言模型是Left-to-Right(LTR)或者是Right-to-Left(RTL)的, 和 RNN 结构匹配
  • MLM 的性质 和 Transformer 的结构匹配
  • BERT实验中, 有15%的WordPiece Token句子会被屏蔽掉, 在屏蔽的时候,又有不同的概率
  • 如果已经选中(15%概率)要屏蔽 my dog is hairy 中的 hairy, 那么我们的处理方式是:
    • 80%: my dog is hairy -> my dog is [MASK]
    • 10%: my dog is hairy -> my dog is apple
    • 10%: my dog is hairy -> my dog is hairy
    • 防止句子中的某个Token 100%都会被mask掉,那么在Fine-tuning的时候模型就会有一些没有见过的单词
    • 加入随机Token的原因是因为Transformer要保持对每个输入Token的分布式表征,否则模型就会记住这个[MASK]是 Token “hairy”
    • 错误单词带来的负面影响: 一个单词被随机替换掉的概率只有\(15% \times 10% = 1.5%\) 这个负面影响其实是可以忽略不计的
  • 另外: 文章指出每次只预测15%的单词,因此模型收敛的比较慢
为什么使用MLM
  • 因为效果好,解释就是MLM更符合Transformer的结构
  • 论文中的实验结果:
    • MNLI(Multi-Genre Natural Language Inference)是多类型自然语言推理任务, 是一个大规模的众包蕴含分类任务, 给定一个句子,目标是预测第二句相对与第一句是一个蕴含语句, 矛盾语句, 还是中性语句
    • 从图中可以看出,在MNLI任务中, MLM预训练 + MNLI Fine-tuning 的效果明显优于 LTR预训练 + MNLI Fine-tuning 的效果
相邻句子预测(NSP)

Next Sentence Prediction

  • NSP 的任务是判断句子B是否是句子A的下文
  • 图中的[CLS]符号就是用于分类的, 如果是的话输出’IsNext‘,否则输出’NotNext‘
  • 训练数据的生成方式是从平行语料中随机抽取的连续两句话,其中50%保留抽取的两句话,它们符合IsNext关系,另外50%的第二句话是随机从预料中提取的,它们的关系是NotNext的
  • 举例来说:
    • Input = [CLS] the man went to [MASK] store [SEP] he bought a gallon [MASK] milk [SEP]
    • Label = IsNext
    • Input = [CLS] the man [MASK] to the store [SEP] penguin [MASK] are flight ##less birds [SEP]
    • Label = NotNext

Fine-tuning 处理下游任务

Fine-tining, 中文也称为微调

  • 下图是BERT在不同任务的的微调方法

  • 第二阶段,Fine-Tuning阶段,这个阶段的做法和GPT是一样的。当然,它也面临着下游任务网络结构改造的问题,在改造任务方面Bert和GPT有些不同

    • 句子类关系任务: 和GPT一样,增加起始和终结符号,输出部分Transformer最后一层每个单词对应部分都进行分类即可
    • 除了生成任务外, 其他任务Bert都涉及到了

BERT的使用

  • Google公开了两个不同规模的 BERT模型:
    • \(BERT_{BASE}\) : 110M模型参数
    • \(BERT_{LARGE}\): 340M模型参数
  • 同时公开了两个模型在大规模数据预训练后的参数集合, 供开发者下载和使用

基于BERT的新秀

  • Token仍然使用词, 但是MLM屏蔽时选择屏蔽短语或者实体

ERNIE from Baidu

  • 参考文章: [ERNIE: Enhanced Representation through Knowledge Integration]
  • 核心思想:
    • 用先验知识来加强预训练模型(考虑实体,短语等级别的屏蔽)
    • 在BERT的预训练阶段, MLM模型中屏蔽一个实体(Entity)或者短语(Phrase)而不是屏蔽一个字(Word)
  • 文中提出三种级别的屏蔽方式
    • 基本级别(Basic-level)
    • 实体级别(Entity-level)
    • 短语级别(Phrase-level)
实验对比

ERINE from THU

  • 参考文章: ERNIE: Enhanced Language Representation with Informative Entities
  • 核心思想:
    • 利用先验知识来加强预训练模型(引入知识图谱)
    • 提出了将知识纳入语言表达模型的方法
    • 使用知识聚合器(Knowledgeable aggregator)和预训练任务 dEA, 更好的融合来自文本和知识图谱的异构信息
  • 知识信息
  • 模型架构

Python——函数重载

Posted on 2019-01-18

Python不支持函数重载,但是Python3提供了一个装饰器@singledispatch,用于定义一个泛型函数

  • 参考博客: https://www.cnblogs.com/sunlong88/articles/singledispatch.html

@singledispath装饰器

普通函数中使用

  • 示例代码
    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
    from functools import singledispatch
    from collections import abc
    @singledispatch
    def show(obj):
    print (obj, type(obj), "obj")

    #参数字符串
    @show.register(str)
    def _(text):
    print (text, type(text), "str")

    #参数int
    @show.register(int)
    def _(n):
    print (n, type(n), "int")


    #参数元祖或者字典均可
    @show.register(tuple)
    @show.register(dict)
    def _(tup_dic):
    print (tup_dic, type(tup_dic), "tuple or dict")

    show(1)
    show("xx")
    show([1])
    show((1,2,3))
    show({"a":"b"})

    # Output:
    1 <class 'int'> int
    xx <class 'str'> str
    [1] <class 'list'> obj
    (1, 2, 3) <class 'tuple'> tuple or dict
    {'a': 'b'} <class 'dict'> tuple or dict

类中使用

  • 示例代码:
    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
    from functools import singledispatch
    class abs:
    def type(self,args):
    ""

    class Person(abs):

    @singledispatch
    def type(self,args):
    super().type("",args)
    print("我可以接受%s类型的参数%s"%(type(args),args))

    @type.register(str)
    def _(text):
    print("str",text)

    @type.register(tuple)
    def _(text):
    print("tuple", text)

    @type.register(list)
    @type.register(dict)
    def _(text):
    print("list or dict", text)

    Person.type("safly")
    Person.type((1,2,3))
    Person.type([1,2,3])
    Person.type({"a":1})
    Person.type(Person,True)

    # Output:
    str safly
    tuple (1, 2, 3)
    list or dict [1, 2, 3]
    list or dict {'a': 1}
    我可以接受<class 'bool'>类型的参数True

Python——pickle

Posted on 2019-01-09

Python pickle


关于pickle模块

  • Python的一个序列化与反序列化模块,支持Python基本数据类型
  • 可以处理自定义的类对象,方法等

内存中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pickle

origin = [1, 2, 3, [4, 5, 6]]
print "origin: %s" % origin
temp = pickle.dumps(origin)
print "temp: %s" % temp
new = pickle.loads(temp)
print "new: %s" % new

# output:
origin: [1, 2, 3, [4, 5, 6]]
temp: (lp0
I1
aI2
aI3
a(lp1
I4
aI5
aI6
aa.
new: [1, 2, 3, [4, 5, 6]]

硬盘中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
import pickle

origin = [1, 2, 3, [4, 5, 6]]
print "origin: %s" % origin
# open a binary and write the result
pickle.dump(origin, open('temp', 'wb'))
# open a binary and read the original object
new = pickle.load(open('temp', 'rb'))
print "new: %s" % new

# output
origin: [1, 2, 3, [4, 5, 6]]
new: [1, 2, 3, [4, 5, 6]]

Numpy——random模块

Posted on 2019-01-09

库名: np.random


RandomState()

  • np.random.RandomState(seed)

    • seed 相同时两个不同的RandomState对象会产生相同的随机数据序列

    • seed 默认值为None,此时不同的RandomState对象产生不同的随机数据序列,此时RandomState将从/dev/urandom 或者从clock otherwise读取seed值

      1
      2
      3
      4
      5
      6
      7
      8
      print np.random.RandomState(1).randint(1, 100010)
      print np.random.RandomState(1).randint(1, 100000)
      print np.random.RandomState(1).randint(1, 100000)
      print np.random.RandomState().randint(1, 100000)
      print np.random.RandomState().randint(1, 100000)
      print np.random.RandomState().randint(1, 100000)
      print np.random.RandomState(1) is np.random.RandomState(1)
      print np.random.RandomState() is np.random.RandomState()
    • 输出如下:

      98540
      98540
      98540
      38317
      42305
      70464
      False
      False


关于初始化向量的维度

  • 不是行向量也不是列向量

    1
    2
    np.random.randn(5)
    # [1,2,3,4,5]
    • shape为(5,)
    • 是一个特殊的数据结构
    • 是一个一维向量,不是矩阵,不是行向量,也不是列向量
  • 列向量

    1
    2
    3
    4
    5
    6
    np.random.randn(5,1)
    # [[1]
    [2]
    [3]
    [4]
    [5]]
    • shape为(5,1)
    • 是一个矩阵
  • 行向量

    1
    2
    np.random.randn(1,5)
    # [[1,2,3,4,5]]
    • shape为(1,5)
    • 是一个矩阵
  • 一个好的习惯是使用向量时用Assert语句确保维度

    1
    assert(a.shape == (3,4))

Numpy——一些说明

Posted on 2019-01-09

关于效率

Numpy包含很多高效的函数,能够替换普通的循环,实现非常快

累加变成向量运算

对向量每个元素进行某个运算生成另一个向量

  • 普通用法

    1
    2
    3
    4
    5
    6
    import numpy as np
    a = np.zeros((n, 1))
    b = np.zeros((n, 1))

    for i in range(n):
    b[i] = math.exp(a[i])
  • 高效用法

    1
    2
    3
    import numpy as np
    a = np.zeros((n, 1))
    b = np.exp(a)
  • 相似的还有log,abs等函数

值得关注的广播机制(broadcasting)

  • 当两个向量(numpy的对象)的维度不同时,Python会将维度小的一个拓展(复制)成与维度大的相同,以便于计算
  • 举例
    1
    2
    a = np.zeros((n, 1))
    b = a + 10
广播规则
  • 形式1

    1
    2
    3
    (m,n) [+-*/] (m,1) 
    <===>
    (m,n) [+-*/] (m,n) # 按列复制第二个n次
  • 形式2

    1
    2
    3
    (m,n) [+-*/] (1,n) 
    <===>
    (m,n) [+-*/] (m,n) # 按行复制第二个m次
  • 形式3

    1
    2
    3
    (m,n) [+-*/] r # r为实数,维度为1
    <===>
    (m,n) [+-*/] (m,n) # 复制r m*n 次
  • 形式4

    1
    2
    3
    (m,1) [+-*/] (1,n) 
    <===>
    (m,n) [+-*/] (m,n) # 按行复制第二个m次,并按列复制第一个n次
需要注意
  • 广播机制使得书写更加美观,代码更加简洁
  • 但广播机制往往会出现用户意想不到的微妙bug, 需要开发者注意

关于矩阵运算的维度

  • axis=i表示第i维计算后将会消失(该维度的size变成1)

多使用reshape函数

  • reshape函数复杂度是常数的(O(1))
  • reshape函数可确保我们的程序正确,不用随意猜测矩阵的维度

DL——Transformer

Posted on 2019-01-04

相关论文介绍

  • Transformer原始文章:
    • Google Brain, NIPS 2017: Attention Is All You Need
    • 文章中介绍了一种应用Attention机制的新型特征提取器,命名为Transformer, 实验证明Transformer优于RNN(LSTM),CNN等常规的特征提取器
  • Transformer的使用:
    • GPT: Improving Language Understanding by Generative Pre-Training
    • BERT: BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
    • 以上两个工作都使用了Transformer作为特征提取器, 使用两阶段训练的方式实现迁移学习(Pre-Training and Fine-Training)

相关博客介绍

  • 强烈推荐看看jalammar的博客: illustrated-transformer
  • 另一篇不错的Attention和Transformer讲解自然语言处理中的自注意力机制(Self-Attention Mechanism)
  • 一篇很多个人理解的博客 《Attention is All You Need》浅读

Transformer讲解

  • 最直观的动态图理解
  • 本文讲解主要按照Google Brain, NIPS 2017: Attention Is All You Need的思路走,该论文的亮点在于:
    • 不同于以往主流机器翻译使用基于 RNN 的 Seq2Seq 模型框架,该论文用 Attention 机制代替了 RNN 搭建了整个模型框架, 这是一个从换自行车零件到把自行车换成汽车的突破
    • 提出了多头注意力(Multi-Head Attention)机制方法,在编码器和解码器中大量的使用了多头自注意力机制(Multi-Head self-attention)
    • 在WMT2014语料库的英德和英法语言翻译任务上取得了先进结果

Transformer是什么?

  • 本质上是个序列转换器
  • 进一步讲,是个 Encoder-Decoder 模型的序列转换器
  • 更进一步的讲,是个 6层Encoder + 6层Decoder 结构的序列转换器
  • 上面的图中,每个 Encoder 是
  • 详细的讲, 每个Encoder是
  • 展开看里面 Encoder 中的数据流向
  • 更进一步的展开看 Encoder 中的数据流向
  • 两层 Encoder + 两层Decoder (其中一个Decoder没有完全画出来) 的数据流向
  • 带细节动图查看数据流向
  • 最后,我们给出Transformer的结构图(来自原文中)

Transformer中的Attention

Transformer中使用了 Multi-Head Attention, 同时也是一种 Self Attention

  • 由于Transformer的Multi_Head Attention中 Query == Key == Query, 所以也是一种 Self Attention
    • 即$$\boldsymbol{Y_{AttentionOutput}} = Self Attention(\boldsymbol{Q},\boldsymbol{K},\boldsymbol{V}) = Attention(\boldsymbol{X},\boldsymbol{X},\boldsymbol{X})$$
  • 更多关于广义Attention的理解请参考: DL——Attention

Multi-Head Attention

  • Muti-Head Attention 由 \(h\) 个 Scaled Dot-Product Attention和其他线性层和Concat操作等组成
    • Scaled Dot Product Attention中Mask操作是可选的
    • Scaled Dot Product Attention数学定义为(没有Mask操作)
      $$
      \begin{align}
      Attention(\boldsymbol{Q},\boldsymbol{K},\boldsymbol{V}) = softmax\left(\frac{\boldsymbol{Q}\boldsymbol{K}^{\top}}{\sqrt{d_k}}\right)\boldsymbol{V}
      \end{align}
      $$
    • Multi-Head Attention的某个输出的数学定义为
      $$
      \begin{align}
      MultiHead(\boldsymbol{Q}, \boldsymbol{K}, \boldsymbol{V}) &= Concat(head_1,\dots,head_h)\boldsymbol{W}^{O} \\
      where \quad head_i &= Attention(\boldsymbol{Q}\boldsymbol{W}_i^Q,\boldsymbol{K}\boldsymbol{W}_i^K,\boldsymbol{V}\boldsymbol{W}_i^V)
      \end{align}
      $$
有关Multi-Head Attention的理解
  • 原论文的描述:

Multi-head attention allows the model to jointly attend to information from different representation subspaces at different positions,

  • 理解:
    • 所谓多头,就是多做几次(\(h\)次)同样的事情(参数\((W_i^Q, W_i^K, W_i^V)\)不共享, 即当 \(i \neq j \) 时, \((W_i^Q, W_i^K, W_i^V) \neq (W_j^Q, W_j^K, W_j^V)\)),然后把结果拼接
    • Multi-Head Attention中, 每个头(Scaled Dot-Product Attention)负责不同的子空间(subspaces at differect positions)
    • 每个头权重不同, 所以他们的关注点也会不同,注意, 初始化时他们的参数不能相同, 否则会造成他们的参数永远相同, 因为他们是同构的
    • 个人理解: 多头的作用可以类比于CNN中的卷积层, 负责从不同的角度提取原始数据的特征

Self Attention

  • Self Attention是只 Key和Query相同的 Attention, 这里因为 Key 和 Value 也相同,所以有 Query == Key == Query
  • 即$$ \boldsymbol{Y_{AttentionOutput}} = Self Attention(\boldsymbol{Q},\boldsymbol{K},\boldsymbol{V}) = Attention(\boldsymbol{X},\boldsymbol{X},\boldsymbol{X})$$

Transformer中的Attention

  • 既是Multi-Head Attention, 也是 Self Attention
  • 所以有$$\boldsymbol{Y_{AttentionOutput}} = MultiHead(\boldsymbol{X},\boldsymbol{X},\boldsymbol{X})$$

Transformer 输入层

  • Transformer的输入层使用了 Word Embedding + Position Embedding
  • 由于Transformer去除RNN的Attention机制完全不考虑词的顺序, 也就是说, 随机打乱句子中词的顺序 (也就是将键值对\((\boldsymbol{K}, \boldsymbol{V})\)对随机打乱), Transformer中Attention的结果不变
  • 实际上, 目前为止, Transformer中的Attention模型顶多是个非常精妙的”词袋模型” (这句话来自博客:https://kexue.fm/archives/4765)

Word Embedding

  • 和之前的词嵌入一样, 将One-Hot值映射成词向量嵌入模型中

Position Embedding

FaceBook的《Convolutional Sequence to Sequence Learning》中曾经用过Position Embedding

  • 在不使用RNN的情况下建模词的顺序, 弥补”词袋模型”的不足
  • 用 Position Embedding来为每个位置一个向量化表示
    • 将每个位置编号,然后每个编号对应一个向量
    • 通过结合位置向量和词向量,就给每个词都引入了一定的位置信息,这样Attention就可以分辨出不同位置的词了
  • 原始论文中, 作者提出了一种周期性位置编码的表示, 数学公式如下:
    $$
    \begin{align}
    PE(pos,2i) &= sin(pos/10000^{2i/d_{\text{model}}}) \\
    PE(pos, 2i+1) &= cos(pos/10000^{2i/d_{\text{model}}})
    \end{align}
    $$
  • 我觉得上述公式太丑了,转换一下写法可能更容易理解
    $$
    \begin{align}
    PE(pos,2i) &= sin\left (\frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}}\right) \\
    PE(pos, 2i+1) &= cos\left (\frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}}\right)
    \end{align}
    $$
    • \(pos\) 是位置编号
    • \(i\) 表示位置向量的第 \(i\) 维
    • 为什么选择\(10000^{\frac{2i}{d_{\text{model}}}}\)? [待更新]
    • 每个维度的位置编码对应着一个正弦函数, 周期为 \(2\pi\)到 \(10000\cdot 2\pi\)
    • 选择正弦函数的原因是假设这将允许模型学到相对位置信息
      • 因为对于固定的 \(k\), \(PE_{pos+k} = LinearFuction(PE_{pos})\), 所以这给模型提供了表达相对位置的可能性
与之前的Position Embedding的区别
  • Position Embedding对模型的意义不同:
    • 以前在RNN、CNN模型中Position Embedding是锦上添花的辅助手段,也就是“有它会更好、没它也就差一点点”的情况,因为RNN、CNN本身就能捕捉到位置信息
    • 在Transformer这个纯Attention模型中,Position Embedding是位置信息的唯一来源,因此它是模型的核心成分之一,并非仅仅是简单的辅助手段
  • Position Embedding的向量构造方式不同
    • 在以往的Position Embedding中,基本都是根据任务训练出来的向量
    • 而Google直接给出了一个构造Position Embedding的公式:
      $$
      \begin{align}
      PE(pos,2i) &= sin\left (\frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}}\right) \\
      PE(pos, 2i+1) &= cos\left (\frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}}\right)
      \end{align}
      $$
    • Google经过实验, 学到的位置嵌入和这种计算得到的位置嵌入结果很相近
    • Google选用这种嵌入方式的原因是这种方式允许模型以后可以扩展到比训练时遇到的序列长度更长的句子

输入层的输出(Attention的输入)

  • 综合词嵌入和位置嵌入信息,我们可以得到下面的公式
    $$
    \begin{align}
    \boldsymbol{x} = \boldsymbol{x}_{WE} + \boldsymbol{x}_{PE}
    \end{align}
    $$
    • \(\boldsymbol{x}\) 为输入层经过词嵌入和位置嵌入后的 输出, 也就是Attention的输入
    • \(\boldsymbol{x}_{WE}\) 指词嵌入的结果
    • \(\boldsymbol{x}_{PE}\) 指位置嵌入的结果

Transformer总结

  • Transformer是一个特征提取能力非常强(超越LSTM)的特征提取器
  • 一些讨论
    • Transformer与CNN没关系,但是Transformer中使用多个 Scaled Dot-Product Attention 来最后拼接的方法(Multi-Head Attention), 就是CNN的多个卷积核的思想
    • Transformer论文原文中提到的残差结构也来源于CNN
    • 无法对位置信息进行很好地建模,这是硬伤。尽管可以引入Position Embedding,但我认为这只是一个缓解方案,并没有根本解决问题。举个例子,用这种纯Attention机制训练一个文本分类模型或者是机器翻译模型,效果应该都还不错,但是用来训练一个序列标注模型(分词、实体识别等),效果就不怎么好了。那为什么在机器翻译任务上好?我觉得原因是机器翻译这个任务并不特别强调语序,因此Position Embedding 所带来的位置信息已经足够了,此外翻译任务的评测指标BLEU也并不特别强调语序
    • Attention如果作为一个和CNN,RNN平级的组件来使用,可能会集成到各自的优点, 而不是”口气”很大的 “Attention is All You Need”

Linux——Ubuntu和Centos服务器管理

Posted on 2019-01-04

Centos

配置静态IP

  • 查看网卡名称

    1
    ifconfig
    • 查看网卡信息,每行的第一项为网卡名称
    • 一般服务器可能有多个网卡,按照需求选择一个即可
    • 网卡信息包含当前网卡的ipv4和ipv6地址,MAC地址等信息
  • 根据网卡名字打开相应网卡的配置文件

    1
    2
    # 假设网卡名称为eth0
    vi /etc/sysconfig/network-scripts/ifcfg-eth0
  • 修改相关配置内容

    1
    2
    3
    4
    5
    6
    7
    IPADDR=12.12.12.12
    NETMASK=255.255.255.0
    GATEWAY=12.12.12.1
    ONBOOT=yes
    BOOTPROTO=static
    DNS1=114.114.114.114
    DNS2=8.8.8.8
    • 等号后面是具体的ip地址名称
    • DNS可以有多个,用数字标识即可
  • 重新启动网络服务

    1
    service network restart

管理用户

修改root密码

默认可远程登录root用户,只需知道密码即可(SSH默认已经安装)

  • 修改root密码

    1
    passwd
  • 若需要找回root密码,参考博客 https://blog.csdn.net/shanvlang/article/details/80385913

添加用户

假设添加用户名为test的用户

  • 添加新用户

    1
    useradd test
    • centos中,以上命令将自动为test用户分配一个属于test用户的/home/test文件夹
  • 为新用户修改密码

    1
    passwd test
  • 添加用户权限

    • 打开配置文件

    • 如果root用户没有该文件的写权限的话需要用chmod u+w /etc/sudoers, 修改完成再改回到chmod u-w /etc/sudoers

      1
      vi /etc/sudoers
    • 编辑以下内容,注意空格类型,最好复制一行修改

      1
      2
      3
      ## Allow root to run any commands anywhere
      root ALL=(ALL) ALL
      test ALL=(ALL) ALL
  • 删除用户

    1
    userdel test

Ubuntu

配置静态IP

  • 查看网卡名称

    1
    ifconfig
    • 查看网卡信息,每行的第一项为网卡名称
    • 一般服务器可能有多个网卡,按照需求选择一个即可
    • 网卡信息包含当前网卡的ipv4和ipv6地址,MAC地址等信息
  • 修改配置文件

    1
    vi /etc/network/interfaces
  • 修改相关配置内容

    1
    2
    3
    4
    5
    6
    7
    8
    # 假设网卡名称为eth0

    auto eth0
    iface eth0 inet static
    address 12.12.12.12
    netmask 255.255.255.0
    gateway 12.12.12.1
    dns-nameserver 114.114.114.114 8.8.8.8
    • dns可以有多个,以空格间隔开
  • 重新启动网络服务

    1
    sudo /etc/init.d/networking restart

管理用户

修改root密码

Ubuntu默认禁用root用户登录,需要配置root账户才能以root身份登录(SSH默认已经安装)

  • 修改root密码

    1
    passwd
  • 若需要找回root密码,参考博客 https://blog.csdn.net/shanvlang/article/details/80385913

添加用户

假设添加用户名为test的用户

  • 添加新用户

    1
    useradd test
    • Ubuntu中以上命令并不会直接为当前用户分配自己的文件夹,所以需要我们为其手动添加一个并使用chown test /home/test命令将文件家分配给test用户,这样使用test用户登录时将会自动转到/home/test文件夹下面工作
  • 为新用户修改密码

    1
    passwd test
  • 添加用户权限

    • 打开配置文件

    • 如果root用户没有该文件的写权限的话需要用chmod u+w /etc/sudoers, 修改完成再改回到chmod u-w /etc/sudoers

      1
      vi /etc/sudoers
    • 编辑以下内容,注意空格类型,最好复制一行修改

      1
      2
      3
      # User privilege specification
      root ALL=(ALL:ALL) ALL
      test ALL=(ALL:ALL) ALL
  • 删除用户

    1
    userdel test

Git——Ubuntu中文乱码问题

Posted on 2019-01-02

解决方案

1
git config --global core.quotepath false

Python——Python3新特性f-string

Posted on 2019-01-02

Formatted string literals


f-string

说明

  • 格式化的字符串文字以“f”为前缀
  • 类似于str.format()接受的格式字符串
  • 它们包含由花括号包围的替换字段
  • 替换字段是表达式,在运行时进行评估,然后使用format()协议进行格式化

工作原理

  • 从字符串中提取的表达式在f字符串出现的上下文中计算
  • 这意味着表达式可以完全访问本地和全局变量
  • 可以使用任何有效的Python表达式,包括函数和方法调用

与之前的表达式对比

  • 之前

    1
    print("%s%s%s" % (a, b, c+d))
  • f-string

    1
    print(f'{a}{b}{c+d}')
1…345…20
Joe Zhou

Joe Zhou

世界上只有一种真正的英雄主义,那就是在认清生活真相之后依然热爱生活。 ——罗曼·罗兰

195 posts
38 tags
GitHub E-Mail
© 2024 Joe Zhou
Powered by Hexo
|
Theme — NexT.Gemini v5.1.4