大学の課題

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
DGELZEX
記事: 1
登録日時: 3年前

大学の課題

#1

投稿記事 by DGELZEX » 3年前

初書き込みです。間違った書き方をしているかもしれませんが、ご容赦ください。

現在、大学の課題でc言語でホップフィールドネットワークのプログラムを書いています。
過去にこのサイトに同じ内容のトピックが作成されているようなのですが、参考にすることができないため、質問させてください。
以下のプログラムの中の /*** この部分を自分で書く ***/の部分を自分で作成する課題です。
具体的に言うと「int StepFunc」「void display_pattern」「void learn_w」「void input_pattern」「void culc_output」を作成しなけれなりません。

1と-1で記されたデータを読み込み、1は■、-1は□の画像として表示します。
実行の際に画像の番号とノイズの付与率を指定して実行します。実行結果はノイズが付与された画像のあとノイズの除去された画像が端末上に表示されます。

このプログラムの作成に必要な数式は以下の2点です
1597565425648.jpg
1597565425648.jpg (30.31 KiB) 閲覧数: 3917 回
一通り書き上げてみたのですが以下の問題が発生しました
①どの番号を指定しても番号に関係なく特定の画像が表示される
②画像の表示の際、ノイズと思われるものが大量に表示された後に徐々にノイズのない画像が表示される。

課題の出題から頑張って作成してきたのですが以上の2点が解らずつまずいてしまいました。大学の先生に同様の事を質問したのですが、相関学習がうまく反映できていないのではないか、との回答がありました。おそらくlearn_wの部分だと思うのですが、どう間違っているのかがわかりません。
今週の木曜午後1時にレポートともに提出しなければならないので、できるなら火曜日までには回答があるとありがたいです。
ご教授お願い致します。

コード:

#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define PatternNo 6
#define DataWidth 20
#define DataHeight 20
#define UnitNo DataWidth *DataHeight
#define TimeMax 2

*/
/********************************************************************
  乱数の発生 (Seedの決定)
********************************************************************/
void init_rnd() { srand((unsigned int)time(NULL)); }

/********************************************************************
  乱数の発生 (0〜1の乱数)
********************************************************************/
double Random() { return ((double)rand() / RAND_MAX); }

/********************************************************************
  出力関数 (ステップ関数){xi(t+1)}
    引数  net  : 内部状態の値{ui(t)}
          pout : 1時刻前の出力の値(p out)
********************************************************************/
int StepFunc(int net, int pout) {
  /* 内部状態(net)の値が0より大きければ  1
     内部状態(net)の値が0より小さければ  -1
     内部状態(net)の値が0ならば前の時刻の出力の値(pout) を返す */

  /*** この部分を自分で書く ***/

  if (net > 0) {
    return 1;
  } else if (net < 0) {
    return -1;
  } else {
    return pout;
  }
}

/********************************************************************
  パターンの表示
    引数  out[i] :  ニューロンの出力値
********************************************************************/
void display_pattern(int out[UnitNo]) {
  int i;

  /* ニューロンの出力値out[i]が 1ならば ■ を表示
     ニューロンの出力値out[i]が-1ならば □ を表示
     DataWidth個分のデータを出力したら改行する    */

  /*** この部分を自分で書く ***/

  for (i = 0; i < UnitNo; i++) {
    if (i > 1 && i % DataWidth == 0) {  //ここびっみょ
      printf("\n");
    }
    if (out[i] == 1) {
      printf("■");
    } else if (out[i] == -1) {
      printf("□");
    }
  }
  printf("\n");
}

/********************************************************************
  学習パターンの読み込み
    引数  PatternID     : パターンの番号
          fname         : ファイル名
          pattern[p][i] : 学習パターン
                           (p番目のパターンのi番目の成分)
   ファイル fname のデータを PatternID番目の学習パターンとして
   pattern[PatternID][i]に読み込む
********************************************************************/
void read_pattern(int PatternID, char *fname, int pattern[PatternNo][UnitNo]) {
  int i;
  FILE *fp;

  /* ファイル fname をオープン */
  if ((fp = fopen(fname, "r")) == NULL) {
    printf("read_pattern(): Cannot open \"%s\"\n", fname);
    exit(1);
  }

  /* データの読み込み */
  for (i = 0; i < UnitNo; i++) {
    fscanf(fp, "%d", &pattern[PatternID][i]);
  }

  /* ファイルをクローズ */
  fclose(fp);
}

/********************************************************************
  学習パターンの読み込み (読み込むファイルの指定)
    引数  pattern[p][i] : 学習パターン
                           (p番目のパターンのi番目の成分)
********************************************************************/
void read_patterns(int pattern[PatternNo][UnitNo]) {
  /* 0番目のパターンとして crow を読み込む */
  read_pattern(0, "crow", pattern);
  /* 1番目のパターンとして duck を読み込む */
  read_pattern(1, "duck", pattern);
  /* 2番目のパターンとして lion を読み込む */
  read_pattern(2, "lion", pattern);
  /* 3番目のパターンとして monkey を読み込む */
  read_pattern(3, "monkey", pattern);
  /* 4番目のパターンとして mouse を読み込む */
  read_pattern(4, "mouse", pattern);
  /* 5番目のパターンとして penguin を読み込む */
  read_pattern(5, "penguin", pattern);
}

/********************************************************************
  相関学習
    引数  pattern[p][i] : 学習パターン
          w[i][j]       : 重み
                    (ニューロンiとニューロンjの間の重み)
********************************************************************/
void learn_w(int pattern[PatternNo][UnitNo], int w[UnitNo][UnitNo]) {
  int p, i, j;

  /* 学習パターンを用いて重み w[i][j] を決定する。
     ただし、自分自身への結合 w[i][i] は0とする */

  /*** この部分を自分で書く ***/

  for (i = 0; i < UnitNo; i++) {
    for (j = 0; j < UnitNo; j++) {
      if (i == j) {
        w[i][j] = 0;
      } else if (i != j) {
        for (p = 1; p < PatternNo; p++) {
          w[i][j] = pattern[p][i] * pattern[p][j];
        }
      }
    }
  }
}

