搭建BP神经网络

news2024/11/24 7:47:18

1.数据集下载
2.C语言代码
BP.h

#ifndef BP_H_INCLUDED
#define BP_H_INCLUDED
const int INPUT_LAYER = 784; //输入层维度
const int HIDDEN_LAYER = 40; //隐含层维度
const int OUTPUT_LAYER = 10; //输出层维度
const double LEARN_RATE = 0.3; //学习率
const int TRAIN_TIMES = 10; //迭代训练次数
class BP
{
private:
    int input_array[INPUT_LAYER]; //输入向量
    int aim_array[OUTPUT_LAYER]; //目标结果
    double weight1_array[INPUT_LAYER][HIDDEN_LAYER]; //输入层与隐含层之间的权重
    double weight2_array[HIDDEN_LAYER][OUTPUT_LAYER]; //隐含层与输出层之间的权重
    double output1_array[HIDDEN_LAYER]; //隐含层输出
    double output2_array[OUTPUT_LAYER]; //输出层输出
    double deviation1_array[HIDDEN_LAYER]; //隐含层误差
    double deviation2_array[OUTPUT_LAYER]; //输出层误差
    double threshold1_array[HIDDEN_LAYER]; //隐含层阈值
    double threshold2_array[OUTPUT_LAYER]; //输出层阈值
public:
    void Init(); //初始化各参数
    double Sigmoid(double x); //sigmoid激活函数
    void GetOutput1(); //得到隐含层输出
    void GetOutput2(); //得到输出层输出
    void GetDeviation1(); //得到隐含层误差
    void GetDeviation2(); //得到输出层误差
    void Feedback1(); //反馈输入层与隐含层之间的权重
    void Feedback2(); //反馈隐含层与输出层之间的权重
    void Train(); //训练
    void Test(); //测试
};
#endif // BP_H_INCLUDED

BP.cpp

