雑多な趣味の記録帳

tom01h.exblog.jp

タグ:ニューラルネット ( 83 ) タグの人気記事

tiny-dnn アクセラレータの pooling が遅い

tiny-dnn アクセラレータが Ultra96 でまともに動くようになったので、CORA にも変更を反映しました。

話は変わって、tiny-dnn を Arm で動かすと Pooling の順伝搬が非常に遅いように見えます。
ソースコード を眺めてみると、カーネル毎のデータにアクセスするためにデータ配列の Index の配列を作って、何度もメモリを読みながらデータアクセスをしている模様。
Intel の場合はこのほうが速いのですかね?

[PR]
by tom01h | 2018-12-21 22:40 | Trackback | Comments(0)

tiny-dnn アクセラレータを Ultra96 で動かしたい5

Ultra96 でキャッシュ有りの DMA 転送を使った tiny-dnn アクセラレータは、学習結果の認識精度が安定しない問題に直面しています。
今までも制御回路のバグで転送バッファを読み出し前に書きつぶしていたり、DMA の転送終了判定を間違っていたりしました。
結局は、どちらも DMA のキャッシュコヒーレンシとは関係ないのですが、キャッシュ有で DMA を使った時だけ問題が見えてきます。
今回もキャッシュコヒーレンシを疑いつつ解析を始めたのですが…

手詰まりなので、DMA 単体からキャッシュコヒーレンシのテストを始めました。
DMA 単体だとうまく動いたので、少しづつ tiny-dnn アクセラレータの構成に近づけていこうと RTL を眺めていたらバグ発見。
AXI ストリームマスタが M_AXIS_TREADY のネゲートを受けるタイミングが、転送開始の直前、もしくは終了の直前だと M_AXIS_TVALID のアサート期間が開始前だと1個多く、終了前だと1個少なくなる。
修正してみましたが… 不発。ここじゃない模様。

今までは udmabuf を大きく確保して分割して使っていましたが、用途別に4個の udmabuf を確保してみました。
なんかちょっと良くなった気がするけどまだ…

で、アクセラレータ行きのバッファの1個を O_SYNC 付きで開くと直った。
こいつが犯人みたいです。
さらに試してみると、今まではバッファ1からアクセラレータにDMAしつつ、ユーザメモリからバッファ2にコピーをする場面がありましたが、これを同じ時間に実行しないようにプログラムを変更したら直りました。原因は不明。
f0054075_00120791.png
github 更新しました。

[PR]
by tom01h | 2018-12-20 23:42 | Trackback | Comments(0)

tiny-dnn アクセラレータを Ultra96 で動かしたい4

キャッシュ付き DMA をいったんあきらめて、キャッシュなしで DMA 転送をしてみました。
こんな感じ で、転送と演算を並列動作しているプログラムは認識率は 97.41% で安定。
並列化していないプログラムは不安定。

プログラムを見比べて思いつく疑惑。

DMA の終了判定を間違っているっぽい。
DMA の転送が終わっていないのに、DMA リセットをかけているのか、IP 側の受け取り状態を解除しているのが原因じゃないかと思う。

よく見る終了判定
while ((dma_addr[0x04/4] & 0x1000)!=0x1000); // Wait for the tx to finish
最初のうちに起きていたハングアップを避けるために今まで使っていた終了判定
while ((dma_addr[0x04/4] & 0x3)==0); // Wait for the tx to finish

よく見る終了判定に変更したら、並列化していないプログラムも 97.41% で安定しました。

シミュレーション結果と一致しないのは、コンパイラのバージョン違いってことにしておきます。

DMA でキャッシュを使う設定(AxCACHE=0xf,AxPROT=0x2,FF41A040=0x3)にしたら…
やはり認識率が一定しません。

この設定で udmabuf を O_SYNC 付きで開くと期待通りの動きです。
やっぱりキャッシュ付き転送になっていないのかな?

残念ながら時間切れ。来週は DMA 単体でテストするかな…

