# 【BERT】BERT 我变瘦了！但还是很强！model compression

## Overview

Overview

Pruning

Why Pruning

Weight Pruning

Neuron Pruning

Bert Pruning

Knowledge Distillation

Theory

DistilBert

Knowledge distillation

architecture choice and initialization

Performance and Ablation

Bert-PKD

Patient Knowledge Distillation

architecture choice

TinyBert

general distillation

Ablation Studies

summary

Parameter Quantization

Architecture Design

Matrix Factorization

Albert

Matrix Factorization

Cross-layer Parameter Sharing

Sentence Order Prediction（SOP）

Ablation Studies

Factors affecting model performance

Dynamic Computation

ref

appendix

Depthwise Separable Convolution

## Pruning

1. 预训练一个大的网络

2. evaluate 网络中参数/神经元的重要性

3. 删除不重要的参数/神经元（少量）

4. 在训练数据上fine-tune

5. 评测新的模型效果

## Knowledge Distillation

Knowledge distillation refers to the idea of model compression by teaching a smaller network, step by step, exactly what to do using a bigger already trained network. The ‘soft labels’ refer to the output feature maps by the bigger network after every convolution layer. The smaller network is then trained to learn the exact behavior of the bigger network by trying to replicate it’s outputs at every level (not just the final loss).

blog.rasa.com/compressi

## Theory

Knowledge Distillation指出大的网络例如通过多个网络进行emsemble的结果，往往能比直接用相同数据训练小模型generalize效果更好。

>>> a = tf.nn.softmax([100.0,10,1])
>>> b = tf.nn.softmax([1.0,0.1,0.01])
>>> with tf.Session() as sess:
...     sess.run([a,b])
...
[array([1., 0., 0.], dtype=float32), array([0.5623834 , 0.22864804, 0.20896856], dtype=float32)]

distillation loss（拟合soft label with temperature） 权重比较大

## DistilBert

DistilBert 的作者团队最初是在Medium上提出自己的想法以及实作，可以参考这篇文章–Smaller, faster, cheaper, lighter: Introducing DistilBERT, a distilled version of BERT，作为论文的引入点。其实论文DistilBERT, a distilled version of BERT: smaller, faster, cheaper and lighter 很简单也很好懂，只要理解KD的机制，就可以轻松的理解好论文。

### Knowledge distillation

distillation loss

nn.KLDivLoss(F.log_softmax(s_logits_slct / self.temperature, dim=-1),
F.softmax(t_logits_slct / self.temperature, dim=-1))

Theory Unsupervised Learning: Deep Generative Model pdf,video (part 1),video (part 2)(2016/12/02)

cross entropy，logistic loss 和 KL-divergence的关系和区别

cross entropy和KL-divergence作为目标函数效果是一样的，从数学上来说相差一个常数。

logistic loss 是cross entropy的一个特例

### architecture choice and initialization

DistilBert将token-type embeddings以及pooler层去掉了 (used for the next sentence classification task) ，这边我不是很理解，因为pooler层对应的是[CLS]的输出，去掉了怎幺做分类任务？可能需要再研究一下。但是我看distilbert 的应用的时候，是有[CLS]层的。

## Bert-PKD

Bert-PKD，在KD的基础上，提出了一种改进，叫做Patient Knowledge Distillation。在这种方法下，得到了和教师模型相同效果的压缩模型。这种方法地提出就是因为我们在普通地KD中，只学习了教师模型地输出，而不注重中间层的参数方式。直观地理解来说，我们怎幺可以只学习题目的答案而错过中间的解题过程？耐心的老师会教大家中间的过程！那幺中间层的选择怎幺选呢，本文Patient Knowledge Distillation for BERT Model Compression提出了两种方式，一种是PKD-last（只学习最后几层的输出），一种是PKD-skip（学习中间每隔一层的输出），这两种方式的选择上，PKD-skip略胜一筹。

### Patient Knowledge Distillation

PKD的loss 主要由三个部分组成

softmax-soft loss

Patient Teacher Loss

N:代表的是 training sample 的个数 M:代表的是 number of layers in student model 学生模型的中间block的个数 所以这边中间隐藏层的表示维度两个模型是一致的。这个公式咋看很复杂，但是其实就是求学生模型的中间隐藏层的归一化后的向量（normalized hidden states）表示的MSE（均方误差）。

：代表的是[CLS] token 的第隐藏层输出， 每个隐藏层有k维 表示的是模型中间隐藏层的对应关系，例如我们有teacher 模型12层，学生模型6层，学生的每个隐藏层的输出要怎幺对应教师的隐藏层，由于我们在softmax-soft中已经显性地学习了最后一层的输出，所以我们只需要对应5个隐藏层的结果就行了。本文提出了两种思路，一种是：

PKD-skip：12层的话

PKD-last：12层的话，

