Hur kan MLK göra så snabba matrismultiplikationer?

Permalänk
Skrivet av Elgot:

Man behöver inte veta så mycket. Du behöver inkludera fftw3f.h och sedan länka till fftw3f.lib (windows) eller libfftw3f (linux) eller mkl. Om biblioten inte finns i systemet kan man bygga dem genom att köra cmake.

Ja, licenser kan ju däremot vara ett problem men man borde komma runt det om man använder mkl.

Jag har redan MKL. MKL fungerar bra...men den är för C99 om man vill ha det i komplex format. Men den har stöd för ANSI C om man klipper och klistrar lite med 2 extra element i en array.

Men jag tyckte att MKL var inge snabb. Den var seg.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Jag har redan MKL. MKL fungerar bra...men den är för C99 om man vill ha det i komplex format. Men den har stöd för ANSI C om man klipper och klistrar lite med 2 extra element i en array.

Du behöver dock som sagt inte ändra i koden; fortsätt att köra fftw-arrayer (som är ansi-c) och länka bara till mkl istället för fftw.

Skrivet av heretic16:

Men jag tyckte att MKL var inge snabb. Den var seg.

I det här fallet verkar faktiskt mkl lite snabbare. 190 ms mot 250 ms för fftw.

Det här programmet bör du kunna bygga direkt och länka till mkl eller fftw:

//#include <fftw3.h> typedef float fftwf_complex[2]; struct fftwf_plan_s; typedef struct fftwf_plan_s* fftwf_plan; int __cdecl fftwf_int_threads(); void __cdecl fftwf_plan_with_nthreads(int nthreads); int __cdecl fftwf_import_wisdom_from_filename(const char* filename); int __cdecl fftwf_export_wisdom_to_filename(const char* filename); fftwf_complex* fftwf_alloc_complex(size_t n); fftwf_plan __cdecl fftwf_plan_dft_2d(int n0, int n1, fftwf_complex* in, fftwf_complex* out, int sign, unsigned flags); void __cdecl fftwf_destroy_plan(fftwf_plan plan); void __cdecl fftwf_free(void* p); void __cdecl fftwf_cleanup_threads(); #define FFTW_FORWARD (-1) #define FFTW_BACKWARD (+1) #define FFTW_MEASURE (0U) #define FFTW_DESTROY_INPUT (1U << 0) #define FFTW_UNALIGNED (1U << 1) #define FFTW_CONSERVE_MEMORY (1U << 2) #define FFTW_EXHAUSTIVE (1U << 3) /* NO_EXHAUSTIVE is default */ #define FFTW_PRESERVE_INPUT (1U << 4) /* cancels FFTW_DESTROY_INPUT */ #define FFTW_PATIENT (1U << 5) /* IMPATIENT is default */ #define FFTW_ESTIMATE (1U << 6) #define FFTW_WISDOM_ONLY (1U << 21) #include <stdlib.h> #include <stdio.h> #include <time.h> const int fftSize = 5000; fftwf_complex* fftInput; fftwf_complex* fftOutput; fftwf_plan fftPlan; int main(int argc, char* argv[]) { // fftwf_init_threads(); // fftwf_plan_with_nthreads(4); fftwf_import_wisdom_from_filename("wisdom.dat"); fftInput = fftwf_alloc_complex(fftSize * fftSize); fftOutput = fftwf_alloc_complex(fftSize * fftSize); fftPlan = fftwf_plan_dft_2d(fftSize, fftSize, fftInput, fftOutput, FFTW_FORWARD, FFTW_MEASURE | FFTW_PRESERVE_INPUT); fftwf_export_wisdom_to_filename("wisdom.dat"); for (int i = 0; i < fftSize * fftSize; ++i) { fftInput[i][0] = rand() % 1000000; fftInput[i][1] = rand() % 1000000; } clock_t start, end; double cpu_time_used; start = clock(); const int N = 10; for (int q = 0; q < N; ++q) fftwf_execute(fftPlan); end = clock(); cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; printf("CPU Time used: %f seconds\n", cpu_time_used/N); fftwf_destroy_plan(fftPlan); fftwf_free(fftInput); fftwf_free(fftOutput); // fftwf_cleanup_threads(); }

Om du länkar till mkl behöver du inte befatta dig med fftw alls.

Permalänk

En nyfiken fråga!