[PR]
by tom01h | 2018-12-13 23:59 | Trackback | Comments(0)

tiny-dnn アクセラレータを Ultra96 で動かしたい3

tiny-dnn アクセラレータがいまだ Ultra96 上では安定して動きません。
実行時間的にはだいたい期待通りなんだけど、実行結果(認識率)に再現性がないです。
いやなことに、正解だと思っている認識率 96.95% よりも高いことが多いのですが…

Interface の 2019年1月号 の読み返したけど、やり忘れていることはなさそう。
udmabuf の説明 を読んでみると、デバイスツリーに登録して dma-coherent を設定しないといけない気もしますが、試してみたけど変わりません。
DMA の設定の相性問題 で Petalinux ツールがうまく動かないのも疑ってみたけど違うようです。
しかも、いつからか Wifi が使えなくなっています。
DMA のデバイスツリーから dma-coherent を外すと Wifi 復活しました。→ 単に dd の書き損じの可能性もあります。

しかし、Ultra96 は何をやるにも時間がかかります。
だいたいの原因は、ルートファイルシステムが 1.5GB もある事かと…
しかも、Petalinux ツールはルートファイルシステムのコピーを何種類も作って、あっちで作ってこっちにコピーとかもしています。
あと、dd もすごく時間かかるし、たまにうまく書けていないこともある感じです。
ちなみに、VirtualBox が PC 内蔵の SD カードリーダを認識してくれないので、古い USB カードリーダを持ち出しています。
それが原因で dd が遅いのもあると思います。
また、形が悪くて隣りのポートもつぶしたりするので USB カードリーダを買ったのですがまだ届きません。
ついでに、机のわきに固定する形の USB ハブ を買いました。
f0054075_20030769.jpg
悪いのは DMA の使い方じゃないのかなぁ?
CORA はちゃんと動いているみたいだけど…

[PR]
by tom01h | 2018-12-11 23:46 | Trackback | Comments(0)

tiny-dnn アクセラレータを Ultra96 で動かしたい2

前回は reserved-memory で Linuz が使わないようにした領域を DMA バッファに使おうと思って上手く出来ませんでした。
udmabuf の使い方もわかったところで、再度 Ultra96 上での実行に挑戦してみます。

結論。速くなったけど、結果に再現性がない。まだ上手く行っていないところあるのかなぁ?
ちなみに認識率はちゃんと動いていると思われる時よりも高くなります。
[覚悟を決めて Verilator で 20000 サンプルの学習をしてみました。96.95% でした。ちなみに 10分ちょっとかかりました。]
f0054075_20231846.png
まだなんか怪しいけど、github に置きました。グラフの上の方を見たければそちらをどうぞ。

Ultra96 への移植では Interface 2019年1月号 がとっても参考になりました。
もう一度読み返して、怪しい動作の解析をしたいと思います。

そうは言っても、記事で気になるところを…
汎用 GEMM アクセラレータを作るのが目的ならこの記事で良いのかなと思います。
が、畳み込みを高速化したいのなら、CPU で im2col をやったらダメかと思います。
転送速度がネックだとわかっていつつ、ほぼ 9倍(3x3conv)にデータを増やしてから転送するなんて…
いや、他がすごく良かったのでここが気になるって話です。
あと、HLS 使ったら仕方ないのか?って気もしますが、ユーザメモリから DMA バッファへの同じデータの転送を何度もやらない工夫をしているみたいですが、何度も同じデータを DMA 転送しているのも気になります。
さらに、IP の中もダブルバッファ化するとか HLS でも出来るのですかね?
出来ないなら、HLS もまだまだって気もします。

[PR]
by tom01h | 2018-12-09 21:18 | Trackback | Comments(0)

tiny-dnn アクセラレータのバグ取りの日

tiny-dnn アクセラレータの動きが不審なので、落ち着いて解析してみます。

