チュートリアル: BeeOND + AzureML:
NVIDIA GPU を使用した HPC スケールの機械学習用の高性能ファイルシステム

原文: Tutorial: BeeOND + AzureML: A High Performance Filesystem for HPC-scale Machine Learning with NVIDIA GPUs
Published 05/25/2021 By Phil Tooley

イントロダクション

近年のディープラーニングのパワーとアプリケーションの爆発的な成長は、GPU コンピューティング ハードウェアの進歩と、ますます接続された世界で利用可能なデータの量が増え続けることの両方によって後押しされています。その結果、最新の高性能機械学習ワークロードは、1TBをはるかに超える巨大なデータセットを持ち、数十から数百のGPUを搭載したクラスターで実行できる規模になっています。しかし、最新のGPUの膨大な演算能力は、同様に膨大なデータスループットを必要とします。ディープラーニングのトレーニングを行う単一のGPUは、数百MB/sの速度でデータを消費し、10~100GB/sの速度でクラスターをトレーニングすることができます。データの枯渇によるボトルネックを回避するには、最新のディープラーニングモデルとNVIDIA GPUハードウェアの容量とスループットの要求に応じて拡張できる高性能データストレージソリューションが必要です。

Azure Machine Learning プラットフォームは、Azure Blob と Azure Files の両方を直接マウントするなど、スケーラブルなデータセット ストレージの多くのオプションを提供します。 これらのサービスは柔軟性と巨大なストレージ スペースを提供しますが、ワークロードにこれらのネットワーク接続ストレージ オプションの機能を超える I/O 要件がある場合はどうなりますか? キャッシュは、ローカル マシンのメモリまたはローカル ディスク ストレージに完全に収まるデータセットの実行可能な戦略ですが、極端なサイズのデータセットの場合、これはオプションではなく、必要に応じて、ある形式の高度にスケーラブルなネットワーク ストレージからのデータのストリーミングに制限されます。 このチュートリアルでは、極端な I/O ニーズを持つ AzureML ワークロード向けの費用対効果が高くスケーラブルなソリューションとして BeeOND ファイルシステムを使用する方法を示します。 私たちのパフォーマンス ベンチマークは、4 つの ND40rs v2 ノード (それぞれに 8 つの NVIDIA V100 Tensor コア GPU を搭載) のクラスターが、読み取りと書き込みの両方で 15GB/秒を超える合計システム帯域幅を達成できることを示しています。

極端な I/O 要件を持つワークロード: CosmoFlow

極端な I/O 要件を持つ ML ワークロードの例として、CosmoFlow を見てみましょう。CosmoFlow は、ダークマター分布の大きな 3D マップから宇宙の宇宙論的パラメーターを学習するための CNN ベースのモデルです。CosmoFlow はMLPerf HPC ベンチマークワークロードの1 つであり、その極端な計算要件のために選ばれました。5.5TB の巨大なベンチマーク データセットがあり、分散トレーニングは 512 NVIDIA V100 GPU 以上に効率的にスケーリングし、各 GPU は平均約 300MB のデータを消費/s ML ワークロードでよくあることですが、CosmoFlow は 1 回の実行で完全なデータセットを何度も繰り返しますが、データセットは大きすぎてメモリやノードのローカル ストレージにキャッシュできません。その結果、何らかの高性能データ ストアからデータをストリーミングする必要があります。

このチュートリアルでは、合計 32 GPU の 4 ノード クラスターで ND40rs v2 インスタンス タイプを使用しました。これは、問題のサイズとしてはかなり控えめなクラスターですが、I/O 帯域幅要件を満たす問題を実証するのにすでに十分な大きさです。各クラスター ノードには 8 個の NVIDIA V100 GPU があり、クラスター全体で 2.5GB/秒または 10GB/秒のノードあたりのスループット要件があり、I/O ボトルネックなしで CosmoFlow をトレーニングできます。Azure ストレージ アカウントの最大下り帯域幅が約 6.25GB/秒 (50Gib/秒) であることを考えると、単一のストレージ アカウントが必要なパフォーマンスを提供できないことは明らかです。Azure NetApp Files は、高性能ネットワーク接続ストレージのもう 1 つのオプションですが、単一インスタンスの最大帯域幅は約 4.5GB/秒であるため、単一の NetApp Files インスタンスでは要件を満たせません。

