鸢尾花分类问题 三层BP神经模型

数据选取

样本总量为150,选取113为训练集,37为测试集.
隐含层层数为1,隐含层结点数量为5.
权值的学习率都选为0.1
输入维度为4,即花萼长度,花萼宽度,花瓣长度,花瓣宽度
输出维度为3,分别是样本为三种鸢尾花的可能性

源代码

#include<stdio.h>
#include<math.h>
#include<time.h>
#include<stdlib.h>
#include<string.h>
#define Data 113				//训练样本个数
#define TestData 37				//测试样本个数
#define In 4					//输入层神经元个数(花萼长度,花萼宽度,花瓣长度,花瓣宽度)
#define Out 3					//输出层神经元个数(样本为三种鸢尾花的可能性(0-1))
#define Neuron 5				//隐含层神经元个数
#define TrainC 40000			//最大训练次数
#define WAlta 0.1				//权值w的学习率
#define VAlta 0.1				//权值v的学习率
struct node {					
	double in[In];
	double out[Out];
};
struct node iris[TestData + Data];//存储所有样本数据
double d_in[Data][In];			//训练样本输入
double d_out[Data][Out];		//训练样本输出
double t_in[TestData][In];		//测试样本输入
double t_out[TestData][Out];	//测试样本输出
double pre[TestData][Out];		//预测样本的实际输出
double v[Neuron][In];			//输入层到隐含层的权值
double y[Neuron];				//隐含层
double w[Out][Neuron];			//隐含层到输出层的权值
double Maxin[In], Minin[In];	//样本输入的最大值和最小值
double Maxout[Out],Minout[Out];	//样本输出的最大值和最小值
double OutputData[Out];			//神经网络的输出
double dw[Neuron][Out], dv[Neuron][In];//权值w和v的修正量
const char* Name[3] = { "Iris-setosa","Iris-versicolor","Iris-virginica" };//鸢尾花种类的名字
double mse;						//均方误差
double rmse;			
double ermse;					//均方根误差
void ReadData() {				//读取文件中的数据
	srand(time(NULL));
	FILE* fp;
	char ch;
	char name[20];
	if ((fp = fopen("data.txt", "rb")) == NULL) {
		printf("不能打开data.txt文件\n");
		exit(0);
	}
	int n = TestData + Data;
	for (int i = 0; i <n ; ++i) {	//转移数据到结构体数组
		for (int j = 0; j < In; ++j) {
			if (j != 0) {
				fscanf(fp, "%c", &ch);
			}
			fscanf(fp, "%lf", &iris[i].in[j]);
		}
		fscanf(fp, "%c", &ch);
		fscanf(fp, "%s", name);
		memset(iris[i].out, 0, sizeof(iris[i].out));
		for (int k = 0; k < 3; ++k) {	//种类维度的数据变换
			if (strcmp(Name[k],name)==0) {
				iris[i].out[k] =1;
				break;
			}
		}
	}
	struct node tmp;
	int t=0;
	for (int i = 0; i < n; ++i) {		//打乱数据
		t = rand() % n;
		tmp = iris[i];
		iris[i] = iris[t];
		iris[t] = tmp;
	}
	for (int i = 0; i < Data; ++i) {	//数据划分为训练集的输入和输出,测试集的输入和输出
		for (int j = 0; j < In; ++j) {
			d_in[i][j] = iris[i].in[j];
		}
		for (int j = 0; j < Out; ++j) {
			d_out[i][j] = iris[i].out[j];
		}
	}
	for (int i = Data; i < TestData+Data; ++i) {
		for (int j = 0; j < In; ++j) {
			t_in[i-Data][j] = iris[i].in[j];
		}
		for (int j = 0; j < Out; ++j) {
			t_out[i-Data][j] = iris[i].out[j];
		}
	}
	fclose(fp);
}
void InitBPNetwork() {
	srand(time(NULL));
	for (int i = 0; i < In; ++i) {				//寻找输入输出的最大值
		Maxin[i] = Minin[i] = d_in[0][i];
		for (int j = 0; j < Data; ++j) {
			Maxin[i] = Maxin[i] > d_in[j][i] ? Maxin[i] : d_in[j][i];
			Minin[i] = Minin[i] < d_in[j][i] ? Minin[i] : d_in[j][i];
		}
	}
	Maxout[0] = Maxout[1] = Maxout[2] = 1;		//最大可能为1,最小可能为0
	Minout[0] = Minout[1] = Minout[2] = 0;
	for (int i = 0; i < In; ++i) {				//根据最大最小值对数据进行归一化
		for (int j = 0; j < Data; ++j) {
			d_in[j][i] = (d_in[j][i] - Minin[i]) / (Maxin[i] - Minin[i]);
		}
	}
	for (int i = 0; i < Out; ++i) {				//归一化
		for (int j = 0; j < Data; ++j) {
			d_out[j][i] = (d_out[j][i] - Minout[i]) / (Maxout[i] - Minout[i]);
		}
	}
	for (int i = 0; i < Neuron; ++i) {			//使用随机值初始化权值
		for (int j = 0; j < In; ++j) {
			v[i][j] = rand() * 2.0 / RAND_MAX - 1;
			dv[i][j] = 0;
		}
	}
	for (int i = 0; i < Out; ++i) {				//使用随机值初始化权值
		for (int j = 0; j < Neuron; ++j) {
			w[i][j] = rand() * 2.0 / RAND_MAX - 1;
			dw[j][i] = 0;
		}
	}
}
void ComputO(int var) {					//前向传播
	double sum;
	for (int i = 0; i < Neuron; ++i) {
		sum = 0;						//存储累加和
		for (int j = 0; j < In; ++j) {	//计算隐含层每个神经元的输出
			sum += v[i][j] * d_in[var][j];
		}
		y[i] = 1 / (1 + exp(-1 * sum));
	}
	for (int i = 0; i < Out; ++i) {		//计算输出层每个神经元的输出
		sum = 0;
		for (int j = 0; j < Neuron; ++j) {
			sum += w[i][j] * y[j];
		}
		OutputData[i] = 1 / (1 + exp(-1 * sum));
	}
}
void BackUpdata(int var) {				//反向传播的权值修正
	double t;
	for (int i = 0; i < Neuron; ++i) {
		t = 0;
		for (int j = 0; j < Out; ++j) {	//修正隐含层与输出层之间的各权值
			dw[j][i] = WAlta * (d_out[var][j] - OutputData[j]) * OutputData[j] * (1 - OutputData[j]) * y[i];
			t += (d_out[var][j] - OutputData[j]) * OutputData[j] * (1 - OutputData[j]) * w[j][i];
			w[j][i] += dw[j][i];
		}
		for (int j = 0; j < In; ++j) {	//修正隐含层与输出层之间的各权值
			dv[i][j] = VAlta * t * y[i] * (1 - y[i]) * d_in[var][j];
			v[i][j]+=dv[i][j];
		}
	}
}
void TrainNetwork() {					//神经网络的训练
	int count = 1;						//记录训练次数
	do {
		mse = 0;						//均方误差设置为0
		for (int i = 0; i < Data; ++i) {//所有训练集的一轮训练
			ComputO(i);					//前向传播
			BackUpdata(i);				//反向传播,调整权值
			for (int j = 0; j < Out; ++j) {	//计算单个样本误差
				double tmp1 = OutputData[j] * (Maxout[j] - Minout[j]) + Minout[j];
				double tmp2 = d_out[i][j] * (Maxout[j] - Minout[j]) + Minout[j];
				mse += pow(tmp1 - tmp2, 2.0);
			}
		}
		mse /= (double)Data * Out;		//计算均方误差
		if (count % 1000 == 0) {		//每1000此训练,显示一次训练误差,以便观察
			printf("%d  %lf\n", count, mse);
		}
		count++;
	} while (count <= TrainC && mse >= 0.01);//训练次数或达到要求,训练结束
	printf("训练结束\n");
	printf("训练次数:%d\n", count);
}
void TestNetwork() {			//神经网络模型评估
	for (int i = 0; i < In; ++i) {	//预测数据归一化
		for (int j = 0; j < TestData; ++j) {
			t_in[j][i] = (t_in[j][i] - Minin[i]) / (Maxin[i] - Minin[i]);
		}
	}
	double sum;
	int m = 0;
	for (int k = 0; k < TestData; ++k) {//计算每一个样本的预测结果
		for (int i = 0; i < Neuron; ++i) {//计算隐含层输出
			sum = 0;
			for (int j = 0; j < In; ++j) {
				sum += v[i][j] * t_in[k][j];
			}
			y[i] = 1 / (1 + exp(-1 * sum));
		}
		for (int i = 0; i < Out; ++i) {//计算输出层的预测结果
			sum = 0;
			for (int j = 0; j < Neuron; ++j) {
				sum += w[i][j] * y[j];
			}
			pre[k][i] = 1 / (1 + exp(-1 * sum)) * (Maxout[i] - Minout[i]) + Minout[i];
		}
		double max = 0;
		int t=0;
		printf("\n编号:%d\n",k);		//进行对比
		printf("预测值:");
		for (int i = 0; i < Out; ++i) {
			printf("%lf ", pre[k][i]);
			if (pre[k][i] > max) {
				max = pre[k][i];
				t = i;
			}
		}
		if (t_out[k][t] == 1) {
			m++;
		}
		printf("\n实际值:");
		for (int i = 0; i < Out; ++i) {
			printf("%lf ", t_out[k][i]);
		}
	}
	double summse=0.0;
	for (int i = 0; i < Out; ++i) {	//计算均方根误差,预测准确率
		double t = 0.0;
		for (int k = 0; k < TestData; ++k) {
			t +=pow(pre[k][i] - t_out[k][i], 2.0);
		}
		summse += sqrt(t / TestData);
	}
	rmse = summse / Out;
	printf("\nrmse: %.4lf,准确率:%lf\n", rmse,(double)m/TestData);
}
int main() {//主函数
	ReadData();
	InitBPNetwork();
	TrainNetwork();
	TestNetwork();
	return 0;
}

运行截图

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

另外

如果vs出现如下图报错,则关闭联想自带杀毒软件(联想杀毒puls)定时扫描可以解决。
还有记得关闭SDL安全检查。
在这里插入图片描述

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值