Om jag har en 3x3 kärna t.ex. Sobel och ska göra gradientanalys. Då kan jag använda FFT.
Vad är då snabbast. Två for-loopar som jämför hur mycket ena pixeln skiljer sig från andra pixeln.

Vad är då snabbast. FFT2D eller två for-loopar som loopar igenom en m*n matris med en 3x3 kärna?

Permalänk

Vi kan ta t.ex detta exempel.

Vad är snabbast här? Om jag använder vanlig conv2 funktion som bygger på 4 eller mer, for-satser, eller om jag använder FFT2D?
Tänk på att FFT2D kräver också en hel del beräkningar då FFT2D använder sig av FFT1D och transponerat.

% compute harris corner score function H = harris(I) I = double(I); % parameters sigma=2; r = 6; % gradient kernel dx = [-1 0 1; -1 0 1; -1 0 1]; % The Mask dy = dx'; % main Ix = conv2(I, dx, 'same'); Iy = conv2(I, dy, 'same'); g = fspecial('gaussian',max(1,fix(6*sigma)), sigma); %%%%%% Gaussien Filter Ix2 = conv2(Ix.^2, g, 'same'); Iy2 = conv2(Iy.^2, g, 'same'); Ixy = conv2(Ix.*Iy, g,'same'); k = 0.04; Hp = (Ix2.*Iy2 - Ixy.^2) - k*(Ix2 + Iy2).^2; H = (10000/max(abs(Hp(:))))*Hp; % set edges zeros H(1:r,:) = 0; H(:,1:r) = 0; H(end-r+1:end,:) = 0; H(:,end-r+1:end) = 0; end

Permalänk

Här kommer en uppdatering:

Beräkningar med olika metoder som använder FFT 2D tar ca 0.45 sekunder totalt med FFTPack från Pretty Fast FFT.
Beräkningar med olika metoder som använder FFT 2D tar ca 0.075 sekunder totalt med FFT från MKL.

Så MKL är en solklar vinnare när det kommer till 2D. Annars så är FFTPack från Pretty Fast FFT snabbare när det kommer till 1D, jämfört med MKL.

Det gäller dock bara mindre matriser och vektorer. T.ex. 100 tusen.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Så MKL är en solklar vinnare när det kommer till 2D. Annars så är FFTPack från Pretty Fast FFT snabbare när det kommer till 1D, jämfört med MKL.

Det gäller dock bara mindre matriser och vektorer. T.ex. 100 tusen.

Kanske finns det en statisk fördröjning i anropet? Om du tänker göra många snarlika beräkningar efter varndra kan du minska antalet anrop genom att utföra många beräkningar åt gången.

Permalänk
Skrivet av Elgot:

Kanske finns det en statisk fördröjning i anropet? Om du tänker göra många snarlika beräkningar efter varndra kan du minska antalet anrop genom att utföra många beräkningar åt gången.

Jag tror att det är så att om jag använder FFT 2D med FFTpack från Pretty Fast FFT så utför jag FFT på raderna först, sedan kolumnerna. Så har man många kolumner, ja då blir det många FFT 1D beräkningar. FFTPack version 5.0 har inte stöd för FFT2D. FFTPack 5.1 har stöd för FFT 2D, men denna FFT 2D är inte så optimerad som Pretty Fast FFT är.

Så här ser min FFT.c fil ut. Du får gärna testa och kolla om du kan göra ett test för att kolla skillnaden.

