1、词表大小:
由于 subword 的广泛使用,NLP 中现在没有太大的词表了。常用的词表大小一般都在 5 万以内,可以直接放在一块显卡上,普通的 Softmax 已经够用了。
退一步讲,即便真的需要对 Softmax 进一步优化和加速,由于 HS 有下面 2 & 3 所述的缺点,现在一般是用 Noise Contractive Estimation 而非 HS。
2、缓存友好性:
HS 这个东西需要反复做 indexing,挑出来某些 ID 对应的向量跟隐状态去算内积,而且每个训练样本要挑的向量个数还是可变的,对并行计算做 batching 实在不友好;从代码的角度讲,这对 TF 这样的静态图框架来说尤其难以实现。
3、并行友好性:
注意区分 总计算量 和 顺序操作的计算量:前者对应 flops,后者对应 latency。前者是指总的运算量,后者是指从输入到输出的关键路径的长度(在有足够多计算资源的情况下,能并行的操作全部并行,最后必须串行的最长路径上需要多少运算量)。
Full Softmax 虽然 total computation 是 O(V) 的,但是其中 sequential operation 是 O(1) 的(注:即便算上归一化求概率的时间,Full Softmax 也只需 O(lg V) 的时间,和 HS 持平);而 Hierarchical Softmax 虽然 total computation 只有 O(lg V),看起来更小,但是 sequential operation 和 total computation 一样,也是 O(lg V) 的!
这意味着,所以当计算核心足够多(>V 个核心)的时候,Full Softmax 并不比 HS 慢!更何况推断的时候,由于不知道目标类别的 ID,HS 不能只算一条目标类别对应的叶节点的概率,而是要整棵树全算一遍,不管是总计算量还是顺序计算量都不再占优势。
在 word2vec 那个年代大家用的都是 CPU,只能串行计算,自然会选择 total computation 更小的 Hierarchical Softmax;而现在大家都在 GPU 上训练,计算核心很多,则会选择 sequential operation 更少、对并行更友好的 Full Softmax。
同理,对于长为 T 的序列,假设每一时间步的运算量为常数,则 RNN 的总计算量为 O(T),Transformer 的总计算量是 O(T^2)(因为需要枚举所有位置对 (i, j) 的组合)。但是如果比较 sequential operation 的话会发现,RNN 的计算量还是 O(T)(因为每个时间步算完才能算下一步),而 Transformer 的计算量则是 O(1)(假设有
这么多计算核心,那么所有结果可以同时算出)。所以在计算资源足够多的前提下,Transformer 速度反而更快(尽管总运算量更大)。