[英]Passing 3d arrays to a convolution function in C
我需要執行 function 來執行 2D 卷積,為此我需要將幾個 3d arrays 傳遞給它。但是我被告知我的方法不是執行此操作的理想方法。
首先,我聲明變量:
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;
然后,卷積看起來像這樣:
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
}
}
}
}
}
}
}
}
(這在“卷積”行返回“無法解析字段'img'”)
然后我將這些值導入到正確的結構中(這是我之前的一個問題,已得到回答: Write values to a 3D array inside a struct in C ),我這樣調用 function:
convolution(test_image, test_filter, test_result, 6, 3, 1, 1, 2);
在我之前的問題中有人告訴我,這不是處理 3D arrays 的理想方式,它可能會使用比我預期更多的 memory。 這是一個非常占用內存的過程,並且將在嵌入式系統中運行,因此優化 memory 分配至關重要。
如果可能的話,我的目標是在任何時間點只分配 3D arrays 中的每一個,以免使用不必要的 memory,並以稍后可以釋放此空間的方式進行。
先感謝您。
您可以使用可變長度 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];
}}
}}}
}
典型的用法是:
// 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);
多維 arrays 可以分配為:
float (*arr)[10][20][30] = malloc(sizeof *arr);
但是由於語法(*arr)[i][j][j]
,訪問元素有點麻煩。 因此,使用指向數組第一個元素的指針並在該指針處分配多個子數組很簡單。
float (*arr)[20][30] = malloc(10 * sizeof *arr);
或使用calloc()
自動歸零並避免溢出。
float (*arr)[20][30] = calloc(10, sizeof *arr);
順便提一句。 我建議將 kernel 的尺寸重新排序為 ODEPTH x KSIZE x KSIZE x IDEPTH。 這將使對 kernel 的迭代更加緩存友好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.