提交 129c21c6 authored 作者: slefrancois's avatar slefrancois

revise fft doc

上级 0a889321
.. _libdoc_gpuarray_fft: .. _libdoc_gpuarray_fft:
=================================================== ==============================================
:mod:`gpuarray.fft` -- Fast Fourier Transforms :mod:`gpuarray.fft` -- Fast Fourier Transforms
=================================================== ==============================================
Performs Fast Fourier Transforms (FFT) on the GPU.
FFT gradients are implemented as the opposite Fourier transform of the output gradients.
.. warning ::
The real and imaginary parts of the Fourier domain arrays are stored as a pair of float32
array, emulating complex64. Since theano does not support complex
number operations, care must be taken to manually implement operators such as complex
multiplication.
.. automodule:: theano.gpuarray.fft .. automodule:: theano.gpuarray.fft
:members: :members: curfft, cuirfft
For example, the code below performs the real input FFT of a box function, which is a sinc function.
The absolute value is plotted, since the phase oscillates due to the box function being
shifted to the middle of the array. The Theano flag ``device=cuda{0,1...}`` must be used.
.. testcode::
import numpy as np
import theano
import theano.tensor as T
from theano.gpuarray import fft
x = T.matrix('x', dtype='float32')
rfft = fft.curfft(x, norm='ortho')
f_rfft = theano.function([x], rfft)
N = 1024
box = np.zeros((1,N), dtype='float32')
box[:, N/2-10: N/2+10] = 1
out = f_rfft(box)
c_out = np.asarray(out[0, :, 0] + 1j*out[0, :, 1])
abs_out = abs(c_out)
.. image:: plot_fft.png
\ No newline at end of file
...@@ -281,18 +281,15 @@ cuirfft_op = CuIRFFTOp() ...@@ -281,18 +281,15 @@ cuirfft_op = CuIRFFTOp()
def curfft(inp, norm=None): def curfft(inp, norm=None):
""" """
Performs the fast Fourier transform of a real-valued output on the GPU Performs the fast Fourier transform of a real-valued input on the GPU.
through the gpuarray backend.
The input must be a real-valued float32 variable of dimensions (m, ..., n). The input must be a real-valued float32 variable of dimensions (m, ..., n).
It performs FFTs of size (..., n) on m batches. It performs FFTs of size (..., n) on m batches.
The output is a GpuArray of dimensions (m, ..., n//2+1, 2). The second to The output is a GpuArray of dimensions (m, ..., n//2+1, 2). The second to
last dimension of the output contains the n//2+1 non-trivial elements of last dimension of the output contains the n//2+1 non-trivial elements of
the real-valued FFTs. The real and imaginary parts are stored as two the real-valued FFTs. The real and imaginary parts are stored as a pair of
float32 arrays, emulating complex64. Since theano does not support complex float32 arrays.
number operations, care must be taken to manually implement operators such
as multiplication.
Parameters Parameters
---------- ----------
...@@ -318,14 +315,12 @@ def curfft(inp, norm=None): ...@@ -318,14 +315,12 @@ def curfft(inp, norm=None):
def cuirfft(inp, norm=None, is_odd=False): def cuirfft(inp, norm=None, is_odd=False):
""" """
Performs the real-valued output inverse Fourier Transform using the Performs the inverse fast Fourier Transform with real-valued output on the GPU.
gpuarray backend.
The input is a variable of dimensions (m, ..., n//2+1, 2) with The input is a variable of dimensions (m, ..., n//2+1, 2) with
type float32 representing the non-trivial elements of m type float32 representing the non-trivial elements of m
real-valued Fourier transforms of initial size (..., n). The real and real-valued Fourier transforms of initial size (..., n). The real and
imaginary parts are stored as two float32 arrays, emulating complex64 imaginary parts are stored as a pair of float32 arrays.
given that Theano does not support complex numbers.
The output is a real-valued float32 variable of dimensions (m, ..., n) The output is a real-valued float32 variable of dimensions (m, ..., n)
giving the m inverse FFTs. giving the m inverse FFTs.
...@@ -344,6 +339,7 @@ def cuirfft(inp, norm=None, is_odd=False): ...@@ -344,6 +339,7 @@ def cuirfft(inp, norm=None, is_odd=False):
is_odd : {True, False} is_odd : {True, False}
Set to True to get a real inverse transform output with an odd last dimension Set to True to get a real inverse transform output with an odd last dimension
of length (N-1)*2 + 1 for an input last dimension of length N. of length (N-1)*2 + 1 for an input last dimension of length N.
""" """
if is_odd not in (True, False): if is_odd not in (True, False):
......
...@@ -9,12 +9,9 @@ from theano.tests import unittest_tools as utt ...@@ -9,12 +9,9 @@ from theano.tests import unittest_tools as utt
import theano.gpuarray.fft import theano.gpuarray.fft
import numpy.fft import numpy.fft
from .config import mode_with_gpu
# Skip tests if pygpu is not available. # Skip tests if pygpu is not available.
from nose.plugins.skip import SkipTest from nose.plugins.skip import SkipTest
from theano.gpuarray.fft import pygpu_available, scikits_cuda_available from theano.gpuarray.fft import pygpu_available, scikits_cuda_available, pycuda_available
from theano.gpuarray.fft import pycuda_available
if not pygpu_available: # noqa if not pygpu_available: # noqa
raise SkipTest('Optional package pygpu not available') raise SkipTest('Optional package pygpu not available')
if not scikits_cuda_available: # noqa if not scikits_cuda_available: # noqa
...@@ -22,8 +19,6 @@ if not scikits_cuda_available: # noqa ...@@ -22,8 +19,6 @@ if not scikits_cuda_available: # noqa
if not pycuda_available: # noqa if not pycuda_available: # noqa
raise SkipTest('Optional package pycuda not available') raise SkipTest('Optional package pycuda not available')
import theano.gpuarray.cuda_fft
# Transform sizes # Transform sizes
N = 64 N = 64
...@@ -35,7 +30,7 @@ class TestFFT(unittest.TestCase): ...@@ -35,7 +30,7 @@ class TestFFT(unittest.TestCase):
x = T.matrix('x', dtype='float32') x = T.matrix('x', dtype='float32')
rfft = theano.gpuarray.fft.curfft(x) rfft = theano.gpuarray.fft.curfft(x)
f_rfft = theano.function([x], rfft, mode=mode_with_gpu) f_rfft = theano.function([x], rfft)
res_rfft = f_rfft(inputs_val) res_rfft = f_rfft(inputs_val)
res_rfft_comp = (np.asarray(res_rfft[:, :, 0]) + res_rfft_comp = (np.asarray(res_rfft[:, :, 0]) +
1j * np.asarray(res_rfft[:, :, 1])) 1j * np.asarray(res_rfft[:, :, 1]))
...@@ -46,7 +41,7 @@ class TestFFT(unittest.TestCase): ...@@ -46,7 +41,7 @@ class TestFFT(unittest.TestCase):
m = rfft.type() m = rfft.type()
irfft = theano.gpuarray.fft.cuirfft(m) irfft = theano.gpuarray.fft.cuirfft(m)
f_irfft = theano.function([m], irfft, mode=mode_with_gpu) f_irfft = theano.function([m], irfft)
res_irfft = f_irfft(res_rfft) res_irfft = f_irfft(res_rfft)
utt.assert_allclose(inputs_val, np.asarray(res_irfft)) utt.assert_allclose(inputs_val, np.asarray(res_irfft))
...@@ -70,7 +65,7 @@ class TestFFT(unittest.TestCase): ...@@ -70,7 +65,7 @@ class TestFFT(unittest.TestCase):
inputs = theano.shared(inputs_val) inputs = theano.shared(inputs_val)
rfft = theano.gpuarray.fft.curfft(inputs) rfft = theano.gpuarray.fft.curfft(inputs)
f_rfft = theano.function([], rfft, mode=mode_with_gpu) f_rfft = theano.function([], rfft)
res_rfft = f_rfft() res_rfft = f_rfft()
res_rfft_comp = (np.asarray(res_rfft[:, :, :, 0]) + res_rfft_comp = (np.asarray(res_rfft[:, :, :, 0]) +
1j * np.asarray(res_rfft[:, :, :, 1])) 1j * np.asarray(res_rfft[:, :, :, 1]))
...@@ -84,12 +79,12 @@ class TestFFT(unittest.TestCase): ...@@ -84,12 +79,12 @@ class TestFFT(unittest.TestCase):
inputs = theano.shared(inputs_val) inputs = theano.shared(inputs_val)
fft = theano.gpuarray.fft.curfft(inputs) fft = theano.gpuarray.fft.curfft(inputs)
f_fft = theano.function([], fft, mode=mode_with_gpu) f_fft = theano.function([], fft)
res_fft = f_fft() res_fft = f_fft()
m = fft.type() m = fft.type()
ifft = theano.gpuarray.fft.cuirfft(m) ifft = theano.gpuarray.fft.cuirfft(m)
f_ifft = theano.function([m], ifft, mode=mode_with_gpu) f_ifft = theano.function([m], ifft)
res_ifft = f_ifft(res_fft) res_ifft = f_ifft(res_fft)
utt.assert_allclose(inputs_val, np.asarray(res_ifft)) utt.assert_allclose(inputs_val, np.asarray(res_ifft))
...@@ -109,7 +104,7 @@ class TestFFT(unittest.TestCase): ...@@ -109,7 +104,7 @@ class TestFFT(unittest.TestCase):
# Unitary normalization # Unitary normalization
rfft = theano.gpuarray.fft.curfft(inputs, norm='ortho') rfft = theano.gpuarray.fft.curfft(inputs, norm='ortho')
f_rfft = theano.function([], rfft, mode=mode_with_gpu) f_rfft = theano.function([], rfft)
res_rfft = f_rfft() res_rfft = f_rfft()
res_rfft_comp = (np.asarray(res_rfft[:, :, :, 0]) + res_rfft_comp = (np.asarray(res_rfft[:, :, :, 0]) +
1j * np.asarray(res_rfft[:, :, :, 1])) 1j * np.asarray(res_rfft[:, :, :, 1]))
...@@ -121,7 +116,7 @@ class TestFFT(unittest.TestCase): ...@@ -121,7 +116,7 @@ class TestFFT(unittest.TestCase):
# No normalization # No normalization
rfft = theano.gpuarray.fft.curfft(inputs, norm='no_norm') rfft = theano.gpuarray.fft.curfft(inputs, norm='no_norm')
f_rfft = theano.function([], rfft, mode=mode_with_gpu) f_rfft = theano.function([], rfft)
res_rfft = f_rfft() res_rfft = f_rfft()
res_rfft_comp = (np.asarray(res_rfft[:, :, :, 0]) + res_rfft_comp = (np.asarray(res_rfft[:, :, :, 0]) +
1j * np.asarray(res_rfft[:, :, :, 1])) 1j * np.asarray(res_rfft[:, :, :, 1]))
...@@ -136,7 +131,7 @@ class TestFFT(unittest.TestCase): ...@@ -136,7 +131,7 @@ class TestFFT(unittest.TestCase):
# Unitary normalization inverse FFT # Unitary normalization inverse FFT
irfft = theano.gpuarray.fft.cuirfft(inputs, norm='ortho') irfft = theano.gpuarray.fft.cuirfft(inputs, norm='ortho')
f_irfft = theano.function([], irfft, mode=mode_with_gpu) f_irfft = theano.function([], irfft)
res_irfft = f_irfft() res_irfft = f_irfft()
irfft_ref_ortho = numpy.fft.irfftn( irfft_ref_ortho = numpy.fft.irfftn(
...@@ -147,7 +142,7 @@ class TestFFT(unittest.TestCase): ...@@ -147,7 +142,7 @@ class TestFFT(unittest.TestCase):
# No normalization inverse FFT # No normalization inverse FFT
irfft = theano.gpuarray.fft.cuirfft(inputs, norm='no_norm') irfft = theano.gpuarray.fft.cuirfft(inputs, norm='no_norm')
f_irfft = theano.function([], irfft, mode=mode_with_gpu) f_irfft = theano.function([], irfft)
res_irfft = f_irfft() res_irfft = f_irfft()
utt.assert_allclose(irfft_ref_ortho * np.sqrt(N * N), utt.assert_allclose(irfft_ref_ortho * np.sqrt(N * N),
...@@ -185,7 +180,7 @@ class TestFFT(unittest.TestCase): ...@@ -185,7 +180,7 @@ class TestFFT(unittest.TestCase):
inputs = theano.shared(inputs_val) inputs = theano.shared(inputs_val)
rfft = theano.gpuarray.fft.curfft(inputs) rfft = theano.gpuarray.fft.curfft(inputs)
f_rfft = theano.function([], rfft, mode=mode_with_gpu) f_rfft = theano.function([], rfft)
res_rfft = f_rfft() res_rfft = f_rfft()
res_rfft_comp = (np.asarray(res_rfft[:, :, :, 0]) + res_rfft_comp = (np.asarray(res_rfft[:, :, :, 0]) +
...@@ -197,7 +192,7 @@ class TestFFT(unittest.TestCase): ...@@ -197,7 +192,7 @@ class TestFFT(unittest.TestCase):
m = rfft.type() m = rfft.type()
ifft = theano.gpuarray.fft.cuirfft(m, is_odd=True) ifft = theano.gpuarray.fft.cuirfft(m, is_odd=True)
f_ifft = theano.function([m], ifft, mode=mode_with_gpu) f_ifft = theano.function([m], ifft)
res_ifft = f_ifft(res_rfft) res_ifft = f_ifft(res_rfft)
utt.assert_allclose(inputs_val, np.asarray(res_ifft)) utt.assert_allclose(inputs_val, np.asarray(res_ifft))
...@@ -206,7 +201,7 @@ class TestFFT(unittest.TestCase): ...@@ -206,7 +201,7 @@ class TestFFT(unittest.TestCase):
inputs = theano.shared(inputs_val) inputs = theano.shared(inputs_val)
irfft = theano.gpuarray.fft.cuirfft(inputs, norm='ortho', is_odd=True) irfft = theano.gpuarray.fft.cuirfft(inputs, norm='ortho', is_odd=True)
f_irfft = theano.function([], irfft, mode=mode_with_gpu) f_irfft = theano.function([], irfft)
res_irfft = f_irfft() res_irfft = f_irfft()
inputs_ref = inputs_val[:, :, :, 0] + 1j * inputs_val[:, :, :, 1] inputs_ref = inputs_val[:, :, :, 0] + 1j * inputs_val[:, :, :, 1]
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论