397 lines
13 KiB
C
397 lines
13 KiB
C
#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++)
|
||
{
|
||
// 遍历输入图像的每一行,步长为2(2x2的池化窗口)
|
||
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]);
|
||
}
|
||
}
|