/********************************************************************
  パターンの入力
    引数  PatternID     : 入力するパターンの番号
          pattern[p][i] : 学習パターン
          input[i]      : 入力パターン
          NoiseLevel    : ノイズレベル (0〜1)
   pattern[p][i]のに含まれるパターンのうち、PatternID番目の
   パターンを入力パターンとしてinput[i]に読み込む。
   NoiseLevelが0でない場合には、NoiseLevelの値に応じて入力
   パターンを反転させたものをinput[i]とする。

   多分この変ミスってる
********************************************************************/
void input_pattern(int PatternID, int pattern[PatternNo][UnitNo],
                   int input[UnitNo], double NoiseLevel) {
  int i;

  /* pattern[p][i]のに含まれるパターンのうち、PatternID番目の
     パターンを入力パターンとしてinput[i]に読み込む。
     NoiseLevel が 0 でない場合には、Random()で乱数を発生させ、
     Random()の値が NoiseLevel 以下の場合には input[i]の値を反転
     (1ならば-1に、-1ならば1にする)させる。 */

  /*** この部分を自分で書く ***/
  for (i = 0; i < UnitNo; i++) {
    input[i] = pattern[i][PatternID];
    if (NoiseLevel != 0) {  //多分あってる
      if (NoiseLevel > Random()) {
        input[i] *= -1;
      }
    }
  }
}

/********************************************************************
  パターンの想起
    引数  w[i][j]       : 重み (ニューロンiとニューロンjの間の重み)
          out[i]        : ニューロンの出力
          N = UnitNo?
          i = N?
*********************************************************************/
//ここまでコンパイルエラーは無し
void calc_output(int w[UnitNo][UnitNo], int out[UnitNo]) {
  int i, j;
  int net;
  for (i = 0; i < UnitNo; i++) {
    /* out[i] の値を計算する */
    /*** この部分を自分で書く ***/
    for (j = 0; j < UnitNo; j++) {
      net = w[i][j] * out[j];
    }
    out[i] = StepFunc(net, out[UnitNo]);
    /* 出力パターンを表示する */
    display_pattern(out);
    // getchar();
  }
}

/************************************************************
  メインプログラム
************************************************************/
int main(int argc, char *argv[]) {
  int pattern[PatternNo][UnitNo]; /* 学習パターン */
  int w[UnitNo][UnitNo];          /* 重み */
  int out[UnitNo];                /* 出力 */
  int PatternID;                  /* 入力パターンの番号 */
  double NoiseLevel;              /* ノイズレベル */
  int t;

  if (argc != 3) {
    printf("プログラムの使用方法 : \n");
    printf("  ./a.out 入力するパターンの番号(0〜5) ノイズレベル(0〜100)\n");
    exit(1);
  }

  PatternID = atoi(argv[1]);
  NoiseLevel = atof(argv[2]) / 100.0;

  init_rnd();             /* 乱数の初期化 */
  read_patterns(pattern); /* 学習パターンの読み込み */
  learn_w(pattern, w);    /* 相関学習 */
  input_pattern(PatternID, pattern, out, NoiseLevel); /* パターンの入力 */
  display_pattern(out); /* 入力パターンの表示 */

  /* 想起 */
  for (t = 0; t < TimeMax; t++) {
    calc_output(w, out);
  }

  return 0;
}

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: 大学の課題

#2

投稿記事 by みけCAT » 3年前

詳しくみてはいませんが、とりあえずざっと見たところ、以下の怪しい点がありました。

●13行目に不正な文字列

コード:

*/
があり、コンパイルエラーになる

●learn_w関数の

コード:

        for (p = 1; p < PatternNo; p++) {
          w[i][j] = pattern[p][i] * pattern[p][j];
        }
という部分は、代入は前の値を上書きするため実質

コード:

        w[i][j] = pattern[PatternNo - 1][i] * pattern[PatternNo - 1][j];
と同じ意味であり、ループの意味がない (和を求めるなどの計算をしたかったのではないか?)

●input_pattern関数の

コード:

    input[i] = pattern[i][PatternID];
という部分は、引数patternの宣言を考えるとpatternの添字のiとPatternIDが逆の方が自然

●calc_output関数の

コード:

    for (j = 0; j < UnitNo; j++) {
      net = w[i][j] * out[j];
    }
という部分は、代入は前の値を上書きするため実質

コード:

    net = w[i][UnitNo - 1] * out[UnitNo - 1];
と同じ意味であり、ループの意味がない (和を求めるなどの計算をしたかったのではないか?)

●calc_output関数の

コード:

    out[i] = StepFunc(net, out[UnitNo]);
という部分は、範囲外のout[UnitNo]を使用している (未定義動作)
また、outのデータを用いた計算が完了する前にoutの値を変えてしまっている
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
あたっしゅ
記事: 664
登録日時: 13年前
住所: 東京23区
連絡を取る:

Re: 大学の課題

#3

投稿記事 by あたっしゅ » 3年前

viewtopic.php?t=17000
(1) ホップフィールドネットワークについて - プログラマ専用SNS ミクプラ(ja)

viewtopic.php?t=8831
(1) C言語でホップフィールドネットワーク - プログラマ専用SNS ミクプラ(ja)

見れないって、これらのことか ?
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。

中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。

返信

“C言語何でも質問掲示板” へ戻る