まずは認識率に再現性がなくなったところから。
tiny-dnn は学習過程でランダムを使っていないみたいで、毎回同じ認識率を出していました。
ところが最近、いつからか分からないけど、認識率に再現性がなくなっていました。
原因はおそらく DMA バッファ(アクセラレータ→ユーザ空間)の上書きです。
DMA バッファからユーザ空間への転送を演算と並列処理できるようにしたことで、演算がとっても短いときにデータの転送が終わる前に次のデータで上書きされていたのかと思います。
DMA バッファをダブルバッファにしたことで、認識率が 96.95% で落ち着くようになりました。
97% 割ってしまったのは悔しいですが…
というか、再現しないときの方が認識率が高いって…

次は傾きの逆伝搬がとっても遅い原因を探ります。
CPU で流している限りは順伝搬と同じくらいの計算量に見えています。
だから、アクセラレータを使っても同じくらいの時間で終わるはずと思ったのですが…
このアクセラレータは出力の深さだけ並列実行できるのですが、逆伝搬では入出力が逆転して入力の深さだけ並列実行するようになります。
そして、入力層の深さは 1ですから、入力の傾きを求める計算では並列実行できません。
バグで遅いのかと思っていたけど違って、このアクセラレータの弱点っぽいです。
がしかし、入力の傾きって必要ないですよね?
少しずるいけど、取っちゃいました。
[Corei5 の値が間違っていたので差し替えました。あと、目標が高すぎるとくじけるので、Celeron 追加しました。]
f0054075_15482969.png
あともう一個。
こっちはまだ直してないけど、乗算器のステージングが1ステージ少なかった。
BRAM から読んだデータを、そのサイクルで乗算器が使っている模様…

[PR]
by tom01h | 2018-12-08 22:40 | Trackback | Comments(0)

tiny-dnn アクセラレータで udmabuf を使う

tiny-dnn アクセラレータの動きが怪しいので udmabuf を使ってみたいと思います。

その前に、バイアスの傾き計算を少し変更しました。
出力の傾きを DMA バッファにコピーするときに、同時にバイアスの傾きを計算することでデータアクセス回数を削減する狙いです。
計算量は少ないので CPU で計算させています。
速くはなりましたが、期待していたほどの効果はありませんでした。
逆伝搬はどこに時間がかかっているのか解析が必要みたいです。

で、udmabuf の話に戻ります。
ドライバ開発の手順はやはり、ここ を参考に進めます。
udmabuf のページのサンプルコードの文字列がなぜか unsigend char* でコンパイルできずにはまりましたが、それ以外は2つのリンク先の通りにやると出来ました。
具体的なことは明日 github に書けることを期待して…

ついでに非キャッシュで DMA をするとどうなるか試してみました。
パイプライン化の効果があったか、パラメタの傾き計算以外はあまり変わりません。
(昨日の絵でオレンジと青が遅くなろうが変わらないってこと。)
パラメタの傾き計算では、すでにテータ転送がネックになるのでしょうか?

あと、遅いのはパラメタの傾き計算じゃなくて、傾きの逆伝搬でした。
条件の違うデータがいろいろと混ざっていますが…
f0054075_00292352.png
続きは明日やろう…

[PR]
by tom01h | 2018-12-07 23:59 | Trackback | Comments(0)

tiny-dnn アクセラレータをパイプライン処理する1

先日は tiny-dnn アクセラレータの処理時間を (順方向だけだが) 大雑把に見積もってみました。
CORA では鉛筆なめた数字に結構近い結果が出ているみたいです。

ついでなので、データ転送と演算の並列処理化を進めたいと思います。
第1段ではユーザメモリと DMA バッファ間の転送とそれ以外を並列処理します。
こんな感じ。
f0054075_20013073.png
大雑把な見積もりでは 7.09秒かかる処理が、CORA では実際には 7.8秒かかっています。

ちなみにこの変更で認識率が上がったのですが、その値が Ultra96 での認識率と一致しています(誤報?)。
Ultra96 はまだちゃんと動いていないのでこっちがおかしいのかと思っていたのですが、おかしいのは今までの CORA の環境なんですかね?