void fft(float xr[], float xi[], size_t n) { #ifdef MKL_FFT_USED /* Load data */ MKL_Complex8* data = (MKL_Complex8*)malloc(n * sizeof(MKL_Complex8)); size_t i; memset(data, 0, n * sizeof(MKL_Complex8)); for (i = 0; i < n; i++) { data[i].real = xr[i]; } /* Prepare FFT */ DFTI_DESCRIPTOR_HANDLE descriptor; DftiCreateDescriptor(&descriptor, DFTI_SINGLE, DFTI_COMPLEX, 1, n); DftiSetValue(descriptor, DFTI_PLACEMENT, DFTI_INPLACE); DftiCommitDescriptor(descriptor); /* Compute FFT */ DftiComputeForward(descriptor, data); /* Load */ for (i = 0; i < n; i++) { xr[i] = data[i].real; xi[i] = data[i].imag; } /* Free */ DftiFreeDescriptor(&descriptor); free(data); #else /* Init */ fftpack_real* wsave = (float*)malloc((2 * n + 15) * sizeof(fftpack_real)); rffti(n, wsave); /* Forward transform */ rfftf(n, xr, wsave); /* Fixing imaginary numbers */ size_t i; memset(xi, 0, n * sizeof(float)); size_t index = 0; xi += 1; for (i = 2; i < n; i += 2) { xi[n - index - 2] = -xr[i]; xi[index++] = xr[i]; xr[i] = 0; } /* Pack */ const size_t half = n/2 + 1; for (i = 2; i < half; i++) { index = i + 1 + (i - 2); xr[i] = xr[index]; } /* Mirror */ index = half - (n % 2 == 0); /* if n % 2 == 0 is true, then 1(even), else 0(odd) */ for (i = half; i < n; i++) { index--; xr[i] = xr[index]; } /* Free */ free(wsave); #endif }

Övrigt så börjar jag närma mig mitt mål med bildklassificering!

Permalänk
Medlem
Skrivet av heretic16:

Jag tror att det är så att om jag använder FFT 2D med FFTpack från Pretty Fast FFT så utför jag FFT på raderna först, sedan kolumnerna. Så har man många kolumner, ja då blir det många FFT 1D beräkningar. FFTPack version 5.0 har inte stöd för FFT2D. FFTPack 5.1 har stöd för FFT 2D, men denna FFT 2D är inte så optimerad som Pretty Fast FFT är.

Så här ser min FFT.c fil ut. Du får gärna testa och kolla om du kan göra ett test för att kolla skillnaden.

void fft(float xr[], float xi[], size_t n) { #ifdef MKL_FFT_USED /* Load data */ MKL_Complex8* data = (MKL_Complex8*)malloc(n * sizeof(MKL_Complex8)); size_t i; memset(data, 0, n * sizeof(MKL_Complex8)); for (i = 0; i < n; i++) { data[i].real = xr[i]; } /* Prepare FFT */ DFTI_DESCRIPTOR_HANDLE descriptor; DftiCreateDescriptor(&descriptor, DFTI_SINGLE, DFTI_COMPLEX, 1, n); DftiSetValue(descriptor, DFTI_PLACEMENT, DFTI_INPLACE); DftiCommitDescriptor(descriptor); /* Compute FFT */ DftiComputeForward(descriptor, data); /* Load */ for (i = 0; i < n; i++) { xr[i] = data[i].real; xi[i] = data[i].imag; } /* Free */ DftiFreeDescriptor(&descriptor); free(data); #else /* Init */ fftpack_real* wsave = (float*)malloc((2 * n + 15) * sizeof(fftpack_real)); rffti(n, wsave); /* Forward transform */ rfftf(n, xr, wsave); /* Fixing imaginary numbers */ size_t i; memset(xi, 0, n * sizeof(float)); size_t index = 0; xi += 1; for (i = 2; i < n; i += 2) { xi[n - index - 2] = -xr[i]; xi[index++] = xr[i]; xr[i] = 0; } /* Pack */ const size_t half = n/2 + 1; for (i = 2; i < half; i++) { index = i + 1 + (i - 2); xr[i] = xr[index]; } /* Mirror */ index = half - (n % 2 == 0); /* if n % 2 == 0 is true, then 1(even), else 0(odd) */ for (i = half; i < n; i++) { index--; xr[i] = xr[index]; } /* Free */ free(wsave); #endif }

Övrigt så börjar jag närma mig mitt mål med bildklassificering!

Bara tiden ger ju inte så mycket information. Har du kört de olika koderna i en profiler för att jämföra i vilka funktioner de spenderar mest tid?

Permalänk
Hedersmedlem
Skrivet av heretic16:

/* Prepare FFT */
DFTI_DESCRIPTOR_HANDLE descriptor;
DftiCreateDescriptor(&descriptor, DFTI_SINGLE, DFTI_COMPLEX, 1, n);
DftiSetValue(descriptor, DFTI_PLACEMENT, DFTI_INPLACE);
DftiCommitDescriptor(descriptor);

Detta kan typiskt ta lite tid, så ett tips är att spara deskriptorn och återanvända den om du behöver göra en likadan beräkning senare. (Och det gäller även i 2d-fallet)

Permalänk
Medlem
Skrivet av Elgot:

Du behöver dock som sagt inte ändra i koden; fortsätt att köra fftw-arrayer (som är ansi-c) och länka bara till mkl istället för fftw.

I det här fallet verkar faktiskt mkl lite snabbare. 190 ms mot 250 ms för fftw.

Det här programmet bör du kunna bygga direkt och länka till mkl eller fftw:

Om du länkar till mkl behöver du inte befatta dig med fftw alls.

Tack för ideen med att länka direkt!

Som nyfiken amatör inom fft/mkl testade jag din kod och länkning. Testade på en gammal laptop med en core duo processor med skillnad till MKL fördel. Jag använde Intel ICX clang/llvm kompilator.
FFTW 0.258474 seconds
MKL 0.176976 seconds

ello@S2~ $ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 39 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 4 On-line CPU(s) list: 0-3 Vendor ID: GenuineIntel Model name: Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz CPU family: 6 Model: 78 Thread(s) per core: 2 Core(s) per socket: 2 Socket(s): 1 Stepping: 3 CPU(s) scaling MHz: 50% CPU max MHz: 2800,0000 CPU min MHz: 400,0000 BogoMIPS: 4800,00 Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmpe rf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ib pb stibp tpr_shadow flexpriority ept vpid ept_ad fsgsbase tsc_adjust sgx bmi1 avx2 smep bmi2 erms invpcid mpx rdseed ad x smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp vnmi md_clear flush_l1d arch_capabilities Virtualization features: Virtualization: VT-x Caches (sum of all): L1d: 64 KiB (2 instances) L1i: 64 KiB (2 instances) L2: 512 KiB (2 instances) L3: 3 MiB (1 instance) NUMA: NUMA node(s): 1 NUMA node0 CPU(s): 0-3 Vulnerabilities: Gather data sampling: Vulnerable: No microcode Itlb multihit: KVM: Mitigation: VMX disabled L1tf: Mitigation; PTE Inversion; VMX conditional cache flushes, SMT vulnerable Mds: Mitigation; Clear CPU buffers; SMT vulnerable Meltdown: Mitigation; PTI Mmio stale data: Mitigation; Clear CPU buffers; SMT vulnerable Retbleed: Vulnerable Spec rstack overflow: Not affected Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Spectre v2: Mitigation; Retpolines, IBPB conditional, IBRS_FW, STIBP conditional, RSB filling, PBRSB-eIBRS Not affected Srbds: Mitigation; Microcode Tsx async abort: Not affected ello@S2~ $ icx test.c -lfftw3 -lfftw3f -o test_fftw ello@S2~ $ ldd test_fftw linux-vdso.so.1 (0x00007ffecefe9000) libfftw3.so.3 => /usr/lib64/glibc-hwcaps/x86-64-v3/libfftw3.so.3.6.10 (0x00007fe563400000) libfftw3f.so.3 => /usr/lib64/glibc-hwcaps/x86-64-v3/libfftw3f.so.3.6.10 (0x00007fe563000000) libm.so.6 => /usr/lib64/glibc-hwcaps/x86-64-v3/libm.so.6 (0x00007fe56367f000) libc.so.6 => /usr/lib64/glibc-hwcaps/x86-64-v3/libc.so.6 (0x00007fe562c00000) /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007fe563791000) ello@S2~ $ ./test_fftw CPU Time used: 0.258474 seconds ello@S2~ $ icx test.c -lmkl_intel_lp64 -qmkl=parallel -lmkl_core -lpthread -lm -o test_mkl ello@S2~ $ ldd test_mkl linux-vdso.so.1 (0x00007f42e1f8d000) libmkl_intel_lp64.so.2 => /opt/intel/oneapi/mkl/2023.2.0/lib/intel64/libmkl_intel_lp64.so.2 (0x00007f42e0a00000) libmkl_core.so.2 => /opt/intel/oneapi/mkl/2023.2.0/lib/intel64/libmkl_core.so.2 (0x00007f42dc600000) libm.so.6 => /usr/lib64/glibc-hwcaps/x86-64-v3/libm.so.6 (0x00007f42dc51c000) libmkl_intel_thread.so.2 => /opt/intel/oneapi/mkl/2023.2.0/lib/intel64/libmkl_intel_thread.so.2 (0x00007f42d8e00000) libiomp5.so => /opt/intel/oneapi/compiler/2023.2.0/linux/compiler/lib/intel64_lin/libiomp5.so (0x00007f42d8800000) libc.so.6 => /usr/lib64/glibc-hwcaps/x86-64-v3/libc.so.6 (0x00007f42d8400000) libdl.so.2 => /usr/lib64/libdl.so.2 (0x00007f42e1f54000) libpthread.so.0 => /usr/lib64/libpthread.so.0 (0x00007f42e1f4f000) /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f42e1f8f000) librt.so.1 => /usr/lib64/librt.so.1 (0x00007f42e1f4a000) libgcc_s.so.1 => /usr/lib64/libgcc_s.so.1 (0x00007f42e1f1f000) ello@S2~ $ ./test_mkl CPU Time used: 0.176976 seconds

