讀到作者用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;}
新聞熱點
疑難解答