FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

Chiselを使ってMNISTハードウェアアクセラレータを実装(ReorderQueueデバッグと実機評価)

前回の続き。MNISTのハードウェアを作成してRISC-Vに接続し動作させる。 前回はReorderBufferを追加してアウトオブオーダ処理をインオーダ処理に変更し、デバッグを行った。

やはりChiselというか、FPGAでのデバッグは難しい。何が起きているのかわからないし、何度も再合成してFPGAを焼き直した。 SDカードを書き換えるのも面倒だ。

とりあえず、プログラムの書き換えはZedBoardのEthernet経由で書き換えられるようにした。

ZedBoard の EthernetのデフォルトIPアドレスを変更する。

ZedBoardの PetaLinuxでは、デフォルトのIPアドレスが192.168.1.5 になっている。 しかし我が家のネットワークは192.168.11.xで設定されているため、そのままでは繋がらない。 ifconfigを書き換えて、ネットワークが繋がるようにする。 これにより、作業用のPCからリコンパイルしたプログラムをscpで転送できるようになったため、プログラムを書き換えるたびにSDカードを取り出してリブートする必要がなくなった。

ifconfig eth0 192.168.11.5 up

ZedBoard での MNISTハードウェア動作確認

結局、ReorderBufferのタグビットの設定をいくつか間違えていたせいで、動作していなかった。 その辺りを修正し、なんとか無事に動作するようになった。 時々謎の不具合というか、時々結果がずれるのだが、これはとりあえず後回しにする。

  • ソフトウェアでの実行結果
root@zynq:~# ./fesvr-zynq train_twolayernet_fix16_full
=== TestNetwork ===
 === start ===
  0 : expect=7, actual= 7 CORRECT
  1 : expect=2, actual= 2 CORRECT
  2 : expect=1, actual= 1 CORRECT
  3 : expect=0, actual= 0 CORRECT
  4 : expect=4, actual= 4 CORRECT
...
193 : expect=9, actual= 9 CORRECT
194 : expect=0, actual= 0 CORRECT
195 : expect=3, actual= 3 CORRECT
196 : expect=1, actual= 1 CORRECT
197 : expect=6, actual= 6 CORRECT
198 : expect=4, actual= 4 CORRECT
199 : expect=2, actual= 2 CORRECT
Final Result : Correct = 185 / 200
Time = 900400921
root@zynq:~# ./fesvr-zynq train_twolayernet_fix16_hw_full  ~
=== TestNetwork ===
 === start ===
  0 : expect=7, actual= 7 CORRECT
  1 : expect=2, actual= 2 CORRECT
  2 : expect=1, actual= 1 CORRECT
  3 : expect=0, actual= 0 CORRECT
  4 : expect=4, actual= 4 CORRECT
...
193 : expect=9, actual= 9 CORRECT
194 : expect=0, actual= 0 CORRECT
195 : expect=3, actual= 3 CORRECT
196 : expect=1, actual= 1 CORRECT
197 : expect=6, actual= 6 CORRECT
198 : expect=4, actual= 4 CORRECT
199 : expect=2, actual= 2 CORRECT
Final Result : Correct = 184 / 200
Time = 222765286

いいね、ちゃんと動いている。 速度としては、専用ハードウェアを使ったほうが4倍程度高速だ。 もう少し高速化できるんじゃないかというアイデアもあるので、少し改造してみようかな。 今は64ビット幅を半分しか使っていないし、もうすこしやり方があるはずだ。

  • 専用ハードウェアでの動作の様子
f:id:msyksphinz:20180128011023g:plain
  • ソフトウェアでの動作の様子
f:id:msyksphinz:20180128011045g:plain

性能解析

まず、784x2個のデータをロードするのに要しているサイクル数を計測した。 RoCCアクセラレータを動かす部分にサイクルカウンタを仕込み、動作を確認してみる。

   uint64_t rocc_start, rocc_end;
      rdmcycle(rocc_start);
    
      rocc_dot (out[b * output_size + o],
                &in_data[b * input_size],
                &wh[o],
                output_size,
                input_size);
      rdmcycle(rocc_end);
      out[b * output_size + o] = fix16_add (out[b * output_size + o], wb[o]);

      printf("rocc_dot(input_size=%04d) : %d\n", input_size, rocc_end - rocc_start);

計測結果だ。 784x2個のデータに対して1データあたり15サイクル程度かかっている。これはかかりすぎだろう。もう少し短縮したい。

f:id:msyksphinz:20180129000315p:plain