Visa signatur

Sweclockers lurker när min plånbok behöver åsikter.

Permalänk
Skrivet av pine-orange:

Bara tiden ger ju inte så mycket information. Har du kört de olika koderna i en profiler för att jämföra i vilka funktioner de spenderar mest tid?

Jag vet inte hur man gör detta i Visual Studio Community 2022.
Hur gör man detta ?

Permalänk
Skrivet av Elgot:

Detta kan typiskt ta lite tid, så ett tips är att spara deskriptorn och återanvända den om du behöver göra en likadan beräkning senare. (Och det gäller även i 2d-fallet)

Tar det tid att deklarera deskriptorn? Det är ju bara lite adressändringar och deklaration av parametrar.

Jo, jag kan återanvända, men då blir koden så spretig. Jag bygger ett bibliotek i C som har samma funktionsargument som Matlab.
Biblioteket ska vara lätt att använda, men även hyfsat snabb.

Vad tror du om FIR istället för FFT?

Permalänk
Hedersmedlem
Skrivet av heretic16:

Tar det tid att deklarera deskriptorn? Det är ju bara lite adressändringar och deklaration av parametrar.

Jo, jag kan återanvända, men då blir koden så spretig. Jag bygger ett bibliotek i C som har samma funktionsargument som Matlab.
Biblioteket ska vara lätt att använda, men även hyfsat snabb.

