Files
c-cnn/cnn.c
2024-11-10 17:10:32 +08:00

194 lines
6.4 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"
// 将原始矩阵复制到填充后的矩阵中央
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;
}