あざらしなので

備忘録と日常のこと

Raspberry Pi4のGPGPUに挑戦(その1)

””””内蔵GPUもったいなくないですか?””””

Raspberry Pi4には計算資源としてCPUの他にVideoCoreⅥ(VC6)と呼ばれるGPUが搭載されています。

GPUを汎用計算に活用するGPGPUは一般的にNvidia社の外付けGPUを用いて行われていますが、組み込みボードやノートPCでもGPUは搭載されているものがあり、GPGPUが可能です。(技術的には)

組み込みボードでは計算資源の拡張が難しいのでGPGPU活用は色々と嬉しいことがあると思います。

今回は組み込みボードの代表格であるRaspberry Piの最新機、Pi4でGPGPUに挑戦します。

VC6-GPGPU プログラミング方法

Python上でVideoCore6のアセンブリを記述&実行できる神ライブラリpy-videocore6がIdein社から公開されています。

github.com

アセンブラなのでプログラミングにはVC6のハードウェア構造を理解する必要がありますが、一般にアーキテクチャリファレンスは公開されていません。また、上記ライブラリ自体のドキュメントも存在せず知識0からの開発はかなり難易度が高いです。

ですが、一応ネット上に公開されている情報からできなくはないです。

1)VC6アーキテクチャはVC4と類似

Raspberry Pi zero,1,2,3に搭載されているVideoCoreⅣ(VC4) GPU完全なアーキテクチャリファレンスが公開されています。

https://docs.broadcom.com/doc/12358545

py-videocore6のVC4版も公開されており(こちらが先)、サンプルのSGEMMを解説したQiita記事も存在します。

github.com

qiita.com

(有料ですが過去に私が執筆した入門書もあります。)

booth.pm

上記をすべて網羅すればVideoCore4のGPGPUができますね。VC4からVC6へのキャッチアップには↓の記事が良いと思います。(リファレンスなしでGPGPUはヤバすぎる....)

Idein Ideas — GPGPUの観点から見る VideoCore VI と VideoCore IV の違い

2)サンプルコードが豊富

実際のプログラミングにはpy-videocore6リポジトリのexamplesフォルダのコードを読めば雰囲気がつかめると思います。testsフォルダにて各機能を試すことができるのでexamplesを読みつつ命令の挙動確認にtestsコードを使うのが良いと思います。

VC4のSGEMMにあったような細かいレジスタ節約のテクニックは同社のQMKL6のsgemmあたりを読めば大体わかります。

github.com

VideoCore6アーキテクチャ

↑の記事にすべて書いてありますが概要だけ一応

VC6はQPUと呼ばれる4way-SIMD演算器が8個搭載されています。命令では各QPUが4cycle使って16way-SIMDとして動作します。FMAがあり、500MHzで駆動するのでFLOPSは

4(QPU) x 8 x 2(FMA) x 0.5 =32GFLOPS

となります。Pi4のCPUは48GFLOPSらしいので""GPGPUで高速化!!""には期待できず、GPUオフロードによるCPUの負荷軽減やCPU-GPU並列計算での高速化とかに使えると思います。

レジスタSIMD計算機なので長さ16のベクトルレジスタとなっています。各QPUにはアキュムレータ5本(r0~r4)と64本(rf0~rf63)のレジスタファイル、1個のスカラ用レジスタ(r5)があります。

レジスタが多く、SIMTではなくSIMDアーキテクチャなので昨今のGPUというよりはベクトル計算機に近いような気がします。(GPUベクトル計算機の明確な違いを良くわかっていない)

次回はVC6でSGEMMを実装します。すでにpy-videocoreのサンプルやQMKL6にて実装されたものが公開されていますが、あえてこれらは深く読まず、自分で考えて書いてみます。実装できたらFLOPSバトルして実装法の差分から考察できれば勉強として楽しそう。

最終的にはCPUのOpenBLAS SGEMMとGPUのSGEMMを使ったCPU-GPU並列動作でどれくらいの性能が出るのか実験したいと思います。SoCのCPUとGPUはメモリが共有なので同時利用による帯域の圧迫や消費電力制限によるクロック制限などで満足に性能は出ないような気がしていますが、面白そうなのでやってみます。

Winograd_k7x7_st2勉強メモ

Winograd_st2勉強メモの続き.今回はカーネル7x7の実装法についてメモする.

カーネル7x7でも3x3と同じように入力ブロックをいくつかのグループに分けて畳み込み計算をする(元論文参照).計算量を削減するために各グループの畳み込みはWinogradで計算する必要があり,3x3では以下のツールで必要な変換行列を求めることができた.

github.com

このツールでは入力にpolynomial interpolation pointsとブロックの出力サイズ,カーネルサイズを与えると計算に必要な変換行列を返してくれる.WinogradはF(N,M)とF(NxN,MxM)は同じ変換行列を使い,計算方法が異なる.そのため上記のツールでは入力がNとMだけで,F(2x2,3x3)やF(4x4,6x6)などの変換行列を知ることが出来た.しかし,7x7_st2にはWinograd F(2x2,4x3)があり,一筋縄ではいかない(そもそもWinograd Convolutionを理解すれば良い話であるが...).

試行錯誤の結果,以下の変換行列でF(2x2,4x3)が計算できることが分かった.(追記:論文に4x3の変換行列について書いてありました...見落としてた)

 G=\begin{pmatrix}
  0.5&   0&   0&   0\\
 -0.5&-0.5&-0.5&-0.5\\
-1/6&1/6&-1/6&1/6\\
1/6&1/3&2/3&4/3  \\
0&0&0&1
\end{pmatrix}
 KG=\begin{pmatrix}
  1&   0.5&   0.5&   0\\
 0&0.5&-0.5&0\\
0&0.5&0.5&1
\end{pmatrix}
 B=\begin{pmatrix}
2&-1&-2&1&0\\
0&-2&-1&1&0\\
0&2&-3&1&0 \\
0&-1&0&1&0 \\
0&2&-1&-2&1
\end{pmatrix}
 KB=\begin{pmatrix}
1&0&0&0\\
0&1&-1&-1\\
-1&1&1&0 \\
0&0&0&1 \\
\end{pmatrix}
 A=\begin{pmatrix}
1&1&1&1&0\\
0&1&-1&2&1
\end{pmatrix}
 KA=\begin{pmatrix}
1&0\\
1&1\\
1&-1\\
0&1
\end{pmatrix}

計算式は以下

Y=A[[ GgKG]⊙[BdKB]]KA

GPGPU実装をするにあたって自分用にリファレンス実装をnumpyで書いた.

github.com

Winograd stride2勉強メモ

Winograd Stride2の実装法ないかなーってググったら新しめの論文が出てきたので読んでメモ
Stride 2 1-D, 2-D, and 3-D Winograd for Convolutional Neural Networks
この論文の提案手法ではNvidiaGPUにて通常の畳み込みよりカーネル3x3で1.44倍,5x5で2.04倍,7x7で2.42倍,3x3x3で1.73倍速くなっているようです.
このメモでは3x3のみ解説していきます
Winograd自体の解説はこちら

続きを読む

Winograd勉強メモ

忘れるからメモ

Winogradとは

畳み込み演算を高速に計算できる(かもしれない)アルゴリズム

論文↓
Fast Algorithms for Convolutional Neural Networks

Winograd F(2x2,3x3)

入力画像を4x4,出力画像を2x2,カーネルサイズを3x3のwinogradアルゴリズム
計算式は以下の通り

Y=A^ T[[ GgG^ T ]⊙[B^ TdB]]A

続きを読む