简单的C语言深度学习算法。

短小精悍的深度学习算法,用来理解深度学习的精髓,涉及深度学习的网络初始化、前向传播、反向传播、权重更新等核心算法功能;有输入层、隐藏层、输出层结构。
 

* prompt:
 * 基于C语言实现的简单深度学习网络(教学用),不使用第三方库,不使用内联函数,要求输出C代码。
 * 网络结构:输入层(2) → 隐藏层(4/ReLU) → 输出层(2/Softmax)
 * 数据集:异或问题(XOR)
 *
 * 这段代码实现了一个简单的2-4-2神经网络,
 * 使用ReLU作为隐藏层激活函数,Softmax作为输出层激活函数。
 * 代码包含网络初始化、前向传播、反向传播和权重更新等核心功能,
 * 能够成功学习XOR问题的解决方案。


/**
 * prompt:
 * 基于C语言实现的简单深度学习网络(教学用),不使用第三方库,不使用内联函数,要求输出C代码。
 * 网络结构:输入层(2) → 隐藏层(4/ReLU) → 输出层(2/Softmax)
 * 数据集:异或问题(XOR)
 *
 * 这段代码实现了一个简单的2-4-2神经网络,
 * 使用ReLU作为隐藏层激活函数,Softmax作为输出层激活函数。
 * 代码包含网络初始化、前向传播、反向传播和权重更新等核心功能,
 * 能够成功学习XOR问题的解决方案。
 */


#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

// 网络参数定义
#define INPUT_SIZE 2    // 输入层节点数
#define HIDDEN_SIZE 4   // 隐藏层节点数
#define OUTPUT_SIZE 2   // 输出层节点数
#define LEARNING_RATE 0.1  // 学习率
#define EPOCHS 10000    // 训练轮数

// 神经网络结构体
typedef struct {
    double weights_ih[INPUT_SIZE][HIDDEN_SIZE];  // 输入层到隐藏层权重
    double weights_ho[HIDDEN_SIZE][OUTPUT_SIZE]; // 隐藏层到输出层权重
    double bias_h[HIDDEN_SIZE];     // 隐藏层偏置
    double bias_o[OUTPUT_SIZE];     // 输出层偏置
} NeuralNetwork;

// 初始化神经网络
void init_network(NeuralNetwork* net) {
    srand(time(NULL));  // 设置随机种子

    // 初始化输入层到隐藏层的权重(-1到1之间的随机值)
    for(int i=0; i<INPUT_SIZE; i++) {
        for(int j=0; j<HIDDEN_SIZE; j++) {
            net->weights_ih[i][j] = ((double)rand() / RAND_MAX) * 2 - 1;
        }
    }

    // 初始化隐藏层到输出层的权重
    for(int i=0; i<HIDDEN_SIZE; i++) {
        for(int j=0; j<OUTPUT_SIZE; j++) {
            net->weights_ho[i][j] = ((double)rand() / RAND_MAX) * 2 - 1;
        }
    }

    // 初始化偏置
    for(int i=0; i<HIDDEN_SIZE; i++) {
        net->bias_h[i] = ((double)rand() / RAND_MAX) * 2 - 1;
    }
    for(int i=0; i<OUTPUT_SIZE; i++) {
        net->bias_o[i] = ((double)rand() / RAND_MAX) * 2 - 1;
    }
}

// ReLU激活函数
double relu(double x) {
    return x > 0 ? x : 0;  // 大于0返回x,否则返回0
}

// ReLU导数(用于反向传播)
double relu_derivative(double x) {
    return x > 0 ? 1 : 0;  // 大于0返回1,否则返回0
}

// Softmax函数(多分类输出)
void softmax(double* input, int size) {
    // 数值稳定性处理:减去最大值
    double max = input[0];
    for(int i=1; i<size; i++) {
        if(input[i] > max) {
            max = input[i];
        }
    }

    // 计算指数和
    double sum = 0.0;
    for(int i=0; i<size; i++) {
        input[i] = exp(input[i] - max);  // 防止数值溢出
        sum += input[i];
    }

    // 归一化
    for(int i=0; i<size; i++) {
        input[i] /= sum;
    }
}

// 前向传播
void forward(NeuralNetwork* net, double* input, double* hidden, double* output) {
    // 输入层到隐藏层计算
    for(int h=0; h<HIDDEN_SIZE; h++) {
        hidden[h] = 0;
        // 加权求和
        for(int i=0; i<INPUT_SIZE; i++) {
            hidden[h] += input[i] * net->weights_ih[i][h];
        }
        hidden[h] += net->bias_h[h];  // 加上偏置
        hidden[h] = relu(hidden[h]);  // 应用ReLU激活
    }

    // 隐藏层到输出层计算
    for(int o=0; o<OUTPUT_SIZE; o++) {
        output[o] = 0;
        for(int h=0; h<HIDDEN_SIZE; h++) {
            output[o] += hidden[h] * net->weights_ho[h][o];
        }
        output[o] += net->bias_o[o];  // 加上偏置
    }

    // 输出层应用softmax
    softmax(output, OUTPUT_SIZE);
}

