项目背景详细介绍
随着人工智能与机器学习的快速发展,神经网络(Neural Network) 已经成为现代计算机科学中不可或缺的核心技术之一。
在工业级项目中,人们往往直接使用:
-
TensorFlow
-
PyTorch
-
ONNX Runtime
-
各类推理框架
但对于 C++ 学习者和算法初学者 来说,如果一开始就依赖这些“黑盒框架”,往往会产生几个严重问题:
-
不清楚神经网络内部到底做了什么
-
不了解前向传播与反向传播的本质
-
无法将数学公式与代码建立对应关系
-
难以在底层系统、嵌入式、游戏引擎中灵活应用
而在很多真实工程场景中,例如:
-
游戏 AI
-
智能决策系统
-
嵌入式设备推理
-
算法教学与科研验证
-
面试与基础能力考察
从零手写一个多层神经网络,反而是一项极具价值的能力。
因此,本项目将以教学与理解为第一目标,在 不使用任何第三方机器学习库 的前提下,完整实现一个:
支持多层结构、前向传播、反向传播、梯度下降训练的 C++ 神经网络
该项目非常适合作为博客长文、人工智能课程、算法与 C++ 综合训练项目。
项目需求详细介绍
本项目的目标需求如下:
1. 功能需求
使用 C++ 实现多层前馈神经网络
支持输入层、隐藏层、输出层
支持 Sigmoid 激活函数
支持前向传播(Forward Propagation)
支持反向传播(Backpropagation)
支持基于梯度下降的权重更新
能够完成简单监督学习任务
2. 网络结构要求
-
全连接网络(Fully Connected)
-
任意层数(示例使用 1 个隐藏层)
-
使用矩阵 / 向量计算(手动实现)
3. 教学与工程要求
数学概念与代码一一对应
代码结构清晰,便于逐层理解
不追求极致性能,追求可读性
可扩展为更复杂网络结构
相关技术详细介绍
1. 神经网络基本组成
一个典型的前馈神经网络由以下部分组成:
神经元(Neuron)
权重(Weight)
偏置(Bias)
激活函数(Activation Function)
数学表达式为:
y = f( Σ(wi * xi) + b )
2. 前向传播(Forward Propagation)
前向传播是指:
从输入层开始,逐层计算,直到输出层得到预测结果
这是**推理(Inference)**的核心过程。
3. 反向传播(Backpropagation)
反向传播是神经网络学习的核心算法,其本质是:
-
利用链式法则
-
从输出层向前逐层计算误差
-
更新权重和偏置
4. 梯度下降(Gradient Descent)
权重更新公式为:
weight = weight – learning_rate * gradient
这是神经网络“学习”的本质。
实现思路详细介绍
整体实现思路如下:
封装神经网络类
-
保存权重矩阵与偏置
-
管理网络层结构
实现前向传播
-
输入 → 隐藏层 → 输出层
实现反向传播
-
输出层误差
-
隐藏层误差
-
权重与偏置更新
训练循环
-
输入样本
-
前向计算
-
反向更新
-
多轮迭代收敛
该结构与所有深度学习框架的底层原理完全一致。
完整实现代码
/****************************************************
* File: NeuralNetwork.h
****************************************************/
#pragma once
#include <vector>
class NeuralNetwork
{
public:
NeuralNetwork(int input, int hidden, int output, double lr);
std::vector<double> predict(const std::vector<double>& input);
void train(const std::vector<double>& input,
const std::vector<double>& target);
private:
double learningRate;
std::vector<std::vector<double>> weightsIH;
std::vector<std::vector<double>> weightsHO;
std::vector<double> biasH;
std::vector<double> biasO;
static double sigmoid(double x);
static double dsigmoid(double y);
};
/****************************************************
* File: NeuralNetwork.cpp
****************************************************/
#include "NeuralNetwork.h"
#include <cmath>
#include <cstdlib>
static double randomWeight()
{
return ((double)rand() / RAND_MAX) * 2.0 – 1.0;
}
NeuralNetwork::NeuralNetwork(int input, int hidden, int output, double lr)
: learningRate(lr)
{
weightsIH.resize(hidden, std::vector<double>(input));
weightsHO.resize(output, std::vector<double>(hidden));
biasH.resize(hidden);
biasO.resize(output);
for (auto& row : weightsIH)
for (auto& w : row) w = randomWeight();
for (auto& row : weightsHO)
for (auto& w : row) w = randomWeight();
for (auto& b : biasH) b = randomWeight();
for (auto& b : biasO) b = randomWeight();
}
double NeuralNetwork::sigmoid(double x)
{
return 1.0 / (1.0 + exp(-x));
}
double NeuralNetwork::dsigmoid(double y)
{
return y * (1.0 – y);
}
std::vector<double> NeuralNetwork::predict(const std::vector<double>& input)
{
std::vector<double> hidden(biasH);
for (size_t i = 0; i < hidden.size(); i++)
for (size_t j = 0; j < input.size(); j++)
hidden[i] += weightsIH[i][j] * input[j];
for (auto& h : hidden) h = sigmoid(h);
std::vector<double> output(biasO);
for (size_t i = 0; i < output.size(); i++)
for (size_t j = 0; j < hidden.size(); j++)
output[i] += weightsHO[i][j] * hidden[j];
for (auto& o : output) o = sigmoid(o);
return output;
}
void NeuralNetwork::train(const std::vector<double>& input,
const std::vector<double>& target)
{
// 前向传播
std::vector<double> hidden(biasH);
for (size_t i = 0; i < hidden.size(); i++)
for (size_t j = 0; j < input.size(); j++)
hidden[i] += weightsIH[i][j] * input[j];
for (auto& h : hidden) h = sigmoid(h);
std::vector<double> output(biasO);
for (size_t i = 0; i < output.size(); i++)
for (size_t j = 0; j < hidden.size(); j++)
output[i] += weightsHO[i][j] * hidden[j];
for (auto& o : output) o = sigmoid(o);
// 输出层误差
std::vector<double> outputErrors(output.size());
for (size_t i = 0; i < output.size(); i++)
outputErrors[i] = target[i] – output[i];
// 隐藏层误差
std::vector<double> hiddenErrors(hidden.size(), 0.0);
for (size_t i = 0; i < hidden.size(); i++)
for (size_t j = 0; j < output.size(); j++)
hiddenErrors[i] += weightsHO[j][i] * outputErrors[j];
// 更新权重 HO
for (size_t i = 0; i < weightsHO.size(); i++)
for (size_t j = 0; j < weightsHO[i].size(); j++)
weightsHO[i][j] += learningRate *
outputErrors[i] * dsigmoid(output[i]) * hidden[j];
// 更新偏置 O
for (size_t i = 0; i < biasO.size(); i++)
biasO[i] += learningRate *
outputErrors[i] * dsigmoid(output[i]);
// 更新权重 IH
for (size_t i = 0; i < weightsIH.size(); i++)
for (size_t j = 0; j < weightsIH[i].size(); j++)
weightsIH[i][j] += learningRate *
hiddenErrors[i] * dsigmoid(hidden[i]) * input[j];
// 更新偏置 H
for (size_t i = 0; i < biasH.size(); i++)
biasH[i] += learningRate *
hiddenErrors[i] * dsigmoid(hidden[i]);
}
/****************************************************
* File: main.cpp
****************************************************/
#include "NeuralNetwork.h"
#include <iostream>
int main()
{
NeuralNetwork nn(2, 4, 1, 0.1);
// 训练 XOR
for (int i = 0; i < 5000; i++)
{
nn.train({0, 0}, {0});
nn.train({0, 1}, {1});
nn.train({1, 0}, {1});
nn.train({1, 1}, {0});
}
std::cout << "0 XOR 0 = " << nn.predict({0, 0})[0] << std::endl;
std::cout << "0 XOR 1 = " << nn.predict({0, 1})[0] << std::endl;
std::cout << "1 XOR 0 = " << nn.predict({1, 0})[0] << std::endl;
std::cout << "1 XOR 1 = " << nn.predict({1, 1})[0] << std::endl;
return 0;
}


