近日阅读 Bert 源码,读到其中所谓“可训练式”的位置编码的部分,似乎具体实现就是初始化一个可训练的,然后把它加到输入上,这就算是可训练的位置编码了。
def __init__(self):
super()
positional_encoding = nn.Parameter()
def forward(self, x):
x += positional_encoding
我不太能确定是否就是这么简单,还是我理解错了。
另外我注意到按照经典 Bert 的实现:
BertModel(
(embeddings): BertEmbeddings(
(word_embeddings): Embedding(30522, 768, padding_idx=0)
(position_embeddings): Embedding(512, 768)
(token_type_embeddings): Embedding(2, 768)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(encoder): BertEncoder(
(layer): ModuleList(
(0): BertLayer(...)
...
(pooler): BertPooler(...)
实际上它只进行了一次 positional_embedding ,也就是在输入的时候,这是否意味着实际上所谓的能把握序列信息的也只有第一层,后面的 bert 层是无法识别位置信息的?
但是这么说的话,按照我上一个帖子的内容 https://v2ex.com/t/868398#reply5 ,bert 的输出根据设置一般有两部分,一部分是类似原始输入序列长度对应长度的数组,表示每个字经过特征提取后的消息,另一部分是一个表示全句子整体信息的层。理论上前者应该与输入是一一对应的,但是它都不能捕捉位置,这不是很矛盾吗
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.