前言 ??本文主要内容是BP神经网络的Python实现(借助tensorflow库)和C++实现(未借助相关库)
Python实现BP神经网络
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'#暂时屏蔽警告,只显示error信息
from plugin import *
#构建数据
x_data = https://www.it610.com/article/np.arange(-1,1,0.01)[: ,np.newaxis]
print("x_data",x_data)
noise = np.random.normal(0,0.05,x_data.shape)
y_data= https://www.it610.com/article/0.5*(np.sin(x_data)+noise)
print("y_data",y_data)#占位符
xs = tf.compat.v1.placeholder(tf.float32,[None,1])
ys =tf.compat.v1.placeholder(tf.float32,[None,1])
h1 = add_layer(xs,1,20,tf.nn.relu)
prediction = add_layer(h1,20,1)
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys-prediction), reduction_indices =[1] ) )
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
init = tf.global_variables_initializer()#初始化所有变量
sess = tf.compat.v1.Session()if __name__ == "__main__":
sess.run(init)
for i in range(10000):
sess.run(train_step,feed_dict = {xs:x_data,ys:y_data})
if i %100 ==0:
print(sess.run(loss,feed_dict = {xs:x_data,ys:y_data}))
C++实现BP神经网络 BP(Back-Propagating)神经网络的特点是向前传送输入数据,向后反馈误差。理论上,一个三层(输入层,隐含层,输出层)的BP神经网络可以实现任意m维到任意n维的映射。
查看相应代码可访问我的github(https://github.com/YuruTu),博客主要发挥介绍性的工作,github上更新最新代码
https://github.com/YuruTu/BPNN/blob/master
头文件pch.h
#ifndef PCH_H
#define PCH_H
#include
#include
#include
#include
#include
#include #endif //PCH_H
【智能算法|BP神经网络(原理及代码实现)】主函数main.cpp
//作者cclplus
//初稿2018/05/01
//如果你认为有必要打赏我,我的支付宝号是707101557@qq.com
#include "pch.h"
using namespace std;
const double pi = atan(1.0) * 4;
//BP神经网络结构
struct BPNN {
int sample_count;
//样本数量
int input_count;
//输入向量的维数
int output_count;
//输出向量的维数
int hidden_count;
//实际使用隐层神经元数量
double study_rate;
//学习速率
double precision;
//精度控制参数
int loop_count;
//循环次数
vector> v;
//隐含层权矩阵
vector> w;
//输出层权矩阵
};
BPNN CREATE_BPNN(int sc, int ic, int oc, int hc, double sr, double p, int lc);
//创建一个BP神经网络
double rand_normal();
//返回一个double类型的随机数
double sigmoid(double net) {
return 1.0 / (1 + exp(-net));
}
double purelin(double net) {
return 1.0 / (1 + exp(-net));
}
BPNN train_bp(vector> x, vector> y, BPNN bp);
//训练
void use_bp(BPNN bp, vector> inoput);
//使用BP神经网络进行前向传导运算
int main() {
//样本数目
int sample_count = 100;
//输入向量维数
int input_count = 1;
//输出向量维数
int output_count = 1;
//实际使用隐层神经元数目
int hidden_count = 4;
//学习速率
double study_rate = 0.02;
//精度控制参数
double precision = 0.001;
//循环次数
int loop_count = 10000;
int i;
double temp, temp1;
//训练样本
vector> x;
vector> y;
vector> input;
x.resize(sample_count);
for (i = 0;
i < sample_count;
i++) {
x[i].resize(input_count);
}
y.resize(sample_count);
for (i = 0;
i < sample_count;
i++) {
y[i].resize(output_count);
}
input.resize(sample_count);
for (i = 0;
i < sample_count;
i++) {
input[i].resize(input_count);
}
//自定义输入与输出
for (i = 0;
i < sample_count;
i++) {
temp = (double)i;
temp1 = (double)sample_count;
x[i][0] = pi / temp1 * temp;
input[i][0] = pi / temp1 * temp;
y[i][0] = 1.0*sin(x[i][0]);
}
BPNN bp;
bp = CREATE_BPNN(sample_count, input_count, output_count, hidden_count, study_rate, precision, loop_count);
bp = train_bp(x, y, bp);
use_bp(bp, input);
return 0;
}
//使用BP神经网络进行前向传导运算
void use_bp(BPNN bp, vector> input) {
//设置临时变量
double temp;
inti, j, k;
vector O1;
O1.resize(bp.hidden_count);
vector> output;
output.resize(100);
for (i = 0;
i < 100;
i++) {
output[i].resize(bp.output_count);
}
for (i = 0;
i < 100;
i++) {
for (j = 0;
j < bp.hidden_count;
j++) {
temp = 0;
for (k = 0;
k < bp.input_count;
k++) {
temp = temp + input[i][k] * bp.v[k][j];
}
O1[j] = sigmoid(temp);
}
for (j = 0;
j < bp.output_count;
j++) {
temp = 0;
for (k = 0;
k < bp.hidden_count;
k++) {
temp = temp + O1[k] * bp.w[k][j];
}
output[i][j] = sigmoid(temp);
}
} for (i = 0;
i < 100;
i++) {
for (j = 0;
j < bp.output_count;
j++) {
printf("%f", output[i][j]);
}
}
printf("\n结束\n");
}//训练一个BP神经网络
BPNN train_bp(vector> x, vector> y, BPNN bp) {
double f, a;
int hc, sc, lc, ic, oc;
f = bp.precision;
//精度控制参数
a = bp.study_rate;
//学习速率
hc = bp.hidden_count;
//隐含层数
sc = bp.sample_count;
//训练样本总数
lc = bp.loop_count;
//循环次数
ic = bp.input_count;
//输入维度
oc = bp.output_count;
//输出维度
//修改量矩阵
vector chg_h;
//隐层
chg_h.resize(hc);
vector chg_o;
//输出层
chg_o.resize(oc);
vector O1;
O1.resize(hc);
vector O2;
O2.resize(oc);
//临时变量
double temp;
int i, j, m, n;
double mse;
//均方误差
double e;
//误差
e = f + 1;
//保证循环顺利执行
for (n = 0;
(e > f) && (n < lc);
n++) {//n代表循环次数
e = 0;
mse = 0;
//全部样本均加入神经网络的训练
for (i = 0;
i < sc;
i++) {
//计算隐层输出向量
for (m = 0;
m < hc;
m++) {
temp = 0;
for (j = 0;
j < ic;
j++) {
temp = temp + x[i][j] * bp.v[j][m];
}
O1[m] = sigmoid(temp);
}
//计算输出值
for (m = 0;
m < oc;
m++) {
temp = 0;
for (j = 0;
j < hc;
j++) {
temp = temp + O1[j] * bp.w[j][m];
}
O2[m] = purelin(temp);
}
//计算输出层的权重修改
for (j = 0;
j < oc;
j++) {
chg_o[j] = O2[j] * (1 - O2[j])*(y[i][j] - O2[j]);
}
//计算隐层的权重修改
for (j = 0;
j < hc;
j++) {
temp = 0;
for (m = 0;
m < oc;
m++) {
temp = temp + bp.w[j][m] * chg_o[m];
}
chg_h[j] = temp * O1[j] * (1 - O1[j]);
}
//计算误差和均方根误差
for (j = 0;
j < oc;
j++) {
e = e + (y[i][j] - O2[j])*(y[i][j] - O2[j]);
mse = mse + y[i][j] * y[i][j];
}
//对权值矩阵做出修改
for (j = 0;
j < hc;
j++) {
for (m = 0;
m < oc;
m++) {
bp.w[j][m] = bp.w[j][m] + a * O1[j] * chg_o[m];
}
}
for (j = 0;
j < ic;
j++) {
for (m = 0;
m < hc;
m++) {
bp.v[j][m] = bp.v[j][m] + a * x[i][j] * chg_h[m];
}
}
}
//每循环一百次输出一次误差
if (n % 100 == 0) {
mse = e / mse;
printf("误差:%f\n", e);
printf("均方根误差:%f\n", mse);
printf("当前循环次数:%d\n", n);
}
}
//循环结束,输出最终信息
printf("循环总次数:%d\n", n);
printf("调整后的隐层权值矩阵:\n");
for (i = 0;
i < ic;
i++) {
for (j = 0;
j < hc;
j++) {
printf("%f", bp.v[i][j]);
}
printf("\n");
}
printf("调整后的输出层权值矩阵:\n");
for (i = 0;
i < hc;
i++) {
for (j = 0;
j < oc;
j++) {
printf("%f", bp.w[i][j]);
}
printf("\n");
}
printf("神经网络训练结束:\n");
printf("最终误差:%f\n", e);
return bp;
}//创建一个BP神经网络
BPNN CREATE_BPNN(int sc, int ic, int oc, int hc, double sr, double p, int lc) {
BPNN bp;
bp.sample_count = sc;
bp.input_count = ic;
bp.output_count = oc;
bp.hidden_count = hc;
bp.study_rate = sr;
bp.precision = p;
bp.loop_count = lc;
int i, j;
bp.v.resize(ic);
//隐含层的权值矩阵,共有input_count行,hidden_count列
for (i = 0;
i < ic;
i++) {
bp.v[i].resize(hc);
}
//数据的初始化
for (i = 0;
i < ic;
i++) {
for (j = 0;
j < hc;
j++) {
bp.v[i][j] = rand_normal();
}
}
bp.w.resize(hc);
//输出层的权值矩阵,共有hidden_count行,output_count列
for (i = 0;
i < hc;
i++) {
bp.w[i].resize(oc);
}
for (i = 0;
i < hc;
i++) {
for (j = 0;
j < oc;
j++) {
bp.w[i][j] = rand_normal();
}
}
return bp;
}//返回一个double类型的随机数,这么做的目的是破坏神经网络结构的对称性
//基本原理,参见独立同分布的中心极限定理
double rand_normal() {
inti;
const int normal_count = 200;
//样本数目采用200个
double ccl_num;
double ccl_s;
double ccl_ar[normal_count];
ccl_num = 0;
for (i = 0;
i < normal_count;
i++) {
ccl_ar[i] = rand() % 1000 / (double)1001;
ccl_num += ccl_ar[i];
}
ccl_num -= (normal_count / 2);
//减去0-1均匀分布的均值
ccl_s = 1.0*normal_count / 12.0;
//0-1分布的方差为1/12
ccl_s = sqrt(ccl_s);
ccl_num /= ccl_s;
//此时ccl_num接近标准正态分布的一个子集
ccl_num /= 100;
//变为正态分布(0,0.01)的一个子集,论文中有给出证明过程
cout << " 随机值" << ccl_num << endl;
return ccl_num;
}
推荐阅读
- 机器学习|机器学习--BP神经网络的C++实现
- 深度学习|【GitHub开源】BP神经网络分类C++实现
- 为什么 Python 3 把 print 改为函数()
- Python 高速增长的三次历史机遇
- 当 Python 中混进一只薛定谔的猫……
- 30 个Python代码实现的常用功能(附案例源码)
- c++|输入输出流知识总结
- 深度辨析 Python 的 eval() 与 exec()
- Python中tuple+=赋值的四个问题