私は、たとえば1,000万クラス程度の大きな語彙を処理できる階層型ソフトマックスモデルの実装に興味があります。これを行うための最良の方法は、多数のクラス数にスケーラブルで効率的であるために何ですか?たとえば、少なくとも 1つの論文 は、各ノードがsqrt(N)
クラスである2レベルのツリーを使用すると、HSが大きなボーカブに対して最大25倍のスピードアップを達成できることを示しています。任意の分岐係数を持つ任意の深さツリーのより一般的なバージョンにも興味があります。
ここに表示されるオプションがいくつかあります。
1)すべてのバッチに対してtf.gather
を実行し、インデックスと分割を収集します。これにより、バッチサイズが大きく、ファットツリーで問題が発生し、係数が頻繁に複製され、OOMエラーが発生します。
2)#1と同様に、tf.embedding_lookup
を使用できます。これは、OOMエラーのヘルプを維持しますが、すべてをCPUに保持し、処理速度を大幅に低下させます。
3)tf.map_fn
とparallel_iterations=1
を使用して、各サンプルを個別に処理し、gatherの使用に戻ります。これははるかにスケーラブルですが、シリアル化のために25倍のスピードアップに実際には近づきません。
HSを実装するためのより良い方法はありますか?深くて狭い木と短くて広い木には異なる方法がありますか?
GPUクラスのパフォーマンスが必要だとおっしゃっています。
しかし今はすべてをCPUに保持し、物事をかなり遅くします
300ユニットの隠しサイズと10Mワードの辞書を使用したいと考えています。
つまり、(float32
と仮定すると)、出力レイヤーのパラメーターと勾配を格納するためだけに、4 * 300 * 10M * 2バイト= 24GBが必要になります。
階層型ソフトマックス(HSM)は、メモリ要件を削減するのではなく、トレーニングを高速化するだけです。
現実的には、次のものも保存する必要があるため、より多くのGPUメモリが必要になります。
他のパラメータとその勾配
オプティマイザーデータ、例運動量トレーニングの速度
アクティベーションと逆伝播された一時データ
フレームワーク固有のオーバーヘッド
したがって、GPUですべての計算を実行する場合、このレイヤーを複数のハイメモリGPUに分散する以外に選択肢はありません。
ただし、別の問題があります。
これを具体的にするために、クラスごとに3Kワード(合計900万ワード)の3Kクラスの2レベルHSMがあるとします。 3Kクラスを8つのGPUに分散して、それぞれが384のクラスをホストするようにします。
バッチ内のすべてのターゲット単語が同じ384クラスからのものである場合、つまりそれらは同じGPUに属しますか? 1つのGPUがすべての作業を行い、他の7つはそれを待ちます。
問題は、バッチ内のターゲットワードが異なるGPUに属している場合でも、TensorFlowでこの計算を実行する場合は、最悪のシナリオと同じパフォーマンスが得られることです(これは、TensorFlowが「指定して実行する」フレームワーク-計算グラフは、最良の場合と最悪の場合で同じです)
これを行うための最良の方法は、多数のクラス数にスケーラブルで効率的であるために何ですか?
モデルの並列処理の上記の非効率性(各GPUはバッチ全体を処理する必要があります)は、すべてを1か所に保持するように努める必要があることを示唆しています。
すべてをホストまたは1つの巨大なGPUに実装していると仮定します。
シーケンスをモデリングしていない場合、またはモデリングしているが、シーケンス全体に対して出力が1つしかない場合、参照したパラメーターのコピーによるメモリオーバーヘッドは、上記のメモリ要件と比較して無視できます。
400 ==バッチサイズ<<クラス数== 3K
この場合、単にgather
またはembedding_lookup
を使用できます(ただし、コピーは非効率的です)
ただし、すべてのタイムステップで出力を使用して、たとえば100の長さのモデルシーケンスを実行する場合、パラメーターのコピーが大きな問題になります。
この場合、C++/CUDA Cにドロップダウンして、このレイヤー全体とそのグラデーションをカスタム操作として実装する必要があると思います。