もう少しいじっていたらさらに認識率が上がりました… わけわかんない…
いや、再現性が無いぞ。

[PR]
by tom01h | 2018-12-06 23:14 | Trackback | Comments(0)

tiny-dnn アクセラレータの計算時間を見積もってみた

Ultra96 上で tiny-dnn アクセラレータがうまく動かないので、気晴らしに理屈をこねてみることにします。

Ultra96 上ではキャッシュを使っての DMA 転送になっていないようで、CORA で実行するよりも遅いです。
順方向の畳み込みの総実行時間が、CORA では 8.4秒に対して Ultra96 では 12.6秒くらいかかっています。
じゃあ、理想的にはどうなのよ?

まず計算時間から。
出力チャンネル方向は並列実行するので、カーネルの(幅×高さ×深さ)×出力の(幅×高さ) が1層分の計算時間(サイクル)です。
下のような構造なので、
f0054075_20263635.png
下のような計算で、1画像の計算量は 24256 サイクルかかります。
f0054075_20273425.png
20000 画像の学習を 100MHz で実行すると約 4.85秒。

データ転送量はフィルタが、カーネルの(幅×高さ×深さ)×出力の深さをミニバッチに付き1回転送。
入力データと出力データは、それぞれの幅×高さ×深さを各データごとに転送する。
DMA バッファから tiny-dnn アクセラレータへの転送は1サイクルあたり 1データです。
[追記 出力データは core から出力バッファへの転送にも同じだけ時間がかかっていることを思い出しました。]
ミニバッチが 16なので、1画像ごとの転送量は下のような計算で 6713.375 [11203.375] サイクルかかります。
20000 画像の学習を 100MHz で実行すると約 1.34[2.24]秒。
f0054075_19202339.png
合わせて約 6.19[7.09]秒。
実際はこれに加えてユーザメモリから DMA バッファへの転送時間も必要ですが、見積もり難しいので数字を出すのは諦めます。
これらすべてに実際にかかっている時間が、CORA では 8.4秒に対して Ultra96 では 12.6秒くらいです。
いまはまだ、一切パイプライン処理が出来ていないので、想像以上に良い線行っている気もします。

[PR]
by tom01h | 2018-12-04 22:17 | Trackback | Comments(0)

tiny-dnn アクセラレータをウェイトの傾き計算に対応する2

DMA 版 tiny-dnn アクセラレータはウェイトの傾き計算に対応していませんでした。
まだまだ高速化の余地は残っていますが、細かい調整の前にすべての重たい計算の高速化を完了したいと思います。

今回の変更は、あまり苦労せずにできました。これで一旦完成と言って良いでしょう。Github を更新しました。
ただ今回は、今までと比べて高速化の度合いが少ないです。
理由は、順方向の特徴量の伝搬、逆方向の特徴量の傾きの伝搬とも、ミニバッチの間はパラメタは固定です。
ミニバッチの最初にパラメタを読み込んで、あとはサンプルごとに入力を入れて結果を出力しています。
しかし、パラメタの傾きの計算では、すべてのデータをサンプルごとに入出力する必要があります。
そんなわけで、データ転送に時間を取られていると想像しています。
f0054075_13592437.png
それでもこのくらいは高速になりました。
ぎりぎり 1分切って、ほぼ 4倍高速です(今更ですが単位はミリ秒です)。

他にやり残していることは…

- ちゃんと DMA に対応した Petalinux を作る
- AXI-Stream マスタは最後の転送で LAST を出す
- 転送と演算と並列実行する
-- ユーザ空間 ⇔ DMA バッファ間の転送
-- DMA バッファ ⇔ IP 内バッファの転送
-- 演算コア → IP 内バッファの転送
- ZynqMP で IOMMU(SMMU) を使ってみる (持ってないけど…)

[PR]
by tom01h | 2018-11-24 14:56 | Trackback | Comments(0)