ホップフィールドネットワークについて

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

ホップフィールドネットワークについて

#1

投稿記事 by kamiya » 8年前

はじめまして。ただいまニューラルネットワークの勉強をしておりホップフィールドネットワークのプログラムを作成しようとしています。
結果が分かりやすいように記憶パターンを小さめで固定して試しています。最初に結合重みwを求めたあとに未知パターンとしてノイズを与えたものでユニットを初期化して想起を行うものなんですが、どうしても更新とエネルギー関数の計算部分がよくわからず変な値が入ってしまいます。コメントアウトした部分が試したもので、Update_State(w, state) と energy = Calculate_Energy_Function(w, state)の部分がうまくいきません。

コード:

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

//定数の設定
#define UNIT              4	/* ニューロンのユニット数 */
#define PATTERN           2	/* 記憶パターンの数 */
#define NOISE            10	/* 付加するノイズの数の上限 */
#define LEARNING_TIMES  1e4	/* 学習回数 (終了条件) */

//関数のプロトタイプ宣言
void Generate_Pattern(int pattern[][UNIT]);
void Set_Weight_Value(int pattern[][UNIT], int w[][UNIT]);
void Set_Initial_State(int pattern[][UNIT], int state[]);
void Update_State(int w[][UNIT], int state[]);
double Calculate_Energy_Function(int w[][UNIT], int state[]);
void Display_Pattern(int state[]);
void Display_Pattern2(int state[]);
void Display_Pattern3(int state[]);
void show_state(int state[UNIT]);

void call(int w[UNIT][UNIT]);
void noise(int pattern[UNIT][UNIT], int state[UNIT]);

int main()
{
	int pattern[PATTERN][UNIT];	/* 記憶パターン */
	int state[UNIT];		/* ネットワ-クの状態 */
	int w[UNIT][UNIT];		/* 結合重み */
	double energy;		/* エネルギ-関数値 */
	int iteration;

	/* 記憶パターンの生成 (分かりやすいように今は固定)*/
	Generate_Pattern(pattern);

	/* 重みの設定 */
	Set_Weight_Value(pattern, w);

	//結合荷重Wの表示
	call(w);

	/* 乱数の初期化 */
	srand((unsigned int)time(NULL));

	/* 初期状態の設定 */
	Set_Initial_State(pattern, state);

	/* 初期状態の表示 */
	Display_Pattern(state);

	//状態の表示
	show_state(state);

	//未知パターンで初期化
	noise(pattern, state);

	/* 未知パターンの表示 */
	Display_Pattern(state);

	//状態の表示
	show_state(state);

	/* 学習の開始 */
	//想起部分の計算?
	for (iteration = 0; iteration < LEARNING_TIMES; iteration++) {

		/* 更新の実行 */
		Update_State(w, state);

		/* エネルギー関数値の計算 */
		energy = Calculate_Energy_Function(w, state);

	}

	/* 途中結果の表示 */
	Display_Pattern2(state);
	show_state(state);
	
	/* 結果の表示 */
	//Display_Pattern3(state);
	//show_state(state);

	return 0;
}

//いまは固定パターンの生成
void Generate_Pattern(int pattern[PATTERN][UNIT])
{
	pattern[0][0] = 1;
	pattern[0][1] = 1;
	pattern[0][2] = -1;
	pattern[0][3] = -1;

	pattern[1][0] = -1;
	pattern[1][1] = 1;
	pattern[1][2] = -1;
	pattern[1][3] = 1;

}
/*
* 重みの設定
*
*   int    pattern : 記憶パターン
*   double w       : 結合重み
*/

void Set_Weight_Value(int pattern[PATTERN][UNIT], int w[UNIT][UNIT])
{
	int i, j, n;

	for (i = 0; i < UNIT; i++) {
		for (j = 0; j < UNIT; j++) {
			w[i][j] = 0;
			if (i != j) {
				for (n = 0; n < PATTERN; n++) {
					w[i][j] += pattern[n][i] * pattern[n][j];
				}
			}
		}
	}
}

