人気ブログランキング |

雑多な趣味の記録帳

tom01h.exblog.jp

タグ:tiny-dnn ( 72 ) タグの人気記事

tiny-dnn アクセラレータの誤差逆伝搬の計算方法

Zynq (Arm CPU 内蔵の FPGA) 上でオープンソースの tiny-dnn を使った MNIST の学習をしています。
tiny-dnn を改変し、計算に時間のかかる畳み込みをプログラマブルロジック(PL)に作ったアクセラレータで並列に計算し、その他は PS 中の CPU で tiny-dnn をそのまま計算します。
今回は進捗じゃなくて、tiny-dnn アクセラレータで使っている誤差逆伝搬の計算方法を紹介します。
自分でも見るたびに毎回悩むので…

書いてある内容は github と一緒です。
あまりちゃんと調べずに自分で考えた方法なのですが、これって実はよく知られた方法ですかね?
さらにもっと良い方法があるなら教えてください。

また、今はアクセラレータ側で並べ替えていますが、いずれ CPU 側で並べ替えるように変更したいと思っています。

では本題。

ハードウェアに計算させるなら、順方向だろうが逆方向だろうが同じような手順で計算させたいですよね。

padding に関してもちょっとだけあるのですが今は置いておくとして…

ウェイトデータを工夫すれば、順方向の畳み込みと同じような計算で逆方向の誤差伝搬を計算できます。
下の絵を見ればわかると思いますが、
1. カーネル内のデータを逆順にする
2. 入力チャネルと出力チャネルをシャッフルする

たんに計算順を変えただけなので説明不要ですよね。
ちなみに、stride!=1 の事は考えていません。
f0054075_13091236.png

by tom01h | 2019-05-22 21:04 | Trackback | Comments(0)

tiny-dnn アクセラレータのデータ転送速度を上げる その1

Zynq (Arm CPU 内蔵の FPGA) 上でオープンソースの tiny-dnn を使った MNIST の学習をしています。
tiny-dnn を改変し、計算に時間のかかる畳み込みをプログラマブルロジック(PL)に作ったアクセラレータで並列に計算し、その他は PS 中の CPU で tiny-dnn をそのまま計算します。
今までは、アクセラレータのデータ入出力は 1サイクルに 1データしか転送できませんでした。
今回からデータ転送を高速化していきたいと思います。

tiny-dnn アクセラレータの扱うデータは、行きは bfloat16、帰りは float(32) です。
対して PS のポートは、Zynq7 で 64bit、ZynqMP で 128bit です。
2つ作るのも面倒なので、今回は小さい方に合わせて行きは 4 (=64/16) ワード、帰りは 2 (=64/32) ワードの同時転送に対応したいと思います。
まぁ、実際にやることは
- 口を増やす
- 同時にたくさん読み書きする
- シーケンサのループ回数を減らす
だけと言ってしまったら元も子もないんですが…

今は転送と演算が並列に動いていて、たぶんほとんどの時間が演算ネックなので、この変更ではたいして速くならないと思います。
いずれ演算並列度を増やすときのための準備です。
と言っても、ミニバッチが小さいときは速くなったように見えますね。
変更前後の順方向伝搬の波形です。

変更前
f0054075_22471827.png
変更後
f0054075_22480871.png

by tom01h | 2019-05-21 20:21 | Trackback | Comments(0)

tiny-dnn アクセラレータをパイプライン動作させる データバッファ編 その4

Zynq (Arm CPU 内蔵の FPGA) 上でオープンソースの tiny-dnn を使った MNIST の学習をしています。
今までは 1個だけしか動作していなかった回路をパイプライン化、マクロ外からの SRC_BUF, DST_BUF へのデータの入出力と、コアの演算を並列化したいと思います。

前回は CORA では動くところまで行ったのですが、Ultra96 ではなぜかちゃんと動きませんでした。
今回は Ultra96 で動かします。

結構手間取ったのですが、Ultra96 でちゃんと動かない理由が判明しました。
このころに取った対策 も同じ理由かと思われます。
そしてその原因は、ライトバッファが悪さをしている。
[追記 メモリバイアの問題と言った方が適切かな?
かといって、この言葉でググってもわかりやすい説明は見つからなかった。
そもそもの問題が難しいんだろうなぁ…]
ここ とか ここ を参考にしました。

自分なりの解釈をすると、
- CPUがデータをセット(1)してレジスタセット(2)によってデバイスを起動してデバイスがデータを読み出す
- レジスタリード(1)でデバイスがデータ転送の完了を確かめてデータを読み出す(2)
どちらの場合も(1)(2)の実行順が入れ替わる可能性があります。
大きなデータを転送する場合は特に問題がないと思いますが、小さいデータの場合は正しくデータ転送が出来ないことがあるみたいです。
順番を保証するためには、__asm__("DSB 15"); を挿入すればよい模様。
使い方は U96/conv2d_op_internal.h を参照ください。

