1. PyTorch 富岳環境

1.1. LICENSE条項

提供したパッチおよび手順はOSSに提供(Upstream化)しており、Upstream化されたPyTorch分は修正BSDライセンスに準拠します。

1.2. 参考情報

1.3. バージョン (checkout.sh、site-packagesなど参照のこと)

  • PyTorch ver.1.13.1

    • Horovod ver.0.26.1

    • oneDNN ver.2.7.0

  • Python ver.3.9.x 以降

    • numpy ver.1.22.x 以降

    • scipy ver.1.7.x 以降

1.4. 構成

最新版のものは、上記GitHubの手順に従いユーザ環境にて構築しご利用下さいませ。 第2ストレージ階層にPyTorch-1.7.0以前のバージョンについては構築済みのものを公 開しています。サンプル問題は互換ではありませんが、動かし方や性能取得方法など 参考にご利用下さい。

/home/apps/oss/PyTorch-1.7.0/:
  bin: 実行バイナリ
  lib, lib64: ライブラリ
    lib/python3.8/site-packages: PyTorchなどPython module一式
  include: インクルードファイル
  build: 構築に用いたscript, patch類
  example: ResNet-50,OpenNMT,Bert,OpenNMT実行例
  docs: ドキュメント類
  old: 旧公開バージョン

なお最新版へは順次富岳への組み込みをしておりますが、PyTorch本体内の構造変化 に伴い、富岳向け高速化が動作しないことがあります。各バージョンの詳しい制限 事項は上記Wikiを参照下さい。

1.5. 構築方法

ご自身で構築される場合は、build以下をご参照下さいませ。手順は、上記参考資料に記載されております。パスなど調整の上ご利用下さいませ。$PATHなどは適時修正が必要です。構築に3時間程度かかります。

$ git clone https://github.com/fujitsu/pytorch.git
$ cd pytorch                     # これ以降このディレクトリを PYTORCH_TOP と呼びます
$ git checkout -b r1.13_for_a64fx origin/r1.13_for_a64fx
$ cd scripts/fujitsu
$ bash 1_python.sh download
$       ・・・

第2ストレージ階層に配置したバージョンは、Githubで公開されている版をVENVを用いず構築したものです。なるべく絶対パスを埋め込まないように調整しましたので、$HOMEへのコピーやステージングでの使用も可能と想定しています。

1.6. 実行方法

本環境一式は、$PATHを通すことでどこに配置しても実行できます。Python moduleはfile数が多いため、多並列では、MDSアクセス高負荷のためimportlibの時間がかかることが想定されます。利用手引き書の、8.2.4.2. 共通ファイル配布のヒントを参考に、必要な共通ファイルをllio_transferで転送するか、tarなどで固めてllio_transferで転送し展開することでステージングによる利用が可能です。

example配下にイメージ読み込み無(Dry Benchmark)のResNet-50の実行例として、ノード内MPI並列有/無、train/inference、tracer、fipp/fapp/PAの取得例がございます。また自然言語処理のOpenNMT、Bert、物体検知Mask R-CNNなどのサンプルも入っており、高速化ライブラリを読み込めるようになっております。ご参照下さいませ。

手順は、上記参考資料に記載あります。パスなど調整の上ご利用下さいませ。

1.7. 制限事項

高速化パッチがあたらなかったり、PyTorchの仕様変更により、バージョン更新に伴い性能維持が困難でした。

  • 構築問題

    1. SVE版softmax/tanh関数の潜在バグ(提供版は初期値を設定することで対応済)。

    2. -Kastで構築しないと、非正規化数の取り扱いの問題で遅くなる。富岳では-Kfast構築を勧める。

  • 動作注意

    1. ulimit -h 8092を設定しないとSEGVになるサンプルが増えた。

    2. 単精度複素数cdotc_()cdotu_()の内積に関するテストでSSL2内でSEGV発生。

  • 性能問題

    1. addなどコード自動生成化などの抽象化に伴い、高速化パッチが適用できくなった。

    2. oneDNNライブラリ関数eltwise, pooling_v2のVer2.6でレベルダウンにより性能が劣化した。Ver.2.7でeltwizeは回復している。

    3. backwardなどで計算経路が変ったため高速化パッチがあたらない。古いコードパスが残っていいたので暫定対処したが、今後のバージョンで高速に動く保証はない。

