C++ 神经网络

2025年3月17日 | 阅读 12 分钟

在本文中,我们将通过示例讨论 C++ 中的神经网络。

什么是神经网络?

神经网络是一种计算模型,其结构与大脑中的神经元相同。它的功能也与神经元相同。它就像一个人工神经系统,用于接收输入信息、处理或操纵它并进行传输。

神经网络的层

神经网络包含三种类型的层:输入层隐藏层输出层

输入层

模型中只有一个输入层,它接收数据集中的所有输入,这些输入就是特征。这些输入信息被提供给神经网络中的隐藏层。

隐藏层

网络中会有很多隐藏层。输入层提供的输入被修改并收敛以获得所需的输出。假设有三个隐藏层,输入被提供给第一个隐藏层,然后更新权重后,这些权重被提供给第二个层。然后再次,更新的权重被提供给第三个隐藏层。之后,这些更新的信息被提供给输出层。

输出层

处理后,数据将在输出层可用。

神经网络基础

神经元和层:每个神经元都像一个生物神经元。层是输入、隐藏和输出层。

激活函数:这些数学函数为模型提供非线性或曲线。一些激活函数是Sigmoid、ReLU 等。这些函数使模型能够学习数据中的复杂模式。ReLU 及其变体(Leaky ReLU、ELU)因其简单性和在许多场景中的有效性而成为隐藏层的热门选择。Sigmoid 和 softmax 通常用于输出层,具体取决于问题的性质。

前向传播和反向传播:前向传播中,权重被更新并收敛以预测准确的输出,但在反向传播中,权重会再次减小并更新以最小化误差。

损失函数:损失函数,也称为成本函数目标函数,量化了预测值和实际值之间的差异。一些损失函数是均方误差、二元交叉熵损失、分类交叉熵损失、合页损失等。选择合适的损失函数很重要,因为它直接影响模型的学习行为,并确保模型针对特定任务得到有效优化。

优化器:这些用于优化权重。其中一些是梯度、Adagrad、Adam、随机梯度下降、RMSprop 优化器等。它们对于实现收敛和准确的输出非常重要。Adam 是目前最好的优化器。

权重初始化:权重的正确初始化对于防止梯度消失和梯度爆炸至关重要。其中一些是XavierGlorot 初始化。

正则化技术:这些技术有助于防止过拟合和欠拟合问题。有两种类型的正则化,即 L1 正则化(即Lasso 正则化)和L2 正则化(即 Ridge 正则化)。一些正则化技术包括回调和提前停止的实现。数据增强用于避免欠拟合。

验证和测试

训练数据集:用于训练网络从数据集中学习的数据集的一部分。

验证数据集:验证数据集是数据的独立一部分,不用于训练模型。相反,它用于在训练期间评估模型的性能。

测试数据集:测试数据集是数据的完全未见过的一部分,用于在训练和验证数据集上训练和调整模型后评估最终模型。

示例

让我们通过一个例子来说明 C++ 中的神经网络。

输出

Neural network in C++
Neural network in C++

说明

此程序很大,因为它包含了神经网络的所有有用技术。所以只需将代码分成函数以获得良好的理解

程序布局

NeuralNetwork 类

构造函数

NeuralNetwork::NeuralNetwork(int inputSize, int hiddenSize, int outputSize)

激活函数

double NeuralNetwork::sigmoid(double x)

激活函数导数

double NeuralNetwork::sigmoidDerivative(double x)

训练方法

void NeuralNetwork::train(vector<vector<double>>& inputs, vector<double>& targets, int epochs, double learningRate)

预测方法

double NeuralNetwork::predict(vector<double>& input)

辅助函数

均方误差计算

double calculateMeanSquaredError(vector<double>& predictedOutputs, vector<double>& actualOutputs)

主函数

int main()

神经网络构造函数

它使用特定的输入、隐藏和输出层大小初始化NeuralNetwork 对象。它接受三个参数:inputSize、hiddenSize 和 outputSize。此构造函数设置神经网络的基本结构,为训练和预测任务做准备。

Sigmoid 函数

这是激活函数,用于计算给定输入值 x 的 sigmoid 激活。Sigmoid 函数将任何实值映射到 0 到 1 之间的范围。它定义为

Sigmoid(x) = 1 / (1+ e^(-x))

double x - 需要计算 sigmoid 激活的输入值。

double - 应用 sigmoid 函数于输入的结果。

此函数的主要目的是为网络引入非线性。

此函数在正向传播和反向传播期间都会被调用或使用。

sigmoidDerivative 函数

sigmoidDerivative 函数计算 sigmoid 激活函数相对于其输入的导数。Sigmoid 函数 σ(x) 的导数由以下公式给出

输入为 double x,需要计算其 sigmoid 导数,输出为应用 sigmoid 函数导数于输入的结果。

train 函数

函数参数为

Inputs:一个二维向量,表示训练的输入数据。

Targets:一个包含相应目标值的向量。

Epochs:它指定要运行的训练过程的迭代次数。

