FPGA開発日記

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

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

誤差逆伝搬法を実装してMNISTの学習と認識プログラムをC言語フルスクラッチで作る。 動作するコードは完成し、今度はこれを固定小数点化しなければならない。今回は固定小数点化の検討を行う。

double –> float で精度を確認する。

まず、これまでに実装したMNISTプログラムの型をすべてdoubleからfloatに変換し、精度をチェックしておく。

github.com

やっていることは、単純にreplaceしているだけだ。これで同様にコンパイルし、実行すると、結果が得られた。

=== TestNetwork ===
Correct = 1342
=== TestNetwork ===
Correct = 5293
=== TestNetwork ===
Correct = 6388
=== TestNetwork ===
Correct = 7874
=== TestNetwork ===
Correct = 8447
=== TestNetwork ===
Correct = 8637
=== TestNetwork ===
Correct = 8700
=== TestNetwork ===
Correct = 8865
=== TestNetwork ===
Correct = 8924
=== TestNetwork ===
Correct = 8907
=== TestNetwork ===
Correct = 8966
=== TestNetwork ===
Correct = 9053

doubleのものと全く変わらない。

double –> 固定小数点

固定小数点化を行うために、まずはフレームワークを導入する。参考にしたのは以下のブログだ。

sunafukin2go.hatenablog.com

上記のサイトを参考に、以下のようにunionを導入した。

typedef union {
  int32_t i;
  struct {
    unsigned int fraction: 16;
    unsigned int decimal : 15;
    unsigned int sign : 1;
  } st_fix16;
} fix16_t;

#define FX16_RAW(fx16) (fx16.i)
#define FX16_SIGN(fx16) (fx16.st_fix16.sign)

これでdoubleで表現されているところをすべてfix16_tに書き換える。C++のtemplateを使えばより簡単になるだろうが、ここではなるべく平易なアセンブリ言語に変換されることを想定して、自分で演算も記述していく。

加算は単純にそのままの値を足すだけでよいが、乗算、除算については桁を合わせるためにひと工夫必要になる。

// 加算
A.i + B.i
// 減算
A.i - B.i
// 乗算
(A.i * B.i) >> 16
// 除算
((A.i << 32) / B.i) >> 16

と、これらの演算を定義して検証しているのだが、どうもうまくいかない。どうにかして固定小数点でのMNISTを動作させられるように、継続してデバッグしていく。