1.8. チュートリアル

ここでは、富岳でPyTorchを使用して、画像認識のResnetサンプルを動かす手順を記載します。 富岳にアカウント作成からログインについてはスタートアップガイドを御参考下さい。ここでは、ログイン後に作業領域~/tutorialでの作業を仮定します。

1.8.1. サンプル問題の準備

PyTorchは、/vol0004/apps/oss/PyTorch-1.7.0があらかじめインストールされてい ます。その中のexampleを作業場所にコピーします。95_outputに実行 例が入っていますので適時ご参照下さいませ。ここではサイズが大きいので、除外してコピーします。 サンプルはそれ以降のPyTorchのバージョンと互換ではありません。適時置き換えてご利用下さい ませ。

$ cd                                         # $HOMEへ移動
$ mkdir -p tutorial/PyTorch                  # 作業ディレクトリの作成
$ cd /vol0004/apps/oss/PyTorch-1.7.0/example # PyTorch環境へ移動
$ tar -cf - --exclude=95_output --exclude=95_log . | (cd ~/tutorial/PyTorch ; tar -xvf -) # 作業ディレクトリへ実行例を除いてコピー
$ cd                                         # $HOMEに戻る
$ cd tutorial/PyTorch                        # 作業ディレクトリへ移動
$ ls                                         # 作業ディレクトリの中身を確認
01_resnet   03_Bert        env.src        README.md
02_OpenNMT  04_Mask-R-CNN  env.src.spack

この中に画像認識(Resnet)、自然言語処理(OpenNMT, Bert)、物体検知 (Mask-R-CNN)のサンプルが入っています。またenv.srcには、実行に必要 な環境変数などの設定が入っています。ご自身でPyTorchを動かす時は、PyTorchを動 かす前に、$ . env.srcを実行して下さい。

富岳でジョブを実行するためには、pjsub job_name.shと実行します。 job_name.shの先頭にジョブ投入に必要な情報が記載されています。

#!/bin/bash
#PJM -L "rscunit=rscunit_ft01,rscgrp=small"        # 384ノードまではsmallを使います
#PJM -L elapse=00:15:00                            # ジョブは最大でも15分で終了します
#PJM -L "node=1:noncont,freq=2200"                 # 1ノードを2200MHzで使用します
#PJM --mpi "shape=1,proc=4"                        # 1ノードをMPI 4プロセスで使用します
#PJM -x PJM_LLIO_GFSCACHE=/vol0004                 # PyTorch本体は/vol0004に置いてあるので指定します
#PJM -j                                            # 標準エラー出力を標準出力にマージします
#PJM -S                                            # ジョブ統計情報の詳細を出力します

また、インタラクティブモードを使って計算ノードに直接ログインすることも可能です。 この場合ジョブ実行はpjsub (job_name).shの代わりに bash (job_name).shとして実行します。

$ pjsub (job_name).sh  # バッチジョブでジョブを投入する

$ pjsub --interact -L "node=1" -L "rscunit=rscunit_ft01" -L "rscgrp=int" -L "elapse=1:00:00" --sparam "wait-time=600" -x "PJM_LLIO_GFSCACHE=/vol0004" # 1ノードを1プロセスで1時間使用する
$ pjsub --interact -L "node=1" -L "rscunit=rscunit_ft01" -L "rscgrp=int" -L "elapse=1:00:00" --sparam "wait-time=600" --mpi "proc=4" -x "PJM_LLIO_GFSCACHE=/vol0004" # 1ノードを4プロセスで1時間使用する

$ bash (job_name).sh  # インタラクティブでジョブを実行する。

1.8.2. Resnetサンプルの実行

ResNet-50のネットワークを用いた画像認識を行なうサンプルコードです。ダミーデータを用い ており、推論、学習、データ分散多並列、性能取得、Spackとの併用、LLIOの利用などの実行例 を用意しています。 サンプルモデルの設定は必ずしも最速になっているわけではないことに留意してください。 /vol0004/apps/oss/PyTorch-1.7.0/example/0*/95_outputに富岳での実行結果の例 がありますので比較することができます。

