使用英特尔MKL进行3D卷积

空军基地

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

该3D数组以列方式存储为类型的1D数组double同样,内核是类型,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并防止它们被修改(我稍后需要在我的代码中使用它们),然后进行向后计算in-place

当我比较从我的代码获得的结果与MATLAB它们获得的结果时,它们有很大的不同。有人可以帮我解决问题吗?我的代码中缺少什么?

这是MATLAB我使用代码:

a = ones( 10, 10, 10 );
kernel = ones( 3, 3, 3 );
aconvolved = convn( a, kernel, 'same' );

这是我的C/C++代码:

#include <stdio.h>
#include "mkl.h"

void Conv3D(
    double *in, double *ker, double *out,
    int nRows, int nCols, int nHeights)
{

    int NI = nRows;
    int NJ = nCols;
    int NK = nHeights;

    double *in_fft  = new double [NI*NJ*NK];
    double *ker_fft = new double [NI*NJ*NK];

    DFTI_DESCRIPTOR_HANDLE fft_desc = 0;
    MKL_LONG sizes[]   = { NK, NJ, NI };
    MKL_LONG strides[] = { 0, NJ*NI, NI, 1 };

    DftiCreateDescriptor( &fft_desc, DFTI_DOUBLE, DFTI_REAL, 3, sizes     );
    DftiSetValue        (  fft_desc, DFTI_PLACEMENT     , DFTI_NOT_INPLACE);   // Out-of-place computation.
    DftiSetValue        (  fft_desc, DFTI_INPUT_STRIDES , strides         );
    DftiSetValue        (  fft_desc, DFTI_OUTPUT_STRIDES, strides         );
    DftiSetValue        (  fft_desc, DFTI_BACKWARD_SCALE, 1/NI/NJ/NK      );
    DftiCommitDescriptor(  fft_desc );

    DftiComputeForward  (  fft_desc, in , in_fft  );
    DftiComputeForward  (  fft_desc, ker, ker_fft );

    for (long long i = 0; i < (long long)NI*NJ*NK; ++i )
        out[i] = in_fft[i]*ker_fft[i];

    // In-place computation.
    DftiSetValue        (  fft_desc, DFTI_PLACEMENT, DFTI_INPLACE );
    DftiCommitDescriptor(  fft_desc      );
    DftiComputeBackward (  fft_desc, out );

    DftiFreeDescriptor  ( &fft_desc );

    delete[] in_fft;
    delete[] ker_fft;

}

int main(int argc, char* argv[])
{
    int n = 10;
    int nkernel = 3;

    double *a          = new double [n*n*n]; // This array is real.
    double *aconvolved = new double [n*n*n]; // The convolved array is also real.
    double *kernel     = new double [nkernel*nkernel*nkernel]; // kernel is real.

    // Fill the array with some 'real' numbers.
    for( int i = 0; i < n*n*n; i++ )
        a[ i ] = 1.0;

    // Fill the kernel with some 'real' numbers.
    for( int i = 0; i < nkernel*nkernel*nkernel; i++ )
        kernel[ i ] = 1.0;

    // Calculate the convolution.
    Conv3D( a, kernel, aconvolved, n, n, n );

    printf("Convolved:\n");
    for( int i = 0; i < n*n*n; i++ )
        printf( "%15.8f\n", aconvolved[i] );

    delete[] a;
    delete[] kernel;
    delete[] aconvolved;

    return 0;
}
查普

您无法使用实值频率数据(仅幅度)反转FFT。前向FFT需要输出复杂数据。这是通过将DFTI_FORWARD_DOMAIN设置设置为来完成的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如上所述)。

另请注意,为避免出现伪影,您希望在每个维度上,ftf的大小至少为M + N-1。通常,您会选择第二高的幂作为速度。

我强烈建议您首先使用FFT在MATLAB中实现它。有许多这样的实现方式(示例),但是我将从基础知识入手,自行完成一个简单的功能。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

使用 Eigen + 英特尔 MKL + Pardiso

来自分类Dev

将 gfortran 与英特尔 MKL 链接

来自分类Dev

英特尔Vtune Profiler:使用Sudo进行远程分析

来自分类Dev

关于如何使用英特尔MKL FFT,是否有任何简单的C ++示例?

来自分类Dev

如何链接英特尔MKL库,仅使用cblas_dgemm函数

来自分类Dev

如何使用Eclipse --start-group --end-group链接英特尔MKL

来自分类Dev

如何链接英特尔MKL库,仅使用cblas_dgemm函数

来自分类Dev

英特尔MKL cblas_dgemm文档错误?

来自分类Dev

FASM是否使用英特尔语法?

来自分类Dev

Pyinstaller numpy“英特尔MKL致命错误:无法加载mkl_intel_thread.dll”

来自分类Dev

在英特尔编程?

来自分类Dev

使用共享内存与CUDA进行3D卷积

来自分类Dev

使用英特尔应用程序框架进行离线缓存?

来自分类Dev

使用英特尔的数学内核库进行特征分解的运行时问题

来自分类Dev

使用英特尔视频卡进行apt-get升级后,“找不到屏幕”

来自分类Dev

借助英特尔SGX进行本地认证

来自分类Dev

在使用替代品英特尔内部函数SSSE3时性能下降

来自分类Dev

检测是否在 Visual Studio 项目的属性中启用了英特尔 MKL

来自分类Dev

英特尔DG33BU 3声哔哔声

来自分类Dev

英特尔Edison模块

来自分类Dev

英特尔XDK + jsPDF

来自分类Dev

英特尔SSD术语

来自分类Dev

英特尔Nextbook降级

来自分类Dev

英特尔XDK信息

来自分类Dev

英特尔媒体SDK:关于mfxIMPL的使用

来自分类Dev

英特尔XDK-使用演示-选项为空

来自分类Dev

英特尔®TinyCrypt:如何使用AES-128 / CTR

来自分类Dev

使用英特尔编译器构建Boost库

来自分类Dev

开始学习如何使用英特尔XDK的最佳场所

Related 相关文章

热门标签

归档