#include <bits/stdc++.h>
#include<iostream>
#include <ctime>
#include <chrono>
#include "BP.h"
using namespace std;
//初始化各参数
void BP::Init()
{
	srand(time(NULL));
	for (int i = 0; i < INPUT_LAYER; i++)
		for (int j = 0; j < HIDDEN_LAYER; j++)
			weight1_array[i][j] = rand() / (double)(RAND_MAX) * 2 - 1;
	for (int i = 0; i < HIDDEN_LAYER; i++)
		for (int j = 0; j < OUTPUT_LAYER; j++)
			weight2_array[i][j] = rand() / (double)(RAND_MAX) * 2 - 1;
	for (int i = 0; i < HIDDEN_LAYER; i++)
		threshold1_array[i] = rand() / (double)(RAND_MAX) * 2 - 1;
	for (int i = 0; i < OUTPUT_LAYER; i++)
		threshold2_array[i] = rand() / (double)(RAND_MAX) * 2 - 1;
}
//sigmoid激活函数
double BP::Sigmoid(double x)
{
	return 1.0 / (1.0 + exp(-x));
}
//得到隐含层输出
void BP::GetOutput1()
{
	for (int j = 0; j < HIDDEN_LAYER; j++)
	{
		double total = threshold1_array[j];
		for (int i = 0; i < INPUT_LAYER; i++)
			total += input_array[i] * weight1_array[i][j];
		output1_array[j] = Sigmoid(total);
	}
}
//得到输出层输出
void BP::GetOutput2()
{
	for (int j = 0; j < OUTPUT_LAYER; j++)
	{
		double total = threshold2_array[j];
		for (int i = 0; i < HIDDEN_LAYER; i++)
			total += output1_array[i] * weight2_array[i][j];
		output2_array[j] = Sigmoid(total);
	}
}
//得到隐含层误差
void BP::GetDeviation1()
{
	for (int i = 0; i < HIDDEN_LAYER; i++)
	{
		double total = 0;
		for (int j = 0; j < OUTPUT_LAYER; j++)
			total += weight2_array[i][j] * deviation2_array[j];
		deviation1_array[i] = (output1_array[i]) * (1.0 - output1_array[i]) * total;
	}
}
//得到输出层误差
void BP::GetDeviation2()
{
	for (int i = 0; i < OUTPUT_LAYER; i++)
		deviation2_array[i] = (output2_array[i]) * (1.0 - output2_array[i]) * (output2_array[i] - aim_array[i]);
}
//反馈输入层与隐含层之间的权重
void BP::Feedback1()
{
	for (int j = 0; j < HIDDEN_LAYER; j++)
	{
		threshold1_array[j] -= LEARN_RATE * deviation1_array[j];
		for (int i = 0; i < INPUT_LAYER; i++)
			weight1_array[i][j] = weight1_array[i][j] - LEARN_RATE * input_array[i] * deviation1_array[j];
	}
}
//反馈隐含层与输出层之间的权重
void BP::Feedback2()
{
	for (int j = 0; j < OUTPUT_LAYER; j++)
	{
		threshold2_array[j] = threshold2_array[j] - LEARN_RATE * deviation2_array[j];
		for (int i = 0; i < HIDDEN_LAYER; i++)
			weight2_array[i][j] = weight2_array[i][j] - LEARN_RATE * output1_array[i] * deviation2_array[j];
	}
}
//训练
void BP::Train()
{
	FILE *train_images;
	FILE *train_labels;
	errno_t err1, err2;

	err1 = fopen_s(&train_images, "train-images.idx3-ubyte", "rb");
	if (err1 != 0) {
		perror("Failed to open train-images.idx3-ubyte");
		return; // 或者采取其他错误处理措施
	}

	err2 = fopen_s(&train_labels, "train-labels.idx1-ubyte", "rb");
	if (err2 != 0) {
		perror("Failed to open train-labels.idx1-ubyte");
		fclose(train_images); // 关闭图像文件
		return; // 或者采取其他错误处理措施
	}

	unsigned char image[INPUT_LAYER];
	unsigned char label[OUTPUT_LAYER];
	unsigned char temp[100];
	//读取文件开头
	fread(temp, 1, 16, train_images);
	fread(temp, 1, 8, train_labels);
	int times = 0; //当前训练了几次
	cout << "开始训练..." << endl << endl;

	

	while (!feof(train_images) && !feof(train_labels))
	{
		fread(image, 1, INPUT_LAYER, train_images);
		fread(label, 1, 1, train_labels);
		//设置输入向量
		for (int i = 0; i < INPUT_LAYER; i++)
		{
			if ((unsigned int)image[i] < 64)
				input_array[i] = 0;
			else
				input_array[i] = 1;
		}
		//设置目标值
		int index = (unsigned int)label[0];
		memset(aim_array, 0, sizeof(aim_array));
		aim_array[index] = 1;
		GetOutput1(); //得到隐含层输出
		GetOutput2(); //得到输出层输出
		GetDeviation2(); //得到输出层误差
		GetDeviation1(); //得到隐含层误差
		Feedback1(); //反馈输入层与隐含层之间的权重
		Feedback2(); //反馈隐含层与输出层之间的权重
		++times;
		if (times % 2000 == 0)
			cout << "已训练 " << times << "组" << endl;
		if (times % 10000 == 0) //每10000组就测试一下
			Test();
	}

	
	// 关闭文件
	fclose(train_images);
	fclose(train_labels);
}
//测试
void BP::Test()
{
	FILE *test_images;
	FILE *test_labels;
	errno_t err1, err2;

	err1 = fopen_s(&test_images, "t10k-images.idx3-ubyte", "rb");
	if (err1 != 0) {
		perror("Failed to open t10k-images.idx3-ubyte");
		return; // 或者采取其他错误处理措施
	}

	err2 = fopen_s(&test_labels, "t10k-labels.idx1-ubyte", "rb");
	if (err2 != 0) {
		perror("Failed to open t10k-labels.idx1-ubyte");
		fclose(test_images); // 关闭图像文件
		return; // 或者采取其他错误处理措施
	}

	unsigned char image[784];
	unsigned char label[10];
	unsigned char temp[100];
	//读取文件开头
	fread(temp, 1, 16, test_images);
	fread(temp, 1, 8, test_labels);
	int total_times = 0; //当前测试了几次
	int success_times = 0; //当前正确了几次
	cout << "开始测试..." << endl;
	

	while (!feof(test_images) && !feof(test_labels))
	{
		fread(image, 1, INPUT_LAYER, test_images);
		fread(label, 1, 1, test_labels);
		//设置输入向量
		for (int i = 0; i < INPUT_LAYER; i++)
		{
			if ((unsigned int)image[i] < 64)
				input_array[i] = 0;
			else
				input_array[i] = 1;
		}
		//设置目标值
		memset(aim_array, 0, sizeof(aim_array));
		int index = (unsigned int)label[0];
		aim_array[index] = 1;
		GetOutput1(); //得到隐含层输出
		GetOutput2(); //得到输出层输出
		//以输出结果中最大的那个值所对应的数字作为预测的数字
		double maxn = -99999999;
		int max_index = 0;
		for (int i = 0; i < OUTPUT_LAYER; i++)
		{
			if (output2_array[i] > maxn)
			{
				maxn = output2_array[i];
				max_index = i;
			}
		}
		//如果预测正确
		if (aim_array[max_index] == 1)
			++success_times;
		++total_times;
		if (total_times % 2000 == 0)
			cout << "已测试:" << total_times << "组" << endl;
	}
	


	cout << "正确率: " << 100.0 * success_times / total_times << "%" << endl << endl;
	cout << "*************************" << endl << endl;

	// 关闭文件
	fclose(test_images);
	fclose(test_labels);
}
int main(int argc, char * argv[])
{
	// 计时器开始
	auto start_time = std::chrono::high_resolution_clock::now();
	BP bp;
	bp.Init();
	//训练数据反复利用TRAIN_TIMES次
	for (int i = 0; i < TRAIN_TIMES; i++)
	{
		cout << "开始第" << i + 1 << "轮迭代" << endl << endl;
		bp.Train();
	}
	// 计时器结束
	auto end_time = std::chrono::high_resolution_clock::now();
	auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
	std::cout << "总时间: " << duration.count() << " milliseconds" << std::endl;
	return 0;
}