learning Rate:它表示每次迭代中更新权重的步长。

函数的返回类型是

其返回类型为void。它不向其他函数返回任何内容,但会修改神经网络对象的内部状态。

函数中使用的变量

int epoch:循环变量,表示训练期间的当前 epoch。

size_t i:循环变量,表示当前训练数据点的索引。

size_t j:循环变量,用于遍历隐藏层。

size_t k:循环变量,用于遍历输入特征。

double weightedSum:临时变量,保存神经元的加权输入之和。

double outputError:表示预测输出与实际目标值之间的误差。

vector<double> hiddenOutput:一个向量,包含给定输入时隐藏层神经元的输出值。

vector<double> hiddenErrors:一个向量,存储隐藏层中的误差,用于反向传播。

此方法中存在的计算和步骤

正向传播

对于每个输入数据点,它计算加权和并将激活函数应用于隐藏层。

反向传播

它通过神经网络反向传播来计算误差。它根据输出误差计算隐藏层中的误差。

权重更新

这与梯度下降概念有关。它根据前一步计算出的误差更新输入层和隐藏层之间的权重。

迭代

迭代基于 epoch,在每次迭代中,整个数据集都会重新训练。它使模型能够根据权重进行调整。

predict 函数

函数中使用的参数

一个向量,包含用于进行预测的输入特征。

返回类型

它返回神经网络的预测。

函数中存在的变量是

hiddenOutput:一个向量,存储应用激活函数 sigmoid 后隐藏层神经元的输出。weightedSum 和 output 是用于预测的变量。

calculation:对于隐藏层中的每个神经元(weights_input_hidden.size() 个神经元)

遍历输入特征并计算加权和(weightedSum),方法是将每个输入特征与其在隐藏层中的相应权重相乘。

将 sigmoid 激活函数应用于weightedSum 以获得神经元的输出。

将 sigmoid 输出存储在hiddenOutput 向量中。

calculateMeanSquaredError 函数

传递给函数的参数是

predictedOutputs:一个向量,包含由神经网络预测的预测输出值。

actualOutputs:一个向量,包含相同输入的实际值

函数的返回类型是

它表示预测输出和实际输出之间计算出的均方误差

计算

该函数首先检查predictedOutputsactualOutputs 向量是否具有相同的大小。如果它们的大小不同,则会向标准错误流(cerr)打印一条错误消息,并且函数返回 -1.0 以指示错误。

该函数检查输入向量是否大小相同,计算预测值和实际值之间的平方误差,计算这些平方误差的平均值,并返回平均平方误差作为神经网络预测准确性的度量。

main 函数

此函数分为五个部分:

  • 数据生成
  • 测试数据生成
  • 神经网络初始化和训练
  • 测试训练好的神经网络
  • 使用用户输入进行预测

数据生成

这部分包含两个向量,名为 inputs,是一个二维向量,名为 outputs,是一个一维向量。现在,我们正在创建由两个输入特征和一个输出特征组成的数据集。数据集包含 500 个数据点。输入被推入 inputs 向量,通过应用关系获得的输出存储在 outputs 向量中。

神经网络初始化和训练

此处使用具有 2 个输入特征、16 个隐藏神经元和 1 个输出神经元的神经网络。现在,使用四个参数调用 train 方法:输入向量、输出向量、epoch 数和学习率。

测试训练好的神经网络

训练好的神经网络在测试数据集上进行测试。使用预测方法为每个测试数据点进行预测。为每个测试数据点打印预测输出和实际输出。使用预测输出和实际输出计算均方误差 (MSE) 以评估模型的性能。

使用用户输入进行预测

用户可以输入自定义数据(在本例中为 {100, 100})。神经网络使用训练模型对提供的输入特征进行预测,并显示预测输出。

结论

神经网络架构包括一个具有 2 个特征的输入层:一个包含 16 个神经元的隐藏层和一个具有单个神经元的输出层。该模型使用包含 500 个数据点的数据集进行训练,每个数据点具有 2 个输入特征和 1 个对应的输出值。通过反向传播,网络调整其权重以在训练阶段最小化预测输出和实际输出之间的差异。

训练后,使用包含 99 个数据点的独立测试数据集评估网络性能。使用均方误差 (MSE) 指标来量化预测的准确性。MSE 衡量神经网络在多大程度上捕捉了数据中的潜在模式,较低的 MSE 值表示更准确的预测。

值得注意的是,多个因素会影响神经网络的有效性。权重的随机初始化会影响训练算法的收敛性,数据集的质量和数量会显着影响模型泛化到未见过数据的能力。此外,训练 epoch 的数量和学习率是影响网络性能的关键超参数。微调这些参数并尝试不同的网络架构可以提高预测的准确性。

此外,神经网络是一个多功能工具,可以应用于各种实际问题,但不限于图像识别、自然语言处理和金融预测。此实现是神经网络的基础理解,可以进一步扩展和优化以应对更复杂的任务和数据集。