FPGA開発日記

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

RISC-V ISS Spike を使ってMNISTのハードウェアアクセラレーションを実装する

前回の続き、前回まででやっと環境が整ったので、MNISTの行列計算の部分をオフロードしてRoCCアクセラレータのシミュレーションを行う。

SpikeでRoCCアクセラレータを模擬するのは以下の操作だ。 行列積の1要素を計算するのに、1番目の行列の要素を行方向にシークしていき、2番目の行列の要素を列方向にシークしていく。 それぞれの値を掛け算し、16bitの固定小数点で加算していく。これで行列積の要素1つ分の計算になる。 この部分をRoCCアクセラレータで一回で実行できるものとし、RoCCアクセラレータのモデルをC++で記述する。

f:id:msyksphinz:20180117002118p:plain

関連記事

RoCCアクセラレータをC++でモデル化する

RoCCアクセラレータをC++でモデルし、以下ようなmatrix16_rocc.ccを作成した。途中で64ビットの計算とか入ってしまっている。 ライブラリと同じ動きをさせるとこのようになってしまった。libfix16をもうちょっと調べて、ハードウェア化しやすい状態までもっていく必要があるなあ。

      case 0: {
        m_length = xs1;
        break;
      }
      case 1: {
        m_v_step = xs1; 
        break;
      }
      case 2: {
        reg_t xs1_p = xs1;
        reg_t xs2_p = xs2;
        for (reg_t i = 0; i < m_length; i++) {
          int32_t a_val = p->get_mmu()->load_int32(xs1_p); xs1_p += sizeof(int32_t);
          int32_t b_val = p->get_mmu()->load_int32(xs2_p); xs2_p += (m_v_step * sizeof(int32_t));
          int64_t product = static_cast<int64_t>(a_val) * b_val;
          int32_t adjust  = (product & 0x8000) >> 15;
          total = total + (product >> 16) + adjust;
        }
        break;
      }

というわけで、RoCCにオフロードする前とオフロードした後で、実行命令数にどれくらい差がでているのか調査した。 SpikeはFunctionalな命令セットシミュレータなので、サイクル数までは計算できない。とりあえずRoCCアクセラレータが正しく上記のDot Productを計算できているかどうかを確認しよう。

  • ハードウェア化する前
./spike --extension=matrix16_rocc --extlib libmatrix16_rocc.so  /home/msyksphinz/work/training/risc-v/mnist/train_twolayernet_fix16_full &> train_twolayernet_fix16_full.log
  • ハードウェア化した場合
./spike --extension=matrix16_rocc --extlib libmatrix16_rocc.so  /home/msyksphinz/work/training/risc-v/mnist/train_twolayernet_fix16_hw &> train_twolayernet_fix16_hw.log
$ for f in `ls -1 train_twolayernet_fix16*.log`; do echo ${f}; cat ${f}; done
train_twolayernet_fix16_full.log
=== TestNetwork ===
 === start ===
Final Result : Correct = 185 / 200
Time = 218279215 - 10031 = 218269184
train_twolayernet_fix16_hw.log
=== TestNetwork ===
 === start ===
Final Result : Correct = 185 / 200
Time = 1345620 - 10031 = 1335589

推論動作は正しく動いていることが確認できた。命令数的にも、しっかり削減できている(ログはTimeってなっているけど...)。

次は、ちゃんとハードウェアを実装してFPGAで動作させよう。

f:id:msyksphinz:20180117003017p:plain