C语言卷积函数传递3D数组的实现优化与嵌入式内存适配
2D卷积函数问题修复及嵌入式内存优化方案
1 编译错误修复
你遇到的field 'img' could not be resolved报错原因非常明确:函数形参中的N、M、P都是结构体指针类型,C语言中访问指针指向的结构体成员需要使用->运算符,而非.运算符。将卷积计算行修改为如下内容即可解决:
P->img[a][b][k] += N->img[ii][jj][p] * M->img[m][n][k];
另外现有代码的输出索引a/b计算逻辑存在越界风险,建议直接根据步长计算输出坐标:
int out_size = (size - ksize) / stride + 1; // 循环内部对应输出位置改为 P->img[i/stride][j/stride][k] += ...
可完全避免索引计数错误问题。
2 嵌入式内存优化方案
针对嵌入式场景的内存限制,可从以下维度优化,保证每类3D数组仅占用一份可释放的内存空间:
2.1 替换固定尺寸结构体为动态张量结构
现有结构体写死了数组尺寸,实际使用时如果输入/输出尺寸小于定义值,会造成大量内存浪费。改用带柔性数组的通用张量结构,可实现内存按需分配:
// 通用3D张量结构体,内存连续分配 typedef struct { int w; int h; int c; float data[]; // 柔性数组成员,不占用结构体本身内存 } Tensor3D; // 按需分配张量内存 Tensor3D* alloc_tensor(int w, int h, int c) { Tensor3D* t = malloc(sizeof(Tensor3D) + sizeof(float) * w * h * c); t->w = w; t->h = h; t->c = c; return t; } // 释放张量内存 void free_tensor(Tensor3D* t) { free(t); }
使用该结构后,你调用时传入size=6的输入,就仅分配6x6x1的输入内存,不需要占用224x224x3的固定空间,可节省99%以上的冗余内存,使用完成后直接调用free_tensor释放即可,全程每类张量仅需分配一次。
2.2 无动态内存分配场景的静态优化
如果你的嵌入式平台不支持动态内存分配,可通过宏定义全局静态 buffer 实现固定内存占用:
// 按需调整宏定义的尺寸,全程仅分配一次 #define INPUT_W 224 #define INPUT_H 224 #define INPUT_C 3 #define KERNEL_SIZE 3 #define OUTPUT_W 112 #define OUTPUT_H 112 #define OUTPUT_C 32 static float input_buf[INPUT_H * INPUT_W * INPUT_C]; static float weight_buf[KERNEL_SIZE * KERNEL_SIZE * INPUT_C * OUTPUT_C]; static float output_buf[OUTPUT_H * OUTPUT_W * OUTPUT_C];
静态内存会在程序启动时一次性分配,不需要手动释放,也不会出现重复占用的问题。
2.3 循环逻辑优化减少内存访问开销
调整循环顺序、去掉不必要的边界判断,可减少缓存 miss 率,降低运行时的内存访问压力:
- 将输入/输出的连续内存访问循环放在最内层,提升缓存命中率
- 提前限制输入遍历的起止范围,去掉循环内部的边界判断分支:将
i的遍历范围改为从ksize/2到size - ksize/2,不需要每次判断ii/jj是否越界
3 优化后卷积函数示例
void convolution(Tensor3D* input, Tensor3D* weight, Tensor3D* output, int stride) { int ksize = weight->h; int kcenter = ksize / 2; int out_idx = 0; for (int k = 0; k < output->c; k++) { for (int i = kcenter; i < input->h - kcenter; i += stride) { for (int j = kcenter; j < input->w - kcenter; j += stride) { float sum = 0.0f; for (int m = 0; m < ksize; m++) { for (int n = 0; n < ksize; n++) { int ii = i + m - kcenter; int jj = j + n - kcenter; for (int p = 0; p < input->c; p++) { int input_idx = ii * input->w * input->c + jj * input->c + p; int weight_idx = m * ksize * input->c * output->c + n * input->c * output->c + p * output->c + k; sum += input->data[input_idx] * weight->data[weight_idx]; } } } int out_h = i / stride; int out_w = j / stride; output->data[out_h * output->w * output->c + out_w * output->c + k] = sum; } } } }
内容的提问来源于stack exchange,提问作者Ricardo
相关产品推荐
相关产品推荐