Det är nog också då den försöker lista ut vilka algoritmer som är optimala för just ditt system och liknande, och är det en snabb FFT kan det bli en märkbar andel av tiden även om det inte handlar om så lång absolut tid.

Du skulle till exempel kunna spara deskriptorn i en statisk variabel och skapa om den om något ändras (eller första gången). Då kan du ha samma anrop som nu men ändå spara tid om du gör många snarlika beräkningar efter varandra.

Permalänk
Skrivet av Elgot:

Det är nog också då den försöker lista ut vilka algoritmer som är optimala för just ditt system och liknande, och är det en snabb FFT kan det bli en märkbar andel av tiden även om det inte handlar om så lång absolut tid.

Du skulle till exempel kunna spara deskriptorn i en statisk variabel och skapa om den om något ändras (eller första gången). Då kan du ha samma anrop som nu men ändå spara tid om du gör många snarlika beräkningar efter varandra.

Ja, fast det skiljer inte så mycket mellan FFTPack och MKL för FFT 1D, ca 5 millisekunder om jag har en 100 tusen lång array. Det är just 2D som det skiljer mellan. Där vinner MKL.

Så jag tror att FFTPack och MKL är i grunden lika optimerad för FFT 1D så det går inte mera.

Om FFTPack tar 0.005 sekunder att utföra en FFT 1D på en 100 tusen lång array, så tar det 0.010 sekunder för MKL att utföra FFT 1D för en lång array. Alltså 50% snabbare, för en 100 tusen lång array.

Så jag tolkar som att MKL går inte att optimera längre. Däremot så är MKL FFT 2D enormt optimerad. Så optimerad att Det märks inte att jag avkommenterar bort FFT2D från MKL under körningen.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Så jag tror att FFTPack och MKL är i grunden lika optimerad för FFT 1D så det går inte mera.

Om FFTPack tar 0.005 sekunder att utföra en FFT 1D på en 100 tusen lång array, så tar det 0.010 sekunder för MKL att utföra FFT 1D för en lång array. Alltså 50% snabbare, för en 100 tusen lång array.

Så jag tolkar som att MKL går inte att optimera längre. Däremot så är MKL FFT 2D enormt optimerad. Så optimerad att Det märks inte att jag avkommenterar bort FFT2D från MKL under körningen.