Azure Virtual Machines の標準イーサネット アダプターは、ハイパーバイザーによって仮想化されます。つまり、ハードウェア オフロードなどのパフォーマンス強化機能は、通常、ゲスト仮想マシンでは利用できません。これにより、全体的なパフォーマンスが制限される可能性があります。たとえば、Azure Blob Storage から ND40rs v2 インスタンスへのデータ ダウンロードのパフォーマンスをベンチマークしたとき、この問題のためにスループットが約 750MB/秒 (6Gib/秒) に制限されていることがわかりました。一部の Azure 仮想マシン タイプは、PCI パススルーを使用してパフォーマンスを向上させる SR-IOV 対応イーサネット (「高速ネットワーク」と呼ばれる) を提供しますが、この機能は現在 Azure ML のプレビュー段階にあり、一般的な使用にはまだ推奨されていません。

一方、ND40rs v2 VMには約3TBのローカルNVMe SSDストレージが搭載されており、読み込み性能は3GB/sをはるかに超えています。1

また、ゲストに直接渡される200GB/sのinfinibandカードにより、フルレートのパフォーマンスが提供されています。

1 もちろん、データセットが十分に小さければ、各ノードに完全なコピーをキャッシュすることもできますが、私たちが求めているのは、極端なデータセットサイズにも対応できるソリューションです。

HPFS オンデマンド

BeeGFSハイ・パフォーマンス・ファイルシステムの開発者は、まさにこれを行うためにBeeOND (BeeGFS on Demand)ツールを開発しました。他のハイ・パフォーマンス・ファイルシステムが同じように使用できない理由はありませんが、BeeONDがオン・ザ・フライ使用のために特別に設計されているという事実は、このチュートリアルのための自然な選択となります。

BeeOND開発者による作業のおかげで、BeeONDファイルシステムの展開は非常に簡単なプロセスであり、3つのステップを必要とします。

  • クラスタ内のすべてのノードにBeeONDソフトウェア・コンポーネントをインストールする。
  • BeeONDツールがノード間で通信するために、(パスワードレスの)SSHを有効にする。
  • クラスタ・ノードのいずれかでBeeONDセットアップ・ツールを実行し、ファイルシステムの一部となるノード、使用するローカル・ストレージ、結果として生じるBeeGFSファイルシステムをマウントする場所を指定する。(ツールはすべてのノードに接続し、ファイルシステムをセットアップするために自動的に設定します。)

AzureML との統合

HPFS をその場で簡単に作成できることがわかったので、Azure ML でどのように機能させるのでしょうか? nAGでは前回のチュートリアルでマスクRCNNを実証し、我々は完全なトレーニングのワークフローを設定するには、PythonのSDKを使用する方法を示しました。 これには、AmlComputeオブジェクトを使用してコンピューティング クラスターを作成し、 Workspaceトレーニングにカスタム Docker コンテナーを使用するようにオブジェクトを構成し、 最後にRunトレーニングの実行を開始するためのオブジェクトを構成して送信することが含まれていました。

BeeOND ファイルシステムを Azure Ml ワークフローに統合したい場合、3 つの主な質問に答える必要があります。

  • BeeOND を構成するために AmlCompute クラスターにアクセスするにはどうすればよいですか?
  • ワークロードが新しいファイルシステムにアクセスできるようにするには、どのように構成すればよいでしょうか?
  • トレーニング データを新しいファイル システムに効率的にステージングするにはどうすればよいでしょうか。

このチュートリアルの残りの部分では、BeeOND をセットアップし、AzureML を介して簡単なベンチマーク スクリプトを実行するために必要な手順を示します。 次のチュートリアルでは、BeeOND ファイルシステムを、CosmoFlow モデルをトレーニングする HPC スケールの ML ワークフローに完全に統合する方法を示します。

BeeOND を AmlCompute クラスターにインストールする

