#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h> //為了取得時間序列
//在程式開始之前先定義函數以便讓main知道
void FileLoad_scan_number_of_training_sets();
void Normalize_data();
void Initial_the_weight();
void Initialize_the_sum();
void Compute_internal_state(int);
void Compute_epison(int);
void Updata_weight_and_bias(int);
void Move_weight_and_bias();
double function_of_hidden_layer(double);
double function_of_output_layer(double);
double first_direvative_of_function_of_hidden_layer(double);
double first_direvative_of_function_of_output_layer(double);
//可供使用者調整
double learning_rate = 0.05;
double mementum;
int time_step = 1000;
int input_dimension=2;
int output_dimension=2;
int number_of_neuron_hidden_layer = 10;
int number_of_training_sets = 0;
int i,j;
double **data_input = 0; //save input of training data
double **data_output = 0; //save target of training daya
double zz; //save tmp calculation number
double *tmp_matrix; //save tmp matrix of all training data
double *max=0; //save the maximum number of training data in each group
double *min=0; //save the minimum number of training data in each group
double **weight_between_input_and_hidden; //weight of the connection between input layer and hidden layer
double **weight_between_hidden_and_output; //weight of the connection between hidden layer and output layer
double *bias_hidden; //bias in hidden layer
double *bias_output; //bias in output layer
double cc; //save tmp random number
double *internal_state_between_input_and_hidden; //internal state in hidden layer
double *internal_state_between_hidden_and_output; //internal state in output layer
double *activation_value_hidden; //activation value in hidden layer
double *y_value_output; //output value in output layer
double sum_of_weight=0; //for calculating the sum of weight
double *total_error; //save total error in output layer
double *epison_hidden; //epison number in hidden layer
double *epison_output; //epison number in output layer
double sum_of_epison=0; //for calculating the sum of epison
int idx = 0;
int count = 0;
double **sum_of_weight_between_input_and_hidden;
double **sum_of_weight_between_hidden_and_output;
double *sum_of_bias_hidden=0;
double *sum_of_bias_output=0;
double **modification_of_weight_between_input_and_hidden=0;
double **modification_of_weight_between_hidden_and_output=0;
double *modification_of_bias_hidden=0;
double *modification_of_bias_output=0;
double nn;
int main(){
FILE *Consq_error_first_dimen;
FILE *Consq_error_second_dimen;
FILE *Consq_output_first_dimen;
FILE *Consq_output_second_dimen;
Consq_error_first_dimen = fopen("C:\\Users\\Wen\\Desktop\\Consq_error_first_dimen.txt", "w+");
Consq_error_second_dimen = fopen("C:\\Users\\Wen\\Desktop\\Consq_error_second_dimen.txt","w+");
Consq_output_first_dimen = fopen("C:\\Users\\Wen\\Desktop\\Consq_output_first_dimen.txt", "w+");
Consq_output_second_dimen = fopen("C:\\Users\\Wen\\Desktop\\Consq_output_scond_dimen.txt", "w+");
FileLoad_scan_number_of_training_sets();
Normalize_data();
Initial_the_weight();
for(count = 0; count<time_step; count++)
{
Initialize_the_sum();
for(idx=0;idx<(number_of_training_sets-1);idx++)
{
Compute_internal_state(idx);
Compute_epison(idx);
Updata_weight_and_bias(idx);
for(i=0;i<output_dimension;i++)
{
if(i==0)
{
fprintf(Consq_error_first_dimen, "%f ", total_error[i]);
fprintf(Consq_output_first_dimen, "%f ", y_value_output[i]);
}
if(i==1)
{
fprintf(Consq_error_second_dimen, "%f ", total_error[i]);
fprintf(Consq_output_second_dimen, "%f ", y_value_output[i]);
}
}
fprintf(Consq_error_first_dimen, "\n");
fprintf(Consq_error_second_dimen, "\n");
fprintf(Consq_output_first_dimen, "\n");
fprintf(Consq_output_second_dimen, "\n");
}
Move_weight_and_bias();
}
fclose(Consq_error_first_dimen);
fclose(Consq_error_second_dimen);
fclose(Consq_output_first_dimen);
fclose(Consq_output_second_dimen);
printf("Build file successfully!");
printf("\n");
printf("\n");
printf("\n");
system("pause");
return 0;
}
void FileLoad_scan_number_of_training_sets()
{
char *char_of_load_training_data;
int length_of_first_column = 500; //每一行字源的長度,可隨意亂設
char first_column_information[500]; //建立一個字元長度為1000的字元矩陣
char comma[] = ","; //以逗號當作分隔符號
FILE *datafile;
datafile = fopen("circle_fail.txt", "r");
if(datafile == NULL) //判斷開檔是否成功
{
printf(" Fail to open file. "); //讀檔失敗的話
}
else
{
while (fgets(first_column_information, sizeof(first_column_information), datafile)) //一次讀取一行
{
number_of_training_sets = number_of_training_sets + 1; //先掃描一遍整體的行數
}
fseek(datafile,0,SEEK_SET); //將讀檔指標從SEEK_SET(文件一開始),指向位移0行的位置(可將指標指定欲達到的位置)
//生成input的二維動態陣列
data_input = (double**)malloc(sizeof(double*)*number_of_training_sets);
for(i=0; i<number_of_training_sets; i++)
{
data_input[i]=(double*)malloc(sizeof(double)*input_dimension);
}
//生成output的二維動態陣列
data_output = (double**)malloc(sizeof(double*)*number_of_training_sets);
for(i=0; i<number_of_training_sets; i++)
{
data_output[i]=(double*)malloc(sizeof(double)*output_dimension);
}
for(i=0;i<number_of_training_sets;i++)
{
if ((fgets(first_column_information, sizeof(first_column_information), datafile))!= NULL) //將data從頭再讀一遍
{
char_of_load_training_data = strtok(first_column_information,comma); //以comma符號為data分割
for(j=0; j<input_dimension; j++)
{
if(char_of_load_training_data!=NULL) //當分割出來的字不是空的時候
{
zz = atof(char_of_load_training_data); //將字元轉換成double
data_input[i][j]=zz; //將讀到的double存進input矩陣
data_output[i][j]=zz; //將讀到的double存進output矩陣
//printf("%f ", data_input[i][j]);
char_of_load_training_data = strtok(NULL, comma); //繼續分割
}
}
}
//printf("\n");
}
}
fclose(datafile); //把檔案關起來以避免錯誤
}
//標準化training data以使得其範圍落在0和1之間
void Normalize_data()
{
tmp_matrix = (double*)malloc(sizeof(double)*number_of_training_sets);
max = (double*)malloc(sizeof(double)*input_dimension);
min = (double*)malloc(sizeof(double)*input_dimension);
for( i=0; i<input_dimension; i++)
{
max[i] = 0; //先把最大值設成一個任意的很小值
min[i] = 9999; //先把最小值設成一個任意的很大值
}
for( i=0; i<input_dimension; i++)
{
for( j=0; j<number_of_training_sets; j++)
{
tmp_matrix[j] = data_input[j][i];
if(tmp_matrix[j]>max[i]) //抓出最大值
{
max[i] = tmp_matrix[j];
}
if(tmp_matrix[j]<min[i]) //抓出最小值
{
min[i] = tmp_matrix[j];
}
}
}
for(i=0; i<input_dimension; i++)
{
for(j=0; j<number_of_training_sets; j++)
{
if(max[i] != min[i])
{
data_input[j][i] = ((data_input[j][i] - min[i]) / (max[i] - min[i]))*1.8-0.9; //normalize data
data_output[j][i] = ((data_output[j][i] - min[i]) / (max[i] - min[i]))*1.8-0.9;
}
else
{
data_input[j][i] = 0; //當其最大值與最小值相等時
data_output[j][i] = 0;
}
}
}
//for(i=0;i<number_of_training_sets;i++)
//{
// for(j=0;j<input_dimension;j++)
// {
// printf("%f ", data_input[i][j]);
// }
// printf("\n");
//}
}
void Initial_the_weight()
{
weight_between_input_and_hidden = (double**)malloc(sizeof(double*)*number_of_neuron_hidden_layer);
for(i=0;i<number_of_neuron_hidden_layer;i++)
{
weight_between_input_and_hidden[i] = (double*)malloc(sizeof(double*)*input_dimension);
}
weight_between_hidden_and_output=(double**)malloc(sizeof(double*)*output_dimension);
for(i=0;i<output_dimension;i++)
{
weight_between_hidden_and_output[i]=(double*)malloc(sizeof(double*)*number_of_neuron_hidden_layer);
}
sum_of_weight_between_input_and_hidden = (double**)malloc(sizeof(double*)*number_of_neuron_hidden_layer);
for(i=0;i<number_of_neuron_hidden_layer;i++)
{
sum_of_weight_between_input_and_hidden[i] = (double*)malloc(sizeof(double*)*input_dimension);
}
sum_of_weight_between_hidden_and_output=(double**)malloc(sizeof(double*)*output_dimension);
for(i=0;i<output_dimension;i++)
{
sum_of_weight_between_hidden_and_output[i]=(double*)malloc(sizeof(double*)*number_of_neuron_hidden_layer);
}
modification_of_weight_between_input_and_hidden = (double**)malloc(sizeof(double*)*number_of_neuron_hidden_layer);
for(i=0;i<number_of_neuron_hidden_layer;i++)
{
modification_of_weight_between_input_and_hidden[i] = (double*)malloc(sizeof(double*)*input_dimension);
}
modification_of_weight_between_hidden_and_output=(double**)malloc(sizeof(double*)*output_dimension);
for(i=0;i<output_dimension;i++)
{
modification_of_weight_between_hidden_and_output[i]=(double*)malloc(sizeof(double*)*number_of_neuron_hidden_layer);
}
bias_hidden = (double*)malloc(sizeof(double)*number_of_neuron_hidden_layer);
bias_output = (double*)malloc(sizeof(double)*output_dimension);
sum_of_bias_hidden = (double*)malloc(sizeof(double)*number_of_neuron_hidden_layer);
sum_of_bias_output = (double*)malloc(sizeof(double)*output_dimension);
modification_of_bias_hidden = (double*)malloc(sizeof(double)*number_of_neuron_hidden_layer);
modification_of_bias_output = (double*)malloc(sizeof(double)*output_dimension);
srand(100);
for(i=0;i<number_of_neuron_hidden_layer;i++)
{
for(j=0;j<input_dimension;j++)
{
//srand(rand()*100);
cc=((double)rand()/(double)(RAND_MAX)); //利用除以最大的亂數來得到0到1之間的亂數浮點數
weight_between_input_and_hidden[i][j]=cc;
}
}
srand(200);
for(i=0;i<output_dimension;i++)
{
for(j=0;j<number_of_neuron_hidden_layer;j++)
{
cc=((double)rand()/(double)(RAND_MAX)); //利用除以最大的亂數來得到0到1之間的亂數浮點數
weight_between_hidden_and_output[i][j]=cc;
}
}
srand(300);
for(i=0;i<number_of_neuron_hidden_layer;i++)
{
//srand(rand()*100);
bias_hidden[i] = ((double)rand()/(double)(RAND_MAX)); //利用除以最大的亂數來得到0到1之間的亂數浮點數
}
srand(400);
for(i=0;i<output_dimension;i++)
{
//srand(rand()*100);
bias_output[i] = ((double)rand()/(double)(RAND_MAX)); //利用除以最大的亂數來得到0到1之間的亂數浮點數
//printf("%f ", bias_output[i]);
}
internal_state_between_input_and_hidden = (double*)malloc(sizeof(double)*number_of_neuron_hidden_layer);
internal_state_between_hidden_and_output = (double*)malloc(sizeof(double)*output_dimension);
activation_value_hidden= (double*)malloc(sizeof(double)*number_of_neuron_hidden_layer);
y_value_output = (double*)malloc(sizeof(double)*output_dimension);
epison_output = (double*)malloc(sizeof(double)*output_dimension);
epison_hidden = (double*)malloc(sizeof(double)*number_of_neuron_hidden_layer);
total_error = (double*)malloc(sizeof(double)*output_dimension);
}
void Initialize_the_sum()
{
for(i=0;i<output_dimension;i++)
{
for(j=0;j<number_of_neuron_hidden_layer;j++)
{
sum_of_weight_between_hidden_and_output[i][j]=0;
modification_of_weight_between_hidden_and_output[i][j]=0;
}
sum_of_bias_output[i] = 0;
modification_of_bias_output[i]=0;
}
for(i=0;i<number_of_neuron_hidden_layer;i++)
{
for(j=0;j<input_dimension;j++)
{
sum_of_weight_between_input_and_hidden[i][j]=0;
modification_of_weight_between_input_and_hidden[i][j]=0;
}
sum_of_bias_hidden[i]=0;
modification_of_bias_hidden[i]=0;
}
}
void Compute_internal_state(int data_idx)
{
for(i=0;i<number_of_neuron_hidden_layer;i++)
{
sum_of_weight = 0;
internal_state_between_input_and_hidden[i] = 0;
for(j=0;j<input_dimension;j++)
{
sum_of_weight = sum_of_weight + weight_between_input_and_hidden[i][j] * data_input[data_idx][j];
}
internal_state_between_input_and_hidden[i] = sum_of_weight + bias_hidden[i];
activation_value_hidden[i] = function_of_hidden_layer(internal_state_between_input_and_hidden[i]);
}
sum_of_weight=0;
for(i=0;i<output_dimension;i++)
{
sum_of_weight = 0;
internal_state_between_hidden_and_output[i] = 0;
for(j=0;j<number_of_neuron_hidden_layer;j++)
{
sum_of_weight = sum_of_weight + weight_between_hidden_and_output[i][j] * activation_value_hidden[j];
}
internal_state_between_hidden_and_output[i] = sum_of_weight + bias_output[i];
y_value_output[i] = function_of_output_layer(internal_state_between_hidden_and_output[i]);
}
for(i=0;i<output_dimension;i++)
{
total_error[i] = (pow((y_value_output[i] - data_output[data_idx+1][i]),2))/2;
//printf("%f ", total_error[i]);
}
}
void Compute_epison(int data_idx)
{
for(i=0;i<output_dimension;i++)
{
epison_output[i] = first_direvative_of_function_of_output_layer(internal_state_between_hidden_and_output[i])*(y_value_output[i] - data_output[data_idx+1][i]);
}
for(i=0;i<number_of_neuron_hidden_layer;i++)
{
for(j=0;j<output_dimension;j++)
{
sum_of_epison = sum_of_epison + weight_between_hidden_and_output[j][i] * epison_output[j];
}
epison_hidden[i] = (first_direvative_of_function_of_hidden_layer(internal_state_between_input_and_hidden[i]))*sum_of_epison;
}
}
void Updata_weight_and_bias(int data_idx)
{
for(i=0; i<output_dimension; i++)
{
for(j=0;j<number_of_neuron_hidden_layer; j++)
{
modification_of_weight_between_hidden_and_output[i][j] = epison_output[i] * activation_value_hidden[j];
}
modification_of_bias_output[i] = epison_output[i];
}
for(i=0;i<output_dimension;i++)
{
for(j=0;j<number_of_neuron_hidden_layer;j++)
{
sum_of_weight_between_hidden_and_output[i][j] = sum_of_weight_between_hidden_and_output[i][j] + modification_of_weight_between_hidden_and_output[i][j];
}
sum_of_bias_output[i] = sum_of_bias_output[i] + modification_of_bias_output[i];
}
for(i=0;i<number_of_neuron_hidden_layer;i++)
{
for(j=0;j<input_dimension;j++)
{
modification_of_weight_between_input_and_hidden[i][j] = epison_hidden[i] * data_input[data_idx][j];
}
modification_of_bias_hidden[i] = epison_hidden[i];
}
for(i=0; i<number_of_neuron_hidden_layer; i++)
{
for(j=0;j<input_dimension;j++)
{
sum_of_weight_between_input_and_hidden[i][j] = sum_of_weight_between_input_and_hidden[i][j] + modification_of_weight_between_input_and_hidden[i][j];
}
sum_of_bias_hidden[i] = sum_of_bias_hidden[i] + modification_of_bias_hidden[i];
}
}
void Move_weight_and_bias()
{
for(i=0;i<output_dimension;i++)
{
for(j=0;j<number_of_neuron_hidden_layer;j++)
{
weight_between_hidden_and_output[i][j] = weight_between_hidden_and_output[i][j] - (learning_rate * sum_of_weight_between_hidden_and_output[i][j]);
}
bias_output[i] = bias_output[i] - learning_rate * sum_of_bias_output[i];
}
for(i=0; i<number_of_neuron_hidden_layer;i++)
{
for(j=0;j<input_dimension;j++)
{
weight_between_input_and_hidden[i][j] = weight_between_input_and_hidden[i][j] - (learning_rate * sum_of_weight_between_input_and_hidden[i][j]);
}
bias_hidden[i] = bias_hidden[i] - learning_rate * sum_of_bias_hidden[i];
}
}
//give data in input layer
double function_of_hidden_layer(double z)
{
return ((exp(z)-exp(-z))/(exp(z)+exp(-z))) ;
}
// give data in hidden layer
double function_of_output_layer(double z)
{
return ((exp(z)-exp(-z))/(exp(z)+exp(-z)));
}
double first_direvative_of_function_of_hidden_layer(double z)
{
return (4/(pow((exp(z)+exp(-z)),2)));
}
double first_direvative_of_function_of_output_layer(double z)
{
return (4/(pow((exp(z)+exp(-z)),2)));
}