Files
stm32-cnn/PORTING/CNN/cnn.c
2024-12-19 14:06:05 +08:00

397 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "cnn.h"
u8 isrun;
void _cnn_run(){
isrun = 1;
}
void print_rslt(float* rslt, u8 input_matrix_length, u32 length){
int _tmp = 0;
printf("[0:0]");
for (int i = 0; i < length; i++) {
printf("%f ",rslt[i]);
if ((i + 1) % input_matrix_length == 0) {
printf("\n[%d:%d]",++_tmp,i+1);
}
}
printf("\r\n");
}
// 将原始矩阵复制到填充后的矩阵中央
float* expand(const float* old_matrix, int old_matrix_length, int layer){
float* new_matrix = (float *)mymalloc(SRAMEX,sizeof(float)*layer*(old_matrix_length+2)*(old_matrix_length+2));
memset(new_matrix, 0, sizeof(float)*layer*(old_matrix_length+2)*(old_matrix_length+2));
for(int l=0; l < layer; l++){
for (int i = 0; i < old_matrix_length; i++) {
for (int j = 0; j < old_matrix_length; j++) {
new_matrix[(i + 1) * (old_matrix_length+2) + (j + 1) +
l * (old_matrix_length+2) * (old_matrix_length+2)]
= old_matrix[i * old_matrix_length + j +
l * (old_matrix_length) * (old_matrix_length)];
}
}
}
return new_matrix;
}
//model 模型名字
//input_matrix 输入图像
//input_matrix_length 输入图像的边长102
//c_rl 输出图像的边长100
//返回卷积的结果
float* convolution(Model model_w, Model model_b, const float* input_matrix, int input_matrix_length){
// 初始化卷积层参数
int im_l = input_matrix_length;
int cr_l = input_matrix_length - 2;
float conv_temp; // 临时变量,用于存储卷积计算的中间结果
//用于合并前的数组具有32*64*50*50(第二层)的大小
float* _conv_rlst = (float *) mymalloc(SRAMEX,sizeof (float) * model_w.num_kernels * (cr_l * cr_l));
memset(_conv_rlst, 0, sizeof (float) * model_w.num_kernels * (cr_l * cr_l));
//子图合并后的数组
float* conv_rlst = (float *) mymalloc(SRAMEX,sizeof (float) * model_w.num_kernels * (cr_l * cr_l));
memset(conv_rlst, 0, sizeof (float) * model_w.num_kernels * (cr_l * cr_l));
// 遍历30个卷积核假设有30个通道
for(int c=0; c < model_w.channel; c++){
for(int k=0; k < model_w.num_kernels; k++){
for(int row = 0; row < cr_l; row++) {
for (int col = 0; col < cr_l; col++) {
conv_temp = 0; // 每个输出像素初始化为0
// 进行3x3的卷积操作
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
// 将输入图像的对应像素与卷积核权重相乘并累加到conv_temp
conv_temp += input_matrix[(c*im_l*im_l) + (row*(im_l)+col) + (x*(im_l)+y)]
* model_w.array[((c+k*model_w.channel)*3*3) + (x*3+y)];
}
}
_conv_rlst[(k*cr_l*cr_l) + (row*cr_l+col)] = conv_temp;
}
}
}
//合并子图
for(int k=0; k < model_w.num_kernels; k++) {
for (int row = 0; row < cr_l; row++) {
for (int col = 0; col < cr_l; col++) {
conv_rlst[(k*cr_l*cr_l) + (row*cr_l+col)] += _conv_rlst[(k*cr_l*cr_l) + (row*cr_l+col)];
}
}
}
}
for(int k=0; k < model_w.num_kernels; k++) {
for (int row = 0; row < cr_l; row++) {
for (int col = 0; col < cr_l; col++) {
conv_temp = conv_rlst[(k * cr_l * cr_l) + (row * cr_l + col)];
// 加上对应卷积核的偏置
conv_temp += model_b.array[k];
// 激活函数ReLU将小于0的值设为0
if (conv_temp > 0)
conv_rlst[(k * (cr_l * cr_l)) + (row * cr_l) + (col)] = conv_temp; // 如果卷积结果大于0存入结果数组
else
conv_rlst[(k * (cr_l * cr_l)) + (row * cr_l) + (col)] = 0; // 否则存入0
}
}
}
myfree(SRAMEX,_conv_rlst);
_conv_rlst = NULL;
return conv_rlst;
}
//num_kernels 卷积核的个数32
//area 池化的面积2*2
//input_matrix 输入图像
//input_matrix_length 输入图像的边长100
//输出图像的边长50
//返回池化的结果
float* pooling(Model model_w, const float* input_matrix, u8 input_matrix_length){
u8 im_l = input_matrix_length;
float pool_temp = 0; // 临时变量,用于存储池化操作的最大值
float* pool_rslt = (float *) mymalloc(SRAMEX,sizeof (float)*model_w.num_kernels*im_l*im_l);
memset(pool_rslt, 0, sizeof (float)*model_w.num_kernels*im_l*im_l);
// 遍历30个通道与卷积核数量相同
for(u8 n=0; n<model_w.num_kernels; n++)
{
// 遍历输入图像的每一行步长为22x2的池化窗口
for(u8 row=0; row<im_l; row=row+2)
{
// 遍历输入图像的每一列步长为2
for(u8 col=0; col<im_l; col=col+2)
{
pool_temp = 0; // 每个池化区域的最大值初始化为0
// 进行2x2的最大池化操作
for(u8 x=0; x<2; x++)
{
for(u8 y=0; y<2; y++)
{
// 更新当前池化区域的最大值
if(pool_temp <= input_matrix[row*im_l+col+x*im_l+y+n*(im_l*im_l)])
pool_temp = input_matrix[row*im_l+col+x*im_l+y+n*(im_l*im_l)];
}
}
// 将最大值存入池化结果数组
pool_rslt[(row/2)*(im_l/2)+col/2+n*((im_l/2)*(im_l/2))] = pool_temp;
}
}
}
return pool_rslt;
}
float* hidden(const float* input_matrix){
float affine1_temp; // 临时变量,用于存储全连接层的中间结果
float *affine1_rslt = (float *) mymalloc(SRAMEX,sizeof(float)*128);
memset(affine1_rslt, 0, sizeof(float)*128);
// 遍历128个神经元假设隐藏层有128个神经元
for(u8 n=0; n<128; n++)
{
affine1_temp = 0; // 每个神经元的输出初始化为0
// 进行矩阵乘法,将池化层输出展平为一维向量后,与全连接层权重进行点积
for(int i=0; i<(128*12*12); i++)
{
affine1_temp = affine1_temp + input_matrix[i] * fc1_weight.array[i+(128*12*12)*n];
}
// 加上对应神经元的偏置
affine1_temp = affine1_temp + fc1_bias.array[n];
// 激活函数ReLU将小于0的值设为0
if(affine1_temp > 0)
affine1_rslt[n] = affine1_temp; // 如果结果大于0存入结果数组
else
affine1_rslt[n] = 0; // 否则存入0
}
// print_rslt(affine1_rslt,1,128);
return affine1_rslt;
}
float* output(Model model_w, const float* input_matrix){
u8 num = model_w.num_kernels;
float affine2_temp; // 临时变量,用于存储输出层的中间结果
float *affine2_rslt = (float *) mymalloc(SRAMEX,(sizeof(float)*num));
memset(affine2_rslt, 0, sizeof(float)*num);
// 遍历10个输出神经元假设有10个类别
for(int n=0; n<num; n++)
{
affine2_temp = 0; // 当前神经元的输出初始化为0
// 进行矩阵乘法,将隐藏层的输出与输出层权重进行点积
for(int i=0; i<128; i++)
{
affine2_temp = affine2_temp + fc2_weight.array[i+128*n] * input_matrix[i];
}
// 加上对应神经元的偏置
affine2_temp = affine2_temp + fc2_weight.array[n];
affine2_rslt[n] = affine2_temp; // 存储输出层的结果
}
return affine2_rslt;
}
void calculate_statistics(Model model, float* value)
{
value[0] = fabsf(model.array[0]);
float sum = 0;
float sum_sq = 0;
for (int i = 0; i < model.maxlength; i++) {
float abs_val = fabsf(model.array[i]);
if (abs_val > value[0]) {
value[0] = abs_val;
}
sum += abs_val;
sum_sq += abs_val * abs_val;
}
value[1] = sum / (float)model.maxlength;
float variance = (sum_sq / (float)model.maxlength) - (value[1] * value[1]);
value[2] = sqrtf(variance);
}
u8 check_threshold(Model model, const float* value)
{
const float threshold = 20;
for (int i = 0; i < model.maxlength; i++) {
float K = (fabsf(model.array[i]) - value[1]) / value[2];
if (K > threshold) {
return 1;
}
}
return 0;
}
float* generateMatrix(Model model, const float* value)
{
float* CNN_data = (float*) mymalloc(SRAMEX,sizeof(float)*100*100);
memset(CNN_data, 0, sizeof(float)*100*100);
u16 x = model.maxlength / 100;
float y = value[0] / 100;
for (int i = 0; i < model.maxlength; i++) {
float absolutevalue = fabsf(model.array[i]);
if (!absolutevalue) {
continue;
}
int xIndex = i / x;
if (xIndex >= 100) xIndex = 99;
int yIndex = (int)(absolutevalue / y);
if (yIndex < 0) yIndex = 0;
CNN_data[yIndex * 100 + xIndex]++;
}
return CNN_data;
}
float calculate_probabilities(Model model_w, float *input_array)
{
float sum = 0;
u8 input_num = model_w.num_kernels;
float *result = (float *) mymalloc(SRAMEX,sizeof(float)*input_num);
memset(result, 0, sizeof(float)*input_num);
float *temp = (float *) mymalloc(SRAMEX,sizeof(float)*input_num);
memset(temp, 0, sizeof(float)*input_num);
for (int i = 0; i < input_num; i++)
{
temp[i] = expf(input_array[i]);
sum = sum + temp[i];
}
for (int j = 0; j < input_num; j++)
{
result[j] = temp[j] / sum;
if(isnan(result[j]))result[j] = 1;
}
int max_index = 0;
float max_value = result[0];
for (int k = 1; k < input_num; k++)
{
if (result[k] > max_value)
{
max_value = result[k];
max_index = k;
}
}
float _tmp = result[max_index] * 100;
myfree(SRAMEX,temp);
temp = NULL;
myfree(SRAMEX,result);
result = NULL;
return _tmp;
}
u8 calculate_layer(Model model_w, float *input_array){
u8 input_num = model_w.num_kernels;
u8 predict_num = 0;
float max_temp = -100;
for(int n=0; n<input_num; n++)
{
if(max_temp <= input_array[n])
{
max_temp = input_array[n]; // 更新最大值
predict_num = n; // 记录最大值对应的类别索引
}
}
print_rslt(input_array,input_num,input_num);
return predict_num+0;
}
void cnn_run(){
float value[3] = {0};
calculate_statistics(data,&value[0]);
if (check_threshold(data,&value[0])){
//初始化生成100 * 100 矩阵
float* _data = generateMatrix(data,&value[0]);
char kind[50];
DEBUG_PRINTF("检测到放电!最大值:%f 平均值:%f 标准差:%f\r\n",value[0],value[1],value[2]);
DEBUG_PRINTF("将原始数据存入SD卡中\r\n");
SDRAM_TO_SD();
char* _uuid = uuid();
// CSTX_4G_RegALiYunIOT(1); //订阅到物模型 用于数据的上报
// send_blocks(_data,_uuid);
//第一层填充102 * 102
DEBUG_PRINTF("第一层开始\n");
float* expand_matrix_1 = expand(_data, 100, 1);
float* conv_rlst_1 = convolution(conv1_weight,conv1_bias,expand_matrix_1, 102);
float* pool_rslt_1 = pooling(conv1_weight, conv_rlst_1, 100);
myfree(SRAMEX,_data);
_data = NULL;
myfree(SRAMEX,expand_matrix_1);
expand_matrix_1 = NULL;
myfree(SRAMEX,conv_rlst_1);
conv_rlst_1 = NULL;
//第二层填充32 * 52 * 52
DEBUG_PRINTF("第二层开始\n");
float* expand_matrix_2 = expand(pool_rslt_1, 50, 32);
float* conv_rlst_2 = convolution(conv2_weight,conv2_bias,expand_matrix_2, 52);
float* pool_rslt_2 = pooling(conv2_weight, conv_rlst_2, 50);
myfree(SRAMEX,pool_rslt_1);
pool_rslt_1 = NULL;
myfree(SRAMEX,expand_matrix_2);
expand_matrix_2 = NULL;
myfree(SRAMEX,conv_rlst_2);
conv_rlst_2 = NULL;
//第三层:填充 64 * 27 * 27
DEBUG_PRINTF("第三层开始\n");
float* expand_matrix_3 = expand(pool_rslt_2, 25, 64);
float* conv_rlst_3 = convolution(conv3_weight,conv3_bias,expand_matrix_3, 27);
float* pool_rslt_3 = pooling(conv3_weight, conv_rlst_3, 25);
myfree(SRAMEX,pool_rslt_2);
pool_rslt_2 = NULL;
myfree(SRAMEX,expand_matrix_3);
expand_matrix_3 = NULL;
myfree(SRAMEX,conv_rlst_3);
conv_rlst_3 = NULL;
DEBUG_PRINTF("第四层开始\n");
float* affine1_rslt = hidden(pool_rslt_3);
DEBUG_PRINTF("第五层开始\r\n");
float* affine2_rslt = output(fc2_weight, affine1_rslt);
DEBUG_PRINTF("概率:%f\r\n",calculate_probabilities(fc2_weight, affine2_rslt));
DEBUG_PRINTF("Label is:%d\r\n",calculate_layer(fc2_weight, affine2_rslt));
// snprintf(kind, 50,"UUID:%s P:%f Label:%d", _uuid, calculate_probabilities(fc2_weight, affine2_rslt), calculate_layer(fc2_weight, affine2_rslt));
// CSTX_4G_ALiYunIOTSenddata_string(kind,"kind_string");
// CSTX_4G_RegALiYunIOT(0); //接收下发时间 信号
myfree(SRAMEX,pool_rslt_3);
pool_rslt_3 = NULL;
myfree(SRAMEX,affine1_rslt);
affine1_rslt = NULL;
myfree(SRAMEX,affine2_rslt);
affine2_rslt = NULL;
} else{
DEBUG_PRINTF("未放电!最大值:%f 平均值:%f 标准差:%f\r\n",value[0],value[1],value[2]);
}
}