管理タスクを実行するために、実行中の AmlCompute クラスターへの SSH アクセスを許可するように AzureML を構成できます。これを有効にするには、クラスターを作成するときに管理者ユーザー名と ssh キーを提供するだけです。これは、ML Studio または SDK インターフェースのいずれかを使用して実行できます。前のチュートリアルでは Python SDK を使用しました単一のワークフローを設定する方法を示しており、BeeOND ファイルシステムを追加するときに、ここでそれらの例に基づいて構築します。前と同じように、AzureML で Mask RCNN のトレーニングを実演したときは、コンピューティング クラスターを作成することから始めます。ただし、今回は、後でクラスターにログインするために使用する管理者ユーザー名と ssh 公開鍵を提供する必要があります。今回はクラスターの自動スケーリングも無効にする必要があります。これにより、ノードがアイドル状態になったためにシャットダウンされたために BeeOND ファイルシステムが失われるのを防ぎます。これを行うには、クラスター サイズが固定され、自動スケーリングが行われないように、min_nodesとmax_nodesを同じ値 (例: 4) に設定します。

from azureml.core import Workspace
from azureml.core.compute import AmlCompute

workspace = Workspace.get("AzureMLDemo")

cluster_config = AmlCompute.provisioning_configuration(
  vm_size="Standard_ND40rs_v2",
  min_nodes=4,
  max_nodes=4,
  idle_seconds_before_scaledown=300,
  admin_username="clusteradmin",
  admin_user_ssh_key=sshpubkey, # Contents of a public key file
  remote_login_port_public_access="Enabled"
  )

cluster = AmlCompute.create(workspace, "MyCluster", cluster_config)

cluster.wait_for_completion()

クラスター ノードが起動して実行されたら、SSH 経由でそれらに接続し、BeeOND を構成できます。

AmlComputeノードへのSSH接続

クラスタ内のノードに接続するためには、AzureMLサービスに接続に必要なIPアドレスとポートを問い合わせる必要があります。この情報はML Studioで確認できますが、複数のノードを設定したいので、Pythonスクリプトを使用してプロセスを自動化するのが理にかなっています。すべてのクラスタノードの接続情報を取得するには、AmlCompute.list_nodes()メソッドを使用します。接続情報を取得したら、手動でノードにsshするか、paramikoやparallel-sshのようなPythonのSSHクライアントを使ってノードに接続し、設定することができます。

nodelist = cluster.list_nodes()

print("Node connection information:")
for i, node in enumerate(nodelist):
  print("\tNode {}: IP: {} - Port: {}".format(i, node['publicIpAddress'], node['port']))

# Parallel-SSH connection example:
from pssh.clients import SSHClient

client = SSHClient(node['publicIpAddress'], port=node['port'], user="clusteradmin")
host_out = client.run_command('nvidia-smi')
for line in host_out.stdout:
    print(line)
    exit_code = host_out.exit_code

このチュートリアルで提供される例では、clusterconnector.pyというファイルにClusterConnectorクラスが含まれています。このクラスには、クラスタを作成し、並列のssh接続を管理するためのすべての機能が含まれており、ファイルをコピーしたり、すべてのノードで一度にコマンドを実行したり、マスターノードでのみコマンドを実行したりするメソッドを備えています。

clusterconnectorクラスを使用して新しいクラスタを作成し、すべてのノードでコマンドを実行するには、次のようにします。

from clusterconnector import ClusterConnector
clusterconn = ClusterConnector(
    workspace=workspace,
    cluster_name="MyCluster",
    ssh_key=sshpubkey,
    vm_type="Standard_ND40rs_v2",
    admin_user="clusteradmin",
)
clusterconn.initialise(min_nodes=4, max_nodes=4)

clusterconn.run_on_all_nodes('nvidia-smi')

これで、copy_to_all_nodesとrun_on_all_nodes、またはcopy_to_master_nodeとrun_on_master_nodeメソッドを使って、すべてのノードまたはマスターノードだけにファイルをコピーしたり、コマンドを実行したりすることができます。

SSHキーの設定

BeeONDのセットアップでノード同士が確実に接続できるようにするには、パスワードレスのSSHを設定し、クラスタ内のノードのプライベートIPアドレスをすべて集めたノードリストを作成する必要があります。この例では、プライベート・クラスターを使用しているため、パスワードレス・SSHキーを使用しますが、本番環境では適切でない場合もあります。以下のスクリプトは、すべてのノードのプライベートIPアドレスのリストと、パスワードなしのSSHキーのペアを作成し、これらのファイルをすべてのノードにコピーします。