（需要特别注意的是，我们这边提到的隐藏层，是指的BERT里面的一个block为单位，也就是encoder级别的）。下面这张图很好的表示三种loss以及两种策略。

### architecture choice

btw，它的ablation studies写的真差

Well-Read Students Learn Better: On the Importance of Pre-training Compact Models TODO：这篇文章好像提到了pretraining的重要度以及初始化的重要度，需要补充进来

## TinyBert

TinyBert作为华为出品的知识蒸馏论文，在笔者写时还在under review的状态，我特别注意到已经提交了第三版了。当时还纳闷，但是读完了文章之后，觉得思路以及工作上还是不错的，但是文笔以及文章的结构就一般，以及loss的设计和模型初始化的选择都需要改进（个人愚见xp）。

TinyBert 提出了，虽然这些思路很不错，但是都不是针对transformer的KD方法，我可以在更细粒度的学习transformer的中间表示，例如虽然Bert-PKD提出了中间block输出学习，但是这仅仅是学习到了这个block的输出，但是这个block是由self-attention+dense组成的，作为学生模型，我学习到了最后的输出结果，但是更中间的结果我没学到呀，我要学得更深！！！针对这个思路，我认为这个也可以叫做VPKD，very patient knowledge distillation 哈哈。因为老师模型在教做题的时候，每个步骤都讲得很仔细，没有一个步骤跳过或者省略。

Tiny Bert的使用说明参见ref

### general distillation

Embedding-layer Distillation

Transformer-layer Distillation

attention based distillation attention 的权重可以获取很多的语言学的知识，所以不能够忽视这些信息。文章中定义每一层的attention loss: 这边的 表示的是attention heads的个数。

hidden states based distillation 除了mimic attention 的权重之外，我们还需要mimic每个encoder的hidden states的输出，: 其中 表示的是学生的某一个block的hidden states的output， 表示的是老师的对应block的hidden states的output，为什幺需要乘以 呢，这是因为做一个线性映射, 是一个可学习的矩阵，目的是把学生模型的特定向量映射到对应的老师模型的向量空间去吗，因为我们 不要求 两个的维度一致。

Prediction-Layer Distillation 最后的这个就是典型的softmax-soft loss了 这边原论文中  我没看到有做temperature的引入，我觉得是错的，如果我说的不对可以联系我哈

step 1: 数据增强，Glove替换相近的词等方式

step 2: 训练特定任务的Bert，然后继续使用特定任务的bert作为老师，重复general distllation的方式。

### Ablation Studies

learning procedures

GD (General Distillation): 相对作用比较小，所以fine-tune和数据是大头

DA (Data Augmentation)：比较重要

：这个只是一般重要，但是这个在DistilBert中还是很重要的，所以我更加觉得这边的loss设计有点问题了。应该使用的是cosine distance loss

：很重要

：很重要

### summary

BertPKD 就直接学习finetune后的教师模型了，它的参数初始化都是用BERT_base的前几层进行初始化的，同时它学习了block的中间输出和最后的预测输出和具体任务的结果cross entropy

DistilBERT 用的是教师模型的skip layer作为参数初始化，（而且ablation studies指出，这还相当重要），然后它还预测了语言模型的MLM loss和最后的KD loss和任务loss

TinyBERT两阶段中，都增加了很多的loss，但是它没有进行参数的初始化，我觉得这个是一个 很重要 需要改进的地方

## Parameter Quantization

parameter quantization使用的是少的bits表示一个value，具体的话，可以使用k-means的方法将权重进行clustering，例如下图所示，我们可以将一个模型的权重聚类成4种，然后每一种都使用2bit表示。如果使用Huffman code表示，能减少更多的空间。

## Matrix Factorization

（see appendix for application in CNN）

## Albert

Matrix Factorization

Parameter sharing

### Matrix Factorization

BERT, XLNET,ROBERTA 的WordPiece的 embedding size E 都是等于 hidden layer size H, i.e., E ≡ H.

def embedding_lookup_factorized(...):
embedding_table = tf.get_variable(  # [vocab_size, embedding_size]
name=word_embedding_name,
shape=[vocab_size, embedding_size],
initializer=create_initializer(initializer_range))
...
flat_input_ids = tf.reshape(input_ids, [-1])  # one rank. shape as (batch_size * sequence_length,)
if use_one_hot_embeddings:
one_hot_input_ids = tf.one_hot(flat_input_ids,depth=vocab_size)  # one_hot_input_ids=[batch_size * sequence_length,vocab_size]
output_middle = tf.matmul(one_hot_input_ids, embedding_table)  # output=[batch_size * sequence_length,embedding_size]
else:
output_middle = tf.gather(embedding_table,flat_input_ids)  # [vocab_size, embedding_size]*[batch_size * sequence_length,]--->[batch_size * sequence_length,embedding_size]
# 2. project vector(output_middle) to the hidden space
project_variable = tf.get_variable(  # [embedding_size, hidden_size]
name=word_embedding_name+"_2",
shape=[embedding_size, hidden_size],
initializer=create_initializer(initializer_range))
output = tf.matmul(output_middle, project_variable) # ([batch_size * sequence_length, embedding_size] * [embedding_size, hidden_size])--->[batch_size * sequence_length, hidden_size]
...
return (output, embedding_table, project_variable)

### Cross-layer Parameter Sharing

Cross-layer Parameter Sharing 防止了模型的参数量随着block的增加而增加

all-shared strategy(ALBERT-style) all-shared strategy指的是，share self-attention以及FFN layer 的参数

shared-attention shared-attention strategy指的是，share self-attention 的参数

shared-FFN shared-FFN strategy指的是，share self-FFN 的参数

not-shared 什幺都不share是原始bert的模式

share strategy的implementation

def layer_scope(idx, shared_type):
if shared_type == 'all':
tmp = {
"layer":"layer_shared",
'attention':'attention',
'intermediate':'intermediate',
'output':'output'
}
elif shared_type == 'attention':
tmp = {
"layer":"layer_shared",
'attention':'attention',
'intermediate':'intermediate_{}'.format(idx),
'output':'output_{}'.format(idx)
}
elif shared_type == 'ffn':
tmp = {
"layer":"layer_shared",
'attention':'attention_{}'.format(idx),
'intermediate':'intermediate',
'output':'output'
}
else:
# 不共享？
tmp = {
"layer":"layer_{}".format(idx),
'attention':'attention',
'intermediate':'intermediate',
'output':'output'
}
return tmp

for layer_idx in range(num_hidden_layers):
idx_scope = layer_scope(layer_idx, shared_type)
with tf.variable_scope(idx_scope['layer'], reuse=tf.AUTO_REUSE):
layer_input = prev_output
with tf.variable_scope(idx_scope['attention'], reuse=tf.AUTO_REUSE):
with tf.variable_scope("output", reuse=tf.AUTO_REUSE):
layer_input_pre = layer_norm(layer_input)
with tf.variable_scope("self"):

### Sentence Order Prediction（SOP）

def create_masked_lm_predictions(tokens, masked_lm_prob,
max_predictions_per_seq, vocab_words, rng):
"""Creates the predictions for the masked LM objective."""
cand_indexes = []
for (i, token) in enumerate(tokens):
if token == "[CLS]" or token == "[SEP]":
continue
# Whole Word Masking means that if we mask all of the wordpieces
# corresponding to an original word. When a word has been split into
# WordPieces, the first token does not have any marker and any subsequence
# tokens are prefixed with ##. So whenever we see the ## token, we
# append it to the previous set of word indexes.
#
# Note that Whole Word Masking does *not* change the training code
# at all -- we still predict each WordPiece independently, softmaxed
# over the entire vocabulary.
if (FLAGS.do_whole_word_mask and len(cand_indexes) >= 1 and
token.startswith("##")):
cand_indexes[-1].append(i)
else:
cand_indexes.append([i])
rng.shuffle(cand_indexes)

“

### Ablation Studies

factorization的影响 我们可以发现在单独（no-shared模型）进行embedding参数的factorization下，模型效果是会降低的。

parameters sharing 的影响 在只使用参数共享没有做embedding factorization的模式下(E=768), 可以发现共享参数都使得模型效果降低，但是共享不同的层，降低的效果不一样

SOP的作用

SOP的作用大大提升了模型的效果

### Factors affecting model performance

EFFECT OF NETWORK DEPTH AND WIDTH

Depth 分析指出，并不是更深的网络更好，在12层和24层效果差不多了，48层的效果，甚至不如24层的好。

Width Hidden size的结论和Depth的结论一直，并不是一味追加hidden size就能够使得模型效果更好，4096的长度效果是最好的。值得注意的是，就算在6144的hidden size上，模型仍然没有over fitting的情况。

DO VERY WIDE ALBERT MODELS NEED TO BE DEEP(ER) TOO ? 在很宽的模型参数Hidden size=4096的情况下，我们需要更深的模型吗？作者通过实验说明，在albert的参数共享的情况下，答案是不需要，12层足矣。

Dropout的作用？我们通过实验在非常深以及非常宽的网络中，甚至在训练了100万次之后，模型都没有overfitting的现象，但是我们模型训练的时候，加入了dropout，这会影响模型的能力(capacity)，所以我们在配置中将dropout rate设为0，并得到更好的结果。

## Depthwise Separable Convolution

TODO：

– pruning 和quantization 和 Dynamic Computation

– Well-Read Students Learn Better: On the Importance of Pre-training Compact Models 论文研读 – appendix修改