Moco希望构建的字典是:(i)大的和(ii)在训练过程中不断演变的一致的。主要通们将字典维护为一个数据样本队列:当前小批处过理的编码表示被加入队列,最老的表示被退出队列。
首先我们假设 Batch size 的大小是 N ,然后现在有个队列 Queue,这个队列的大小是 K(K>N) ,注意这里 K 一般是 N 的数倍,比如 K=3N,K=5N,... ,但是 K 总是比 N 要大的 (代码里面 K=65536 ,即队列大小实际是65536)。
下面如上图所示,有俩网络,一个是 Encoder fq ,另一个是Momentum Encoder fMk 。这两个模型的网络结构是一样的,初始参数也是一样的 (但是训练开始后两者参数将不再一样了)。 fq 与 fMk 是将输入信息映射到特征空间的网络,特征空间由一个长度为 C 的向量表示,它们在代码里面分别表示为:f_q , f_k 和 C。
代码里的 k 可以看作模板,q 看作查询元素,每一个输入未知图像的特征由 f_q 提取, 现在给一系列由 f_k 提取的模板特征 (比如狗的特征、猫的特征) ,就能使用 f_q 与 f_k 的度量值来确定 f_q 是属于什么。
这里采用infoNCE的对比损失函数:
fk权重具体更新公式:
在实验中,相对较大的动量(例如,m = 0.999,我们的默认值)比较小的值(例如,m = 0.9)工作得更好,这表明缓慢发展的键编码器是利用队列的核心。
在实验中,我们发现使用BN会阻止模型学习好的表示,通过shuffling BN解决:我们使用多个GPU进行训练,并针对每个GPU独立地对样本执行BN(就像通常的做法一样)。对于关键编码器fk,在分配到gpu之间之前,我们将当前小批中的样本顺序进行洗牌(并在编码后重新洗牌);查询编码器fq的小批处理的样例顺序没有更改。这确保用于计算查询及其正键的批统计信息来自两个不同的子集。