与英特尔MKL的3D卷积

时间:2014-12-02 06:51:24

标签: c++ c 3d convolution intel-mkl

我编写了一个C/C++代码,该代码使用英特尔MKL来计算具有 300×200×200个元素的数组的3D卷积。我想应用3×3×35×5×5的内核。 3D输入数组和内核都具有实际值。

此3D数组以列方式存储为double类型的1D数组。类似地,内核的类型为double,并以列方式保存。例如,

for( int k = 0; k < nk; k++ ) // Loop through the height.
    for( int j = 0; j < nj; j++ ) // Loop through the rows.
        for( int i = 0; i < ni; i++ ) // Loop through the columns.
        {
            ijk = i + ni * j + ni * nj * k;
            my3Darray[ ijk ] = 1.0;
        }

对于卷积的计算,我想对输入数组和内核执行not-in-place FFT并防止它们被修改(我需要稍后在我的代码中使用它们)然后执行反向计算{ {1}}。

当我将从我的代码中获得的结果与由in-place获得的结果进行比较时,它们是非常不同的。有人可以帮我解决这个问题吗?我的代码中缺少什么?

以下是我使用的MATLAB代码:

MATLAB

这是我的a = ones( 10, 10, 10 ); kernel = ones( 3, 3, 3 ); aconvolved = convn( a, kernel, 'same' ); 代码:

C/C++

1 个答案:

答案 0 :(得分:3)

您无法使用实值频率数据(仅幅度)反转FFT。正向FFT需要输出复杂数据。这可以通过将DFTI_FORWARD_DOMAIN setting设置为DFTI_COMPLEX来完成。

DftiCreateDescriptor( &fft_desc, DFTI_DOUBLE, DFTI_COMPLEX, 3, sizes     );

这样做会隐式地将后向域设置为复杂。

您还需要一种复杂的数据类型。可能是这样的,

MKL_Complex16* in_fft  = new MKL_Complex16[NI*NJ*NK];

这意味着您必须将实部和虚部相乘:

for (size_t i = 0; i < (size_t)NI*NJ*NK; ++i) {
    out_fft[i].real = in_fft[i].real * ker_fft[i].real;
    out_fft[i].imag = in_fft[i].imag * ker_fft[i].imag;
}

逆FFT的输出也很复杂,假设您的输入数据是真实的,您可以抓住.real组件,这就是您的结果。这意味着您将需要一个临时的复杂输出数组(例如,如上所述out_fft)。

另请注意,为了避免瑕疵,您希望fft的大小在每个维度上(至少)M + N-1。一般来说,你会为速度选择2的最高功率。

我强烈建议您先使用FFT在MATLAB中实现它。有许多这样的实现可用(example),但我会从基础开始,并自己做一个简单的功能。