BP神经网络C语言实现中的关键步骤是什么?

小贝
预计阅读时长 21 分钟
位置: 首页 小红书 正文

BP神经网络及其C语言实现详解

bp神经网络 c

一、基本概念

神经网络简介

神经网络是由简单的神经元组成的广泛互联的网络,其具有适应性,可以模拟生物神经系统对真实世界所做出的交互反应,神经网络的基本单位是神经元模型,单个神经元可以接收网络中其他神经元的信息,如果接收的信息超过阈值,则此神经元被激活,接着向其他神经元发送信息。

神经元模型

神经元模型包含输入、权重、偏置和激活函数几个要素,输入为多个信号,通过带权重的连接传递到神经元,总输入值与神经元的阈值进行比较,然后通过激活函数处理产生神经元的输出。

2.1 M-P神经元模型

M-P神经元模型是典型的神经元模型,其基本结构如下:

输入:X1, X2, ..., Xn

权重:W1, W2, ..., Wn

bp神经网络 c

偏置:Bias

激活函数:f(x)

输出:y

计算公式为:

\[ z = \sum_{i=1}^{n} w_i x_i + \text{Bias} \]

\[ y = f(z) \]

激活函数

激活函数引入非线性因素,提高模型的表示能力,常见的激活函数包括Sigmoid、Tanh、Step、ReLU、Softmax等,本文主要使用Sigmoid函数。

bp神经网络 c

Sigmoid函数的公式为:

\[ \sigma(x) = \frac{1}{1+e^{-x}} \]

多层前馈神经网络

多层前馈神经网络(multi-layer feedforward neural network)的结构包含输入层、隐藏层和输出层,每层的神经元与下一层全连接,同层之间不存在连接,也没有跨层连接。

二、BP神经网络理论推导

BP神经网络结构

BP神经网络采用标准的梯度下降误差逆传播方式进行训练,我们以一个3层前馈神经网络为例,其结构如下:

输入层:n个输入节点

隐层:h个神经元

输出层:m个神经元

BP神经网络的训练

训练过程根据训练数据来调整神经元之间的连接权以及每个功能神经元的阈值,具体步骤如下:

1、内随机初始化神经网络中的连接权重和阈值。

2、遍历训练集中的每一个样本,计算样本的与。

3、根据计算结果,计算误差。

4、根据误差对神经网络中的参数进行反馈学习,更新参数。

5、重复上述过程直到迭代若干次或者累积误差小于特定值。

2.1 参数更新公式

假设某次训练过程中神经网络的输入的某个训练数据为,经过神经网络的输出为,其中第k个输出神经元的阈值为,输出层第k个神经元的阈值为,隐层到输出层的权重为,输入层到隐层的权重为。

误差定义为:

\[ E = \frac{1}{2} \sum_{k=1}^{m} (aim\_output_{k} a_{k})^{2} \]

权重和阈值的更新公式为:

\[ v_{ij} = v_{ij} \eta \frac{\partial E}{\partial v_{ij}} \]

\[ w_{ij} = w_{ij} \eta \frac{\partial E}{\partial w_{ij}} \]

\[ \gamma_{i} = \gamma_{i} \eta \frac{\partial E}{\partial \gamma_{i}} \]

\[ \theta_{i} = \theta_{i} \eta \frac{\partial E}{\partial \theta_{i}} \]

η表示学习率。

三、C语言实现

训练模块