高速化の度合いはこんな感じ。
f0054075_09201694.png
やっと原因が分かってすっきりしましたが、やっぱり ZynqMP は難しいです。

ついで
NahiViva で Vivado プロジェクト再現できるようにしました。説明は こっち を見た方が良いかも。
U96/xilinx-ultra96-reva-2018.2/hardware に必要なファイルをダウンロードして、open_project_gui.cmd 実行でプロジェクトが再現されます。
なんだかとってもすごい仕組みです。

by tom01h | 2019-05-19 10:05 | Trackback | Comments(0)

tiny-dnn アクセラレータをパイプライン動作させる データバッファ編 その3

Zynq (Arm CPU 内蔵の FPGA) 上でオープンソースの tiny-dnn を使った MNIST の学習をしています。
今までは 1個だけしか動作していなかった回路をパイプライン化、マクロ外からの SRC_BUF, DST_BUF へのデータの入出力と、コアの演算を並列化したいと思います。

今日は、前回シミュレーションで動作確認した回路を FPGA で流し、高速化の効果を確認します。
シミュレーションで確認済みの事とはいっても、FPGA で動かしてみるときはいつも何かトラブります。
CORA は昨日のうちに動いていたのですが…
なぜか Ultra96 はちゃんと動かなくなってしまいましたが、今回は結構速くなりました。
f0054075_22165269.png
そろそろ転送速度ネックと部分とかも出てきそうな気がするのですが、どうなんでしょうかね?
github 更新しました。
ちなみに、Ultra96 は udmabuf を O_SYNC 付きで開くと動くので、キャッシュコヒーレンシが問題の模様…

by tom01h | 2019-05-16 22:55 | Trackback | Comments(0)

tiny-dnn アクセラレータをパイプライン動作させる データバッファ編 その2

Zynq (Arm CPU 内蔵の FPGA) 上でオープンソースの tiny-dnn を使った MNIST の学習をしています。
tiny-dnn を改変し、計算に時間のかかる畳み込みをプログラマブルロジック(PL)に作った専用回路で並列に計算し、その他は PS 中の CPU で tiny-dnn をそのまま計算します。
今までは順番にどれか 1個だけしか動作していなかった回路をパイプライン化しています。
今回は、マクロ外からの SRC_BUF, DST_BUF へのデータの入出力と、コアの演算を並列化したいと思います。

tiny-dnn アクセラレータの動作は…
ミニバッチの最初にパラメタをCORE内のバッファにセット。
1サンプル分のデータをSRC_BUFにセット(赤)。
それらのデータを使ってCORE内のアキュムレータレジスタに1カーネル分の内積結果を蓄える(薄紫)。
1カーネルの計算が終わったら結果をDST_BUFにコピー(濃い紫)。
1サンプル分繰り返して、終わったらDST_BUFからデータを読み出す(緑)。

f0054075_20253421.png
このころ の変更が紫のループと紫の下矢印の並列化です。
今回の並列化は、紫と赤、緑の並列化です。
こんな感じで速くなるはず。[追記 シミュレーションでは、オレンジと青の部分はありません。]
f0054075_20310639.png
ΔWの計算時には出力から逆伝搬してきた傾き(Wに保存)と、順伝搬してきた入力データ(Dに保存)の両方を1サンプル毎に更新する必要があるため、動作がちょっと違います。
そしてまだ先の話になりますが、tiny-dnn では畳み込み層ではサンプルごとのΔWを保存しています。
しかし、結局使う前にミニバッチ分を足しこんでいるみたいなので、PL 側で足しこんだ方がデータ転送量の削減になります。
まぁ、今回の変更にはまだ入りませんが…
f0054075_20414032.png
github を更新しました。
by tom01h | 2019-05-13 21:44 | Trackback | Comments(0)

tiny-dnn アクセラレータをパイプライン動作させる データバッファ編 その1

今までは順番にどれか 1個だけが動作していた回路をパイプライン化しています。
前回は、コア内で計算して結果をアキュムレートレジスタに格納する回路と、アキュムレートレジスタから結果を読み出して DST_BUF にコピーする回路を並列動作するようにしました。
今回は、マクロ外からの SRC_BUF, DST_BUF へのデータの入出力と、コアの SRC_BUF, DST_BUF をアクセスしながら演算する動作を並列化したいと思います。

