エポックからエポックに成長するpytorchの高IOデータセットから読み取る方法


8

私はTensorflowを使用していますが、通常はディープラーニングフレームワークによって異なるユーザー向けのドキュメントを作成しています

ローカルファイルシステム(TB +)に適合しないデータセットを操作するとき、リモートデータストアからデータをサンプリングし、サンプルをローカルでTensorflow標準tfrecords形式に書き込みます。

トレーニングの最初のエポックの間、私は数個の値をサンプリングしただけなので、ローカルデータのエポックは非常に小さく、それでトレーニングします。上エポック2 Iは、データファイルは、次のエポックのためのローカルデータファイルの拡張セットに私のサンプリングサブプロセス(今より)と電車で製造されていたものを再検討します。エポックごとにプロセスを繰り返します。このようにして、サンプルのローカルキャッシュを構築し、ローカルストレージがいっぱいになると古いサンプルを削除できます。ローカルサンプルキャッシュは、モデルが最も分散を必要とする頃に(トレーニングの後半に向かって)大きくなります。

Python / Tensorflowでは、PythonのGILがデータ転送速度(300-600 MB /秒、データは未処理の科学的な非圧縮性)をサポートできないため、Pythonトレーニングループプロセスでデータをデシリアライズしないことが重要であり、したがってGPUパフォーマンスPython GILがトレーニングループを高速に処理できない場合に問題が発生します。

tfrecordsサブプロセスからサンプルをファイルに書き込む(Pythonマルチプロセッシング)と、テンソルフローのネイティブTFRecordsDatasetがPythonの外部で逆シリアル化を実行できるため、PythonのGILの問題を回避でき、高いIOデータレートでGPUを飽和させることができます。

Pytorchでこの問題にどう対処するか知りたいのですが。使用しているサンプリング戦略について書いていて、TensorflowとPyTorchの両方のユーザーに特定の推奨事項を提供したいのですが、PyTorchの前処理エコシステムについて十分に詳しく説明できません。

補足:これらのデータ転送速度をサポートする唯一の純粋なPythonベースのソリューションは、System V共有メモリとマルチプロセッシングを備えたPython 3.8で提供される可能性がありますが、まだ十分にサポートされていないため、まだ試していません(まもなく)。既存のマルチプロセッシングソリューションは、トレーニングループプロセスでの逆シリアル化を必要とするため、高IOレートでの逆シリアル化中にGILをロックするため、十分ではありません。


2
データ転送速度がPython GILの影響を受けることをどのようにして知っていますか?私の知る限りでは、ほとんどの場合、GILの影響を受けるのはCPUバウンドオペレーションであり、I / Oバウンドオペレーションではありません。
爆弾

私のテストでは、Pythonプロセス間で達成できる最も速いデータレートで逆シリアル化を行うだけで、ターゲットプロセスを100%のCPU使用率に保ちます。私は多くのアプローチ、非同期、マルチプロセッシング、さらには直接ソケット読み取りを試みました。直接ソケット読み取りの場合、プロセス全体で4 GB /秒を取得でき、バイナリ文字列を結合しようとした瞬間に2 GB /秒に低下し、さらに複雑なものは最大約1 GB /秒の最大転送速度に低下します。これで、ターゲットプロセスがコアを完全に利用し、GILがロックされました。
David Parks

大規模なニューラルネットワークで圧縮されたJPEGを移動するために必要なIOは、小規模なネットワークでの非圧縮の科学データトレーニングが要求するものと比較して小さいため、これは実際にはimagenetのような一般的な大規模なデータセットの問題ではありません。
David Parks

1
文字列結合はCPUバウンド操作に分類され、マシンのI / O容量をまったく使用せずに、100%のCPU容量を簡単に要求できます。したがって、GILがI / Oスループットを制限している証拠ではありません。
爆弾

2
DataLoader私の答えのようにデータが読み込まれる場合、これらの簡単な操作はメインプロセスのGILを要求しません。
爆弾

回答:


7

実際、を使用すると、サブプロセスのデータを簡単に逆シリアル化できますtorch.utils.data.DataLoadernum_workers引数を1以上の値に設定すると、独自のpythonインタープリターとGILを使用してサブプロセスを生成できます。