Fast det är ju lätt att testa. Prova att göra ett typiskt anrop några tusen gånger i en loop och mät hur lång tid det tar (med och utan mkl-initialisering).

Permalänk
Skrivet av Elgot:

Fast det är ju lätt att testa. Prova att göra ett typiskt anrop några tusen gånger i en loop och mät hur lång tid det tar (med och utan mkl-initialisering).

Jag har gjort detta. Det är koden ovan som jag postade.
Där använder jag MKL FFT och sedan använder jag FFTPack.
#20227873

Permalänk
Hedersmedlem
Skrivet av heretic16:

Jag har gjort detta. Det är koden ovan som jag postade.
Där använder jag MKL FFT och sedan använder jag FFTPack.
#20227873

Om du för skojs skull testar detta då

#ifdef MKL_FFT_USED static size_t currentSize = 0; static MKL_Complex8* data = NULL; static DFTI_DESCRIPTOR_HANDLE descriptor = NULL; if(n != currentSize) { if(n > currentSize) { if(data != NULL) free(data); data = (MKL_Complex8*)malloc(n * sizeof(MKL_Complex8)); } currentSize = n; if(descriptor != NULL) DftiFreeDescriptor(&descriptor); DftiCreateDescriptor(&descriptor, DFTI_SINGLE, DFTI_COMPLEX, 1, n); DftiSetValue(descriptor, DFTI_PLACEMENT, DFTI_INPLACE); DftiCommitDescriptor(descriptor); } /* Load data */ size_t i; memset(data, 0, n * sizeof(MKL_Complex8)); for (i = 0; i < n; i++) { data[i].real = xr[i]; } /* Compute FFT */ DftiComputeForward(descriptor, data); /* Load */ for (i = 0; i < n; i++) { xr[i] = data[i].real; xi[i] = data[i].imag; } #else

(jaja, den kanske läcker lite minne och så nu)

Permalänk
Skrivet av Elgot:

Om du för skojs skull testar detta då

#ifdef MKL_FFT_USED static size_t currentSize = 0; static MKL_Complex8* data = NULL; static DFTI_DESCRIPTOR_HANDLE descriptor = NULL; if(n != currentSize) { if(n > currentSize) { if(data != NULL) free(data); data = (MKL_Complex8*)malloc(n * sizeof(MKL_Complex8)); } currentSize = n; if(descriptor != NULL) DftiFreeDescriptor(&descriptor); DftiCreateDescriptor(&descriptor, DFTI_SINGLE, DFTI_COMPLEX, 1, n); DftiSetValue(descriptor, DFTI_PLACEMENT, DFTI_INPLACE); DftiCommitDescriptor(descriptor); } /* Load data */ size_t i; memset(data, 0, n * sizeof(MKL_Complex8)); for (i = 0; i < n; i++) { data[i].real = xr[i]; } /* Compute FFT */ DftiComputeForward(descriptor, data); /* Load */ for (i = 0; i < n; i++) { xr[i] = data[i].real; xi[i] = data[i].imag; } #else

(jaja, den kanske läcker lite minne och så nu)

Exakt samma snabbhet. Blev ingen skillnad.
Jag förstår inte varför detta är relevant? Jag menar, jag kör ju bara FFT 1D en gång redan

Det är bara dumt att köra FFT 1D för FFT 2D. Bättre att använda en funktion som är enbart FFT 2D istället för att köra FFT 1D på alla rader, sedan alla kolumner.

Det vore mer relevant att optimera FFT 2D för FFTPack, istället för att köra FFT 1D för varje kolumn och rad. Tyvärr så är det så FFT2D fungerar.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Exakt samma snabbhet. Blev ingen skillnad.
Jag förstår inte varför detta är relevant? Jag menar, jag kör ju bara FFT 1D en gång redan

Jaha, jag antog att du skulle göra många beräkningar. Om det bara gäller en och det handlar om bråkdelar av sekunder är det kanske inte lönt att lägga så mycket energi på det.

Permalänk
Skrivet av Elgot:

Jaha, jag antog att du skulle göra många beräkningar. Om det bara gäller en och det handlar om bråkdelar av sekunder är det kanske inte lönt att lägga så mycket energi på det.

Ja, precis. Jag gjorde förut FFT 1D flera gånger för att skapa FFT 2D. Det kanske detta du trodde.
Men igår kom jag på att MKL har stöd för FFT 2D.