// 反向传播
void backward(NeuralNetwork* net, double* input, double* hidden, double* output,
              double* target, double* d_weights_ih, double* d_weights_ho,
              double* d_bias_h, double* d_bias_o) {
    // 计算输出层误差(预测值-真实值)
    double output_error[OUTPUT_SIZE];
    for(int o=0; o<OUTPUT_SIZE; o++) {
        output_error[o] = output[o] - target[o];
    }

    // 计算隐藏层到输出层的梯度(误差*隐藏层输出)
    for(int h=0; h<HIDDEN_SIZE; h++) {
        for(int o=0; o<OUTPUT_SIZE; o++) {
            d_weights_ho[h*OUTPUT_SIZE + o] = output_error[o] * hidden[h];
        }
    }

    // 输出层偏置梯度就是输出误差
    for(int o=0; o<OUTPUT_SIZE; o++) {
        d_bias_o[o] = output_error[o];
    }

    // 计算隐藏层误差(反向传播误差)
    double hidden_error[HIDDEN_SIZE] = {0};
    for(int h=0; h<HIDDEN_SIZE; h++) {
        for(int o=0; o<OUTPUT_SIZE; o++) {
            hidden_error[h] += output_error[o] * net->weights_ho[h][o];
        }
        hidden_error[h] *= relu_derivative(hidden[h]);  // 乘以激活函数导数
    }

    // 计算输入层到隐藏层的梯度(隐藏层误差*输入值)
    for(int i=0; i<INPUT_SIZE; i++) {
        for(int h=0; h<HIDDEN_SIZE; h++) {
            d_weights_ih[i*HIDDEN_SIZE + h] = hidden_error[h] * input[i];
        }
    }

    // 隐藏层偏置梯度就是隐藏层误差
    for(int h=0; h<HIDDEN_SIZE; h++) {
        d_bias_h[h] = hidden_error[h];
    }
}

// 更新权重
void update_weights(NeuralNetwork* net,
    const double* d_weights_ih,
    const double* d_weights_ho,
    const double* d_bias_h,
    const double* d_bias_o) {
    // 更新输入层到隐藏层权重
    for(int i=0; i<INPUT_SIZE; i++) {
        for(int h=0; h<HIDDEN_SIZE; h++) {
            net->weights_ih[i][h] -= LEARNING_RATE * d_weights_ih[i*HIDDEN_SIZE + h];
        }
    }

    // 更新隐藏层到输出层权重
    for(int h=0; h<HIDDEN_SIZE; h++) {
        for(int o=0; o<OUTPUT_SIZE; o++) {
            net->weights_ho[h][o] -= LEARNING_RATE * d_weights_ho[h*OUTPUT_SIZE + o];
        }
    }

    // 更新偏置
    for(int h=0; h<HIDDEN_SIZE; h++) {
        net->bias_h[h] -= LEARNING_RATE * d_bias_h[h];
    }

    for(int o=0; o<OUTPUT_SIZE; o++) {
        net->bias_o[o] -= LEARNING_RATE * d_bias_o[o];
    }
}

// 训练网络
void train(NeuralNetwork* net, double inputs[4][2], int targets[4][2]) {
    // 梯度缓存
    double d_weights_ih[INPUT_SIZE * HIDDEN_SIZE] = {0};
    double d_weights_ho[HIDDEN_SIZE * OUTPUT_SIZE] = {0};
    double d_bias_h[HIDDEN_SIZE] = {0};
    double d_bias_o[OUTPUT_SIZE] = {0};

    for(int epoch=0; epoch<EPOCHS; epoch++) {
        for(int sample=0; sample<4; sample++) {  // 遍历4个XOR样本
            double hidden[HIDDEN_SIZE] = {0};
            double output[OUTPUT_SIZE] = {0};

            // 前向传播
            forward(net, inputs[sample], hidden, output);

            // 反向传播计算梯度
            backward(net, inputs[sample], hidden, output, targets[sample],
                    d_weights_ih, d_weights_ho, d_bias_h, d_bias_o);

            // 更新权重
            update_weights(net, d_weights_ih, d_weights_ho, d_bias_h, d_bias_o);
        }
    }
}

// 预测函数
void predict(NeuralNetwork* net, double* input) {
    double hidden[HIDDEN_SIZE] = {0};
    double output[OUTPUT_SIZE] = {0};

    forward(net, input, hidden, output);

    printf("Input: [%.1f, %.1f] => Output: [%.4f, %.4f] => ",
           input[0], input[1], output[0], output[1]);
    if(output[0] > output[1]) {
        printf("Predicted: 0 (%.2f%%)\n", output[0]*100);
    } else {
        printf("Predicted: 1 (%.2f%%)\n", output[1]*100);
    }
}

int main() {
    NeuralNetwork net;
    init_network(&net);  // 初始化网络

    // XOR数据集
    double inputs[4][2] = {
        {0, 0},  // 0 XOR 0 = 0
        {0, 1},  // 0 XOR 1 = 1
        {1, 0},  // 1 XOR 0 = 1
        {1, 1}   // 1 XOR 1 = 0
    };

    // 目标输出(one-hot编码)
    int targets[4][2] = {
        {1, 0},  // 0
        {0, 1},  // 1
        {0, 1},  // 1
        {1, 0}   // 0
    };

    // 训练网络
    train(&net, inputs, targets);

    // 测试网络
    printf("XOR Problem Results:\n");
    for(int i=0; i<4; i++) {
        predict(&net, inputs[i]);
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值