一个简单的用C语言实现神经网络的框架
  HJwyUgQ6jyHT 15天前 14 0
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define INPUT_SIZE 2
#define HIDDEN_SIZE 3
#define OUTPUT_SIZE 1

/* 定义神经元结构体 */
typedef struct _neuron {
     
       
    double* weights;  // 权重数组
    double bias;      // 偏置值
    double output;    // 输出
} neuron;

/* 定义隐藏层和输出层结构体 */
typedef struct _layer {
     
       
    int size;         // 层数
    neuron* neurons;  // 神经元数组
} layer;

/* 定义神经网络结构体 */
typedef struct _network {
     
       
    layer input_layer;    // 输入层
    layer hidden_layer;   // 隐藏层
    layer output_layer;   // 输出层
} network;

/* 初始化神经元 */
void init_neuron(neuron* n, int size) {
     
       
    n->weights = (double*)malloc(sizeof(double) * size);
    for (int i = 0; i < size; i++) {
     
       
        n->weights[i] = ((double)rand() / RAND_MAX) * 2 - 1;
    }
    n->bias = ((double)rand() / RAND_MAX) * 2 - 1;
}

/* 初始化层 */
void init_layer(layer* l, int size, int input_size) {
     
       
    l->size = size;
    l->neurons = (neuron*)malloc(sizeof(neuron) * size);
    for (int i = 0; i < size; i++) {
     
       
        init_neuron(&l->neurons[i], input_size);
    }
}

/* 初始化神经网络 */
void init_network(network* net) {
     
       
    init_layer(&net->input_layer, INPUT_SIZE, 0);
    init_layer(&net->hidden_layer, HIDDEN_SIZE, INPUT_SIZE);
    init_layer(&net->output_layer, OUTPUT_SIZE, HIDDEN_SIZE);
}

/* 计算神经元输出值 */
double activate(neuron* n, double* inputs) {
     
       
    double sum = 0;
    for (int i = 0; i < INPUT_SIZE; i++) {
     
       
        sum += inputs[i] * n->weights[i];
    }
    sum += n->bias;
    return 1.0 / (1.0 + exp(-sum));
}

/* 前向传播 */
void forward(network* net, double* inputs) {
     
       
    /* 输入层计算 */
    for (int i = 0; i < INPUT_SIZE; i++) {
     
       
        net->input_layer.neurons[i].output = inputs[i];
    }

    /* 隐藏层计算 */
    for (int i = 0; i < HIDDEN_SIZE; i++) {
     
       
        neuron* n = &net->hidden_layer.neurons[i];
        n->output = activate(n, inputs);
    }

    /* 输出层计算 */
    for (int i = 0; i < OUTPUT_SIZE; i++) {
     
       
        neuron* n = &net->output_layer.neurons[i];
        n->output = activate(n, [n->output_layer.neurons[j].output for j in range(HIDDEN_SIZE)]);
    }
}

/* 计算误差 */
double error(double* target_output, double* output) {
     
       
    double err = 0;
    for (int i = 0; i < OUTPUT_SIZE; i++) {
     
       
        err += pow(target_output[i] - output[i], 2);
    }
    return err;
}

/* 反向传播 */
void backward(network* net, double* target_output, double learning_rate) {
     
       
    /* 计算输出层误差 */
    for (int i = 0; i < OUTPUT_SIZE; i++) {
     
       
        neuron* n = &net->output_layer.neurons[i];
        double output = n->output;
        double error = -(target_output[i] - output) * output * (1 - output);
        n->bias -= learning_rate * error;
        for (int j = 0; j < HIDDEN_SIZE; j++) {
     
       
            n->weights[j] -= learning_rate * error * net->hidden_layer.neurons[j].output;
        }
    }

    /* 计算隐藏层误差 */
    for (int i = 0; i < HIDDEN_SIZE; i++) {
     
       
        neuron* n = &net->hidden_layer.neurons[i];
        double output = n->output;
        double error = 0;
        for (int j = 0; j < OUTPUT_SIZE; j++) {
     
       
            neuron* o = &net->output_layer.neurons[j];
            error += o->weights[i] * (target_output[j] - o->output) * o->output * (1 - o->output);
        }
        n->bias -= learning_rate * error;
        for (int j = 0; j < INPUT_SIZE; j++) {
     
       
            n->weights[j] -= learning_rate * error * net->input_layer.neurons[j].output;
        }
    }
}

/* 训练神经网络 */
void train(network* net, double** training_inputs, double** training_outputs, int epochs, double learning_rate) {
     
       
    for (int epoch = 0; epoch < epochs; epoch++) {
     
       
        double total_error = 0;
        for (int i = 0; i < NUM_EXAMPLES; i++) {
     
       
            forward(net, training_inputs[i]);
            total_error += error(training_outputs[i], [net->output_layer.neurons[j].output for j in range(OUTPUT_SIZE)]);
            backward(net, training_outputs[i], learning_rate);
        }
        printf("Epoch %d: error = %f\n", epoch, total_error);
    }
}

