这里回顾了BERT的重要自监督任务:masked input:randomly mask some tokes and predict them
作者提到了3点看法(以后随着技术发展,背景又肯定不一样了):
1.cv和nlp架构不同(cv—过去十年是卷积的时代,nlp,由transformer主宰)
2.图像和语言的数据特点不同——图像具有较高的空间信息冗余度,即使缺失一两个像素,图像的空间信息也不会遭到很大损失。但是语言就不同了(想象一下说话缺动词或者缺主语,听不懂了吧)。因此作者提出了,将图像的mask ratio提高到惊人的75%,只使用剩余的25%去reconstruct图像,这样做的目的是迫使机器“好好学习”,即原文所说
This strategy largely reduces redundancy and creates a challenging selfsupervisory task that requires holistic understanding beyond low-level image statistics。
3.The autoencoder’s decoder, which maps the latent
representation back to the input, plays a different role between reconstructing text and images.这条似乎还是个实验性的结论.
overhead 开销
这里讲了如何实现mask:
1.random shuffle tokens列表(实现随机mask)
2直接remove列表最后数目为ratiolen(tokens)的元素。这些元素就是mask掉的tokens.
3.encode剩下的元素
4.encoded列表又append上数目为ratiolen(tokens)的mask tokens,并unshuffle这个列表。具体细节见下面源码阅读。
6.将unshuffle后的列表加上他们的positional embedding,并给decoder.
代码demo实操:
使用gan loss的mae效果非常好,如上,第三个和第四个分别是重构图片与重构图片补上未遮挡patch所形成的图片。(重构图片没有对那些未遮挡patch的tokens的模型输出计算损失并优化,只对mask的部分进行优化)
pytorch版本官方源码阅读
1.关于depth:
由于mae的encoder直接沿袭ViT的架构,因此它的深度参数直接省略了,直接在不同规模的模型命名中体现:如图:
以上是models_mae.py
仅仅有decoder_depth的参数。想看encoder的深度,需要到model_ViT.py中找。
# add pos embed w/o cls token
x = x + self.pos_embed[:, 1:, :]
对于以上的代码段:cls_token没有position_embedding
2.关于decoder
和encoder一样,官方实现decoder采用了ViT 的transformer架构。
这里是forward_decoder函数。这里对应上面第四步unshuffle操作,可以看到,cls_token始终位于所有token开头,没有参与shuffle与unshuffle操作。每一个mask_token都是一个可以学习的参数。
这里我不太明白,decoder_pos_embed直接就加到x上,这里x是包括cls_token的,cls_token按理不应该有pos_embed不是吗
关于爱因斯坦求和np.einsum
官方文档介绍,numpy
官方文档介绍,torch
在这里,einsum的作用是把第二个维度放到了最后,最后的维度变为nhwpqc。einsum非常灵活,首先自己用六个字母nchpwq指定了x张量的下标,然后做了维度调换的操作变为nhwpqc。从而接下来的reshape做准备。
关于训练和demo展示的区别
细节:一张图片patchify经过mae的encoder和decoder,得到输出是(1,token_length(不包括cls),patch_size x patch_size x in_chans).mae输出没有经过unpatchify的操作。
mae在训练时实际将target,即标签图片首先patchify,然后跟自己的输出进行误差计算。在demo展示时其输出经过unpatchify方得到图片的标准维度,可以展示。
源码Block引用:如果你安装了最新的timm,
在Block的参数列表中,qk_scale=None参数应删去
mae util中正余弦编码有一行assert,内容是检查embed_dim是不是偶数,如果是奇数就会报错。
embed数目为奇数