diff --git a/cnn.c b/cnn.c index e69de29..53d774d 100644 --- a/cnn.c +++ b/cnn.c @@ -0,0 +1,193 @@ +#include "cnn.h" + + + +// 将原始矩阵复制到填充后的矩阵中央 +float* expand(const float* old_matrix, u8 old_matrix_num){ + float* new_matrix = (float *)malloc(sizeof(float)*(old_matrix_num+2)*(old_matrix_num+2)); + memset(new_matrix, 0, sizeof(float)*(old_matrix_num+2)*(old_matrix_num+2)); + for (u8 i = 0; i < old_matrix_num; i++) { + for (u8 j = 0; j < old_matrix_num; j++) { + new_matrix[(i + 1) * (old_matrix_num+2) + (j + 1)] = old_matrix[i * old_matrix_num + j]; + } + } + return new_matrix; +} + +//卷积核的个数:32 +//卷积的面积:3*3 +//输入图像 +//输入图像的边长:102 +//输出图像的边长:100 +//返回卷积的结果 +float* convolution(u8 num_kernels, u8 area, const float* input_matrix, u8 input_matrix_length){ + // 初始化卷积层参数 + float conv_temp; // 临时变量,用于存储卷积计算的中间结果 + float* conv_rlst = (float *) malloc(sizeof (float)*32*100*100); + memset(conv_rlst, 0, sizeof (float)*32*100*100); + // 遍历30个卷积核(假设有30个通道) + for(int n=0; n<32; n++) + { + // 遍历输出图像的每一行(卷积输出大小为24x24) + for(int row=0; row<100; row++) + { + // 遍历输出图像的每一列 + for(int col=0; col<100; col++) + { + conv_temp = 0; // 每个输出像素初始化为0 + // 进行5x5的卷积操作 + for(int x=0; x<3; x++) + { + for(int y=0; y<3; y++) + { + // 将输入图像的对应像素与卷积核权重相乘,并累加到conv_temp + conv_temp += input_matrix[row*102+col+x*102+y] * conv1_weight.array[x*3+y+n*(3*3)]; + } + } + // 加上对应卷积核的偏置 + conv_temp += conv1_bias.array[n]; + // 激活函数:ReLU(将小于0的值设为0) + if(conv_temp > 0) + conv_rlst[row*100+col+n*100*100] = conv_temp; // 如果卷积结果大于0,存入结果数组 + else + conv_rlst[row*100+col+n*100*100] = 0; // 否则存入0 + } + } + } + return conv_rlst; +} + +int main(){ + model_init(); + model_write("all"); + model_switchdata("data"); + +//填充102 * 102 + float* expand1_matrix = expand(data.array, 100); + + float* conv_rlst = convolution(32,3,expand1_matrix,102); + + + for (int i = 0; i < 1000; i++) { + printf("%f ", conv_rlst[i]); + if ((i + 1) % 102 == 0) { + printf("\n"); + } + } + + + + + + + + + + + + + +// float pool_temp = 0; // 临时变量,用于存储池化操作的最大值 +// float pool_rslt[32*50*50] = {0}; +// // 遍历30个通道(与卷积核数量相同) +// for(int n=0; n<32; n++) +// { +// // 遍历输入图像的每一行,步长为2(2x2的池化窗口) +// for(int row=0; row<100; row=row+2) +// { +// // 遍历输入图像的每一列,步长为2 +// for(int col=0; col<100; col=col+2) +// { +// pool_temp = 0; // 每个池化区域的最大值初始化为0 +// // 进行2x2的最大池化操作 +// for(int x=0; x<2; x++) +// { +// for(int y=0; y<2; y++) +// { +// // 更新当前池化区域的最大值 +// if(pool_temp <= conv_rlst[row*100+col+x*100+y+n*(100*100)]) +// pool_temp = conv_rlst[row*100+col+x*100+y+n*(100*100)]; +// } +// } +// // 将最大值存入池化结果数组 +// pool_rslt[(row/2)*50+col/2+n*(50*50)] = pool_temp; +// } +// } +// } +// + + + + + + + + + + + +//// 隐藏层参数地址 +// float *affine1_w; // 指向第一个全连接层权重的内存地址的指针 +// float *affine1_b; // 指向第一个全连接层偏置的内存地址的指针 +// affine1_param_init(); // 初始化全连接层参数 +// float *affine1_rslt; // 指向存储隐藏层计算结果的内存地址的指针 +// float affine1_temp; // 临时变量,用于存储全连接层的中间结果 +// +//// 遍历100个神经元(假设隐藏层有100个神经元) +// for(int n=0; n<100; n++) +// { +// affine1_temp = 0; // 每个神经元的输出初始化为0 +// +// // 进行矩阵乘法,将池化层输出展平为一维向量后,与全连接层权重进行点积 +// for(int i=0; i<4320; i++) +// { +// affine1_temp = affine1_temp + pool_rslt[i] * affine1_w[i+4320*n]; +// } +// +// // 加上对应神经元的偏置 +// affine1_temp = affine1_temp + affine1_b[n]; +// +// // 激活函数:ReLU(将小于0的值设为0) +// if(affine1_temp > 0) +// affine1_rslt[n] = affine1_temp; // 如果结果大于0,存入结果数组 +// else +// affine1_rslt[n] = 0; // 否则存入0 +// } +// +// +// +// float *affine2_w; // 指向第二个全连接层(输出层)权重的内存地址的指针 +// float *affine2_b; // 指向第二个全连接层(输出层)偏置的内存地址的指针 +// float affine2_temp; // 临时变量,用于存储输出层的中间结果 +// affine2_param_init(); // 初始化输出层参数 +// +// float affine2_rslt[10]; // 存储输出层的结果(假设输出层有10个神经元) +// +//// 比较输出层的最大值 +// float temp = -100; // 用于存储最大值的临时变量,初始化为一个非常小的值 +// int predict_num; // 用于存储预测的数字(对应最大值的索引) +// +//// 遍历10个输出神经元(假设有10个类别) +// for(int n=0; n<10; n++) +// { +// affine2_temp = 0; // 当前神经元的输出初始化为0 +// +// // 进行矩阵乘法,将隐藏层的输出与输出层权重进行点积 +// for(int i=0; i<100; i++) +// { +// affine2_temp = affine2_temp + affine2_w[i+100*n] * affine1_rslt[i]; +// } +// +// // 加上对应神经元的偏置 +// affine2_temp = affine2_temp + affine2_b[n]; +// affine2_rslt[n] = affine2_temp; // 存储输出层的结果 +// +// // 寻找最大值 +// if(temp <= affine2_rslt[n]) +// { +// temp = affine2_rslt[n]; // 更新最大值 +// predict_num = n; // 记录最大值对应的类别索引 +// } +// } + return 0; +} diff --git a/cnn.h b/cnn.h index 382535c..5d72551 100644 --- a/cnn.h +++ b/cnn.h @@ -1,6 +1,7 @@ #ifndef _CNN_H_ #define _CNN_H_ - +#include "cnn_model.h" +#include diff --git a/cnn_model.h b/cnn_model.h index 08c1e82..aa7ef5a 100644 --- a/cnn_model.h +++ b/cnn_model.h @@ -29,7 +29,7 @@ typedef struct { #define FC1_WEIGHT_ARRSIZE (128*18432) //2359296 #define FC2_BIAS_ARRSIZE (7) #define FC2_WEIGHT_ARRSIZE (7*128) //896 -#define DATA_ARRSIZE (1250000) //1250000 +#define DATA_ARRSIZE (100*100) //1250000 diff --git a/main.c b/main.c index 485f076..2161761 100644 --- a/main.c +++ b/main.c @@ -1,20 +1,20 @@ +//// +//// Created by Qi on 2024/11/9. +//// // -// Created by Qi on 2024/11/9. +//#include "cnn_model.h" // - -#include "cnn_model.h" - -void main(){ - u8 res; - model_init(); - model_write("all"); - model_switchdata("C1autosave00095_right_new_2"); - - - - - - - model_info("all"); - DEBUG_PRINTF("\r\nEnd结束"); -} \ No newline at end of file +//void main(){ +// u8 res; +// model_init(); +// model_write("all"); +// model_switchdata("C1autosave00095_right_new_2"); +// +// +// +// +// +// +// model_info("all"); +// DEBUG_PRINTF("\r\nEnd结束"); +//} \ No newline at end of file