运行截图
在这里插入图片描述

测量迭代10轮所用的时间:在main()函数中添加计时器:std::chrono::high_resolution_clock

学习率0.10.20.3
准确率94.48%95.02%95.15%
时间717.224s869.209s725.855s

正确率的增长逐渐变得缓慢,程序的运行时间也要相应的加长

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1043422.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Sringcloud:一、微服务介绍+常用技术框架和技术对比+服务拆分demo

微服务介绍 单体架构 简介 将业务所有功能集中在一个项目中开发&#xff0c;打成一个包部署优点 架构简单部署成本低 缺点 耦合度高&#xff0c;不利于后续更新迭代 分布式架构 简介 每个业务模块作为一个独立项目开发&#xff0c;称为一个服务&#xff0c;但通常仍共用一…

Spark集成ClickHouse(笔记)

目录 前言&#xff1a; 一.配置环境 1.安装clickhouse驱动 2.配置clickhouse环境 二.spark 集成clickhouse 直接上代码&#xff0c;里面有一些注释哦&#xff01; 前言&#xff1a; 在大数据处理和分析领域&#xff0c;Spark 是一个非常强大且广泛使用的开源分布式计算框架…

从想象力到生产力,VR全景技术让亚运会走进你的身边

杭州亚运会开幕&#xff0c;各方面氛围感直接拉满&#xff0c;既是一场体育盛会&#xff0c;也是一场科技盛宴&#xff0c;VR技术也融入了亚运会的方方面面。在5G技术的加持下&#xff0c;VR全景技术可以将亚运会各项赛事提升到一个很高的水平&#xff0c;观众即使不在现场&…

【医疗图像处理软件】重要功能集合

很高兴在雪易的CSDN遇见你 &#xff0c;给你糖糖 欢迎大家加入雪易社区-CSDN社区云 一起挑战150岁生命线&#xff01; 前言之前&#xff1a;从事医疗器械行业使我们更加关注自己的健康&#xff0c;每天看着髋膝关节置换的手术视频&#xff0c;我们会更加爱护自己的膝盖。同…

给你两个集合,要求{A} + {B}

先看题&#xff1a; 看完题后你会觉得&#xff1a;哇&#xff0c;好简单&#xff0c;STL一下就出来啦。 #include <iostream> #include <set>using namespace std;int main() {int n, m;while (cin >> n >> m) {set<int> set_a;for (int i 0;…

第二证券:造谣?判了!有人少花四五万!美元突破近10个月高位

当地时间9月25日&#xff08;周一&#xff09;&#xff0c;美国三大股指停步四连跌。纳斯达克我国金龙指数跌1.1%&#xff0c;抱负轿车跌近10%。蔚来跌幅明显收窄&#xff0c;盘终跌超2%。美元指数一度升破106关口&#xff0c;刷新上一年11月底以来的10个月最高&#xff0c;此前…

Qt扫盲-QSqlQueryModel理论总结

QSqlQueryModel理论总结 一、概述二、使用1. 与 view 视图 绑定2. 分离视图&#xff0c;只存数据 一、概述 QSqlQueryModel是用于执行SQL语句和遍历结果集的高级接口。它构建在较低级的 QSqlQuery之上&#xff0c;可用于向QTableView 等视图类提供数据&#xff0c;也是使用了Q…

中国大模型的路,是不是走歪了?

大数据产业创新服务媒体 ——聚焦数据 改变商业 在这波全球大模型的浪潮中&#xff0c;中国与美国无疑成为了领军者。但中美在大模型的发展策略上却出现了显著的分歧。美国&#xff0c;以OpenAI为代表&#xff0c;持续致力于通用型大模型的研发。与此相反&#xff0c;中国则将…