loader = torch.utils.data.DataLoader(your_dataset, num_workers=n, **kwargs)
for epoch in range(epochs):
    for batch_idx, data in enumerate(loader):
         # loader in the main process does not claim GIL at this point

A Dataloadertorch.utils.data.Datasetからデータを取得する必要があります。あなたのケースで適切なサブクラスを実装することは簡単な仕事ではないかもしれません。Datasetすべてのエポックのインスタンスを再作成する必要がある場合は、このようなことを行うことができます。

for epcoh in range(epochs):
    dset = get_new_dataset()
    loader = torch.utils.data.DataLoader(dset, num_workers=n, **kwargs)
    for batch_idx, data in enumerate(loader):
        # Do training

またはさらに良い

dset = get_new_dataset()
loader = torch.utils.data.DataLoader(dset, num_workers=n, **kwargs)

for epcoh in range(epochs):
    last_batch_idx =  (len(dset)-1) // loader.batch_size
    for batch_idx, data in enumerate(loader):
        # Prepare next loader in advance to avoid blocking
        if batch_idx == last_batch_idx:
            dset = get_new_dataset()
            loader = torch.utils.data.DataLoader(dset, num_workers=n, **kwargs)
        # Do training

注意点として、すなわち、ほとんどの場合、GILの影響を受けていることのCPUバウンドの操作ではなく、I / Oバウンドの操作がありますのでご注意くださいthreading任意の純粋なI / O重い操作のために行うとあなたも必要性がないだろうsubprocess。詳細については、この質問とこのウィキペディアの記事を参照してください。


確認のために、torch.utils.data.DataLoaderサブプロセスからデータをGPUに配置しますか、それともPythonのマルチプロセッシングを使用してデータをトレーニングループプロセスに移動しようとしていますか?1GB /秒に近いデータレートでのあるプロセスから別のプロセスへの逆シリアル化は、1つ以上の完全な作業コアであることを発見したので、TFでこのアプローチを試行したときに遭遇したGILの問題 しかし、torch.utils.data.DataLoaderPythonの逆シリアル化を必要としない方法でGPUにデータを移動する場合、問題はありません。その理解を確認したいだけです。
David Parks

@DavidParksあるプロセスから別のプロセスへの逆シリアル化をテストする場合、どの特定の関数を使用しますか?逆シリアル化プロセスにはCPUバウンド操作が含まれているため、GILの問題が発生しているようです。
爆弾

私はマルチプロセッシング(非常に遅い)、パイプ(より良い)、およびrawソケット読み取り(最高)を試しました。I / OレートがGB /秒のかなりの割合である場合、これらは機能せず、1コアを超えるデータを移動するだけなので、Pythonソリューション(3.8以前とSystem V共有メモリ)はTensorflowで私にとってばらばらになります。そのため、tfrecordsファイルに書き込み、Pythonの外部でtensorflowに逆シリアル化を実行させます。TFはPython GILをロックせず、操作を並列化します。そのため、Python GILがアイドル状態でトレーニングループにサービスを提供できる間、メインプロセスは600%のCPUを使用します。
David Parks

@DavidParksつまり、どのような逆シリアル化関数またはライブラリを使用しますか?(プロセス間通信ライブラリではありません)。 torch.utils.data.DataLoader600%以上のCPUを簡単に利用でき、トレーニングがほとんどGPU計算である場合、メインプロセスはほとんどの場合CPU能力をあまり必要としません(トレーニングがほとんどCPU計算である場合、pytorchの行列演算は複数を簡単に利用できるため、問題はありませんCPU)。
爆弾

ピクルを使用してPythonプロセス間で逆シリアル化し、次にPythonジェネレーター関数を使用してサンプルをTensorFlowエコシステムにフィードします。それが私に失敗したアプローチです。データがTensorFlowエコシステムに入ると、GPUに配置され、トレーニングは別の話になります。TFは、PythonサブプロセスがデータをTFにフィードする方法を提供していません。いくつかのオプションしかありません。tfrecords形式のデータ(プロトコルバッファー形式)が最も論理的です。PyTorchの方が簡単かもしれません。PyTorchユーザーにここで検証してもらいます。
David Parks
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.