$ cd 01_resnet                 # 画像認識(ResNet-50)のサンプル問題です
$ ls -1                        # ファイルを確認します。以下、順番を入れ替えています
submit_val.sh                  # 推論基本動作確認用 (1ノード, 1プロセス、48コア, ダミーデータ) (4分)
submit_train.sh                # 学習基本動作確認用 (1ノード, 1プロセス、48コア, ダミーデータ) (2分)
submit_val_multi.sh            # 推論基本動作確認用 (1ノード, 4プロセス、12コア/プロセス, ダミーデータ) (3分)
submit_train_multi.sh          # 学習基本動作確認用 (1ノード, 4プロセス、12コア/プロセス, ダミーデータ) (4分)
submit_spack.sh                # 一部PythonやPython moduleをSpackにて使用する例
submit_tar.sh                  # 大並列を想定して、Python moduleをtarで固めて実行する例
submit_llio_pre.sh             # 大並列を想定して、llip_transferで転送するファイルリストを作成する例
submit_llio_main.sh            # 作成されたファイルリストからllio_transferを使用して実行する例
submit_llio_spack_main.sh      # 大並列を想定して、llip_transferでSpackを併用しつつ転送するファイルリストを作成する例
submit_llio_spack_pre.sh       # 作成されたファイルリストからllio_transferを試用して実行する例
submit_trace.sh                # PyTorch Profilerによる性能取得例
submit_fipp.sh                 # Fujitsu Profiler fippによる性能取得例
submit_fapp.sh                 # Fujitsu HWカウンタ fappによる性能取得例
submit_pa.sh                   # Fujitsu HWカウンタ 精密PA性能情報取得例
run_all.sh                     # 全てのサンプルを一括実行するスクリプト
run_llio.sh                    # llio_transferを用いてファイルリストを作成し、本計算をするスクリプト
run_llio_spack.sh              # Spackを使用している時にllio_transferを用いてファイルリストを作成し、本計算をするスクリプト
run_tar.sh                     # Python関係のファイルをtarで固めて実行するスクリプト
test_eval.py                   # 1プロセス推論で使用するPythonコード
test_train.py                  # 1プロセス学習で使用するPythonコード
pytorch_fapp.py                # PyTorchプロファイラ並びにfappカウンタ区間情報をうめたPythonコード
pytorch_synthetic_benchmark.py # データ分散多並列で実行する時に使用するPythonコード
resnet.py                      # ResNet-50のネットワーク定義ファイル

1ノードを1プロセスで画像認識の学習する例を実行します。

$ pjsub submit_train.sh
$ less submit_train.sh.(job_id).out
>> script option: Namespace(batch=256, itr=20, lr=0.001, momentum=0.9, trace=False, type='cpu_mkltensor', weight_decay=0.0)
## Start Training
[    1] loss: 7.269 time: 2.555 s
[    2] loss: 5.051 time: 2.320 s
[    3] loss: 1.229 time: 2.303 s
[    4] loss: 0.012 time: 2.303 s
[    5] loss: 0.000 time: 2.304 s         # ダミーデータで学習させているので
[    6] loss: 0.000 time: 2.304 s         # loss 値はすぐにゼロになります
[    7] loss: 0.000 time: 2.303 s
[    8] loss: 0.000 time: 2.303 s
[    9] loss: 0.000 time: 2.303 s
(省略)

使用できるメモリの範囲でバッチサイズは大きいほど性能の効率は良くなります。但し、 CPUではピークの性能が高くない(単精度で6.6TF程)ため、多くの場合、多ノードでマルチプロセ スで実行する必要があります。submit_train_multi.sh, submit_val_multi.shは 4プロセスでデータ並列学習と推論を実行する例です。 1プロセスのテストで使用しているモ デルとは別のモデルを、異なるパラメーで実行しています。 submit_val_multi.shは4並列で推論を行いますが、 推論の場合、各プロセスは非同期で実行を進めていきます。 以下は富岳(2.2GHz)のsubmit_train_multi.shの出力例です。 4プロセス合計で 100img/sec以上の値が出ています。

(省略)
Running benchmark...
Iter #0: 28.5 img/sec per CPU             # この値は、rank0 プロセスの値
Iter #1: 28.5 img/sec per CPU
Iter #2: 28.5 img/sec per CPU
Iter #3: 28.5 img/sec per CPU
Iter #4: 28.5 img/sec per CPU
Img/sec per CPU: 28.5 +-0.0
Total img/sec on 4 CPU(s): 114.0 +-0.1    # この値は4プロセスの合計値