/* 测试神经网络 */
void test(network* net, double** test_inputs) {
     
       
    for (int i = 0; i < NUM_TEST_EXAMPLES; i++) {
     
       
        double* inputs = test_inputs[i];
        forward(net, inputs);
        printf("[");
        for (int j = 0; j < INPUT_SIZE; j++) {
     
       
            printf("%f ", inputs[j]);
        }
        printf("] -> [");
        for (int j = 0; j < OUTPUT_SIZE; j++) {
     
       
            printf("%f ", net->output_layer.neurons[j].output);
        }
        printf("]\n");
    }
}

int main(int argc, char** argv) {
     
       
    /* 初始化随机数种子 */
    srand((unsigned int)time(NULL));

    /* 定义训练集和测试集 */
    double* training_inputs[NUM_EXAMPLES] = {
     
       
        (double[]){
     
       0, 0},
        (double[]){
     
       0, 1},
        (double[]){
     
       1, 0},
        (double[]){
     
       1, 1}
    };
    double* training_outputs[NUM_EXAMPLES] = {
     
       
        (double[]){
     
       0},
        (double[]){
     
       1},
        (double[]){
     
       1},
        (double[]){
     
       0}
    };
    double* test_inputs[NUM_TEST_EXAMPLES] = {
     
       
        (double[]){
     
       0, 0},
        (double[]){
     
       0, 1},
        (double[]){
     
       1, 0},
        (double[]){
     
       1, 1}
    };

    /* 初始化神经网络 */
    network net;
    init_network(&net);

    /* 训练神经网络 */
    train(&net, training_inputs, training_outputs, NUM_EPOCHS, LEARNING_RATE);

    /* 测试神经网络 */
    test(&net, test_inputs);

    return 0;
}


解释说明

这是一个简单的实现,仅仅展示了神经网络框架的基本结构和算法。
该程序实现了一个简单的多层感知机(Multilayer Perceptron, MLP)神经网络,并使用该神经网络来解决XOR逻辑运算问题。以下是程序的主要流程:

定义常量:程序中定义了输入层、隐藏层和输出层的大小,以及学习率、迭代轮数、训练集和测试集的大小等常量。
定义结构体:程序中定义了三个结构体:神经元结构体(neuron)、层结构体(layer)和神经网络结构体(network),用于存储神经网络的各种参数信息。
初始化神经网络:程序中通过调用init_network函数初始化神经网络。在初始化过程中,会为每个神经元随机生成一组权重并将其存储在神经元结构体中。
前向传播:程序中通过调用forward函数实现前向传播算法。在前向传播中,程序会依次计算输入层、隐藏层和输出层的神经元的输出值。
计算误差:程序中定义了error函数用于计算预测结果与实际结果之间的误差。
反向传播:程序中通过调用backward函数实现反向传播算法。在反向传播中,程序首先计算输出层的误差,然后将误差信号向后传递到隐藏层和输入层,最后使用梯度下降算法更新权重和偏置值。
训练神经网络:程序中通过调用train函数对神经网络进行训练。训练过程中,程序会多次迭代计算误差并调整权重和偏置值,以使神经网络的性能逐步提高。
测试神经网络:程序中通过调用test函数对已经训练好的神经网络进行测试,并输出测试结果。
具体来说,该神经网络是一个三层结构的MLP,其中包含1个输入层、1个隐藏层和1个输出层。输入层大小为2,隐藏层大小为3,输出层大小为1。在训练阶段,程序使用反向传播算法对神经网络进行学习,然后使用前向传播算法进行预测,最后输出测试结果。

测试方法

定义测试集:在主函数中定义一个包含多组输入数据的测试集,每组输入数据都是一个大小为2的double类型数组

double* test_inputs[NUM_TEST_EXAMPLES] = {
     
       
        (double[]){
     
       0, 0},
        (double[]){
     
       0, 1},
        (double[]){
     
       1, 0},
        (double[]){
     
       1, 1}
};

调用test函数:在主函数中调用test函数,对测试集中的每一组输入数据进行测试,并输出测试结果。

/* 测试神经网络 */
test(&net, test_inputs);

在test函数内部,程序会依次计算每一组输入数据的输出结果,并将结果输出到控制台上。具体来说,程序会按照如下格式输出每组输入数据和其对应的输出结果:

[IN] -> [OUT]

其中,IN表示输入数据,OUT表示神经网络的输出结果。对于本例中的神经网络,输出结果只有一个值。

最后,通过观察输出结果,可以评估该神经网络在XOR逻辑运算问题上的性能表现

编译方法

gcc -o program program.c -lm

这里使用了-lm参数,表示需要链接数学库libm。因为本程序使用了数学函数,如exp和log等。

运行可执行文件,开始训练和测试神经网络。

./program

注意,本程序中使用了随机数生成函数,运行结果可能会略有不同。如果多次运行结果不一致,可以尝试增加训练轮数或调整学习率等参数来改善程序的性能。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 15天前 0

暂无评论

HJwyUgQ6jyHT