「Daskデータフレームのパーティションサイズについて知りたいことのほとんどすべて」

「Daskデータフレームのパーティションサイズに関するすべての興味深い情報」

XGBoostモデルで効果的に活用する方法

プレビュー画像(著者提供)

最近、私と同僚たちは、Xgboost機械学習モデルとDaskを利用して、大規模な高負荷サービスに取り組んでいます。分散データ処理と予測生成のためのツールとしてDaskを最大限活用することに成功した結果を共有したいと思います。

Daskとは何ですか?

Daskは、大量のデータの分散処理のためのライブラリです。その基本的なコンセプトは、大きな配列を小さなパーティションに分割することです。

Dask Dataframeのストレージと処理方法は次のようになります:テーブルは小さなデータフレーム(pandas DataFramesと考えてください)に分割され、メモリに全体のテーブルを保存する必要がありません。ソーステーブル全体のサイズはメモリにロードするには大きすぎるかもしれませんが、個々のパーティションは可能です。さらに、このようなデータストレージは、複数のプロセッサコアを効率的に利用して計算を並列化することができます。

同時に、これらのパーティション(チャンク)のサイズは開発者によって決定されます。つまり、同じデータフレームはたとえば「スプリット1」や「スプリット2」を使用して複数のパーティションに分割することができます(図1を参照)。

図1. Daskデータフレームをパーティションに分割する(著者提供の画像)

適切なパーティションサイズの選択は重要です。なぜなら、最適でない場合、データの処理が遅くなる可能性があるからです。最適なパーティションサイズは、全体のデータセットのサイズや、サーバー(またはノートパソコン)のリソース(CPUの数や利用可能なRAM量)によって異なります。

免責事項:以降、便宜のため、データセットのサイズを行数で測定します。すべてのテーブルは4つの列(3つのフィーチャー+1つのターゲット)で構成されます。アルゴリズムをシステムに実装する際、テーブルの行数ではなく要素の総数(行数×列数)にすべての依存関係を構築しました。

問題点

Daskは、単純な統計や集計を計算するために使用できますが、Daskはまた、大量のデータを使用して大規模な機械学習モデル(例:XGBoost)のトレーニングにも使用できます。私たちが開発していたサービスでは、小さな仮想マシンの場合、わずか8-16GBのRAMを使用して2-10万のレコードに対してモデルをトレーニングする必要があるため、実験を行うことにしました。

単純な統計を計算する場合でも、パーティションのサイズは非常に重要です。なぜなら、2つの場合において計算アルゴリズムの処理を著しく遅くする可能性があるからです:

  • パーティションが大きすぎるため、RAMでの処理に時間とリソースがかかりすぎる
  • パーティションが小さすぎるため、これらのテーブルをDaskが頻繁にメモリにロードする必要があります — 計算自体よりも同期およびアップロード/ダウンロードに時間がかかります

つまり、同じ計算リソースを使用しても、最適でないパーティションサイズを選択することでプログラムのパフォーマンスが著しく低下する可能性があります(図2)。図2は、異なるパーティションサイズのDaskデータフレーム上でXGBoostモデルを適合させる時間を示しています。5回の実行の平均実行時間が表示されています。

図2. パーティションサイズがXGBoostモデルの適合速度に与える影響。これらの実験の元のデータフレームには、50万行と4つの列が含まれています(著者提供の画像)

この記事では、Daskデータフレームのパーティションの最適なサイズのアルゴリズムについて説明します。この記事で示されているすべてのテーブルは、Dask Xgboostの機械学習モデルに適合させるために使用されます。また、役立ついくつかのヒントも共有します。

ドキュメントのヒント

公式のDaskドキュメントには、「Dask DataFrames Best Practices」というような、Daskオブジェクト(データフレーム、配列など)を正しく処理するためのヒントが記載されているウェブページがあります。

特にこのページでは、次のようなアドバイスが示されています。

各パーティションごとに約100MBのデータを目指してください。

ただし、このアドバイスは大まかなものであり、サーバーの計算仕様、ソースデータセットのサイズ、および問題の解決の具体的な要素を考慮していません。

実験の設定

前述のように、最適なパーティションのサイズは次の3つの条件に依存するとされています:

  • フルデータセットのサイズ
  • XGBoostとDaskが使用できるCPUリソース(プロセスの数)
  • 使用可能なランダムアクセスメモリ(RAM)

そのため、実験中には計算リソースの数とソースデータセットのサイズを変化させました。考慮されるケースは以下の通りです:

  • パーティションのサイズ(行数、千単位):[5, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000](13のケース)
  • フルデータセットのサイズ(行数、千単位):[100, 200, 300, 400, 500, 600, 1000, 2000, 3000, 4000](10のケース)
  • CPUリソース(ワーカー数):[2, 3, 4](3のケース)
  • 各ワーカーごとの使用可能なランダムアクセスメモリ(RAM):[1GB, 2GB, 4GB](3のケース)

