FPGA開発日記

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

ニューラルネットワーク C/C++実装の検討 1.

前回までで、「機械学習と深層学習」をやり切ったのだが、これを使っていろんなことをやってみたい。

機械学習と深層学習 ―C言語によるシミュレーション―

機械学習と深層学習 ―C言語によるシミュレーション―

せっかくニューラルネットワークC/C++での記述について勉強したので、これでいろんなアプリケーションを作ってみたい。まずは、Cの実装を使ってMNISTを作ってみるための検討をしてみよう。

ベースにするニューラルネット

ニューラルネットのベースにするのは、比較対象として明確な「ゼロから作るディープラーニング」のMNISTネットワークとしたい。

ここの第5章:「誤差逆伝搬法」の章では、MNISTのための2層ニューラルネットワークを作っている。まずForward方向には、以下のようなネットワークを構成していた。

Affineレイヤ1、ReLUレイヤ1、Affineレイヤ2、そして出力層としてSoftmaxを使っている。

f:id:msyksphinz:20170622015132p:plain

        # レイヤの生成
        self.layers = OrderedDict()
        self.layers['Affine1'] = Affine(self.params['W1'], self.params['b1'])
        self.layers['Relu1'] = Relu()
        self.layers['Affine2'] = Affine(self.params['W2'], self.params['b2'])

        self.lastLayer = SoftmaxWithLoss()

それぞれをC言語で実装することを考えてみよう。

Affineレイヤでは、行列WとベクトルXの積、さらにその結果に対してバイアスを掛けることになる。

double affine (double *o, double *e,
               double **wh, double *b,
               int output_size, int input_size)
{
  for (int i = 0; i < output_size; i++) {
    o[i] = 0;
    for (int j = 0; j < input_size; j++) {
      o[i] += e[j] * wh[i][j];
    }
    o[i] += b[i];
  }
}

次に、ReLU活性化関数は0以下ならば0、そうでなければ入力値となるので、

double relu (double *o, double *e, int input_size)
{
  for (int i = 0; i < input_size; i++) {
    o[i] = e[i] > 0.0 ? e[i] : 0.0;
  }
}

Softmaxはさらに複雑だ。まだテストしていないので合っているのかいるのか分からないが…

double softmax (double *o, double *e, int input_size)
{
  double max = e[0];
  for (int i = 1; i < input_size; i++) {
    max = max < e[i] ? e[i] : max;
  }
  double exp_sum = 0.0;
  double *exp_a = (double *)malloc(sizeof(double) * input_size);
  for (int i = 0; i < input_size; i++) {
    exp_a[i] = exp (e[i] - max);
    exp_sum += exp_a[i];
  }
  for (int i = 0; i < input_size; i++) {
    o[i] = exp_a[i] / exp_sum;
  }
}
````