简单神经网络
简单神经网络:输入层2个神经元 隐层4个神经元 输出层预测
#include "pch.h" #include <iostream> #include <cmath> #include <vector> #include <fstream> #include <random> #define INNODE 2 #define HIDENODE 4 #define OUTNODE 1 double rate = 0.8; double threshold = 1e-4; size_t mosttimes = 1e6; struct Sample { std::vector<double> in, out; }; struct Node { double value{}, bias{}, bias_delta{}; std::vector<double> weight, weight_delta; }; namespace utils { inline double sigmoid(double x) { double res = 1.0 / (1.0 + std::exp(-x)); return res; } std::vector<double> getFileData(std::string filename) { std::vector<double> res; std::ifstream in(filename); if (in.is_open()) { while (!in.eof()) { double buffer; in >> buffer; res.push_back(buffer); } in.close(); } else { std::cout << "Error in reading " << filename.c_str() << std::endl; } return res; } std::vector<Sample> getTrainData(std::string filename) { std::vector<Sample> res; std::vector<double> buffer = getFileData(filename); for (size_t i = 0; i < buffer.size(); i += INNODE + OUTNODE) { Sample tmp; for (size_t t = 0; t < INNODE; t++) { tmp.in.push_back(buffer[i + t]); } for (size_t t = 0; t < OUTNODE; t++) { tmp.out.push_back(buffer[i + INNODE + t]); } res.push_back(tmp); } return res; } std::vector<Sample> getTestData(std::string filename) { std::vector<Sample> res; std::vector<double> buffer = getFileData(filename); for (size_t i = 0; i < buffer.size(); i += INNODE) { Sample tmp; for (size_t t = 0; t < INNODE; t++) { tmp.in.push_back(buffer[i + t]); } res.push_back(tmp); } return res; } } Node *inputLayer[INNODE], *hideLayer[HIDENODE], *outLayer[OUTNODE]; inline void init() { std::mt19937 rd; rd.seed(std::random_device()()); std::uniform_real_distribution<double> distribution(-1, 1); for (size_t i = 0; i < INNODE; i++) { ::inputLayer[i] = new Node(); for (size_t j = 0; j < HIDENODE; j++) { ::inputLayer[i]->weight.push_back(distribution(rd)); ::inputLayer[i]->weight_delta.push_back(0.f); } } for (size_t i = 0; i < HIDENODE; i++) { ::hideLayer[i] = new Node(); ::hideLayer[i]->bias = distribution(rd); for (size_t j = 0; j < OUTNODE; j++) { ::hideLayer[i]->weight.push_back(distribution(rd)); ::hideLayer[i]->weight_delta.push_back(0.f); } } for (size_t i = 0; i < OUTNODE; i++) { ::outLayer[i] = new Node(); ::outLayer[i]->bias = distribution(rd); } } inline void reset_delta() { for (size_t i = 0; i < INNODE; i++) { ::inputLayer[i]->weight_delta.assign(::inputLayer[i]->weight_delta.size(), 0.f); } for (size_t i = 0; i < HIDENODE; i++) { ::hideLayer[i]->bias_delta = 0.f; ::hideLayer[i]->weight_delta.assign(::hideLayer[i]->weight_delta.size(), 0.f); } for (size_t i = 0; i < OUTNODE; i++) { ::outLayer[i]->bias_delta = 0.f; } } int main() { init(); std::vector<double> buffer = ::utils::getFileData("D:\\traindata.txt"); std::vector<Sample> train_data; for (size_t i = 0; i < buffer.size(); i += INNODE + OUTNODE) { Sample tmp; for (size_t t = 0; t < INNODE; t++) { tmp.in.push_back(buffer[i + t]); } for (size_t t = 0; t < OUTNODE; t++) { tmp.out.push_back(buffer[i + INNODE + t]); } train_data.push_back(tmp); } // training for (size_t times = 0; times < mosttimes; times++) { reset_delta(); double error_max = 0.f; for (auto &idx : train_data) { for (size_t i = 0; i < INNODE; i++) { ::inputLayer[i]->value = idx.in[i]; } // 正向传播 for (size_t j = 0; j < HIDENODE; j++) { double sum = 0; for (size_t i = 0; i < INNODE; i++) { sum += ::inputLayer[i]->value * ::inputLayer[i]->weight[j]; } sum -= ::hideLayer[j]->bias; ::hideLayer[j]->value = utils::sigmoid(sum); } for (size_t j = 0; j < OUTNODE; j++) { double sum = 0; for (size_t i = 0; i < HIDENODE; i++) { sum += ::hideLayer[i]->value * ::hideLayer[i]->weight[j]; } sum -= ::outLayer[j]->bias; ::outLayer[j]->value = utils::sigmoid(sum); } // 计算误差 double error = 0.f; for (size_t i = 0; i < OUTNODE; i++) { double tmp = std::fabs(::outLayer[i]->value - idx.out[i]); error += tmp * tmp / 2; } error_max = std::max(error_max, error); // 反向传播 for (size_t i = 0; i < OUTNODE; i++) { double bias_delta = -(idx.out[i] - ::outLayer[i]->value) * ::outLayer[i]->value * (1.0 - ::outLayer[i]->value); ::outLayer[i]->bias_delta += bias_delta; } for (size_t i = 0; i < HIDENODE; i++) { for (size_t j = 0; j < OUTNODE; j++) { double weight_delta = (idx.out[j] - ::outLayer[j]->value) * ::outLayer[j]->value * (1.0 - ::outLayer[j]->value) * ::hideLayer[i]->value; ::hideLayer[i]->weight_delta[j] += weight_delta; } } for (size_t i = 0; i < HIDENODE; i++) { double sum = 0; for (size_t j = 0; j < OUTNODE; j++) { sum += -(idx.out[j] - ::outLayer[j]->value) * ::outLayer[j]->value * (1.0 - ::outLayer[j]->value) * ::hideLayer[i]->weight[j]; } ::hideLayer[i]->bias_delta += sum * ::hideLayer[i]->value * (1.0 - ::hideLayer[i]->value); } for (size_t i = 0; i < INNODE; i++) { for (size_t j = 0; j < HIDENODE; j++) { double sum = 0.f; for (size_t k = 0; k < OUTNODE; k++) { sum += (idx.out[k] - ::outLayer[k]->value) * ::outLayer[k]->value * (1.0 - ::outLayer[k]->value) * ::hideLayer[j]->weight[k]; } ::inputLayer[i]->weight_delta[j] += sum * ::hideLayer[j]->value * (1.0 - ::hideLayer[j]->value) * ::inputLayer[i]->value; } } } if (error_max < ::threshold) { std::cout << "Success with " << times + 1 << " times training." << std::endl; std::cout << "Maximum error: " << error_max << std::endl; break; } auto train_data_size = double(train_data.size()); for (size_t i = 0; i < INNODE; i++) { for (size_t j = 0; j < HIDENODE; j++) { ::inputLayer[i]->weight[j] += rate * ::inputLayer[i]->weight_delta[j] / train_data_size; } } for (size_t i = 0; i < HIDENODE; i++) { ::hideLayer[i]->bias += rate * ::hideLayer[i]->bias_delta / train_data_size; for (size_t j = 0; j < OUTNODE; j++) { ::hideLayer[i]->weight[j] += rate * ::hideLayer[i]->weight_delta[j] / train_data_size; } } for (size_t i = 0; i < OUTNODE; i++) { ::outLayer[i]->bias += rate * ::outLayer[i]->bias_delta / train_data_size; } } std::vector<Sample> test_data = utils::getTestData("D:\\testdata.txt"); // predict for (auto &idx : test_data) { for (size_t i = 0; i < INNODE; i++) { ::inputLayer[i]->value = idx.in[i]; } for (size_t j = 0; j < HIDENODE; j++) { double sum = 0; for (size_t i = 0; i < INNODE; i++) { sum += ::inputLayer[i]->value * inputLayer[i]->weight[j]; } sum -= ::hideLayer[j]->bias; ::hideLayer[j]->value = utils::sigmoid(sum); } for (size_t j = 0; j < OUTNODE; j++) { double sum = 0; for (size_t i = 0; i < HIDENODE; i++) { sum += ::hideLayer[i]->value * ::hideLayer[i]->weight[j]; } sum -= ::outLayer[j]->bias; ::outLayer[j]->value = utils::sigmoid(sum); idx.out.push_back(::outLayer[j]->value); for (auto &tmp : idx.in) { std::cout << tmp << " "; } for (auto &tmp : idx.out) { std::cout << tmp << " "; } std::cout << std::endl; } } return 0; }
训练集:
0 0 0
0 1 1
1 0 1
1 1 0
0.8 0.8 0
0.6 0.6 0
0.4 0.4 0
0.2 0.2 0
1.0 0.8 1
1.0 0.6 1
1.0 0.4 1
1.0 0.2 1
0.8 0.6 1
0.6 0.4 1
0.4 0.2 1
0.2 0 1
0.999 0.666 1
0.666 0.333 1
0.333 0 1
0.8 0.4 1
0.4 0 1
0 0.123 1
0.12 0.23 1
0.23 0.34 1
0.34 0.45 1
0.45 0.56 1
0.56 0.67 1
0.67 0.78 1
0.78 0.89 1
0.89 0.99 1
测试用例:
0.111 0.112
0.001 0.999
0.123 0.345
0.123 0.456
0.123 0.789
0.234 0.567
0.234 0.678
0.387 0.401
0.616 0.717
0.701 0.919