雑多な趣味の記録帳

tom01h.exblog.jp

カテゴリ:未分類( 274 )

Zynq で DMA を試す

数日前から書いているように、tiny-dnn アクセラレータを高速化するには、自らデータを取りに行くように変更するのが良いと思っています。
そのためには PL 上に作る回路が tiny-dnn の動くユーザ空間にアクセスする必要があり、先日も参考にした ここ にあるように IOMMU(SMMU) が必要になります。そして、IOMMU は 7世代の Zynq には載っていなくて、UltraScale+ 世代には載っているようです。
とりあえず今持っている 7世代の Zynq でも真似事だけは試してみたく、DDR の一部を PS-PL 間の転送用バッファとして使ってみようと思います。

まずは、先ほどの SMMU のページの真似をして AXI DMA の ブロックデザインを作成します。
f0054075_15515727.png
DMA のアドレスマップは PS-PL 間転送用バッファだけが見えるように変更します。
f0054075_15520915.png
なんか、どうやっても AXI DMA 付きの PetaLinux が作れなかったので、同じアドレスに AXI BRAM を置いて作った PetaLinux で bitファイルだけ差し替えて使います。
そして、PetaLinux が使うアドレスを減らして、PS-PL 間の転送用バッファを確保します。
project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi に追加。
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
ranges;
dma_reserved: dma@0x1c000000 {
reg = <0x1c000000 0x04000000>;
};
};

さらに、SMMUのページのテストプログラムを変更します。
- 転送元、転送先を mmap した PS-PL 間転送用バッファに変更
- SMMU の設定をがっつり削除
こんな感じ になりました。ファイル名が…
大雑把に言うと、バッファ上に /dev/mem 経由で書いた値を DMA で別のアドレスにコピーして、/dev/mem 経由で確認します。
一応、動いているように見えます。

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

tiny-dnn アクセラレータを高速化したい

今までの tiny-dnn アクセラレータは、CPUと密結合されることを前提として作っていました。
そして、出力チャンネル分だけ並列に計算しますが、せいぜいその程度の並列性しかありません。
でも Zynq は特に PS から PL への転送は遅く、最初の試行ではアクセラレータを使うとかえって遅くなりました。
もっと大きな塊でアクセラレータに仕事を投げないといけないと思うのですが、その前にもう少し実験をしておきたいと思います。

まずは、PL にAXI BRAM をインスタンスして時間を計ってみました。
計算機能がないのでパスするわけはないのですが、今まで使ってきた MNIST 学習プログラムを流してみます。
アクセラレータ無しよりも数割だけ速くなりました。たったのこれだけじゃ… 疎結合アクセラレータへの移行は決定です。

ついでに、AXI BRAM 用に作った Linux を使って、tiny-dnn アクセラレータの乗ったシステムで流してみます。
tinu-dnn 用 Linux と tiny-dnn回路の組み合わせ時と同じ時間になりました。ちゃんと学習もできます。
Linux のデバイスツリーの問題ではないのですかね。

というわけで、疎結合用のアクセラレータの仕様を考えることにします…

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

Zynq と IOMMU について

現状の tiny-dnn アクセラレータは、CPU と アクセラレータが密結合されていることを前提に作っています。
が、実際の Zynq では結構遠くて性能が出ていません。Linux のデバイスツリーの書き方が悪いのかも調べてみたいとも思っていますが、根本的にはもっと通信を減らさないといけないと思います。
どう減らすのかといえば、現状はデータを随時 CPU からくべているのですが、アクセラレータが自発的にとりに行くようにするのが良いのかと…

そうなってくると問題が一つ、
tiny-dnn は Linux 上で動くユーザアプリケーションだし、データの置いてある物理メモリアドレス分からないじゃん!

世の中にはそれを解決するために IOMMU なるものがあるらしいです。
CPU は MMU を使ってユーザ空間と物理空間のアドレス変換をしているのですが、CPU 以外がアドレス変換に使うのが IOMMU です。
まぁ、どこを調べてもユーザアプリ用とは書いてなくて、仮想マシン上で動くゲスト OS 用と書いていますが…

で、Zynq で使っている Arm の場合は、(システム) SMMU という名前で呼ぶのが普通らしい。
そして Zynq にも入っていないか調べてみると、どうやら 7 世代には入っていないみたい。
でも UltraScale+ 世代には入っているみたいです。新しいのを買えば原理的にはできそうな感じですが、スキル的には難しそうな予感です…
ここ の真似でもすればよいのかなぁ?

[PR]
by tom01h | 2018-10-17 20:55 | Trackback | Comments(0)

tiny-dnn アクセラレータを Zynq で動かす

tyny-dnn アクセラレータを作成中です。
今回は、今まで Verilator 上で検証していたアクセラレータに AXI Lite インタフェースを付けて、Zynq で動かしてみました。
動きはしたのですが… ソフトだけで計算した時よりも遅い…
(cov forward 72249ms → 179729ms elapsed)
f0054075_21504290.png

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

MNIST 画像を加工してみる2

自動でデータを生成できるようにしました。
全部ランダムで、
  • 10個の画像を選んでくる
  • アスペクト比は固定で拡大縮小する
  • 見切れないように慎重に X,Y 座標を選ぶ
