Jetson xavierをCUDAで動かして、さしあたって10倍早くなる

MNISTの手書き数字データをアソシアトロンで認識させ、評価したいと思っている。6万個の学習データがあるので、想起ベクトルを75264次元にしている。1文字のピクセル数は文字28ビット×28ビット=784で、文字データのラベルは、1バイトなので本当は、1ピクセル256次元使いたいのだが、そうすると、私のJetson xavierでは、メモリを食い尽くしてしまうので、1文字の1バイトデータを96bit(CUDAは32の倍数が好みだから)に縮小して、結局、784×96=75264で、結局上の次元になる。

だから、アソシアトロンの想起マトリクスは75264×75264=5664669696要素を持つことになって、巨大である。でもこれならば、なんとかGPUのグローバルメモリを取れて、データのコミュニケーションができる。ただし、1データをunsigned shortの2バイトで、マトリクスの右上三角と左下三角は対称的なので、片側の三角だけをデータで取るなどの操作をしなければならない。まともに作ると、グローバルメモリに乗らないのだ。

6万個のデータをすべて想起行列に載せることはまだやっていないが、約50個のデータを載せてみた。XavierのGPUを使わずCPU(8コア乗っている)だけで1スレッドだけ使って動かすと、5分かかる。timeコマンドを使って計算した結果は次のようなものである。

real 5m47.163s
user 5m46.680s
sys 0m0.456s

まともに6万個やると、100時間、つまり4日ほどまるまるコンピュータを動かさないといけない。

これをJetson XavierのGPU(512コア)で並列計算させると、50個30秒で終わる。timeコマンドの結果は次のようになっている。

real 0m30.672s
user 0m28.764s
sys 0m1.656s

10倍早い。それでも6万個やると10時間かかる。1個のデータの計算に用いている総スレッド数は、2次元で、75264×75264=5664669696個にもなるが、いろいろなオーバーヘッドから、10倍にしかなっていない。まだ、ナイーブなプログラム(普通のCPUのプログラムをそのままGPU用にかえただけのもの)なので、パフォーマンスが出ていないのだろうと思う。

ちなみに、6年ほど前に購入したNVIDIAのTelsa k20cで、試してみよう。こちらは2千数百個のコアを持っている。同じように実行した結果は次のようなものだった。

real 0m48.809s
user 0m43.691s
sys 0m4.450s

最新のXavierよりも、遅い。

プログラムは、調整しおえたらGitHUに上げると思う。

CUDA nvprof で、Error: incompatible CUDA driver version の対処法

答え:root権限を与えてnvprofを実行する。

例:(「CUDAプロフェッショナルプログラミング」を読んでいるところなので)

sudo /usr/local/cuda-10.0/bin/nvprof --metrics gld_throughput ./sumMatrix 32 32

ちなみに、私の環境は以下のとおり。

$ nvprof --version
nvprof: NVIDIA (R) Cuda command line profiler
Copyright (c) 2012 - 2018 NVIDIA Corporation
Release version 10.0.117 (21)
$ nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2018 NVIDIA Corporation
Built on Sun_Aug_12_21:08:25_CDT_2018
Cuda compilation tools, release 10.0, V10.0.117

デバイスは、Jetpack Xavier です。

Jetson Xavier のセットアップメモ

アソシアトロン でMNISTの手書き数字の認識テストをさせたくてシステムを作った。ただ、6万個の学習データを使って、うまく認識させるためにはベクトルの次元を大きくしなくてはならず、それで学習させると、MacPro の24スレッドをフルに使っても計算に50時間かかる(笑)今それをやらせている。

アソシアトロン の学習とディープラーニングの学習の決定的な違いは、前者が極めて単純な行列計算の膨大な積み重ねになっているところだ。ディープラーニングのバックプロパゲーションというのは、多変数の非線形の最適化で、並列処理が難しい。プロは、うまくやっているのだろうが、相互依存が激しくて、並列処理にふさわしく処理を分割できないのだ。

その点、アソシアトロン は、計算をどこまでも細かく分解できる。

こうなると、GPUの並列処理がうまくいくように思う。ということで、CUDAで並列処理を、久しぶりにやってみようという気になった。Linux用の古いTELSAも持っているし、MAC用のTELSAまで持っている。が、ここは、最新のNVIDIAのJetson Xavier (写真左)を使ってみよう。Xavierは、私が奉職している大学の遠い昔の設立者の方と同じ呼び名である。

