2

私はニューラル ネットワークの経験がまったくないので、今のところ FANN ライブラリで遊んで学習しています。したがって、目的はネットワークをトレーニングして正弦関数を近似することです。そのために、3 層 NN 1 入力、3 隠しニューロン、1 出力ニューロンを使用しています。コードは

const unsigned int num_input = 1;
const unsigned int num_output = 1;
const unsigned int num_layers = 3;
const unsigned int num_neurons_hidden = 3;

struct fann *ann;

ann = fann_create_standard(num_layers, num_input, num_neurons_hidden, num_output);

fann_set_activation_steepness_hidden(ann, 1);
fann_set_activation_steepness_output(ann, 1);

fann_set_activation_function_hidden(ann, FANN_SIGMOID_SYMMETRIC);
fann_set_activation_function_output(ann, FANN_SIGMOID_SYMMETRIC);

fann_set_train_stop_function(ann, FANN_STOPFUNC_BIT);
fann_set_bit_fail_limit(ann, 0.01f);

fann_set_training_algorithm(ann, FANN_TRAIN_RPROP);

fann_randomize_weights(ann, 0, 1);

for(int i=0; i<2; ++i) {
    for(float angle=0; angle<10; angle+=0.1) {
        float sin_anle = sinf(angle);
        fann_train(ann, &angle, &sin_anle);
    }
}

int k = 0;
for(float angle=0; angle<10; angle+=0.1) {
    float sin_anle = sinf(angle);
    float *o = fann_run(ann, &angle);
    printf("%d\t%f\t%f\t\n", k++, *o, sin_anle);
}

fann_destroy(ann);

ただし、実際の正弦関数とは関係のない結果が得られました。ネットワーク設計に根本的な誤りがあると思います。

4

1 に答える 1

6

次の行で、最適化アルゴリズムの Resilient Backpropagation (Rprop) を選択します。

fann_set_training_algorithm(ann, FANN_TRAIN_RPROP);

Rpropバッチ更新アルゴリズムです。これは、更新ごとにトレーニング セット全体を提示する必要があることを意味します。fann_trainのドキュメントには、

提示されるパターンは 1 つだけなので、このトレーニングは常に増分トレーニングです (fann_train_enum を参照)。

したがって、適切な最適化オプションはFANN_TRAIN_INCREMENTAL. バッチ学習fann_train_on_dataには、 、fann_train_on_fileまたはのいずれかの方法を使用する必要がありfann_train_epochます。

コードを変更したときに気づいたことは次のとおりです。

  • あなたの急勾配は高すぎます。デフォルト値 (0.5) を使用しました。
  • トレーニング エポックが少なすぎます。20万くらい使ってる
  • 関数が複雑すぎて、隠れニューロンが 3 つしかありません。周期的な関数なので、決して簡単ではありません。そこで、近似した正弦関数の範囲を [0,3] に変更しました。これははるかに単純です。
  • ビット フェイル リミットが厳しすぎます。:) に設定しました0.02f
  • Rprop はあまり優れたトレーニング アルゴリズムではありません。より高速な Levenberg-Marquardt などを実装する必要があります。

私が得た解決策は完璧ではありませんが、少なくともほぼ正しいです:

0       0.060097        0.000000
1       0.119042        0.099833
2       0.188885        0.198669
3       0.269719        0.295520
4       0.360318        0.389418
5       0.457665        0.479426
6       0.556852        0.564642
7       0.651718        0.644218
8       0.736260        0.717356
9       0.806266        0.783327
10      0.860266        0.841471
11      0.899340        0.891207
12      0.926082        0.932039
...

この変更されたコードを使用しました:

#include <cstdio>
#include <cmath>
#include <fann.h>
#include <floatfann.h>

int main()
{
  const unsigned int num_input = 1;
  const unsigned int num_output = 1;
  const unsigned int num_layers = 3;
  const unsigned int num_neurons_hidden = 2;

  const float angleRange = 3.0f;
  const float angleStep = 0.1;
  int instances = (int)(angleRange/angleStep);

  struct fann *ann;

  ann = fann_create_standard(num_layers, num_input, num_neurons_hidden, num_output);

  fann_set_activation_function_hidden(ann, FANN_SIGMOID_SYMMETRIC);
  fann_set_activation_function_output(ann, FANN_SIGMOID_SYMMETRIC);

  fann_set_train_stop_function(ann, FANN_STOPFUNC_BIT);
  fann_set_bit_fail_limit(ann, 0.02f);

  fann_set_training_algorithm(ann, FANN_TRAIN_INCREMENTAL);

  fann_randomize_weights(ann, 0, 1);

  fann_train_data *trainingSet;
  trainingSet = fann_create_train(instances, 1, 1); // instances, input dimension, output dimension
  float angle=0;
  for(int instance=0; instance < instances; angle+=angleStep, instance++) {
      trainingSet->input[instance][0] = angle;
      trainingSet->output[instance][0] = sinf(angle);
  }

  fann_train_on_data(ann, trainingSet, 20000, 10, 1e-8f); // epochs, epochs between reports, desired error

  int k = 0;
  angle=0;
  for(int instance=0; instance < instances; angle+=angleStep, instance++) {
      float sin_angle = sinf(angle);
      float *o = fann_run(ann, &angle);
      printf("%d\t%f\t%f\t\n", k++, *o, sin_angle);
  }

  fann_destroy(ann);

  return 0;
}

fann_create_trainFANN 2.2.0 以降で利用可能であることに注意してください。

于 2012-05-15T09:58:07.353 に答える