读到作者用java实现的神经网络解决异或等问题
以下为c++实现版本
接口略有不同
具体关键的更新的证明详见机器学习或大牛博客
有一个关键的地方是 权值的初始化
原本是都初始化0 但是楼主也意识到 这样无论怎样更新 隐层不同神经元对应输入层同一神经元的权值都相同 相当于 仍然用一个线性函数划分 不可线性划分的区域
思考良久就初始化为随机数了 然而不行 后来看了别人的初始化 发现了这个
//关键的初始化权值 for (int i = 0; i < lastlayerneunum; ++i) this->Last_weight[i] = (2.0*(double)rand() / RAND_MAX) - 1;改了一下 瞬间问题都没了 也很神奇 至于原因 楼主开学要回去问学长 有知道的大神也请赐教一下为代码 如有bug 欢迎指正
楼主有些懒 成员函数的实现都在类内部了 有点难看 还请别介意
TransferFunc.h 激励函数类及类型的定义
//TransferFunc.h//created by WK#ifndef TRANSFERFUNC_H#define TRANSFERFUNC_H#include <cmath>enum Functypes{ FUNCTYPE_TANH, FUNCTYPE_STEP, FUNCTYPE_LINEAR, FUNCTYPE_SIGMOID};class Function{PRivate: double Step(double input) { if (input < 0) return 0; else return 1; } double Linear(double input) { return input; } double Sigmoid(double input) { return 1.0 / (1.0 + exp(-1.0*input)); }public: double GetResult(int funcType, double input) { switch (funcType) { case FUNCTYPE_TANH: return tanh(input); case FUNCTYPE_STEP: return Step(input); case FUNCTYPE_LINEAR: return Linear(input); case FUNCTYPE_SIGMOID: return Sigmoid(input); default: return input; } }};#endif // !TRANSFERFUNC_HDataSet.h 数据集类型//DateSet.h//created by WK#ifndef DATASET_H#define DATASET_H#include <vector>using namespace std;//数据集class DataSet{private: int InputNum; int OutputNum; vector<double*> DataMap;public: DataSet(int inputnum, int outputnum) { this->InputNum = inputnum; this->OutputNum = outputnum; } void AddRow(double *inputArray, double *outputArray) { double *data = new double[this->InputNum + this->OutputNum]; for (int i = 0; i<this->InputNum; ++i) { data[i] = inputArray[i]; } for (int i = 0; i<this->OutputNum; ++i) { data[InputNum + i] = outputArray[i]; } this->DataMap.push_back(data); } int GetInputNum() { return this->InputNum; } int GetOutputNum() { return this->OutputNum; } int GetRows() { return DataMap.size(); } vector<double*> GetDataMap() { return DataMap; } };#endif // !DATASET_HMultiLayerPerceptron.cpp神经元定义以及单隐层神经网络定义 以及 异或问题的解决
#include <vector>#include <iostream>#include "TransferFunc.h"#include "DataSet.h"#include <time.h>#include <cstdlib>using namespace std;#define WINITVALUE 0.001#define TINITVALUE 0//神经元class Neuron{private: double Input; double Output; double Threshold; double *Last_weight; //神经元维护后向的权重 int LastLayerNeuNum; int TransferFunctionType; Function Transferfunction;public: Neuron(double threshold, int lastlayerneunum, int funcType) { this->Input = 0; this->Output = 0; this->Threshold = threshold; this->LastLayerNeuNum = lastlayerneunum; this->TransferFunctionType = funcType; this->Last_weight = new double[lastlayerneunum]; //关键的初始化权值 for (int i = 0; i < lastlayerneunum; ++i) this->Last_weight[i] = (2.0*(double)rand() / RAND_MAX) - 1; } void SetInput(double input) { this->Input = input; } double GetOutput() { this->Output = Transferfunction.GetResult(this->TransferFunctionType, this->Input - this->Threshold); return this->Output; } double* GetThreshold() { return &this->Threshold; } double *GetWeight() { return this->Last_weight; } void SetFuncType(int functype) { this->TransferFunctionType = functype; }};//多层感知机class MultiLayerPerceptron{private: int OutTransfetFunctionType; int HideTransfetFunctionType; int InTransfetFunctionType; int InLayerNeuNum; int HideLayerNeuNum; int OutLayerNeuNum; double Speed; Neuron **InputNeurons; Neuron **OutputNeurons; Neuron **HidenNeurons;public: MultiLayerPerceptron(int intransferfunctiontype, int inLayerNeuNum, int hidetransferfunctiontype, int hideLayerNeuNum, int outtransferfunctiontype, int outLayerNeuNum, double speed) { this->InTransfetFunctionType = intransferfunctiontype; this->HideTransfetFunctionType = hidetransferfunctiontype; this->OutTransfetFunctionType = outtransferfunctiontype; this->InLayerNeuNum = inLayerNeuNum; this->HideLayerNeuNum = hideLayerNeuNum; this->OutLayerNeuNum = outLayerNeuNum; this->Speed = speed; this->InputNeurons = (Neuron**)new void*[inLayerNeuNum]; for (int i = 0; i < inLayerNeuNum; ++i) this->InputNeurons[i] = new Neuron(TINITVALUE, 0, intransferfunctiontype); this->HidenNeurons = (Neuron**)new void*[hideLayerNeuNum]; for (int i = 0; i < hideLayerNeuNum; ++i) this->HidenNeurons[i] = new Neuron(TINITVALUE, inLayerNeuNum, hidetransferfunctiontype); this->OutputNeurons = (Neuron**)new void*[outLayerNeuNum]; for (int i = 0; i < outLayerNeuNum; ++i) this->OutputNeurons[i] = new Neuron(TINITVALUE, hideLayerNeuNum, outtransferfunctiontype); } //获取正向的输出 void GetOutput(double *output) { double sum; for (int i = 0; i < this->HideLayerNeuNum; ++i) { sum = 0; for (int j = 0; j < this->InLayerNeuNum; ++j) sum += this->HidenNeurons[i]->GetWeight()[j] * this->InputNeurons[j]->GetOutput(); this->HidenNeurons[i]->SetInput(sum); } for (int i = 0; i < this->OutLayerNeuNum; ++i) { sum = 0; for (int j = 0; j < this->HideLayerNeuNum; ++j) sum += this->OutputNeurons[i]->GetWeight()[j] * this->HidenNeurons[j]->GetOutput(); this->OutputNeurons[i]->SetInput(sum); output[i] = this->OutputNeurons[i]->GetOutput(); } } //学习所有数据一次更新权值以及阈值 void Learn(DataSet *trainingSet) { double *expect; double *data; double *output = new double[this->OutLayerNeuNum]; for (int i = 0; i < trainingSet->GetRows(); ++i) { data = trainingSet->GetDataMap()[i]; expect = data + trainingSet->GetInputNum(); for (int j = 0; j < trainingSet->GetInputNum(); ++j) this->InputNeurons[j]->SetInput(data[j]); this->GetOutput(output); //更改隐藏层到输出层权重以及阈值 //更新公式详见机器学习 for (int j = 0; j < this->OutLayerNeuNum; ++j) { double delta = this->Speed * output[j] * (1 - output[j]) * (expect[j] - output[j]); for (int k = 0; k < this->HideLayerNeuNum; ++k) this->OutputNeurons[j]->GetWeight()[k] += (delta * this->HidenNeurons[k]->GetOutput()); *this->OutputNeurons[j]->GetThreshold() -= delta; } //更改输入层到隐藏层的权重以及阈值 //更新公式详见机器学习 for (int j = 0; j < this->HideLayerNeuNum; ++j) { double t = 0; for (int k = 0; k < this->OutLayerNeuNum; ++k) t += (this->OutputNeurons[k]->GetWeight()[j] * output[k] * (1 - output[k])*(expect[k] - output[k])); double delta = this->HidenNeurons[j]->GetOutput() * (1 - this->HidenNeurons[j]->GetOutput()) * t; for (int k = 0; k < this->InLayerNeuNum; ++k) this->HidenNeurons[j]->GetWeight()[k] += (this->Speed * this->InputNeurons[k]->GetOutput() * delta); *this->HidenNeurons[j]->GetThreshold() -= (this->Speed * delta); } } } void Test(DataSet *trainingSet) { double *output = new double[this->OutLayerNeuNum]; double *expect = new double[this->OutLayerNeuNum]; for (int i = 0; i < trainingSet->GetRows(); ++i) { for (int j = 0; j < trainingSet->GetInputNum(); ++j) this->InputNeurons[j]->SetInput(trainingSet->GetDataMap()[i][j]); this->GetOutput(output); for (int j = 0; j < trainingSet->GetOutputNum(); ++j) { cout << "output: "; cout << output[j] << "/t"; cout << "expect: "; cout << trainingSet->GetDataMap()[i][trainingSet->GetInputNum()+j]<<"/t"; } cout << endl; } cout << endl; cout << "in to hide W:" << endl; for (int i = 0; i < this->HideLayerNeuNum; ++i) { for (int j = 0; j < this->InLayerNeuNum; ++j) { cout << this->HidenNeurons[i]->GetWeight()[j] << " "; } cout << endl; } cout << endl; cout << "hide to out W:" << endl; for (int i = 0; i < this->OutLayerNeuNum; ++i) { for (int j = 0; j < this->HideLayerNeuNum; ++j) { cout << this->OutputNeurons[i]->GetWeight()[j] << " "; } cout << endl; } }};int main(){ DataSet *trainingSet = new DataSet(2, 1); trainingSet->AddRow(new double[2]{ 1,1 }, new double[1]{ 0 }); trainingSet->AddRow(new double[2]{ 1,0 }, new double[1]{ 1 }); trainingSet->AddRow(new double[2]{ 0,1 }, new double[1]{ 1 }); trainingSet->AddRow(new double[2]{ 0,0 }, new double[1]{ 0 }); //层激励函数类型 神经元个数... 学习速率 MultiLayerPerceptron *m = new MultiLayerPerceptron(FUNCTYPE_LINEAR, 2, FUNCTYPE_SIGMOID, 5, FUNCTYPE_SIGMOID, 1, 0.9); //学习1000次 for (int i = 0; i < 10000; ++i) m->Learn(trainingSet); m->Test(trainingSet); system("pause"); return 0;}
新闻热点
疑难解答