注:Daskの「Worker」は、それに割り当てられた計算リソースを使用して、他のワーカーと独立かつ並行して実行される、コンピュータ(サーバー)上のプロセスです。

したがって、1170(13 x 10 x 3 x 3)のケースが分析されました。 より頑健な実行時間の推定を得るために、各ケースを5回実行し、指標(実行時間)を平均化しました。

調査の一環として、仮想マシンが負荷を処理できなくなるデータセットのサイズの限界を見つけることで、サービスのスケーリングをより成功させることを目指しました。

結果

まず、実験から得られた一般的な可視化結果を考えてみましょう。異なるCPUコア数、RAMの量、元のデータセットのサイズ、およびパーティションのサイズを使用して実行を行いました。実験を完了した後、与えられた条件(RAM、CPU、およびソースデータセットのサイズ)での実行時間が最小となる最適なソリューション(パーティションサイズ)だけを示すテーブルを作成しました。収集された指標の相関行列は、図3に示されています。

図3. 実験結果の相関行列(著者による画像)

グラフからわかるように、実行時間に最も大きな影響を及ぼしたのは明らかに元のデータセットのサイズでした。ワーカーの数やRAMの量もフィット時間に大きな影響を与えます。チャンクサイズは比較的弱い影響しかありません。ただし、これは実行時間とパーティションサイズの依存関係が非線形である可能性があるためであり、それは図2の曲線で確認できます。また、図4も計測が正しく行われていることを確認できます。なぜなら、結果が私たちの期待と一致しているからです。

3Dグラフのアニメーションを見てみましょう(アニメーション1)。

アニメーション1. 異なるテストケースのグラフであり、各フレームは元のデータセットの固定サイズです。各ケースの最適な表面が表示されています(著者による画像)

このアニメーションでは、最適な(プロセス数とワーカーごとのRAMの組み合わせごとに)ケースは赤で囲まれています。つまり、データセットのサイズ、コアの数、RAM、およびパーティションのサイズが与えられる条件の下で、アルゴリズムの実行時間が最小になる状態が表示されています。グラフにはまた、グレーの分かれ目のある最適な表面が表示されています(注:表面はすべてのケースに対してグローバルです)。

アニメーションから、いくつかのフレームには実験データがないことがわかります(ドットがない)(図4)。これは、提案された計算リソースがモデルの実行に不十分であったことを意味します。

図4. 400万行のデータセットのモデリング結果。RAMが4未満の場合、結果はありません(画像提供元)

この図からわかるように、このデータセットのサイズでは、コアの数が少ない場合は、より大きなパーティションを形成する必要があります。ただし、この依存関係はすべてのケースに当てはまるわけではありません。

計算リソースが不足している場合の実行結果に基づいて、次の可視化が準備されました(図5)。

図5. モデル適合を開始しないデータボリュームの制限。オブジェクトの数は、表の行数に列数を掛けた数で計算されます(画像提供元)

また、失敗した実行の統計に基づいて、以下の結論(ヒント)が得られました:メモリの容量が制限されている場合、小さなパーティションサイズを使用する方が信頼性が高いです。

議論

この研究を基に、Dask XGBoostモデルをより効果的に構成するためのいくつかのヒントが得られました。この研究は、比較的小さなサーバー(数百ギガバイトのRAMや数十のCPUを持たない)でDaskを効率的に実行するために行われました。

実験では、最適なハイパープレーンが明らかにされました。これらはガウシアンプロセスを使用してモデル化されています。このアルゴリズムに基づいて、最適なパーティションサイズが自動的に選択されます(アニメーション2)。

アニメーション2. 異なる条件(CPU、RAM、ソースデータセットサイズ)に対する最適な表面。各フレームには特定のソースデータセットサイズの条件が表示されます(画像提供元)

アニメーションからわかるように、平均的には、ソースデータセットの行数が増えるにつれて、最適なパーティションサイズが減少します

結論(&ヒント)

XGBoostモデルのトレーニングに最適なパーティションサイズがどのようなサイズであるかについてお読みいただいて興味を持っていただけたことを願っています。

この記事が非常に「技術的」になったことを認識しています。そのため、最後まで読んだ方々にはいくつかのヒントを提供します:

  • 実行時間を測定している場合は、計算を複数回実行して結果を平均するようにしてください。ランタイムは確率的であるためです。
  • どのようなパーティションのサイズを選択すべきか迷った場合は、より小さい誤りを出す方が良いです(そうしないとアルゴリズムは長時間実行されるだけでなく、エラーでクラッシュする場合があります)。
  • Daskでローカルクラスターを初期化するには、cluster = LocalCluster()およびClient(cluster)のコマンドが使用されます。Singletonパターンを使用してコード内で一度だけクラスターを初期化することを強くお勧めします。Pythonでそれを実装する方法はこちらで確認できます。そうしないと、毎回新しいクラスターを初期化します。
  • 平均的には、ソースデータセットの行数が増えるにつれて、最適なパーティションサイズが減少します。

ダスクと機械学習に関する記事は、Mikhail Sarafanovワイヤードハットのチームによって発表されました。

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more