ソースを読んでみると、マクロ外から細かな制御をしているはずなのに、バッチコントローラは自力で動いているみたいです。
もっと外からの制御を信じた方が簡単な制御にできますね。
これを機に直しておこうと思います。

そして、順方向だけ直してみた暫定版の波形。
バッチサイズが2だといまいちわかりにくいですねぇ。

変更前
f0054075_00315598.png
変更後
f0054075_00320454.png

by tom01h | 2019-05-12 23:59 | Trackback | Comments(0)

tiny-dnn アクセラレータをパイプライン動作させる アキュムレートレジスタ編 その2

tiny-dnn アクセラレータの可読性が上がったので、今までは順番にどれか 1個だけが動作していた回路をパイプライン化したいと思います。
今回は、コア内で計算して結果をアキュムレートレジスタに格納する回路と、アキュムレートレジスタから結果を読み出して DST_BUF にコピーする回路です。

先週はシミュレーションで確かめるところまで進めました。
が、FPGA で試してみると原因は分かりませんがちゃんと動きません。
で、結局原因は分からないままなのですが、コア内のバッファをダブルバッファと言うよりかはビクティムバッファと呼んだ方が良さそうな形に書き換えました。
そしたら動きました。原因は不明…

そして、たいして速くなりませんでした…
[追記 カーネルサイズが5x5だからあまり速くならなかったけど、もっと小さければ効果が出てくるのかと思います。]
f0054075_21370804.png

by tom01h | 2019-04-24 23:29 | Trackback | Comments(0)

tiny-dnn アクセラレータの並列度を上げるには?

tiny-dnn アクセラレータは、現状では output channel の数だけ同時に積和演算をしています。
実験で使っている MNIST では最大で 16並列です。もう少し一般的な問題でも数百くらいが限界?
それと比べると、大きな FPGA では DSP をもっとたくさん持っているし、8bit の符号なし乗算は 2MUL/DSP 出来るはず。
そんなわけで、もう一つ並列を作るパラメータが欲しいです。
もちろん、ミニバッチ内のサンプル別に並列を作るのがわかりやすいですが、それだと遊びとしては面白くないのでサンプル内の並列度を高めたい。
フィーチャマップを分割するのだろうけど、大きく分割するのと細かく分割するのとどっちが良いのか…
f0054075_11432445.png
大きく分割すると、ここに書いてある みたいにハローが必要になるんですね。
細かく分割するのメモリアクセスの効率がよさそうだけど、扱いが難しそう…

by tom01h | 2019-04-22 23:47 | Trackback | Comments(0)

tiny-dnn アクセラレータをパイプライン動作させる アキュムレートレジスタ編 その1

tiny-dnn アクセラレータの可読性が上がったので、今までは順番にどれか 1個だけが動作していた回路をパイプライン化したいと思います。

今回は赤丸部分、コア内で計算して結果をアキュムレートレジスタ (図には無いけど) に格納する回路と、アキュムレートレジスタから結果を読み出して DST_BUF にコピーする回路です。
読出し前に結果が破壊されないように、アキュムレートレジスタをダブルバッファにしました。
f0054075_14530974.png
下はちょっと難しいタイミングの動作波形。
DST_BUF の書き込み口が 1個しかないために複数のコアから順に 1個づつ結果を読み出すのですが、コアで計算をする時間よりも転送時間の方が長い場合です。
下から 2番目の信号が計算をしている時間、数字が動いているのが各コアから結果を読み出している時間です。
コアの演算器を有効利用できていませんが、まぁ、レアケースだと思うので…
いや、MobileNet みたいに DW Conv とか 1x1 Conv あるとレアじゃないですが…
f0054075_14592373.png
ちなみに変更前はこんな感じでした。
コアの演算器自体はすでにパイプライン動作しているので、結果読出し中に次の計算が始まっていて少し話がややこしいですけど…
f0054075_15044661.png
FPGA で流して時間計ってみたいけど、明日の朝早いので我慢します。


by tom01h | 2019-04-19 20:40 | Trackback | Comments(0)

tiny-dnn アクセラレータのタイミングバグを修正

だいぶ前に気付いていたバグ ですが、長い間放置していたタイミングバグを修正しました。

コアのパイプが、BRAM から読んだデータを同じサイクルで乗算器の入力に使っているというものです。
この状態で CORA Z7 向けに 100MHz で合成すると、バグの部分で 2.7ns 違反します。
修正後はアドレス生成回路が 2.4ns 違反です。たぶん最適化の余地はあるかと…
コア部分では 1.7ns の違反です。シフトアウト判定が遅い模様。
面倒ですが、case 文で 4bit シフタを書きますかね。

by tom01h | 2019-04-17 22:01 | Trackback | Comments(0)