完成卷积功能

This commit is contained in:
Qiea
2024-11-10 17:10:32 +08:00
parent 271bd6efa1
commit 266ad428f0
4 changed files with 214 additions and 20 deletions

193
cnn.c
View File

@@ -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++)
// {
// // 遍历输入图像的每一行步长为22x2的池化窗口
// 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;
}

3
cnn.h
View File

@@ -1,6 +1,7 @@
#ifndef _CNN_H_
#define _CNN_H_
#include "cnn_model.h"
#include <stdio.h>

View File

@@ -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

36
main.c
View File

@@ -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结束");
}
//void main(){
// u8 res;
// model_init();
// model_write("all");
// model_switchdata("C1autosave00095_right_new_2");
//
//
//
//
//
//
// model_info("all");
// DEBUG_PRINTF("\r\nEnd结束");
//}