简体   繁体   English

将 3d arrays 传递给 C 中的卷积 function

[英]Passing 3d arrays to a convolution function in C

I need to do a function that executes a 2D convolution and for that I need to pass to it a couple of 3d arrays. However I've been told my method is not an ideal way to do this.我需要执行 function 来执行 2D 卷积,为此我需要将几个 3d arrays 传递给它。但是我被告知我的方法不是执行此操作的理想方法。

First, I declare the variables:首先,我声明变量:

typedef struct {
    float img[224][224][3];
} input_224_t;

typedef struct {
    float img[112][112][32];
} input_112_t;

typedef struct {
    float img[3][3][32];
} weightsL1_t;

Then, the convolution looks like this:然后,卷积看起来像这样:

void convolution(input_224_t* N, weightsL1_t* M, input_112_t* P, int size, int ksize, int channels, int filters, int stride)
{
    // Effectively pads the image before convolution. Technically also works for pointwise, but it's inefficient.
    // find center position of kernel (half of kernel size)
    int kcenter = ksize / 2;

    // Declare output indexes
    int a = 0;
    int b = -1;

    for (int k = 0; k < filters; ++k)                   // filters
    {
        for (int i = 0; i < size; i = i + stride)       // rows
        {
            for (int j = 0; j < size; j = j + stride)   // columns
            {
                b++;
                if (b == ksize) {b=0;a++;}              // Increment output index
                for (int m = 0; m < ksize; ++m)         // kernel rows
                {
                    for (int n = 0; n < ksize; ++n)     // kernel columns
                    {
                        // Index of input signal, used for checking boundary
                        int ii = i + (m - kcenter);
                        int jj = j + (n - kcenter);

                        // Ignore input samples which are out of bound
                        if (ii >= 0 && ii < size && jj >= 0 && jj < size) {
                            for (int p = 0; p < channels; ++p)  // channels
                            {
                                P.img[a][b][k] += N.img[ii][jj][p] * M.img[m][n][k];    // convolve
                            }
                        }
                    }
                }
            }
        }
    }
}

(This returns "field 'img' could not be resolved" at the "convolve" line) (这在“卷积”行返回“无法解析字段'img'”)

I then import the values into the correct structs (which was a previous question of mine which has been answered: Write values to a 3D array inside a struct in C ) and I call the function like this:然后我将这些值导入到正确的结构中(这是我之前的一个问题,已得到回答: Write values to a 3D array inside a struct in C ),我这样调用 function:

convolution(test_image, test_filter, test_result, 6, 3, 1, 1, 2);

I have been told in my previous question that this is not an ideal way to handle 3D arrays, and that it may use a lot more memory than I intend.在我之前的问题中有人告诉我,这不是处理 3D arrays 的理想方式,它可能会使用比我预期更多的 memory。 This is a very memory-intensive process, and this will run in an embedded system, so optimizing memory allocation is paramount.这是一个非常占用内存的过程,并且将在嵌入式系统中运行,因此优化 memory 分配至关重要。

My objective, if possible, is to only allocate one of each of these 3D arrays at any point in time as to not use unnecessary memory, and do it in a way that this space can be freed at a later point.如果可能的话,我的目标是在任何时间点只分配 3D arrays 中的每一个,以免使用不必要的 memory,并以稍后可以释放此空间的方式进行。

Thank you in advance.先感谢您。

You could use Variable Length Arrays as function parameters.您可以使用可变长度 Arrays 作为 function 参数。

void convolve(int isize,  // width/height of input (224)
              int osize,  // width/height of output (112)
              int ksize,  // width/height of kernel (3)
              int stride, // shift between input pixels, between consecutive outputs
              int pad,    // offset between (0,0) pixels between input and output
              int idepth, int odepth, // number of input and output channels
              float idata[isize][isize][idepth],
              float odata[osize][osize][odepth],
              float kdata[idepth][ksize][ksize][odepth])

{
  // iterate over the output
  for (int oy = 0; oy < osize; ++oy) {
  for (int ox = 0; ox < osize; ++ox) {
  for (int od = 0; od < odepth; ++od) {
      odata[oy][ox][od] = 0;
      for (int ky = 0; ky < ksize; ++ky) {
      for (int kx = 0; kx < ksize; ++kx) {
          // map position in output and kernel to the input
          int iy = stride * oy + ky - pad;
          int ix = stride * ox + kx - pad;
          // use only valid inputs
          if (iy >= 0 && iy < isize && ix >= 0 && ix < isize)
              for (int id = 0; id < idepth; ++id)
                  odata[oy][ox][od] += kdata[id][ky][kx][od] * idata[iy][ix][id];
      }}
  }}}
}

Typical usage would be:典型的用法是:

// allocate input
float (*idata)[224][3] = calloc(224, sizeof *idata);
// fill input using idata[y][x][d] syntax

// allocate kernel
float (*kdata)[3][3][32] = calloc(3, sizeof *kdata);
// fill kernel

// allocate output
float (*odata)[112][32] = calloc(112, sizeof *odata);

convolve(224, 112, 3, // input, output, kernel size
         2, // stride
         1, // pad input by one pixel what will center the kernel
         3, 32, // number of input and output channels
         idata, odata, kdata);

// free memory if it is no longer used
free(idata); free(odata); free(kdata);

The multidimentional arrays could be allocated with:多维 arrays 可以分配为:

float (*arr)[10][20][30] = malloc(sizeof *arr);

however accessing elements is a bit cumbersome due to syntax (*arr)[i][j][j] .但是由于语法(*arr)[i][j][j] ,访问元素有点麻烦。 Therefore it is simple to use a pointer to the first element of array and allocate multiple subarrays at this pointer.因此,使用指向数组第一个元素的指针并在该指针处分配多个子数组很简单。

float (*arr)[20][30] = malloc(10 * sizeof *arr);

or with calloc() with automated zeroing and avoiding overflows.或使用calloc()自动归零并避免溢出。

float (*arr)[20][30] = calloc(10, sizeof *arr);

BTW.顺便提一句。 I suggest to reorder dimensions of the kernel to ODEPTH x KSIZE x KSIZE x IDEPTH.我建议将 kernel 的尺寸重新排序为 ODEPTH x KSIZE x KSIZE x IDEPTH。 This would make iterating over the kernel more cache-friendly.这将使对 kernel 的迭代更加缓存友好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM