Merge pull request #17 from zhxnlp/patch-6

Update 3.1-如何实现一个BERT.md
This commit is contained in:
erenup 2021-08-22 22:44:33 +08:00 committed by GitHub
commit ab21219f3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 9 additions and 7 deletions

View File

@ -1,9 +1,11 @@
## 前言
本文包含大量源码和讲解通过段落和横线分割了各个模块同时网站配备了侧边栏帮助大家在各个小节中快速跳转希望大家阅读完能对BERT有深刻的了解。同时建议通过pycharm、vscode等工具对bert源码进行单步调试调试到对应的模块再对比看本章节的讲解。
涉及到的jupyter可以在[代码库篇章3-编写一个Transformer模型BERT下载](https://github.com/datawhalechina/learn-nlp-with-transformers/tree/main/docs/%E7%AF%87%E7%AB%A03-%E7%BC%96%E5%86%99%E4%B8%80%E4%B8%AATransformer%E6%A8%A1%E5%9E%8B%EF%BC%9ABERT)
涉及到的jupyter可以在代码库篇章3-编写一个Transformer模型[BERT下载](https://github.com/datawhalechina/learn-nlp-with-transformers/tree/main/docs/%E7%AF%87%E7%AB%A03-%E7%BC%96%E5%86%99%E4%B8%80%E4%B8%AATransformer%E6%A8%A1%E5%9E%8B%EF%BC%9ABERT)
本篇章将基于H[HuggingFace/Transformers, 48.9k Star](https://github.com/huggingface/transformers)进行学习。本章节的全部代码在[huggingface bert注意由于版本更新较快可能存在差别请以4.4.2版本为准](https://github.com/huggingface/transformers/tree/master/src/transformers/models/bert)HuggingFace 是一家总部位于纽约的聊天机器人初创服务商,很早就捕捉到 BERT 大潮流的信号并着手实现基于 pytorch 的 BERT 模型。这一项目最初名为 pytorch-pretrained-bert在复现了原始效果的同时提供了易用的方法以方便在这一强大模型的基础上进行各种玩耍和研究。
本篇章将基于[HuggingFace/Transformers, 48.9k Star](https://github.com/huggingface/transformers)进行学习。本章节的全部代码在[huggingface bert](https://github.com/huggingface/transformers/tree/master/src/transformers/models/bert)注意由于版本更新较快可能存在差别请以4.4.2版本为准。
HuggingFace 是一家总部位于纽约的聊天机器人初创服务商,很早就捕捉到 BERT 大潮流的信号并着手实现基于 pytorch 的 BERT 模型。这一项目最初名为 pytorch-pretrained-bert在复现了原始效果的同时提供了易用的方法以方便在这一强大模型的基础上进行各种玩耍和研究。
随着使用人数的增加,这一项目也发展成为一个较大的开源社区,合并了各种预训练语言模型以及增加了 Tensorflow 的实现,并且在 2019 年下半年改名为 Transformers。截止写文章时2021 年 3 月 30 日)这一项目已经拥有 43k+ 的star可以说 Transformers 已经成为事实上的 NLP 基本工具。
@ -601,7 +603,7 @@ def forward(
- set_input_embeddings为 embedding 中的 word_embeddings 赋值;
- _prune_heads提供了将注意力头剪枝的函数输入为{layer_num: list of heads to prune in this layer}的字典,可以将指定层的某些注意力头剪枝。
** 剪枝是一个复杂的操作,需要将保留的注意力头部分的 Wq、Kq、Vq 和拼接后全连接部分的权重拷贝到一个新的较小的权重矩阵(注意先禁止 grad 再拷贝并实时记录被剪掉的头以防下标出错。具体参考BertAttention部分的prune_heads方法.**
**剪枝是一个复杂的操作,需要将保留的注意力头部分的 Wq、Kq、Vq 和拼接后全连接部分的权重拷贝到一个新的较小的权重矩阵(注意先禁止 grad 再拷贝并实时记录被剪掉的头以防下标出错。具体参考BertAttention部分的prune_heads方法.**
```python
@ -786,11 +788,11 @@ class BertModel(BertPreTrainedModel):
1. word_embeddings上文中 subword 对应的嵌入。
2. token_type_embeddings用于表示当前词所在的句子辅助区别句子与 padding、句子对间的差异。
3 position_embeddings句子中每个词的位置嵌入用于区别词的顺序。和 transformer 论文中的设计不同,这一块是训练出来的,而不是通过 Sinusoidal 函数计算得到的固定嵌入。一般认为这种实现不利于拓展性(难以直接迁移到更长的句子中)。
3. position_embeddings句子中每个词的位置嵌入用于区别词的顺序。和 transformer 论文中的设计不同,这一块是训练出来的,而不是通过 Sinusoidal 函数计算得到的固定嵌入。一般认为这种实现不利于拓展性(难以直接迁移到更长的句子中)。
三个 embedding 不带权重相加,并通过一层 LayerNorm+dropout 后输出,其大小为(batch_size, sequence_length, hidden_size)。
** [这里为什么要用 LayerNorm+Dropout 呢?为什么要用 LayerNorm 而不是 BatchNorm可以参考一个不错的回答transformer 为什么使用 layer normalization而不是其他的归一化方法](https://www.zhihu.com/question/395811291/answer/1260290120)**
**这里为什么要用 LayerNorm+Dropout 呢?为什么要用 LayerNorm 而不是 BatchNorm可以参考一个不错的回答[《transformer 为什么使用 layer normalization而不是其他的归一化方法》](https://www.zhihu.com/question/395811291/answer/1260290120)**
```python
@ -1105,7 +1107,7 @@ $$SDPA(Q, K, V) = softmax(\frac{QK^T}{\sqrt(d_k)})V$$
而这些注意力头,众所周知是并行计算的,所以上面的 query、key、value 三个权重是唯一的——这并不是所有 heads 共享了权重,而是“拼接”起来了。
**[原论文中多头的理由为 Multi-head attention allows the model to jointly attend to information from different representation subspaces at different positions. With a single attention head, averaging inhibits this. 而另一个比较靠谱的分析有:为什么 Transformer 需要进行 Multi-head Attention](https://www.zhihu.com/question/341222779/answer/814111138)**
**原论文中多头的理由为 Multi-head attention allows the model to jointly attend to information from different representation subspaces at different positions. With a single attention head, averaging inhibits this. 而另一个比较靠谱的分析有:[《为什么 Transformer 需要进行 Multi-head Attention](https://www.zhihu.com/question/341222779/answer/814111138)**
看看 forward 方法:
```
@ -1161,7 +1163,7 @@ def transpose_for_scores(self, x):
attention_scores = attention_scores + relative_position_scores_query + relative_position_scores_key
# ...
```
**[关于爱因斯坦求和约定参考以下文档torch.einsum - PyTorch 1.8.1 documentation](https://pytorch.org/docs/stable/generated/torch.einsum.html)**
**关于爱因斯坦求和约定,参考以下文档:[《torch.einsum - PyTorch 1.8.1 documentation](https://pytorch.org/docs/stable/generated/torch.einsum.html)**
对于不同的positional_embedding_type有三种操作