训练模块包含训练以及验证过程,注意此神经网络的输入输出都需要预先进行归一化处理,以下是一个简单的C语言实现示例:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define IN_N 784  // 输入层节点数
#define HIDDEN_N 500  // 隐藏层节点数
#define OUT_N 10  // 输出层节点数
#define LEARNING_RATE 0.1  // 学习率
#define MAX_ITER 10000  // 最大迭代次数
#define TOLERANCE 0.0001  // 误差容忍度
typedef struct {
    double val;
    double bias;
    double weight[HIDDEN_N];
} Node;
Node input[IN_N], hidden[HIDDEN_N], output[OUT_N];
double g[OUT_N], e[HIDDEN_N];
double trainx[IN_N], trainy[OUT_N];
// Sigmoid激活函数
double sigmoid(double x) {
    return 1.0 / (1.0 + exp(-x));
}
// 初始化网络
void init() {
    for (int i = 0; i < IN_N; i++) {
        for (int j = 0; j < HIDDEN_N; j++) {
            input[i].weight[j] = ((double)rand() / RAND_MAX) 0.5;
        }
    }
    for (int i = 0; i < HIDDEN_N; i++) {
        hidden[i].bias = ((double)rand() / RAND_MAX) 0.5;
        for (int j = 0; j < OUT_N; j++) {
            hidden[i].weight[j] = ((double)rand() / RAND_MAX) 0.5;
        }
    }
    for (int i = 0; i < OUT_N; i++) {
        output[i].bias = ((double)rand() / RAND_MAX) 0.5;
    }
}
// 前向传播
void forward() {
    // 输入层读取数据
    for (int i = 0; i < IN_N; i++) {
        input[i].val = trainx[i];
    }
    // 输入层->隐藏层
    for (int i = 0; i < HIDDEN_N; i++) {
        hidden[i].val = 0;
        for (int j = 0; j < IN_N; j++) {
            hidden[i].val += input[j].val * input[j].weight[i];
        }
        hidden[i].val -= hidden[i].bias;
        hidden[i].val = sigmoid(hidden[i].val);
    }
    // 隐藏层->输出层
    for (int i = 0; i < OUT_N; i++) {
        output[i].val = 0;
        for (int j = 0; j < HIDDEN_N; j++) {
            output[i].val += hidden[j].val * hidden[j].weight[i];
        }
        output[i].val -= output[i].bias;
        output[i].val = sigmoid(output[i].val);
    }
}
// 反向传播
void backpropagate() {
    // 计算g和e
    for (int i = 0; i < OUT_N; i++) {
        g[i] = output[i].val * (1 output[i].val) * (trainy[i] output[i].val);
    }
    for (int i = 0; i < HIDDEN_N; i++) {
        e[i] = hidden[i].val * (1 hidden[i].val) * 0;  // 这里需要进一步展开计算所有输出节点对当前隐藏节点的影响
        for (int j = 0; j < OUT_N; j++) {
            e[i] += g[j] * hidden[i].weight[j];
        }
    }
    // 更新参数(简化版,未展示所有细节)
    for (int i = 0; i < HIDDEN_N; i++) {
        for (int j = 0; j < OUT_N; j++) {
            hidden[i].weight[j] += LEARNING_RATE * e[i] * output[j].val;
        }
        hidden[i].bias -= LEARNING_RATE * e[i];
    }
    for (int i = 0; i < IN_N; i++) {
        for (int j = 0; j < HIDDEN_N; j++) {
            input[i].weight[j] += LEARNING_RATE * trainx[i] * e[j];
        }
    }
}
// 训练函数
void train() {
    init();
    for (int iter = 0; iter < MAX_ITER; iter++) {
        forward();
        backpropagate();
        // 计算误差(均方误差)
        double error = 0;
        for (int i = 0; i < OUT_N; i++) {
            error += (trainy[i] output[i].val) * (trainy[i] output[i].val);
        }
        if (error < TOLERANCE) break;
    }
}

拟合模块

拟合模块用于将训练好的神经网络应用于实际数据的拟合,以下是一个简单的C语言实现示例:

// 拟合函数(简化版)
void fit(double* in, double* out) {
    for (int i = 0; i < IN_N; i++) {
        input[i].val = in[i];
    }
    forward();
    for (int i = 0; i < OUT_N; i++) {
        out[i] = output[i].val;
    }
}

主函数示例

以下是一个完整的主函数示例,演示如何使用上述模块进行BP神经网络的训练和拟合:

int main() {
    // 示例训练数据(手写数字识别)
    double trainx[IN_N] = { /* 输入数据 */ };
    double trainy[OUT_N] = { /* 标签数据 */ };
    
    // 训练网络
    train();
    
    // 测试数据(手写数字识别)
    double testx[IN_N] = { /* 输入数据 */ };
    double testy[OUT_N];
    
    // 拟合测试数据
    fit(testx, testy);
    
    // 输出结果
    for (int i = 0; i < OUT_N; i++) {
        printf("Output %d: %f
", i, testy[i]);
    }
    
    return 0;
}

四、相关问题与解答栏目

问题1:什么是BP神经网络?

答:BP神经网络,即Back Propagation神经网络,是一种按误差逆传播算法训练的多层前馈神经网络,是目前应用最广泛的神经网络之一,它通过梯度下降法不断调整网络的权值和阈值,使网络的误差平方和最小,BP神经网络主要用于分类和函数逼近问题,详细内容请参见本文第一部分“基本概念”和第二部分“BP神经网络理论推导”。

各位小伙伴们,我刚刚为大家分享了有关“bp神经网络 c”的知识,希望对你们有所帮助。如果您还有其他相关问题需要解决,欢迎随时提出哦!

-- 展开阅读全文 --
头像
什么是Blob文件在JavaScript中的使用?
« 上一篇 2024-12-03
如何有效实施API认证程序以确保数据安全?
下一篇 » 2024-12-03
取消
微信二维码
支付宝二维码

发表评论

暂无评论,1人围观

目录[+]