1.8.3. LLIO_transferによるPython moduleなどのデータ転送

サンプルでは1ノードを用いた例で実行していますが、3rack 1,000並列を越えてくると、画像デー タの増大やPythonモジュールの読み込みに時間がかかるようになるため、予めデータを第1階 層ストレージに持って行くことをお勧めします。第2階層FEFSへのアクセスを減らすため run_tar.shでは、Python環境一式をtarで固めて、計算ノードで展開 するサンプルスクリプトを用意しています。 しかし、計算ノードでは基本的にtar展開処理に伴うファイルI/Oも遅いため、 llio_transferを用いて、必要なファイルだけ転送する方法を推奨します。

$ rm -Rf strace_log               # 不要なファイルを消去します
$ pjsub submit_llio_pre.sh        # 転送すべきファイルをstraceを用いて検索します
$ egrep -v '= \-1 ENOENT|O_DIRECTORY' ./strace_log/strace.0.* | egrep O_RDONLY | cut -d\" -f 2  |egrep ^/vol.... >> llio_transfer.list  # 出力されたstraceの結果から、転送するファイルリストを作成します
$ pjsub submit_llio_main.sh       # lliop_transferを用いた本計算です

submit_llip_pre.shで、必要なファイルを取り出すため、ランク0のみstraceを動かして、アクセスしたファイルを出力します。straceの処理は多少時間がかかるため、 batchサイズや繰り返し回数は少なく設定しています。ここで得られたstraceのログから grepを用いて、転送するファイルリストを作成しています。作成されたファイルリス トの例です。

$ cat llio_transfer.list                      # 転送するファイルの確認
/vol0004/apps/oss/PyTorch-1.7.0/bin/python3
/vol0004/apps/oss/PyTorch-1.7.0/lib/libtcmalloc.so
/vol0004/apps/oss/PyTorch-1.7.0/lib/libpython3.8.so.1.0
/vol0004/apps/oss/PyTorch-1.7.0/lib/python3.8/encodings/__pycache__/__init__.cpython-38.pyc
(省略)

submit_llio_main.shでは、

cat ./llio_transfer.list | xargs -L 100 llio_transfer

として、計算の前にリスト内の1,000ほどのファイルを第1階層に転送しています。

1.8.4. SpackによるPython moduleの利用

実際にPyTorchを用いて学習する際には、/vol0004/apps/oss/PyTorch-1.7.0に用意されたPython moduleだけでは足りず、自分でPython moduleを組み込む必要があります。 一般には、以下の方法で、$HOME/.localに必要なPython moduleを構築して組み込 むことができます。

