-
Notifications
You must be signed in to change notification settings - Fork 5.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
【complex op】 No.10 add complex support for exp/expm1 #56398
Changes from 13 commits
0fd0b59
6c1a3ef
da55715
ed85ed9
077f534
11cf229
b43efdf
1d4e2da
4f09e7b
6eacc19
989f273
0210cee
4083ff1
9513cce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1167,6 +1167,33 @@ struct ExpGradFunctor : public BaseActivationFunctor<T> { | |
} | ||
}; | ||
|
||
template <typename T> | ||
struct ExpGradFunctor<ComplexType<T>> | ||
: public BaseActivationFunctor<ComplexType<T>> { | ||
template <typename Device, | ||
typename X, | ||
typename Out, | ||
typename dOut, | ||
typename dX> | ||
void operator()(Device d, X x UNUSED, Out out, dOut dout, dX dx) const { | ||
dx.device(d) = dout * out.unaryExpr(Conj<T>()); | ||
} | ||
|
||
static constexpr ActBwdOpFwdDeps FwdDeps() { | ||
return ActBwdOpFwdDeps::kDepOut; | ||
} | ||
}; | ||
|
||
template <typename T> | ||
struct Expm1 {}; | ||
|
||
template <typename T> | ||
struct Expm1<ComplexType<T>> { | ||
HOSTDEVICE ComplexType<T> operator()(const ComplexType<T>& val) const { | ||
return exp(val) - static_cast<ComplexType<T>>(1); | ||
} | ||
}; | ||
|
||
// expm1(x) = e^x - 1 | ||
template <typename T> | ||
struct Expm1Functor : public BaseActivationFunctor<T> { | ||
|
@@ -1178,6 +1205,15 @@ struct Expm1Functor : public BaseActivationFunctor<T> { | |
} | ||
}; | ||
|
||
template <typename T> | ||
struct Expm1Functor<ComplexType<T>> | ||
: public BaseActivationFunctor<ComplexType<T>> { | ||
template <typename Device, typename X, typename Out> | ||
void operator()(Device d, X x, Out out) const { | ||
out.device(d) = x.unaryExpr(Expm1<ComplexType<T>>()).eval(); | ||
} | ||
}; | ||
|
||
template <typename T> | ||
struct Expm1GradFunctor : public BaseActivationFunctor<T> { | ||
template <typename Device, | ||
|
@@ -1194,6 +1230,21 @@ struct Expm1GradFunctor : public BaseActivationFunctor<T> { | |
} | ||
}; | ||
|
||
template <typename T> | ||
struct Expm1GradFunctor<ComplexType<T>> | ||
: public BaseActivationFunctor<ComplexType<T>> { | ||
template <typename Device, | ||
typename X, | ||
typename Out, | ||
typename dOut, | ||
typename dX> | ||
void operator()(Device d, X x UNUSED, Out out, dOut dout, dX dx) const { | ||
dx.device(d) = dout * out.unaryExpr(Conj<T>()) + dout; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 请教一下,为什么这里 expm1 (exp - 1) 的 梯度是 dout*(exp + 1) :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 事实上我也不是很理解,tensorflow 的梯度实现也是不用加上这个 dout 的: 但是我看到 paddle 的其他数据类型的梯度实现是加上了这个 dout,并且我不加上这个 dout 确实梯度误差检查过不了,所以我就加上了,我也想请教下 paddle 的前辈们是不是 paddle 的算子梯度的实现这块不一样导致这样的结果。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. exp(x)-1的grad是exp(x),exp(x)=(exp(x)-1)+1=out+1 |
||
} | ||
|
||
static constexpr ActBwdOpFwdDeps FwdDeps() { return kDepOut; } | ||
}; | ||
|
||
// relu(x) = max(x, 0) | ||
template <typename T> | ||
struct ReluCPUFunctor : public BaseActivationFunctor<T> { | ||
|
@@ -2790,6 +2841,16 @@ struct CudaExpFunctor<double> : public BaseActivationFunctor<double> { | |
} | ||
}; | ||
|
||
template <typename T> | ||
struct CudaExpFunctor<ComplexType<T>> | ||
: public BaseActivationFunctor<ComplexType<T>> { | ||
// exp(x) = exp(x) | ||
__device__ __forceinline__ ComplexType<T> operator()( | ||
const ComplexType<T> x) const { | ||
return static_cast<ComplexType<T>>(exp(x)); | ||
} | ||
}; | ||
|
||
template <typename T> | ||
struct CudaSeluFunctor : public BaseActivationFunctor<T> { | ||
typename BaseActivationFunctor<T>::AttrPair GetAttrs() { | ||
|
@@ -2866,6 +2927,20 @@ struct CudaExpGradFunctor : public BaseActivationFunctor<T> { | |
} | ||
}; | ||
|
||
template <typename T> | ||
struct CudaExpGradFunctor<ComplexType<T>> | ||
: public BaseActivationFunctor<ComplexType<T>> { | ||
// dx = dout * exp(x) | ||
__device__ __forceinline__ ComplexType<T> operator()( | ||
const ComplexType<T> dout, const ComplexType<T> out) const { | ||
return static_cast<ComplexType<T>>(dout * conj(out)); | ||
} | ||
|
||
static constexpr ActBwdOpFwdDeps FwdDeps() { | ||
return ActBwdOpFwdDeps::kDepOut; | ||
} | ||
}; | ||
|
||
template <typename T> | ||
struct CudaReciprocalFunctor : public BaseActivationFunctor<T> { | ||
using MPType = typename phi::dtype::MPTypeTrait<T>::Type; | ||
|
@@ -2906,6 +2981,15 @@ struct CudaExpm1Functor<double> : public BaseActivationFunctor<double> { | |
} | ||
}; | ||
|
||
template <typename T> | ||
struct CudaExpm1Functor<ComplexType<T>> | ||
: public BaseActivationFunctor<ComplexType<T>> { | ||
__device__ __forceinline__ ComplexType<T> operator()( | ||
const ComplexType<T> x) const { | ||
return static_cast<ComplexType<T>>(Expm1<ComplexType<T>>()(x)); | ||
} | ||
}; | ||
|
||
template <typename T> | ||
struct CudaExpm1GradFunctor : public BaseActivationFunctor<T> { | ||
// dx = dout * out | ||
|
@@ -2918,6 +3002,20 @@ struct CudaExpm1GradFunctor : public BaseActivationFunctor<T> { | |
} | ||
}; | ||
|
||
template <typename T> | ||
struct CudaExpm1GradFunctor<ComplexType<T>> | ||
: public BaseActivationFunctor<ComplexType<T>> { | ||
// dx = dout * exp(x) | ||
__device__ __forceinline__ ComplexType<T> operator()( | ||
const ComplexType<T> dout, const ComplexType<T> out) const { | ||
return static_cast<ComplexType<T>>(dout * conj(out) + dout); | ||
} | ||
|
||
static constexpr ActBwdOpFwdDeps FwdDeps() { | ||
return ActBwdOpFwdDeps::kDepOut; | ||
} | ||
}; | ||
|
||
template <typename T> | ||
struct CudaSinFunctor : public BaseActivationFunctor<T> { | ||
using MPType = typename phi::dtype::MPTypeTrait<T>::Type; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -567,7 +567,7 @@ def exp(x, name=None): | |
out = e^x | ||
|
||
Args: | ||
x (Tensor): Input of Exp operator, an N-D Tensor, with data type int32, int64, float32, float64 or float16. | ||
x (Tensor): Input of Exp operator, an N-D Tensor, with data type int32, int64, float16, float32, float64, complex64 or complex128. | ||
name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. | ||
|
||
Returns: | ||
|
@@ -617,7 +617,7 @@ def expm1(x, name=None): | |
out = e^x - 1 | ||
|
||
Args: | ||
x (Tensor): Input of Expm1 operator, an N-D Tensor, with data type int32, int64, float32, float64 or float16. | ||
x (Tensor): Input of Expm1 operator, an N-D Tensor, with data type int32, int64, float16, float32, float64, complex64 or complex128. | ||
name (str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. | ||
|
||
Returns: | ||
|
@@ -640,7 +640,16 @@ def expm1(x, name=None): | |
check_variable_and_dtype( | ||
x, | ||
'x', | ||
['float16', 'uint16', 'float32', 'float64', 'int32', 'int64'], | ||
[ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 该方法的 docstring 也相应修改一下 |
||
'float16', | ||
'uint16', | ||
'float32', | ||
'float64', | ||
'int32', | ||
'int64', | ||
'complex64', | ||
'complex128', | ||
], | ||
'expm1', | ||
) | ||
helper = LayerHelper('expm1', **locals()) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -149,9 +149,46 @@ def init_dtype(self): | |
self.dtype = np.float64 | ||
|
||
|
||
class TestExpPrim_ZeroDim(TestExpFp32_Prim): | ||
class TestExp_Complex64(OpTest): | ||
def setUp(self): | ||
self.op_type = "exp" | ||
self.python_api = paddle.exp | ||
self.public_python_api = paddle.exp | ||
self.init_dtype() | ||
self.init_shape() | ||
self.if_enable_cinn() | ||
np.random.seed(1024) | ||
x = ( | ||
np.random.uniform(-1, 1, self.shape) | ||
+ 1j * np.random.uniform(-1, 1, self.shape) | ||
).astype(self.dtype) | ||
out = np.exp(x) | ||
self.inputs = {'X': OpTest.np_dtype_to_fluid_dtype(x)} | ||
self.outputs = {'Out': out} | ||
self.convert_input_output() | ||
|
||
def test_check_output(self): | ||
self.check_output() | ||
|
||
def test_check_grad(self): | ||
self.check_grad(['X'], 'Out', max_relative_error=0.006) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这里的 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 是的 |
||
|
||
def init_dtype(self): | ||
self.dtype = np.complex64 | ||
|
||
def init_shape(self): | ||
self.shape = [] | ||
self.shape = [10, 12] | ||
|
||
def if_enable_cinn(self): | ||
pass | ||
|
||
def convert_input_output(self): | ||
pass | ||
|
||
|
||
class TestExp_Complex128(TestExp_Complex64): | ||
def init_dtype(self): | ||
self.dtype = np.complex128 | ||
|
||
|
||
class Test_Exp_Op_Fp16(unittest.TestCase): | ||
|
@@ -189,9 +226,13 @@ def setUp(self): | |
self.python_api = paddle.expm1 | ||
self.init_dtype() | ||
self.init_shape() | ||
|
||
np.random.seed(2049) | ||
x = np.random.uniform(0.1, 1, self.shape).astype(self.dtype) | ||
if self.dtype == np.complex64 or self.dtype == np.complex128: | ||
x = ( | ||
np.random.uniform(-1, 1, self.shape) | ||
+ 1j * np.random.uniform(-1, 1, self.shape) | ||
).astype(self.dtype) | ||
out = np.expm1(x) | ||
|
||
self.inputs = {'X': OpTest.np_dtype_to_fluid_dtype(x)} | ||
|
@@ -205,6 +246,16 @@ def test_check_output(self): | |
self.check_output() | ||
|
||
|
||
class TestExpm1_Complex64(TestExpm1): | ||
def init_dtype(self): | ||
self.dtype = np.complex64 | ||
|
||
|
||
class TestExpm1_Complex128(TestExpm1): | ||
def init_dtype(self): | ||
self.dtype = np.complex128 | ||
|
||
|
||
class TestExpm1_ZeroDim(TestExpm1): | ||
def init_shape(self): | ||
self.shape = [] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这里之前的pr应该已经加了exp, 可以同步一下最新的代码,不要加重复了
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
好的