Add complex layer for transpose & matmul, test=develop (#24195)
* Add complex layer for transpose & matmul, test=develop * Tiny fixes in doc, test=develop * Fix docs, test=developrevert-24314-dev/fix_err_msg
parent
e1a7a88057
commit
f0046889ff
@ -0,0 +1,75 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from ..helper import is_complex, is_real, complex_variable_exists
|
||||
from ...fluid.framework import ComplexVariable
|
||||
from ...fluid import layers
|
||||
|
||||
__all__ = ['matmul', ]
|
||||
|
||||
|
||||
def matmul(x, y, transpose_x=False, transpose_y=False, alpha=1.0, name=None):
|
||||
"""
|
||||
Applies matrix multiplication to two complex number tensors. See the
|
||||
detailed description in :ref:`api_fluid_layers_matmul`.
|
||||
|
||||
Args:
|
||||
x (ComplexVariable|Variable): The first input, can be a ComplexVariable
|
||||
with data type complex32 or complex64, or a Variable with data type
|
||||
float32 or float64.
|
||||
y (ComplexVariable|Variable): The second input, can be a ComplexVariable
|
||||
with data type complex32 or complex64, or a Variable with data type
|
||||
float32 or float64.
|
||||
transpose_x (bool): Whether to transpose :math:`x` before multiplication.
|
||||
transpose_y (bool): Whether to transpose :math:`y` before multiplication.
|
||||
alpha (float): The scale of output. Default 1.0.
|
||||
name(str|None): A name for this layer(optional). If set None, the layer
|
||||
will be named automatically.
|
||||
|
||||
Returns:
|
||||
ComplexVariable: The product result, with the same data type as inputs.
|
||||
|
||||
Examples:
|
||||
.. code-block:: python
|
||||
|
||||
import numpy as np
|
||||
import paddle
|
||||
import paddle.fluid.dygraph as dg
|
||||
with dg.guard():
|
||||
x = np.array([[1.0 + 1j, 2.0 + 1j], [3.0+1j, 4.0+1j]])
|
||||
y = np.array([1.0 + 1j, 1.0 + 1j])
|
||||
x_var = dg.to_variable(x)
|
||||
y_var = dg.to_variable(y)
|
||||
result = paddle.complex.matmul(x_var, y_var)
|
||||
print(result.numpy())
|
||||
# [1.+5.j 5.+9.j]
|
||||
"""
|
||||
# x = a + bi, y = c + di
|
||||
# mm(x, y) = mm(a, c) - mm(b, d) + (mm(a, d) + mm(b, c))i
|
||||
complex_variable_exists([x, y], "matmul")
|
||||
a, b = (x.real, x.imag) if is_complex(x) else (x, None)
|
||||
c, d = (y.real, y.imag) if is_complex(y) else (y, None)
|
||||
ac = layers.matmul(a, c, transpose_x, transpose_y, alpha, name)
|
||||
if is_real(b) and is_real(d):
|
||||
bd = layers.matmul(b, d, transpose_x, transpose_y, alpha, name)
|
||||
real = ac - bd
|
||||
imag = layers.matmul(a, d, transpose_x, transpose_y, alpha, name) + \
|
||||
layers.matmul(b, c, transpose_x, transpose_y, alpha, name)
|
||||
elif is_real(b):
|
||||
real = ac
|
||||
imag = layers.matmul(b, c, transpose_x, transpose_y, alpha, name)
|
||||
else:
|
||||
real = ac
|
||||
imag = layers.matmul(a, d, transpose_x, transpose_y, alpha, name)
|
||||
return ComplexVariable(real, imag)
|
@ -0,0 +1,62 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
import paddle
|
||||
import numpy as np
|
||||
import paddle.fluid as fluid
|
||||
import paddle.fluid.dygraph as dg
|
||||
|
||||
|
||||
class TestComplexMatMulLayer(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self._places = [fluid.CPUPlace()]
|
||||
if fluid.core.is_compiled_with_cuda():
|
||||
self._places.append(fluid.CUDAPlace(0))
|
||||
|
||||
def compare(self, x, y):
|
||||
for place in self._places:
|
||||
with dg.guard(place):
|
||||
x_var = dg.to_variable(x)
|
||||
y_var = dg.to_variable(y)
|
||||
result = paddle.complex.matmul(x_var, y_var)
|
||||
np_result = np.matmul(x, y)
|
||||
self.assertTrue(np.allclose(result.numpy(), np_result))
|
||||
|
||||
def test_complex_xy(self):
|
||||
x = np.random.random(
|
||||
(2, 3, 4, 5)).astype("float32") + 1J * np.random.random(
|
||||
(2, 3, 4, 5)).astype("float32")
|
||||
y = np.random.random(
|
||||
(2, 3, 5, 4)).astype("float32") + 1J * np.random.random(
|
||||
(2, 3, 5, 4)).astype("float32")
|
||||
self.compare(x, y)
|
||||
|
||||
def test_complex_x(self):
|
||||
x = np.random.random(
|
||||
(2, 3, 4, 5)).astype("float32") + 1J * np.random.random(
|
||||
(2, 3, 4, 5)).astype("float32")
|
||||
y = np.random.random((2, 3, 5, 4)).astype("float32")
|
||||
self.compare(x, y)
|
||||
|
||||
def test_complex_y(self):
|
||||
x = np.random.random((2, 3, 4, 5)).astype("float32")
|
||||
y = np.random.random(
|
||||
(2, 3, 5, 4)).astype("float32") + 1J * np.random.random(
|
||||
(2, 3, 5, 4)).astype("float32")
|
||||
self.compare(x, y)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -0,0 +1,42 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
import paddle
|
||||
import numpy as np
|
||||
import paddle.fluid as fluid
|
||||
import paddle.fluid.dygraph as dg
|
||||
|
||||
|
||||
class TestComplexTransposeLayer(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self._places = [fluid.CPUPlace()]
|
||||
if fluid.core.is_compiled_with_cuda():
|
||||
self._places.append(fluid.CUDAPlace(0))
|
||||
|
||||
def test_identity(self):
|
||||
data = np.random.random(
|
||||
(2, 3, 4, 5)).astype("float32") + 1J * np.random.random(
|
||||
(2, 3, 4, 5)).astype("float32")
|
||||
perm = [3, 2, 0, 1]
|
||||
np_trans = np.transpose(data, perm)
|
||||
for place in self._places:
|
||||
with dg.guard(place):
|
||||
var = dg.to_variable(data)
|
||||
trans = paddle.complex.transpose(var, perm=perm)
|
||||
self.assertTrue(np.allclose(trans.numpy(), np_trans))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Reference in new issue