C++ 用英特尔MKL实现三维卷积
我已经编写了一个C++ 用英特尔MKL实现三维卷积,c++,c,3d,convolution,intel-mkl,C++,C,3d,Convolution,Intel Mkl,我已经编写了一个C/C++代码,它使用英特尔MKL计算一个数组的三维卷积,这个数组大约有300×200×200个元素。我想应用一个内核,它要么是3×3×3要么是5×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++
C/C++
代码,它使用英特尔MKL计算一个数组的三维卷积,这个数组大约有300×200×200
个元素。我想应用一个内核,它要么是3×3×3
要么是5×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;
}
这是我的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;
}
#包括
#包括“mkl.h”
void Conv3D(
双进双出,
整数n行,整数n行,整数n行)
{
int NI=nRows;
int NJ=nCols;
int NK=n重量;
double*in_fft=新的double[NI*NJ*NK];
double*keru fft=新的双精度[NI*NJ*NK];
DFTI描述符处理fft描述=0;
MKL_长尺寸[]={NK,NJ,NI};
MKL_大步[]={0,NJ*NI,NI,1};
DftiCreateDescriptor(&fft_desc,DFTI_DOUBLE,DFTI_REAL,3,大小);
DftiSetValue(fft_desc,DFTI_PLACEMENT,DFTI_NOT_INPLACE);//错位计算。
DftiSetValue(fft_desc,DFTI_输入_步长,步长);
DftiSetValue(fft_desc,DFTI_输出_步长,步长);
DftiSetValue(fft描述,DFTI向后标度,1/NI/NJ/NK);
DftiCommitDescriptor(fft_desc);
DFTIComputerForward(fft_desc,in,in_fft);
DFTIComputerForward(fft_desc,ker,ker_fft);
对于(长i=0;i<(长)NI*NJ*NK;++i)
out[i]=in_fft[i]*ker_fft[i];
//就地计算。
DftiSetValue(fft描述、DFTI放置、DFTI放置);
DftiCommitDescriptor(fft_desc);
DFTICOMPUTER向后(fft_desc,out);
DftiFreeDescriptor(&fft_desc);
删除fft中的[];
删除[]k_fft;
}
int main(int argc,char*argv[])
{
int n=10;
int nkernel=3;
double*a=新的double[n*n*n];//此数组是实数组。
double*a卷积=新的double[n*n*n];//卷积数组也是实数组。
double*kernel=newdouble[nkernel*nkernel*nkernel];//内核是真实的。
//用一些“实数”填充数组。
对于(int i=0;i
不能使用实值频率数据(仅幅度)反转FFT。前向FFT需要输出复杂数据。这是通过将DFTI\U复数设置为
DftiCreateDescriptor( &fft_desc, DFTI_DOUBLE, DFTI_COMPLEX, 3, sizes );
这样做会隐式地将向后域设置为complex
您还需要一个复杂的数据类型。大概是
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;
}
用于(尺寸i=0;i<(尺寸)NI*NJ*NK;++i){
out\u fft[i]。real=in\u fft[i]。real*ker\u fft[i]。real;
out_fft[i].imag=in_fft[i].imag*ker_fft[i].imag;
}
逆FFT的输出也很复杂,假设您的输入数据是真实的,您只需获取.real
分量,这就是您的结果。这意味着您将需要一个临时的复杂输出数组(如上所述,out\u fft
)
还要注意,为了避免伪影,您希望fft的大小在每个维度上(至少)为M+N-1。一般情况下,你会选择下一个最高的两倍的速度
我强烈建议您首先使用FFTs在MATLAB中实现它。有很多这样的实现(),但我会从基础开始,自己做一个简单的函数。我喜欢你的问题,但我无能为力。然而,如果你给了别人期望的结果和你的结果,他们可能会帮助你。
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;
}