著名数字音频工作站FL Studio 21.0.3.3517中文破解安装图文激活教程

在一个技术继续塑造我们日常生活的世界里&#xff0c;创造力找到了表达自己的新渠道。FL Studio 21成为一个强大的工具&#xff0c;使个人能够创作自己的音乐杰作。一个人需要广泛的乐器知识或一个成熟的工作室来创作交响乐的日子已经一去不复返了。有了FL Studio 21&#xff0…

MySQL作业:索引、视图、存储、函数

学生表&#xff1a;Student (Sno, Sname, Sex , Sage, Sdept) 学号&#xff0c;姓名&#xff0c;性别&#xff0c;年龄&#xff0c;所在系 Sno为主键 课程表&#xff1a;Course (Cno, Cname,) 课程号&#xff0c;课程名 Cno为主键 学生选课表&#xff1a;SC (Sno, Cno, Score) …

【响应式布局】

响应式布局 1 什么是响应式布局2 响应式布局的5种实现方案2.1 百分比布局2.2 媒体查询布局2.3 rem响应式布局2.4 vw / vh响应式布局2.5 flex弹性布局 1 什么是响应式布局 响应式布局就是一个网站能够兼容多个终端——而不是为每个终端做一个特定的版本。这个概念是为解决移动互…

地球的某一片红薯地中秋圆《乡村振兴战略下传统村落文化旅游设计》——旅行季许少辉八月新书辉少许想象和世界一样宽广

地球的某一片红薯地中秋圆《乡村振兴战略下传统村落文化旅游设计》——旅行季许少辉八月新书辉少许想象和世界一样宽广 地球的某一片红薯地中秋圆《乡村振兴战略下传统村落文化旅游设计》——旅行季许少辉八月新书辉少许想象和世界一样宽广]

定义现代化实时数据仓库,SelectDB 全新产品形态全面发布

导读&#xff1a;9 月 25 日&#xff0c;2023 飞轮科技产品发布会在线上正式召开&#xff0c;本次产品发布会以 “新内核、新图景” 为主题&#xff0c;飞轮科技 CEO 马如悦全面解析了现代化数据仓库的演进趋势&#xff0c;宣布立足于多云之上的 SelectDB Cloud 云服务全面开放…

C++学习资源

https://www.cnblogs.com/xueweihan/p/13928719.html GitHub - Light-City/CPlusPlusThings: C那些事 GitHub - 0voice/introduce_c-cpp_manual: 一个收集C/C新手学习的入门项目&#xff0c;整理收纳开发者开源的小项目、工具、框架、游戏等&#xff0c;视频&#xff0c;书籍&a…

[密码学入门]仿射密码(Affine)

加密算法y(axb)mod N 解密算法x*(y-b)mod N(此处的为a关于N的乘法逆元&#xff0c;不是幂的概念&#xff09; 如何求&#xff0c;涉及的知识挺多&#xff0c;还没想好怎么写&#xff0c;丢番图方程&#xff0c;贝祖定理&#xff08;又译裴蜀定理&#xff09;&#xff0c;扩展欧…

学物联网有前途吗?

学物联网有前途吗&#xff1f; 物联网即“万物相连的互联网”&#xff0c;是互联网基础上的延伸和扩展的网络&#xff0c;将各种信息传感设备与互联网结合起来而形成的一个巨大网络&#xff0c;实现在任何时间、任何地点&#xff0c;人、机、物的互联互通。最近很多小伙伴找我&…

中国智能产业高峰论坛:文档大模型与文档图像智能理解的进展和思考

✓ 写在前面✓ 文档大模型的思考与探索✓ 文档图像大模型的进展✓ 多模态大模型与文档图像智能理解多模态大模型的应用和发展文档图像智能理解的技术和挑战产业应用和前景展望 ✓ 写在前面 2023 年第十二届中国智能产业高峰论坛&#xff08;CIIS 2023&#xff09;于 9 月 17-1…

LeetCode 474.一和零 动态规划 一维dp(两个维度)

https://leetcode.cn/problems/ones-and-zeroes/description/ 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集的长度&#xff0c;该子集中 最多 有 m 个 0 和 n 个 1 。 如果 x 的所有元素也是 y 的元素&#xff0c;集合 x 是集合 y 的…

在SpringBoot中利用Redis实现互斥锁

在SpringBoot中利用Redis实现互斥锁 基本知识 前提条件&#xff0c;有一个能够在Springboot中使用Redis的项目&#xff0c;或者能够直接开也行 为什么要实现互斥锁&#xff1a;当我们利用Redis存储热点数据时&#xff0c;突然就过期失效或者被删除了&#xff0c;导致大量请求同…