最近学习bp神经网络,但是网上的代码很多都是做分类决策,我们要拟合函数需要对代码进行修改,进行回归预测,修改思路就是将输出层的激活函数改为f(x)=x,并且对反向传播过程中更改隐藏层到输出层的权重公式进行修改。
生成测试数据程序。
贴几个参考的博文:
神经网络实现连续型变量的回归预测(python)
BP神经网络与Python实现
C++实现的BP神经网络(代码与详解)
# 生成测试数据 import numpy as np import pandas as pd import math if __name__ == "__main__": # 训练集和验证集样本总个数 sample = 100 path='C:/Users/Desktop/data/' train_data_path = path+'train.csv' test_data_path = path+'test.csv' # 构造生成数据的模型,全部置0,获取空列表 X1 = np.zeros((sample, 1)) X2 = np.zeros((sample, 1)) X3 = np.zeros((sample, 1)) #生成随机的sigama1 sigama2 sigama3 全部置0,获取空列表 Z1=np.zeros((sample, 1)) Z2=np.zeros((sample, 1)) Z3=np.zeros((sample, 1)) #生成随机数 Z1[:, 0] = np.random.normal(-4,2, sample) #正态分布随机数 Z2[:, 0] = np.random.normal(-2,0, sample) #正态分布随机数 Z3[:, 0] = np.random.uniform(0,2,sample) #均匀分布随机数 #生成固定的随机数,测试固定sigama值与随机的区别 c1=np.random.normal(-4,2) c2=np.random.normal(-2,0) c3=np.random.uniform(0,2) i=0 #生成符合x1^2+x2^2+x3^2<=10的数据 while(ipytorch
import torch import torch.nn as nn import pandas as pd class Net(nn.Module): def __init__(self,n_input,n_hidden,n_output): super(Net,self).__init__() self.hidden1 = nn.Linear(n_input,n_hidden) #此为输入层到隐藏层 输入为3 输出为6 self.predict = nn.Linear(n_hidden,n_output) #此为隐藏层到输出层 输入为6 输出为1 def forward(self,input): out = self.hidden1(input) #隐藏层加权 out = torch.sigmoid(out) #relu(out) #激活函数对加权后的数据进行 *** 作 out =self.predict(out) #输出结果 return out if __name__ == "__main__": #读取数据 path = 'C:/Users/Desktop/data/' train_data_path = path + 'train.csv' validate_data_path = path + 'test.csv' dt=pd.read_csv(train_data_path) dt.head() dataset=dt.values X=dataset[:,:3].astype(float) Y=dataset[:, -1].astype(float) #将数据转换为tensor x, y = (torch.tensor(X), torch.tensor(Y)) x = x.to(torch.float32) y=y.to(torch.float32) #定义一个输入神经元为3 隐藏层神经元为6 输出神经元为1的bp神经网络 net = Net(3, 10, 1) print(net) optimizer = torch.optim.SGD(net.parameters(), lr=0.1) #定义损失函数 MSELoss的函数为均方误差函数 (1/n)*(y1-y2)^2 loss_func = torch.nn.MSELoss() for t in range(500): prediction = net(x) print(prediction[0]) loss = loss_func(prediction, y) optimizer.zero_grad() loss.backward() optimizer.step() print('Train Epoch:{}tLoss:{:.6f}'.format(t+1,loss.item()))python代码
from __future__ import division import math import random import pandas as pd import numpy as np random.seed(0) # 生成区间[a, b)内的随机数 def rand(a, b): return (b - a) * random.random() + a # 生成大小 I*J 的矩阵,默认零矩阵 def makeMatrix(I, J, fill=0.0): m = [] for i in range(I): m.append([fill] * J) return m # 函数 sigmoid def sigmoid(x): return 1.0 / (1.0 + math.exp(-x)) # 函数 sigmoid 的导数 def dsigmoid(x): return x * (1 - x) class NN: """ BP神经网络 """ def __init__(self, ni, nh, no): # 输入层、隐藏层、输出层的节点(数) self.ni = ni + 1 # 增加一个偏差节点 self.nh = nh + 1 self.no = no # 激活神经网络的所有节点(向量) self.ai = [1.0] * self.ni self.ah = [1.0] * self.nh self.ao = [1.0] * self.no # 建立权重(矩阵) self.wi = makeMatrix(self.ni, self.nh) self.wo = makeMatrix(self.nh, self.no) # 设为随机值 for i in range(self.ni): for j in range(self.nh): self.wi[i][j] = rand(-0.2, 0.2) for j in range(self.nh): for k in range(self.no): self.wo[j][k] = rand(-2, 2) '''前向传播''' def update(self, inputs): if len(inputs) != self.ni - 1: raise ValueError('与输入层节点数不符!') # 激活输入层 for i in range(self.ni - 1): self.ai[i] = inputs[i] # 激活隐藏层 for j in range(self.nh - 1): sum = 0.0 for i in range(self.ni): sum = sum + self.ai[i] * self.wi[i][j] self.ah[j] = sigmoid(sum) # 激活输出层 for k in range(self.no): sum = 0.0 for j in range(self.nh): sum = sum + self.ah[j] * self.wo[j][k] self.ao[k] = sigmoid(sum) return self.ao """ 反向传播 """ def backPropagate(self, targets, lr): # 计算输出层的误差 output_deltas = [0.0] * self.no for k in range(self.no): error = targets[k] - self.ao[k] output_deltas[k] = dsigmoid(self.ao[k]) * error # 计算隐藏层的误差 hidden_deltas = [0.0] * self.nh for j in range(self.nh): error = 0.0 for k in range(self.no): error = error + output_deltas[k] * self.wo[j][k] hidden_deltas[j] = dsigmoid(self.ah[j]) * error # 更新输出层权重 for j in range(self.nh): for k in range(self.no): change = output_deltas[k] * self.ah[j] self.wo[j][k] = self.wo[j][k] + lr * change # 更新输入层权重 for i in range(self.ni): for j in range(self.nh): change = hidden_deltas[j] * self.ai[i] self.wi[i][j] = self.wi[i][j] + lr * change # 计算误差 error = 0.0 for k in range(self.no): error += 0.5 * (targets[k] - self.ao[k]) ** 2 return error def test(self, patterns): count = 0 x = patterns[:,0:3] y = patterns[:,3:4] for p in range(len(patterns)): targets = y[p] result = self.update(x[p]) print(x[p], ':', targets, '->', result) count += (targets == result) accuracy = float(count / len(patterns)) print('accuracy: %-.9f' % accuracy) def weights(self): print('输入层权重:') for i in range(self.ni): print(self.wi[i]) print() print('输出层权重:') for j in range(self.nh): print(self.wo[j]) def train(self, patterns, iterations=1000, lr=0.1): # lr: 学习速率(learning rate) count = 0 x = patterns[:,0:3] y = patterns[:,3:4] for i in range(iterations): error = 0.0 for p in range(len(patterns)): inputs = x[p] targets = y[p] self.update(inputs) error = error + self.backPropagate(targets, lr) if i % 100 == 0: print('error: %-.9f' % error) def iris(): df = pd.read_csv('train.csv', encoding='utf-8') ''' # 读取数据 raw = pd.read_csv('train.csv') raw_data = raw.values raw_feature = raw_data[0:, 0:3] for i in range(len(raw_feature)): ele = [] ele.append(list(raw_feature[i])) if raw_data[i][3] == 'Iris-setosa': ele.append([1, 0, 0]) elif raw_data[i][4] == 'Iris-versicolor': ele.append([0, 1, 0]) else: ele.append([0, 0, 1]) data.append(ele) ''' # 读取数据 raw = df[['x1', 'x2', 'x3','y']] data = np.array(raw) # 随机排列数据 # random.shuffle(data) training = data[0:100] test = data[101:150] nn = NN(3, 5, 1) nn.train(training, iterations=10000) nn.weights() nn.test(test) if __name__ == '__main__': iris()C++代码
#include#include #include #include #include #include #include #include #include #include //设置精度 #include using namespace std; #define INNODE 3 // 输入结点数 #define HIDENODE 6 // 隐含结点数 #define OUTNODE 1 // 输出结点数 #define LEARNINGRATE 0.9// 学习速率(注意:越高虽然越快 也容易误差较大) #define SAMPLE 100 typedef struct inputNode { double value; // 输入值 std::vector weight // 输入层单个节点对下一层每个节点的权值 , wDeltaSum; // 单个加权的不同样本和 }InputNode; typedef struct outputNode { double o_value // 节点最终值 经过偏移与激活函数后的值 , rightout // 正确输出值 , bias // 偏移量 每个节点只有一个 , bDeltaSum; // 反向传播时 经过计算后的偏移量需要改变的值 因为有多个样本所以是sum }OutputNode; typedef struct hiddenNode { double o_value // 节点最终值 经过偏移与激活函数后的值 , bias // 偏移量 每个节点只有一个 , bDeltaSum; // 反向传播时 经过计算后的偏移量需要改变的值 因为有多个样本所以是sum std::vector weight // 隐藏层单个节点对下一层每个节点的加权值 , wDeltaSum; // 单个加权的不同样本和 }HiddenNode; typedef struct sample { std::vector in // 输入层value的迭代器 里面的数据有输入层节点数个(输入层每个节点的value值 代表一份样本数据中 一个输入属性的值) , out; // 输出层rightout的迭代器 里面的数据也有输出层层节点数个(输出层每个节点的rightout值 代表一份样本数据 应该输出属性的正确值) }Sample; class Util { public: // 获得txt文件中准备的数据 std::vector getFileData(char* fileName); }; vector Util::getFileData(char* fileName) { vector res; ifstream input(fileName); if (!input) { return res; } string buff; while (getline(input, buff)) { char* datas = (char*)buff.c_str(); const char* spilt = " "; // strtok字符串拆分函数 char* data = strtok(datas, spilt); while (data != NULL) { // atof是stdlib头文件下转化字符串为数字的函数 res.push_back(atof(data)); // NULL代表从上次没拆分完地方继续拆 data = strtok(NULL, spilt); } } input.close(); return res; } class BpNet { public: BpNet(); // 构造函数 用来初始化加权和偏移 void fp(); // 单个样本前向传播 void bp(); // 单个样本后向传播 void doTraining(std::vector sampleGroup, double threshold, int mostTimes); // 训练(更新 weight, bias) void afterTrainTest(std::vector & testGroup); // 神经网络学习后进行预测 void setInValue(std::vector inValue); // 设置学习样本输入 void setOutRightValue(std::vector outRightValue); // 设置学习样本输出 public://设置成public就不用get、set麻烦 double error; //误差率 InputNode* inputLayer[INNODE]; // 输入层(任何模型都只有一层) OutputNode* outputLayer[OUTNODE]; // 输出层(任何模型都只有一层) HiddenNode* hiddenLayer[HIDENODE]; // 隐含层(我们这个只有一个隐藏层所以一维数组 但如果有多层是二维数组) }; inline double getRandom() { return ((2.0*(double)rand() / RAND_MAX) - 1); } inline double sigmoid(double x) { // 一般bp用作分类的话都用该函数 double ans = 1.0 / (1.0 + exp(-x)); return ans; } BpNet::BpNet() { srand((unsigned)time(NULL)); // error初始值,只要能保证大于阀值进入训练就可以 error = 100.f; for (int i = 0; i < INNODE; i++) { inputLayer[i] = new InputNode(); for (int j = 0; j < HIDENODE; j++) { inputLayer[i]->weight.push_back(getRandom()); inputLayer[i]->wDeltaSum.push_back(0.f); } } for (int i = 0; i < HIDENODE; i++) { hiddenLayer[i] = new HiddenNode(); hiddenLayer[i]->bias = getRandom(); // 初始化加权 for (int j = 0; j < OUTNODE; j++) { hiddenLayer[i]->weight.push_back(getRandom()); hiddenLayer[i]->wDeltaSum.push_back(0.f); } } for (int i = 0; i < OUTNODE; i++) { outputLayer[i] = new OutputNode(); outputLayer[i]->bias = getRandom(); } } void BpNet::fp() { // 遍历隐藏层节点 for (int i = 0; i < HIDENODE; i++) { double sum = 0.f; // 遍历输入层每个节点 for (int j = 0; j < INNODE; j++) { sum += inputLayer[j]->value * inputLayer[j]->weight[i]; } // 增加偏移 sum += hiddenLayer[i]->bias; // 调用激活函数 设置o_value hiddenLayer[i]->o_value = sigmoid(sum); } // 遍历输出层节点 for (int i = 0; i < OUTNODE; i++) { double sum = 0.f; // 遍历隐藏层节点 for (int j = 0; j < HIDENODE; j++) { sum += hiddenLayer[j]->o_value * hiddenLayer[j]->weight[i]; } sum += outputLayer[i]->bias; outputLayer[i]->o_value = sum; //第一个修改点 } } void BpNet::bp() { for (int i = 0; i < OUTNODE; i++) { double tmpe = fabs(outputLayer[i]->o_value - outputLayer[i]->rightout); // 计算误差 参照上面第一个公式 error += tmpe * tmpe / 2; } int i = 0; for (i = 0; i < OUTNODE; i++) { // 偏移应该变化的值 参照b2公式 double bDelta = (-1) * (outputLayer[i]->rightout - outputLayer[i]->o_value) ; outputLayer[i]->bDeltaSum += bDelta; //cout << "正确值:" << outputLayer[i]->rightout << "预测值:" << outputLayer[i]->o_value< rightout - outputLayer[j]->o_value) * hiddenLayer[i]->o_value; hiddenLayer[i]->wDeltaSum[j] += wDelta; } } for (int i = 0; i < HIDENODE; i++) { double sum = 0; // 因为是遍历输出层节点 不可以确定有多少个输出节点 参照b1公式的第一个公因式 for (int j = 0; j < OUTNODE; j++) { sum += (-1) * (outputLayer[j]->rightout - outputLayer[j]->o_value) * hiddenLayer[i]->weight[j]; } // 参照公式b1 hiddenLayer[i]->bDeltaSum += (sum * hiddenLayer[i]->o_value * (1 - hiddenLayer[i]->o_value)); } for (int i = 0; i < INNODE; i++) { // 从公式b1和w1可以看出 两个公式是有公因式 所以这部分代码相同 double sum = 0; for (int j = 0; j < HIDENODE; j++) { for (int k = 0; k < OUTNODE; k++) { sum += (-1) * (outputLayer[k]->rightout - outputLayer[k]->o_value) * hiddenLayer[j]->weight[k]; } // 参照公式w1 inputLayer[i]->wDeltaSum[j] += (sum * hiddenLayer[j]->o_value * (1 - hiddenLayer[j]->o_value) * inputLayer[i]->value); } } } void BpNet::doTraining(vector sampleGroup, double threshold, int mostTimes) { int sampleNum = sampleGroup.size(); int trainTimes = 0; bool isSuccess = true; while (error >= threshold) { // 判断是否超过最大训练次数 if (trainTimes > mostTimes) { isSuccess = false; break; } cout << "训练次数:" << trainTimes++ << "tt" << "当前误差: " << error << endl; error = 0.f; // 初始化输入层加权的delta和 for (int i = 0; i < INNODE; i++) { inputLayer[i]->wDeltaSum.assign(inputLayer[i]->wDeltaSum.size(), 0.f); } // 初始化隐藏层加权和偏移的delta和 for (int i = 0; i < HIDENODE; i++) { hiddenLayer[i]->wDeltaSum.assign(hiddenLayer[i]->wDeltaSum.size(), 0.f); hiddenLayer[i]->bDeltaSum = 0.f; } // 初始化输出层的偏移和 for (int i = 0; i < OUTNODE; i++) { outputLayer[i]->bDeltaSum = 0.f; } // 完成所有样本的调用与反馈 for (int iter = 0; iter < sampleNum; iter++) { setInValue(sampleGroup[iter].in); setOutRightValue(sampleGroup[iter].out); fp(); bp(); } cout << "正确值:" << outputLayer[0]->rightout << "预测值:" << outputLayer[0]->o_value << endl; // 修改输入层的加权 for (int i = 0; i < INNODE; i++) { for (int j = 0; j < HIDENODE; j++) { //每一个加权的和都是所有样本累积的 所以要除以样本数 inputLayer[i]->weight[j] -= LEARNINGRATE * inputLayer[i]->wDeltaSum[j] / sampleNum; } } // 修改隐藏层的加权和偏移 for (int i = 0; i < HIDENODE; i++) { // 修改每个节点的偏移 因为一个节点就一个偏移 所以不用在节点里再遍历 hiddenLayer[i]->bias -= LEARNINGRATE * hiddenLayer[i]->bDeltaSum / sampleNum; // 修改每个节点的各个加权的值 for (int j = 0; j < OUTNODE; j++) { hiddenLayer[i]->weight[j] -= LEARNINGRATE * hiddenLayer[i]->wDeltaSum[j] / sampleNum; } } //修改输出层的偏移 for (int i = 0; i < OUTNODE; i++) { outputLayer[i]->bias -= LEARNINGRATE * outputLayer[i]->bDeltaSum / sampleNum; } } if (isSuccess) { cout << endl << "训练成功!!!" << "tt" << "最终误差: " << error << endl << endl; } else { cout << endl << "训练失败! 超过最大次数!" << "tt" << "最终误差: " << error << endl << endl; } } void BpNet::afterTrainTest(vector & testGroup) { int testNum = testGroup.size(); for (int iter = 0; iter < testNum; iter++) { // 把样本输出清空 testGroup[iter].out.clear(); setInValue(testGroup[iter].in); // 从隐藏层从输入层获取数据 for (int i = 0; i < HIDENODE; i++) { double sum = 0.f; for (int j = 0; j < INNODE; j++) { sum += inputLayer[j]->value * inputLayer[j]->weight[i]; } sum += hiddenLayer[i]->bias; hiddenLayer[i]->o_value = sigmoid(sum); } // 输出层从隐藏层获取数据 for (int i = 0; i < OUTNODE; i++) { double sum = 0.f; for (int j = 0; j < HIDENODE; j++) { sum += hiddenLayer[j]->o_value * hiddenLayer[j]->weight[i]; } sum += outputLayer[i]->bias; outputLayer[i]->o_value = sigmoid(sum); // 设置输出的值 testGroup[iter].out.push_back(outputLayer[i]->o_value); } } } void BpNet::setInValue(vector sampleIn) { // 对应一次样本 输入层每个节点的输入值 for (int i = 0; i < INNODE; i++) { inputLayer[i]->value = sampleIn[i]; } } void BpNet::setOutRightValue(vector sampleOut) { // 对应一次样本 输出层层每个节点的正确值 for (int i = 0; i < OUTNODE; i++) { outputLayer[i]->rightout = sampleOut[i]; } } void getInput(double& threshold, int& mostTimes); // 获得输入的阀值和误差大小 vector getTrianData(); // 从文件获取训练数据 没获取到直接退出 vector getTestData(); // 从文件获取测试数据 没获取到直接退出 void showTest(vector testGroup); // 输出测试数据的结果 void getInput(double& threshold, int& mostTimes) { cout << "训练及测试数据已从文件读入" << endl << endl; cout << "请输入XOR训练最大误差:"; //0.0001最好 cin >> threshold; cout << "请输入XOR训练最大次数:"; cin >> mostTimes; } void showTest(vector testGroup) { // 输出测试结果 cout << "系统测试数据:" << endl; for (int i = 0; i < testGroup.size(); i++) { for (int j = 0; j < testGroup[i].in.size(); j++) { cout << testGroup[i].in[j] << "t"; } cout << "-- XOR训练结果 :"; for (int j = 0; j < testGroup[i].out.size(); j++) { cout << testGroup[i].out[j] << "t"; } cout << endl; } cout << endl << endl; system("pause"); } vector getTestData() { Util util; vector testData = util.getFileData("test.txt"); if (testData.size() == 0) { cout << "载入测试数据失败!" << endl; exit(0); } const int groups = testData.size() / 2; // 创建测试数据 Sample testInOut[101]; for (int i = 0, index = 0; i < groups; i++) { for (int j = 0; j < 2; j++) { testInOut[i].in.push_back(testData[index++]); } } // 初始化数据 return vector (testInOut, testInOut + groups); } vector getTrianData() { Util util; vector trainData = util.getFileData("data.txt"); if (trainData.size() == 0) { cout << "载入训练数据失败!" << endl; exit(0); } const int groups = SAMPLE; cout << groups< (trainInOut, trainInOut + groups); } int main() { // 准备所有数据 BpNet bpNet; vector sampleGroup = getTrianData(); //vector testGroup = getTestData(); double threshold; // 设定的阀值 即为设定的误差 int mostTimes; // 最大训练次数 // 获取输入 并提示数据已经录入 //getInput(threshold, mostTimes); threshold = 0.05; mostTimes = 100; // 进行训练 bpNet.doTraining(sampleGroup, threshold, mostTimes); // 训练后测试录入的数据 这里的参数是引用 //bpNet.afterTrainTest(testGroup); // 打印提前录入数据的测试结果 //showTest(testGroup); cout << "程序结束" << endl; return 0; } 欢迎分享,转载请注明来源:内存溢出
评论列表(0条)