今年初めに買ったのだが、セットアップが面倒で、なんども失敗したので放置しておいた。しかし、ここはちゃんと動かさなければならない。

ホストコンピュータは、MacProに入れたVirtualBoxのUbuntu_18.04だ。基本、本家の次のサイトをベースにセットアップすべきだ。
(A) How to Install JetPack
MacのVirtualBoxだから、次のサイトからも色々教えていただいた。
(B) MacBook Pro で Jetson AGX Xavier をセットアップ
本家のサイトのインストラクション通りにやったが、途中でうまくいかなくなった。色々試したので、何が良かったのか、正確にはわからなくなってしまったが、特に大事なポイントだけは記録のために押さえておこう。

大きな流れは、ホストコンピュータにCUDAのツールキットなどのシステムをダウンロードし、デバイスに送信するという二段階になっている。本家の手順に、コメントしておこう。

(1)最初は、本家(A)の手順6のComponent Managerでは、Fullを選んでおけば良い。ここを進むと、インストールが開始されるが、それは、ホストコンピュータに必要なシステムがダウンロードされることとと理解しておく。
(2)次に、デバイスに送り込む手続きに入る。手順9にFlash OSを手順6で選ぶかどうかのことが書かれているが、最初は選んだままで良い。その際、ちゃんとUSBでホストとデバイスを繋いでおかなければならない。VirtualBoxの場合は、通常はMACがUSBを使っているので、Ubuntuに変更しなくてはならないことを忘れないように。
(3)そうすると手順10でネットワークの形式を聞いてくるが、ここは標準で選択されているUSB経由のネットワークにしておけば良い。USB経由のネットワークのIPアドレスが割り振られる。
(4)そうすると、手順14が出てくる。この辺りから混乱してくる。当初のリカバリーモードとは違って、一旦 デバイスのUbuntuを立ち上げた後のリカバリーモードで、違うようなのだ。実際、押すボタンも違う。ここは、手順14に忠実にやる。その際、USBがちゃんと繋げてないとエラーになる。
(5)しかし、ここで途中で止まってしまう現象に出くわし、困った。そこで、サイト(B)の教示に従う。つまり、その時は、一旦、CTL-Cでターミナルを閉じて、終了画面を出させて、ダウンロードしたものを削除せずに、インストールウィンドウも閉じる。そして、再度、デバイスを普通に立ち上げて、そこに割り振られたIPアドレスを確認する。
(6)その後、再度、NVIDAのインストーラを立ち上げる。手順9で、FLASH OSのインストールをしないように、no actionにする。ここがポイント。そうすると、次に、デバイスのIPアドレスとユーザー名とパスワードを聞いてくる。ここで、IPアドレスは先に確認したもの、ユーザー名はnvidia、パスワードもnvidiaと入れていけば、次に、インストールが開始される(!!)。なお、(B)では、nvidiaではなく、ubuntuと書いてあるが、私の場合、ubuntuでは失敗した。そのユーザーはあるが、ここは、基本的ユーザーのnvidiaにしなければならなかった。

全く、なんども失敗し、実に面倒だった。

なお、そのままほっておくと、デバイスはチンチかちんに熱くなる。心配になるので、ホームにある、./jetson_clocks.shをsudoで動かすと、ファンがうるさいほど回ってくれるので、すぐ冷却される。

./jetson_clocks.shは、CPUやGPUのクロックを確認するツールらしい。こちらで少し説明がされている。

また、サンプルは、

$ cd
$ ./jetson_clocks.sh
$ cd /usr/local/cuda/bin
$  sudo –user=nvidia ./cuda-install-samples-10.0.sh  /home/nvidia
$ cd  /home/nvidia/NVIDIA_CUDA-8.0_Samples
$ make -j 8
$ cd  5_Simulations/smokeParticles
$ ./smokeParticles

で実行させることができる。コンパイルには時間がかかるので、注意。実行の様子は、以下のツイッターの動画をみてください。

こちらを参考にさせていただいた。

これから、こちらもまた面倒なのだが、CUDAでC++プログラミングである。