Denna kod nedan ger exakt samma resultat om Matlab.

Jag använder FFT för att göra gaussisk filtrering av bilder.
Det är så att jag använder en algoritm som heter BRISK https://se.mathworks.com/help/vision/ref/detectbriskfeatures....

Det är lite svårt att läsa orginalpappret om BRISK. Men i grunden så handlar det om att använda sig av FAST (eller AGAST som OpenCV använder, ska tydligen vara en förbättrad version av FAST, men det tvivlar jag på) för att hitta intressepunkter.

Intressepunkter är hörn och kanter. Oavsett hur man roterar bilden, eller skalar bilden, så är dessa intressepunkterna fixerade. När man vet intressepunkterna, vilket är koordinater, då kan man räkna ut SIFT-rotationen kring dessa punkterna. För att göra detta så måste man använda Sobel-filtrering, vilket använder conv2, vilket använder FFT2D.

Men innan man börjar med intressepunkter så måste man använda gaussisk filtrering över bilden, så inte hela bilden är en stor intressepunkt. Gaussisk filtrering använder FFT2D också.

Så FFT2D används väldigt mycket i just att filtrera och ändra i bilder - på gott och ont.
Jag kan förklara hela BRISK om du vill. Det finns en som heter ORB - Oriented FAST Rotated BRIEF, vilket är nästan samma som BRISK, men BRIEF är snabbare, men sämre på skalning.

/* Import the library FFTPack */ #ifndef MKL_FFT_USED #include "FFTpack/fftpack.h" /* Special case when we want to turn complex into complex */ static void complex_to_complex_fft(float xr[], float xi[], size_t n); #endif /* Fast Fourier Transform * XR[m*n] - Real values * XI[m*n] - Imaginary values * This is exactly the same as fft2(A) = fft(fft(A).').' inside Matlab. The .' is very important */ void fft2(float XR[], float XI[], size_t row, size_t column) { #ifdef MKL_FFT_USED /* Load data */ const size_t row_column = row * column; MKL_Complex8* data = (MKL_Complex8*)malloc(row_column * sizeof(MKL_Complex8)); size_t i; MKL_LONG dim_sizes[2] = { row, column }; memset(data, 0, row_column * sizeof(MKL_Complex8)); for (i = 0; i < row_column; i++) { data[i].real = XR[i]; } /* Prepare FFT */ DFTI_NO_ERROR; DFTI_DESCRIPTOR_HANDLE descriptor; DftiCreateDescriptor(&descriptor, DFTI_SINGLE, DFTI_COMPLEX, 2, dim_sizes); DftiSetValue(descriptor, DFTI_PLACEMENT, DFTI_INPLACE); DftiCommitDescriptor(descriptor); /* Compute FFT */ DftiComputeForward(descriptor, data); /* Load */ for (i = 0; i < row_column; i++) { XR[i] = data[i].real; XI[i] = data[i].imag; } /* Free */ DftiFreeDescriptor(&descriptor); free(data); #else /* Transpose XR for column major */ tran(XR, row, column); /* Do FFT on each column of XR and XI */ size_t i, shift; for (i = 0; i < column; i++) { shift = row * i; fft(XR + shift, XI + shift, row); } /* Do transpose */ tran(XR, column, row); tran(XI, column, row); /* Do FFT on each row of XR and XI */ for (i = 0; i < row; i++) { shift = column * i; complex_to_complex_fft(XR + shift, XI + shift, column); } #endif } #ifndef MKL_FFT_USED static void complex_to_complex_fft(float xr[], float xi[], size_t n) { /* Init */ fftpack_real* wsave = (fftpack_real*)malloc((4 * n + 15) * sizeof(fftpack_real)); cffti(n, wsave); /* Backward transform */ fftpack_real* c = (fftpack_real*)malloc(2 * n * sizeof(fftpack_real)); size_t i, index = 0; for (i = 0; i < n; i++) { c[index++] = xr[i]; c[index++] = -xi[i]; /* This is the same as .' in Matlab */ } cfftb(n, c, wsave); /* Fill */ index = 0; for (i = 0; i < n; i++) { xr[i] = c[index++]; xi[i] = -c[index++]; /* This is the same as .' in Matlab */ } /* Free */ free(wsave); free(c); } #endif