FPGA開発日記

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

フルスクラッチから作るニューラルネットワーク (9. 精度変更、libfixmathを用いた固定小数点化)

誤差逆伝搬法を実装してMNISTの学習と認識プログラムをC言語フルスクラッチで作る、その続き。

固定小数点化については、他社の作ったライブラリを使うほうが良い気がして来たので、調査をしていると以下のライブラリを見つけた。MITの作った固定小数点ライブラリらしい。

整数部16ビット、小数部16ビットとなっており、筋は良さそうなライブラリだ。

libfixmath - Wikipedia

github.com

このライブラリのありがたいところは、三角関数などの実装に加えて、指数関数の実装もされているところだ。

特にニューラルネットワークにおいてsoftmax関数はexp演算を多用する。このため、固定小数点演算ライブラリにexpが入っているのは非常にありがたいのだ。

libfixmathを使ってMNISTプログラムを固定小数点化する

実装自体は非常に簡単だ。まずはlibfixmathライブラリをcloneしてビルドしておく。ライブラリとしてlibfixmath.aが出来るので、自分のプログラムのリンク時にコチラを呼び出しておけばよい。

浮動小数点からlibfixmathへの置き換えだが、まず固定小数点の型としてfix16_tが定義されている。こちらを活用することになる。

  • 固定値の代入
float a = 1.0;
fix16_t b = fix16_from_dbl(1.0);   // fix16_from_floatもある
float f = fix16_to_float (fx16);
float d = fix16_to_dbl (fx16);
  • 演算

fix16_t fx16_add = fix16_add (fx16_a, fx16_b);  // add = a + b;
fix16_t fx16_mul = fix16_mul (fx16_a, fx16_b);  // mul = a * b;

fix16_t fx16_exp = fix16_exp (fx16_a);          // exp = exp (a)

madd = fix16_add (madd, fix16_mul (fx16_a, fx16_b)); // madd = madd + (a * b);

など、大抵の演算が実行可能だ。

これを用いて、MNISTのプログラムの固定小数点化を行った。

github.com

MNISTの認識精度

doubleでの演算、floatでの演算、fix16_t での演算でのMNISTの認識精度の比較を行った。

  • double : 90.53%
  • float : 90.25%
  • fix16_t : 90.42%

全くそん色ない精度だ。特に実装の問題はないと思われる。ただし、問題はその実行速度だ。何故かfix16_tを使うと非常に遅くなってしまった。

これは、今後解析を行っていくものとする。とりあえず、x86以外のマイコンやボードに、移植を行っていこうかな。

f:id:msyksphinz:20170630022526p:plain