void call(int w[UNIT][UNIT])
{
	int i, j;
	for (i = 0; i < UNIT; i++){
		for (j = 0; j < UNIT; j++){
			if (j % 4 == 0) {
				printf("\n");
			}
			printf("%d ", w[i][j]);
		}
	}
	printf("\n結合重み↑\n");
}
/* 初期状態の設定
* int pattern : 記憶パターン
* int state   : ネットワ-クの初期状態
*/
void Set_Initial_State(int pattern[PATTERN][UNIT], int state[UNIT])
{
	int p;
	int i;

	/* 想起するパターンの選定 */
	p = rand() % PATTERN;
	if (p < 0 || p > PATTERN - 1) {
		printf("選択した記憶パターンが範囲外です。\n");
		exit(-1);
	}

	for (i = 0; i < UNIT; i++) {
		state[i] = pattern[p][i];
	}
	printf("\n想起対象  パターン%d", p + 1);
}

//ユニットの初期化
void noise(int pattern[PATTERN][UNIT], int state[UNIT])
{
	int i, j;
	for (i = 0; i < NOISE; i++) {
		j = rand() % UNIT;
		if (state[j] == -1) {
			state[j] = 1;
		}
		else {
			state[j] = -1;
		}
	}
	printf("\nユニットを未知パターンで初期化");

}

/*
* 状態の更新
* int  w           : 結合重み
* int  state       : ネットワ-クの状態
*/
void Update_State(int w[UNIT][UNIT], int state[UNIT])
{
	int i, j, n;
	int out;

	for (i = 0; i < UNIT; i++) {
		for (j = 0; j < UNIT; j++) {
			for (n = 0; n < UNIT; n++){
				//エネルギーが収束したとき終了?
				//printf("\n%d * %d \n",w[i][j],state[j]);
				//state[j] = w[i][j] + state[j];
			}
		}
	}
}
/*
* エネルギー関数値の計算
*
* doubel w     : 結合重み
* int    state : ネットワ-クの状態
*/
double Calculate_Energy_Function(int w[UNIT][UNIT], int state[UNIT])
{/*
	int i, j;
	double energy = 0;

	for (i = 0; i < UNIT; i++){
		for (j = 0; j < UNIT; j++){

			energy = -0.5*(w[i][j]*(state[i]*state[j]));
		}
	}
	return (energy);*/
}

/*
* パターンの表示
*
* int state : ネットワ-クの状態
*/
void Display_Pattern(int state[UNIT])
{
	int i;

	printf("\n");

	if (state[0] == 1)
		printf("■");
	else
		printf("□");
	for (i = 1; i < UNIT; i++) {
		if (i % 10 == 0) {
			printf("\n");
		}
		if (state[i] == 1)
			printf("■");
		else
			printf("□");
	}
	printf("\n");
}

void Display_Pattern2(int state[UNIT])
{
	int i;
	printf("\nユニットの内部状態");
	printf("\n");

	if (state[0] == 1)
		printf("■");
	else
		printf("□");
	for (i = 1; i < UNIT; i++) {
		if (i % 10 == 0) {
			printf("\n");
		}
		if (state[i] == 1)
			printf("■");
		else
			printf("□");
	}
	printf("\n");
}

void Display_Pattern3(int state[UNIT])
{
	int i;
	printf("\n想起結果");
	printf("\n");

	if (state[0] == 1)
		printf("■");
	else
		printf("□");
	for (i = 1; i < UNIT; i++) {
		if (i % 10 == 0) {
			printf("\n");
		}
		if (state[i] == 1)
			printf("■");
		else
			printf("□");
	}
	printf("\n");
}

void show_state(int state[UNIT])
{
	int i;
	for (i = 0; i < UNIT; i++){
		printf("%d ", state[i]);
	}
	printf("\n");
}

yoko
記事: 24
登録日時: 13年前

Re: ホップフィールドネットワークについて

#2

投稿記事 by yoko » 8年前

このプログラムだと、
エネルギー関数の計算はいらないと思います。
http://www-ailab.elcom.nitech.ac.jp/lec ... /hop3.html
にある通り、
エネルギー関数を最小にする結合荷重の計算をプログラムで行っているからです。

また、プログラムは実行していませんが、
http://www-ailab.elcom.nitech.ac.jp/lec ... /hop2.html
にあるとおり、
記憶できる数が大体ニューロンユニット数×0.15なので、
ニューロン数が13は無いと想起できないので、
ニューロン数を増やす必要があると思います。
プログラムを見た感じでは正しく書けていると思いますので。

なお、一般的に想起しやすいパターンは
2つのパターンを比較したときに同じ個所と異なる箇所が半々に近いものとなります。

また、既知かもしれませんが、記憶したパターンの反転パターンに近い場合は
想起の際は反転パターンが想起されることがあります。

閉鎖

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