node_list = clusterconn.cluster.list_nodes()

with open('nodefile', 'wt') as fh:
  for node in node_list:
    fh.write("{}\n".format(node['privateIpAddress']))

clusterconn.copy_to_all_nodes('nodefile', '~/nodefile')

ssh_keygen = (r'sudo ssh-keygen -b 4096 -f /root/.ssh/id_rsa -N "" && '
              r'sudo cat /root/.ssh/id_rsa.pub' | tee $HOME/masterkey')
clusterconn.run_on_master_node(ssh_keygen)
clusterconn.copy_from_master_node('~/masterkey', 'masterkey')
clusterconn.copy_to_all_nodes('masterkey', '~/masterkey')

この方法では、マスターノードで秘密鍵を直接生成し、異なるノード間でのコピーを避けることで、潜在的なセキュリティ問題を最小限に抑えています。その後、公開鍵はマスターから他のすべてのノードにコピーバックされます。次のステップでは、公開鍵をワーカー・ノードの最終的な場所に移動させます。

BeeONDソフトウェアのインストール

BeeONDは、Azure MLが使用しているUbuntuディストリビューション用のビルド済みパッケージとして提供されています。そのため、インストールは、BeeONDパッケージ・リポジトリを追加してからBeeONDパッケージをインストールすることになります。ClusterConnectorを使用して効率的にこれを行うために、すべてのノードで実行されるインストール・スクリプトを作成することができます。また、SSH キーが正しい場所にコピーされていることを確認するために、このスクリプトにいくつかの追加ロジックを追加し、BeeOND インストーラのいくつかの構成オプションを設定します。以下は、Debian 9/Ubuntu 18.04を実行しているシステムにBeeONDをプロビジョニングするスクリプトです。

#!/bin/bash

echo "Installing master public key:"
cat masterkey | sudo tee -a /root/.ssh/authorized_keys

echo -e "\n\n### Provisioning BeeOND FS:\n"

echo "Adding BeeOND public key"
wget -q https://www.beegfs.io/release/latest-stable/gpg/DEB-GPG-KEY-beegfs -O- | sudo apt-key add -

echo "Adding BeeOND repo"
wget -q https://www.beegfs.io/release/beegfs_7.2/dists/beegfs-deb9.list -O- | \
  sudo tee /etc/apt/sources.list.d/beegfs-deb9.list &>/dev/null

echo "Updating apt index and installing BeeOND"
sudo apt-get update -q
sudo apt-get install -y beeond

echo "Configuring path to kernel headers"
cat <<EOF | sudo tee /etc/beegfs/beegfs-client-autobuild.conf
buildArgs=-j20 OFED_INCLUDE_PATH=/usr/src/ofa_kernel/default/include
buildEnabled=true
EOF

このスクリプトはいくつかの異なる作業を行います。まず、前のステップで作成した公開鍵を、最終的に/rootフォルダにコピーします。次に、BeeONDパッケージをインストールするために、BeeONDファイル・リポジトリとその公開鍵をパッケージ・マネージャの構成に追加します。その後、パッケージ・マネージャー・インデックスが更新され、BeeONDソフトウェアがインストールされます。最後に、小さな設定スニペットがBeeONDクライアント用に追加され、後で必要なビルド依存性を見つけることができます。

この例では、スクリプトが provision_beeond.sh として保存されているものとします。

clusterconn.copy_to_all_nodes('provision_beeond.sh', '~/provision_beeond.sh')
clusterconn.run_on_all_nodes('sudo bash ./provision_beeond.sh')

BeeONDファイルシステムの起動

最後に、BeeONDファイルシステムを起動します。これを行うには、スタートアップ・スクリプトをノードの1つだけで実行し、先にアップロードしたノードリストを提供して、クラスタ内で使用するノードをBeeONDに伝えます。また、基礎となるストレージに使用するパス(VM上のローカルNVMeのための/mnt/resource)と、ファイルシステムをマウントするパス(このチュートリアルでは/mnt/scratchを使用します)を伝えるためのオプションを渡します。これにもclusterconnectorを使用します。

beecmd='sudo beeond start -n nodefile -f /root/bgconf -d /mnt/resource -c /mnt/scratch -F'
clusterconn.run_on_master_node(beecmd)

ClusterConnectorクラスに加えて、このチュートリアルのサンプルにはBeeONDClusterConnectorクラスも含まれています。これはこのセクションのすべてのステップを実装しており、BeeONDファイルシステムを備えたすぐに使えるクラスタを非常に簡単に作成することができます。

from clusterconnector import BeeONDClusterConnector

beeclusterconn = BeeONDClusterConnector(
    workspace=workspace,
    cluster_name="MyCluster",
    ssh_key=sshpubkey,
    vm_type="Standard_ND40rs_v2",
    admin_user="clusteradmin",
)
beeclusterconn.initialise(num_nodes=4, beeond_mnt="/mnt/scratch")

これは、上に示したすべてのステップを実装して、/mnt/scratchにマウントされたBeeONDファイルシステムを持つ固定サイズの4ノード・クラスタを作成します。

AzureMLワークロードでのBeeONDの使用

Mask-RCNチュートリアルと同様に、カスタムDockerコンテナを使用してワークロードをデプロイし、以前と同様にトレーニング用のEnvironmentオブジェクトに定義します。AzureML SDKは、Dockerの様々な設定オプションを提供しており、カスタムのDockerコマンドライン引数を渡す方法も含まれています。これを使って、新しいBeeONDファイルシステムをDockerコンテナに好きなマウントポイントにバインドマウントするための引数を渡すことができます。例えば、Beeond FSを/mnt/scratchにマッピングし、コンテナ内のディレクトリ/dataにマッピングするには、-v /mnt/scratch:/dataという引数を渡します。これを、カスタムDockerfileに基づいて環境を作成するために以前使用したコードと組み合わせると、次のようになります。

from azureml.core import Workspace, Environment

workspace = Workspace.get("AzureMLDemo")

environment = Environment("CosmoFlowDockerEnvironment")

environment.docker.enabled = True # Tell AzureML we want to use Docker
environment.docker.base_dockerfile = "./MyDockerfile" # Path to local Dockerfile
environment.python.user_managed_dependencies = True  # AzureML shouldn't try to install things

environment.docker.arguments = ['-v', '/mnt/scratch:/data'] # Bind mount our BeeOND FS

environment = environment.register(workspace) # Validate and register the environment

これで、ワークロードが実行されると、コンテナ内の/dataディレクトリにあるBeeONDファイルシステムにアクセスできるようになります。

パフォーマンスのテスト

ファイルシステムのパフォーマンスを評価するために、elbencho storage benchmarking toolを使用しました。elbenchoは、最新の分散ストレージファイルシステムのパフォーマンスをテストするために設計されており、同時に多くのクライアントからのオペレーションのオーケストレーションをサポートしています。elbenchoは、デバイス全体、ファイルシステムのリード/ライト、GPUデータ転送のベンチマークなど、さまざまなテストをサポートしています。このチュートリアルでは、ハイパフォーマンス・ストレージのための汎用ソリューションとしてのBeeONDのパフォーマンスを実証するために、ファイルシステムのリード/ライトテストを行うことにしました。

ベンチマークを実際に実行するために、AzureMLで使用するカスタムDockerコンテナにelbenchoをインストールしました。このためのDockerfileは、付属のGitHubリポジトリで公開されています。ベンチマークのジョブは、Mask R-CNNチュートリアルと同様に送信できます。ここでは、AzureMLにbashスクリプトを実行するように指示し、希望する設定でelbenchoを実行するようにします。

script_conf = ScriptRunConfig(
        source_directory="scripts",
        command=["bash", "./run_elbencho_multifile.sh", ...],
        compute_target=clusterconnector.cluster,
        environment=environment,
        distributed_job_config=parallelconfig,
    )

scriptは明示的にPythonスクリプトを想定していますが、commandは任意の有効なLinuxコマンドラインを想定しています。完全なジョブ投入スクリプトは、GitHub リポジトリの beeond_run_elbencho.py と elbencho オーケストレーションスクリプト scripts/run_elbencho_multifile.sh にあります。

我々のケースでは、ND40rs_v2インスタンスの4ノードのBeeONDクラスタ(合計32のNVIDIA V100GPU)をテストしました。ファイルサイズは256kBから64MB、クライアントあたりのI/Oスレッド数は1から128までとし、すべてのノードで同時に読み書きのパフォーマンスをベンチマークしました(このケースでは、クラスタノードがストレージサーバとクライアントを兼ねていることを思い出してください)。各テストでは合計12800個のファイルを使用し、各フェーズの前後ですべてのファイルキャッシュを削除して、読み取りベンチマークがRAMキャッシュからではなく、真にNVMeからのものであることを確認しました。4ノードのクラスターで得られた結果を以下に示します。

beeond
4台のND40rs_v2ノードにおけるBeeondファイルシステムの集約的な読み取りと書き込みのパフォーマンス

これは、4つのノード上でチューニングされていない「箱から出したばかり」のパフォーマンスとしては素晴らしい結果であり、システム全体のバンド幅は10GB/sを確実に超え、クライアントごとに複数の並列I/Oスレッドを使用した大規模ファイルでは2.5GB/s/ノードに達しています。この性能は、約16MBのデータファイルと高度な並列アクセスパターンに対して約2.5GB/s/nodeの読み取り性能を必要とするCosmoFlowにとって、十分なものです。場合によっては、読み取り性能はシステム全体の帯域幅が15GB/sを超え、書き込み性能も大容量ファイルの並列書き込みで15GB/sを確実に超えることもある。データの傾向を詳しく見ると、ここには「メタデータの制限」と「帯域幅の制限」という2つの異なるパフォーマンス体制があることがわかります。

メタデータの制限は、より小さなファイルで発生し、トータルのスループットはBeeGFSメタデータ・サーバがアクセスされるファイルの数に追いつくかどうかに依存します。例えば、256kBと1MBのファイルでは、リードとライトの両方で、ノードあたりのパラレルI/Oスレッドが1から8になるとパフォーマンスが向上しますが、スレッドの数がさらに増えるとパフォーマンスが停滞し、メタデータ・サーバがリクエストでオーバーロードになると再び低下します。デフォルトでは、BeeONDツールはクラスタ・インスタンスに1つのメタデータ・サーバしか設定しませんが、必要に応じてもう1つメタデータ・サーバを追加することで、スモール・ファイルの読み取り性能を向上させることができます。書き込みパフォーマンスの改善は、メタデータの同期が問題となるため、複数のメタデータ・サーバーを使用する場合は少し複雑になります。

一方で、I/O帯域幅が制限されているケースもあります。これは、大容量のファイルの場合、メタデータのリクエスト率が非常に低く、ファイルごとに多くのデータを転送する必要がある場合に見られます。この場合、最初にI/Oスレッドを増やすとパフォーマンスが向上し、NVMeディスクのI/O帯域幅が飽和すると失速しますが、メタデータ制限の場合に比べて、競合の増加によるパフォーマンスの低下は小さくなります。これはデータの書き込みよりも読み込みの方が問題となりますが、これは書き込み時にシステムが追加でライトキャッシュを利用して実効書き込み速度を向上させることができるためです。読み取りベンチマークでは、NVMeからすべてのデータを確実に読み取るために、意図的にすべてのキャッシュを削除しているため、これは不可能です。また、システム全体の帯域幅を見るとその影響は見えませんが、個々のファイルのスループットは、競合の増加によって影響を受け、そのファイルのI/Oが遅くなる可能性があることにも注意してください。

クラウドHPC移行サービス

nAGはクラウドHPC移行サービスHPCコンサルティングを提供しており、組織がクラウドとHPCのために数値計算アプリケーションを最適化するのを支援します。HPCに関するベンダーにとらわれない公平なアドバイスとnAGがクラウドへの移行をどのように支援できるかについては、HPCとクラウドのコンサルティングとサービスをご覧ください。

関連情報
MENU
© 日本ニューメリカルアルゴリズムズグループ株式会社 2025
Privacy Policy  /  Trademarks