その後、順に画像を配置していきますが、すでに画像の置いてある場所を覚えておきます。
新たな画像を置くとき、 33%以上が重なる場合はその画像を没にします。
とりあえず25画像生成してみました。
f0054075_20164866.png
このデータセットで遊んでみたくて、とりあえず YOLO を勉強中です。今は v3 まで出ているようですが、まずは初代から。
まずは ここ を読んでみました。ほんの少しだけ分かった気になってます。つまり、画像分類問題と比べて、出力層が違うってだけですね。で、分類問題では分類数が出力数だったけど、YOLO の場合は 20 分類に対して 7×7×30 の出力がある。ただ、細かいことは分かりません。
つぎに ここ を見てみました。最初はやってみた系と思ったけど、後ろの方に解説(翻訳?)があって、先の解説で足りない部分もちゃんと説明している気もしますが、まだ自分で作れるほどには理解はできません。
でも、よく考えると画像分類問題も出力層 (SoftmaxWithLoss) の詳細は理解してない気もします…
なので、分からないまま真似すればよいかと思って、YOLOv2 だけど この実装 を眺めてみたりしています。

[PR]
by tom01h | 2018-10-11 21:10 | Trackback | Comments(0)

tiny-dnn アクセラレータ用 FPU 作成3

tiny-dnn と Verilator を使って、アクセラレータを作成・検証しています。
昨日は比較的愚直に FMA を作ってみましたが、累積している数をいちいち正規化してから積とアラインするのは無駄なので、正規化前の値を使ってアラインすることにしました。そのため、演算途中の精度が良く分からない事になっています。
この変更で、計算中には正規化する必要がなくなります。正規化回路を1個にして、読み出し時だけ使えば良くなりました。これでシミュレーションは結構速くなります。
ついに、アクセラレータ(順方向のみ)のコア部分が出来たつもりです。あとは、AXI インタフェースを付けて、ソフトをちょっと改造すれば、FPGA で流せるはずです。だと良いな…

[PR]
by tom01h | 2018-10-10 00:28 | Trackback | Comments(0)

tiny-dnn アクセラレータ用 FPU 作成2

tiny-dnn と Verilator を使って、アクセラレータを作成・検証しています。
周波数出るか分からないですがとりあえず 3段パイプ構成 にしました。難しいことを考えなくても1サイクルピッチで動ける構成です。
1サイクル目がウェイト用メモリアクセス。
2サイクル目がアラインメントと関和。
3サイクル目がノーマライズです。
3サイクル目から2サイクル目のバイパスがあります。
現状はノーマライズ→アラインメント→加算のパスがあってとっても遅いと予想していますが、ノーマライズ→アラインメントはとっても無駄なので最適化可能なはずです。

[PR]
by tom01h | 2018-10-09 00:30 | Trackback | Comments(0)

tiny-dnn アクセラレータ用 FPU 作成1

tiny-dnn と Verilator を使って、アクセラレータを作成・検証しています。
最初は real 型を使ってホスト CPU の FPU で計算していたのですが、そのままでは FPGA に持っていけないので自前で FPU の MAC を作ろうと思います。
まずはサイクルタイムなんか気にしない、1サイクルで全部計算しちゃうバージョンです。
パラメータと畳み込み層に入力するデータは bfloat16 で計算します。累積途中の仮数は 16bit 精度で計算して、出力は単精度(下位は0うめ)です。
変換は0方向丸め(言い換えると下位ビット無視)です。
シミュレーション時間がとっても長くなったので、学習用データは 3008 個に減らしています。
とりあえず動いてるっぽいです。次はパイプライン化か?1サイクルピッチにするにはどうすればよいのだろう?
f0054075_17305081.png

[PR]
by tom01h | 2018-10-08 19:14 | Trackback | Comments(0)

tiny-dnn アクセラレータの準備の道のりは長い…

tiny-dnn を zynq の Arm の Petalinux 上で動かして、重たい処理を FPGA にオフロードしたいと思っています。
アクセラレータの使い方はバイナリニューラルネットの時と同じで、内蔵するウェイトメモリのアドレスを指定してデータを書き込むと、指定アドレスからウェイトを読み出して、書き込みデータと掛け算をして、結果を内部レジスタに累積していきます。
今回は課題が MNIST でネットが小さいので、最大 16並列で作っています。
real を使った Verilog シミュレーションで、順方向だけ置き換えた環境 ではちゃんと動いているようです。

そろそろ FPGA でもお試ししたいと思ったのですが、real じゃ合成できないよね?とか、頑張って FPU 作るにしても、毎サイクルの FMA って難しそうだよね?とか、AXI のインタフェース持ってないじゃん?とか、いろいろ問題あって、どこから手を付けたものか…
で、まずは整数で、しかも、並列なしで作ってみました。AXI インタフェースは、性能出ませんが SD カードインタフェースを作った時の物を使います。
コアな部分はこんな感じ。見難くてすみません…
reg [15:0] sum;
always @(posedge S_AXI_ACLK)
if (S_AXI_ARVALID) begin
if(S_AXI_ARADDR[15]==1'b0)
wb_dat_o_i<=ram[S_AXI_ARADDR[14:2]];
else
wb_dat_o_i<=sum;
end
always @(posedge S_AXI_ACLK)
if ((axist==4'b0011)&S_AXI_BREADY)begin
if(wb_adr_i[15]==1'b0)
ram[wb_adr_i[14:2]]<=S_AXI_WDATA;
else
sum<=sum+S_AXI_WDATA*ram[wb_adr_i[14:2]];
end
でもって、結果は正しそうです。
f0054075_20154682.png

[PR]
by tom01h | 2018-10-07 22:13 | Trackback | Comments(0)

Windows10 October Update

今回も DVD イメージをダウンロードしてからのアップグレードです。
何が新しくなったのかはよくわかりません。
f0054075_23424575.png

[PR]
by tom01h | 2018-10-04 23:43 | Trackback | Comments(0)