$ . env.src
$ wget https://(...module_name...)
$ cd (module_name)
$ python3 setup.py clean
$ python3 setup.py bdist_wheel
$ pip3 install --user dist/*.whl

なお、PyTorchで使用するPythonは富士通Cコンパイラのclangモードにて構築しているため、 上記方法では、Python moduleも富士通コンパイラにて構築されます。

外部Python moduleを使用する際には、システムからSpackにて提供されているものを使用する こともできます。Spackでは、あとからloadしたPythonやPython moduleが、動かすために必要 な環境変数LD_LIBRARY_PATHやPYTHONPATHが上書きしますので、使いたいモジュールをなるべく 最後に読み込むようにします。

$ pjsub submit_spack.sh

実際にSpackの設定や提供モジュールを読み込んでいるのは、../env.src.spack内 からです。

$ # Spack
$ . /vol0004/apps/oss/spack/share/spack/setup-env.sh                   # Spackを利用するための環境設定
$ spack load /bo2w4et #py-mpi4py@3.1.2%fj@4.7.0 arch=linux-rhel8-a64fx # mpi4pyをSpackで利用する
$ export LD_LIBRARY_PATH=/lib64:${LD_LIBRARY_PATH}                     # 現段階で問題が発生することがあるため最後に必ず環境変数を並べ替え
$ which python3                                                        # どのPythonが動作しているか確認
$ python3 -c "from mpi4py import MPI"                                  # 動作確認

1.8.5. 性能プロファイルの取得

AI計算をしていると、性能が出ているのかの確認が必要になる場合があります。性能 プロファイル情報を取得する方法としては、PyTorch標準のtorch.autograd.profiler.profile、 富士通プロファイラ、Python標準のcProfileなどの利用が使用できます。ここでは、PyTorch標 準プロファイラ、富士通Profilerの使用例を紹介します。

  • PyTorch標準のプロファイラ:NNの関数レベルでコストを出力することができます。若干メモリを多く使用します。Pythonのループ構造(tab位置)が変るため、コード修正が必要になることがあります。

  • 富士通プロファイラ:バイナリの関数レベルで分析できます。インバランスやMPIのコストも取得できます。またfappやPAを使用することで、詳細のHWカウンタ情報を取得できます。

  • cProfile:Python処理レベルで分析できます。

PyTorch標準のプロファイラを動かす場合は、

$ pjsub submit_trace.sh

です。pytorch_fapp.py内のmainが呼ばれる箇所で、torch.autograd.profiler.profileにより プロファルを取得できます。

with torch.autograd.profiler.profile(record_shapes=True) as prof:
    bench()
print(prof.key_averages().table(sort_by="self_cpu_time_total"))

結果は、ジョブの標準出力に出力されます、

$ less submit_trace.sh.output.(JOB_ID)/0/stdout.1.0 # 標準出力の内容を確認
(省略)
---------------------------------------------  ------------  ------------  ------------  ------------  ------------  ------------
Name                                      Self CPU %   Self CPU    CPU total %     CPU total  CPU time avg         # of Calls
---------------------------------------------  ------------  ------------  ------------  ------------  ------------  ------------
aten::mkldnn_convolution_backward_weights  29.35%       37.254s        29.41%       37.326s      14.085ms          2650
aten::mkldnn_convolution_backward_input    28.67%       36.395s        28.67%       36.395s      13.998ms          2600
aten::mkldnn_convolution                   24.27%       30.804s        24.27%       30.804s      11.624ms          2650
aten::native_batch_norm_backward            5.04%        6.399s         5.09%        6.460s       2.438ms          2650
aten::native_batch_norm                     3.87%        4.915s         3.87%        4.915s       1.855ms          2650
aten::mkldnn_relu_backward                  3.03%        3.850s         3.03%        3.850s       1.572ms          2450
aten::add_                                  1.45%        1.841s         1.45%        1.841s     108.958us         16900
(省略)

上位コストのうちconvolution処理で、MKL DNNライブラリの処理が呼ばれていることがわかります。 富士通プロファイラを使用する場合は、

$ pjsub submit_fipp.sh # fippにてコスト分布を取得する場合
$ pjsub submit_fapp.sh # fappにてHWカウンタ情報などを取得する場合
$ pjsub submit_pa.sh   # 精密詳細PA17回取りにて、詳細の性能を取得する場合

それぞれ、pa*, rep*にプロファイリング情報が出力されるため、ログインノード上で fipppx, fapppxを使用することで、プロファイルを取得することができます。

$ fipppx -A -Ibalance,cpupa,call -l 0 -d pa_fipp  # fippにてコスト分布を取得する場合。
(省略)
              Cost          %  Operation (s)        Barrier          %    Start      End
   -------------------------------------------------------------------------------------
             75590   100.0000      7561.2109          13969    18.4800       --       --   Application
   -------------------------------------------------------------------------------------
             14058    18.5977      1406.2031          13969    18.4800       --       --   __?unknown
              8846    11.7026       884.8591              0     0.0000       --       --   dnnl::impl::cpu::aarch64::jit_aarch64_sve_512_1x1_convolution_bwd_data_t<(dnnl_data_type_t)3, (dnnl_data_type_t)3, (dnnl_data_type_t)3>::execute_backward_data(dnnl::impl::exec_ctx_t const&) const::{lambda(int, int)#1}::operator()(int, int) const
(省略)

$ fapppx -A -Icpupa,mpi -d pa_fapp # loginノードでHWカウンタなど情報を得る場合
(省略)
                   Execution                 Floating-point  Mem throughput  Mem throughput
      Kind          time(s)          GFLOPS   peak ratio(%)          (GB/s)   peak ratio(%)
    ---------------------------------------------------------------------------------------
       AVG         162.9340         59.7380         84.8550          4.6851          0.4575     all 0
       MAX         185.0194         62.6767         89.0293          4.9344          0.4819
       MIN         160.5495         49.7601         70.6819          4.1564          0.4059
(省略)

Pythonでfappを使用して区間指定するためには、fappタイマ区間の 挿入するためのPython wrapperをimportしてます。

pytorch_fapp.py:
  import fapp
  (省略)
  fapp.start("main",1,1)
  for x in range(args.num_iters):
      time = timeit.timeit(benchmark_step, number=args.num_batches_per_iter)
      img_sec = args.batch_size * args.num_batches_per_iter / time
      log('Iter #%d: %.1f img/sec per %s' % (x, img_sec, device))
      img_secs.append(img_sec)
  fapp.stop("main",1,1)
  (省略)

プロファイラの詳細の情報は、ポータルのマニュアルから最新の言語環境を選択し、プロファイラ使用手引書をご覧下さいませ。

1.9. 注意

高速化のために富士通研究所がA64fx向けに組み込んだoneDNN-2.7.0以下のバージョンを使用しています。 画像認識、自然言語処理解析、物体検知など処理の高速化しております。 使用するネットワークによっては、不具合や高速に動作しない関数がある可能性もございますので、問題がある場合は、何らかの別の関数に置き換えるなどにより対応下さいますようお願い致します。

高速化、サポートバージョン、モジュールなどの要望は、使用するネットワークスクリプトをご呈示の上、利用者アカウントのサポートデスク(運技サポートデスク若しくはHPCIサポートデスク)へ御願い致します。対応に数ヶ月を要することもございますのでご了承下さいませ。

1.10. 将来の対応予定

  1. 済 OpenNMTの制限事項の解除 (2021.4頃)

  2. 済 Mask R-CNN対応 (2021.4頃)

  3. 済 オプショナルPython module: netcdfの提供 (2021.4頃)

  4. Spackによるユーザ環境でのbuild (2021後半頃)

  5. Singurarityによるコンテナ提供 (2021後半頃)

  6. 富士通言語環境への追従 (随時)

  7. PyTorch, oneDNNバージョンアップへの追従 (随時)

  8. 旧バージョンへの対応 (2021後半頃)

  9. サポートモジュールの拡大 (随時)

  10. FX700での提供 (2021後半頃)

1.11. 履歴

  • 2020/07/05(日) tcsds-1.2.25-02で構築公開

  • 2020/08/20(木) tcsds-1.2.26で構築更新

    • engine.cpp障害対応

  • 2020/09/08(火) tcsds-1.2.26で構築更新

    • 構築オプション変更

  • 2020/09/08(火) tcsds-1.2.26bで構築更新

  • 2020/10/27(月) tcsds-1.2.27bで構築更新

    • largepageでの実行例の追加

    • fapp、fapp、PA取得時の例を追加

    • 実行スクリプトの調整

  • 2021/2/18(木) PyTorch-1.6.0、PyTorch-1.7.0公開

    • tcsds-1.2.29で構築

    • mpi4py、pandas追加

  • 2021/2/21(日) tcsds-1.3.30aで構築

    • trace、fipp、fapp、PAサンプル追加

  • 2021/5/20(木) Mask R-CNN対応、oneDNN-2.1.0L1を組み込み

    • PyTorch-1.7.0をtcsds-1.3.31で構築

    • OpenNMTのサンプルが止まる問題を修正

  • 2021/10/15(金) ドキュメント公開(Ver.1.0)

  • 2021/12/07(火) ドキュメントアップデート(Ver.1.1) LLIO使用を推奨

  • 2021/12/09(木) tcsds-1.2.33で構築

    • oneDNN追加、llioサンプル追加、spack併用サンプル追加

  • 2021/12/20(月) tcsds-1.2.34で構築 (Spackサンプル34版未対応)

  • 2021/12/26(日) vol0004以外ユーザの対応

    • ユーザ環境でのサンプル実行対応

    • 01_resnet: spack sample, llio sample 未動作

  • 2021/12/30(木) 01_resnet: spack sample, llio sample対応

    • exampleをユーザがbuildするとinstallで失敗しますが、/vol0004/appにコピーをしています

  • 2022/2/28(月) ドキュメントアップデート(Ver.1.2) 日本語チュートリアルを追加

  • 2023/7/13(木) ドキュメントアップデート(Ver.1.3) 新バージョン(PyTorch-1.13.1など)に関する記述記載