PyTorch Distributed Elastic における RendezvousTimeoutError の原因と解決策


PyTorch Distributed Elastic における torch.distributed.elastic.rendezvous.RendezvousTimeoutError は、分散学習の初期化プロセスでタイムアウトが発生したことを示すエラーです。これは、ワーカーノード間で通信に問題が発生した場合や、ワーカーノードの起動に時間がかかった場合などに発生します。

原因

このエラーが発生する主な原因は以下の通りです。

  • 古いバージョンの PyTorch
    古いバージョンの PyTorch を使用している場合、Rendezvous プロセスにバグが存在する可能性があり、タイムアウトが発生する可能性があります。
  • ワーカーノードの起動遅延
    一部のワーカーノードが他のワーカーノードよりも起動に時間がかかる場合、Rendezvous プロセスがタイムアウトする可能性があります。
  • ネットワークの問題
    ワーカーノード間のネットワーク接続が不安定または途切れている場合、Rendezvous プロセスがタイムアウトする可能性があります。

解決策

このエラーを解決するには、以下の対策を試すことができます。

  • PyTorch のアップグレード
    最新バージョンの PyTorch を使用していることを確認してください。古いバージョンの PyTorch には、Rendezvous プロセスのバグが存在する可能性があります。
  • ワーカーノードの起動順序の調整
    すべてのワーカーノードが同時に起動するようにしてください。ワーカーノードの起動順序を制御できるジョブオーケストレーションツールを使用することができます。
  • ネットワークの確認
    ワーカーノード間のネットワーク接続が安定していることを確認してください。ファイアウォール設定が Rendezvous プロセスを妨げていないことも確認してください。
  • Gang scheduling を使用して、すべてのワーカーノードが同時に起動されるようにすることができます。
  • Rendezvous タイムアウト値を調整することができます。これを行うには、torch.distributed.elastic.init_process_group() 関数の timeout 引数を使用します。
  • Rendezvous プロセスのログを記録して、問題の原因を特定するのに役立ててください。

この問題は、PyTorch Distributed Elastic を使用して分散学習を行う場合によく発生します。上記の解決策を試しても問題が解決しない場合は、PyTorch コミュニティフォーラムで助けを求めることをお勧めします。

プログラミング

この問題は、Rendezvous プロセスがタイムアウトしたことを示すエラーです。Rendezvous プロセスは、ワーカーノード間で通信して、分散学習を実行するために必要な情報を共有するために使用されます。

このエラーをプログラムで処理するには、try...except ブロックを使用することができます。以下の例は、RendezvousTimeoutError が発生した場合にエラーメッセージを出力する方法を示しています。

try:
    torch.distributed.elastic.init_process_group()
except torch.distributed.elastic.rendezvous.RendezvousTimeoutError:
    print("Rendezvous timed out.")


import torch
import torch.distributed.elastic as dist


def main():
    try:
        # ランクとワールドサイズを初期化する
        rank = dist.get_rank()
        world_size = dist.get_world_size()

        # 分散学習を実行する
        # ...

    except torch.distributed.elastic.rendezvous.RendezvousTimeoutError:
        print(f"Rank {rank}: Rendezvous timed out.")

    finally:
        # 分散環境を終了する
        dist.shutdown()


if __name__ == "__main__":
    main()

このコードでは、まず torch.distributed.elastic.init_process_group() 関数を使用して、分散環境を初期化します。この関数は、現在のワーカーノードのランクとワールドサイズを取得します。

次に、分散学習を実行します。この部分は、具体的な学習タスクによって異なります。

try...except ブロックを使用して、RendezvousTimeoutError を処理します。このエラーが発生した場合、エラーメッセージが出力されます。

最後に、dist.shutdown() 関数を使用して、分散環境を終了します。

以下のコードは、RendezvousTimeoutError が発生した場合に再試行する例です。

import torch
import torch.distributed.elastic as dist
import time


def main():
    for _ in range(3):
        try:
            # ランクとワールドサイズを初期化する
            rank = dist.get_rank()
            world_size = dist.get_world_size()

            # 分散学習を実行する
            # ...

            break

        except torch.distributed.elastic.rendezvous.RendezvousTimeoutError:
            print(f"Rank {rank}: Rendezvous timed out. Retrying...")
            time.sleep(1)

    else:
        print("Rendezvous failed after 3 retries.")

    finally:
        # 分散環境を終了する
        dist.shutdown()


if __name__ == "__main__":
    main()


再試行

最も簡単な代替手段は、RendezvousTimeoutError が発生した場合に再試行することです。多くの場合、一時的なネットワークの問題やワーカーノードの起動遅延が原因でエラーが発生するため、再試行することで問題が解決することがあります。

以下のコードは、最大3回まで init_process_group を再試行する例です。

import torch
import torch.distributed.elastic as dist
import time

def main():
    for _ in range(3):
        try:
            # ランクとワールドサイズを初期化する
            rank = dist.get_rank()
            world_size = dist.get_world_size()

            # 分散学習を実行する
            # ...

            break
        except torch.distributed.elastic.rendezvous.RendezvousTimeoutError:
            print(f"Rank {rank}: Rendezvous timed out. Retrying...")
            time.sleep(1)

    else:
        print("Rendezvous failed after 3 retries.")

if __name__ == "__main__":
    main()

再試行する前に、少しだけ待つようにしてください。1秒程度待つことで、ネットワークの状態が安定するのを待つことができます。

Gang Scheduling

Gang scheduling は、すべてのワーカーノードを同時に起動するジョブオーケストレーション手法です。これにより、ワーカーノード間の起動時間の差がなくなり、RendezvousTimeoutError の発生を抑制することができます。

Kubernetes や Slurm などのジョブオーケストレーションツールを使用して、Gang scheduling を実装することができます。

バックエンドの変更

PyTorch Distributed Elastic は、複数のバックエンドをサポートしています。デフォルトのバックエンドは TCPStore ですが、GlooStoreNcclStore などの他のバックエンドを使用することもできます。

異なるバックエンドは、異なるネットワーク特性を持っているため、特定の環境では別のバックエンドの方がうまく動作する可能性があります。

init_process_group 関数の store 引数を使用して、使用するバックエンドを指定することができます。

dist.init_process_group(store="gloo")

ログの確認

RendezvousTimeoutError が発生した場合、ログを確認することで、問題の原因を特定することができます。

PyTorch Distributed Elastic は、以下のログレベルを提供しています。

  • ERROR
  • WARNING
  • INFO
  • DEBUG

ログレベルを DEBUG に設定することで、Rendezvous プロセスに関する詳細な情報を確認することができます。

ログを確認するには、以下のコマンドを使用することができます。

export TORCH_DISTRIB_DEBUG=1

コミュニティへの問い合わせ

上記の方法を試しても問題が解決しない場合は、PyTorch コミュニティフォーラムで助けを求めることをお勧めします。

PyTorch コミュニティには、多くの経験豊富なユーザーがおり、問題解決に役立つアドバイスを提供してくれる可能性があります。

注意事項

これらの代替手段は、根本的な原因を解決するものではありません。根本的な原因を解決するには、ネットワークの問題やワーカーノードの起動遅延などの問題に対処する必要があります。

また、これらの代替手段を使用すると、パフォーマンスが低下したり、予期しない動作が発生したりする可能性があることに注意してください。