未验证 提交 a8e355af 编写于 作者: Z zhupengyang 提交者: GitHub

revert logsumexp op(#27145)

上级 847f93f9
// 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.
#include "paddle/fluid/operators/reduce_ops/logsumexp_op.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
namespace paddle {
namespace operators {
class LogsumexpOpMaker : public ops::ReduceOpMaker {
protected:
virtual std::string GetName() const { return "logsumexp"; }
virtual std::string GetOpType() const { return "Reduce logsumexp"; }
};
template <typename T>
class LogsumexpGradOpMaker : public framework::SingleGradOpMaker<T> {
public:
using framework::SingleGradOpMaker<T>::SingleGradOpMaker;
protected:
void Apply(GradOpPtr<T> op) const override {
op->SetType("logsumexp_grad");
op->SetInput("X", this->Input("X"));
op->SetInput("Out", this->Output("Out"));
op->SetInput(framework::GradVarName("Out"), this->OutputGrad("Out"));
op->SetAttrMap(this->Attrs());
op->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
}
};
} // namespace operators
} // namespace paddle
REGISTER_OPERATOR(logsumexp, ops::ReduceOp, ops::LogsumexpOpMaker,
ops::LogsumexpGradOpMaker<paddle::framework::OpDesc>,
ops::LogsumexpGradOpMaker<paddle::imperative::OpBase>);
REGISTER_OPERATOR(logsumexp_grad, ops::ReduceGradOp);
REGISTER_OP_CPU_KERNEL(logsumexp,
ops::ReduceKernel<paddle::platform::CPUDeviceContext,
float, ops::LogsumexpFunctor>,
ops::ReduceKernel<paddle::platform::CPUDeviceContext,
double, ops::LogsumexpFunctor>);
REGISTER_OP_CPU_KERNEL(
logsumexp_grad, ops::ReduceGradKernel<paddle::platform::CPUDeviceContext,
float, ops::LogsumexpGradFunctor>,
ops::ReduceGradKernel<paddle::platform::CPUDeviceContext, double,
ops::LogsumexpGradFunctor>);
// Copyright (c) 2018 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.
#include "paddle/fluid/operators/reduce_ops/logsumexp_op.h"
REGISTER_OP_CUDA_KERNEL(logsumexp,
ops::ReduceKernel<paddle::platform::CUDADeviceContext,
float, ops::LogsumexpFunctor>,
ops::ReduceKernel<paddle::platform::CUDADeviceContext,
double, ops::LogsumexpFunctor>);
// 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.
#pragma once
#include "paddle/fluid/operators/reduce_ops/reduce_op.h"
namespace paddle {
namespace operators {
struct LogsumexpFunctor {
template <typename DeviceContext, typename X, typename Y, typename Dim>
void operator()(const DeviceContext& place, X* x, Y* y, const Dim& dim) {
auto x_dim = x->dimensions();
auto t_dim = x_dim;
for (int i = 0; i < static_cast<int>(dim.size()); i++) {
t_dim[dim[i]] = 1;
}
auto r_dim = x_dim;
for (int i = 0; i < static_cast<int>(r_dim.size()); i++) {
r_dim[i] = 1;
}
for (int i = 0; i < static_cast<int>(dim.size()); i++) {
r_dim[dim[i]] = x_dim[dim[i]];
}
auto y_dim = y->dimensions();
auto x_max = x->maximum(dim);
y->device(place) =
(x_max +
(*x - x_max.reshape(t_dim).broadcast(r_dim)).exp().sum(dim).log())
.reshape(y_dim);
}
};
struct LogsumexpGradFunctor {
template <typename DeviceContext, typename X, typename Y, typename DX,
typename DY, typename Dim>
void operator()(const DeviceContext& place, X* x, Y* y, DX* dx, DY* dy,
const Dim& dim, int size) {
dx->device(place) = dy->broadcast(dim) * (*x - y->broadcast(dim)).exp();
}
};
} // namespace operators
} // namespace paddle
// Copyright (c) 2018 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.
// .part used to speed up nvcc compile
#include "paddle/fluid/operators/reduce_ops/logsumexp_op.h"
REGISTER_OP_CUDA_KERNEL(
logsumexp_grad, ops::ReduceGradKernel<paddle::platform::CUDADeviceContext,
float, ops::LogsumexpGradFunctor>,
ops::ReduceGradKernel<paddle::platform::CUDADeviceContext, double,
ops::LogsumexpGradFunctor>);
...@@ -12,128 +12,60 @@ ...@@ -12,128 +12,60 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import print_function
import paddle import paddle
import paddle.fluid as fluid
import unittest import unittest
import numpy as np import numpy as np
from op_test import OpTest from op_test import OpTest
from paddle.fluid import Program, program_guard
from paddle.fluid.layer_helper import LayerHelper
def ref_logsumexp(x, axis=None, keepdim=False, reduce_all=False): class TestLogSumOpError(unittest.TestCase):
if isinstance(axis, int):
axis = (axis, )
elif isinstance(axis, list):
axis = tuple(axis)
if reduce_all:
axis = None
out = np.log(np.exp(x).sum(axis=axis, keepdims=keepdim))
return out
class TestLogsumexp(OpTest):
def setUp(self):
self.op_type = 'logsumexp'
self.shape = [2, 3, 4, 5]
self.dtype = 'float64'
self.axis = [-1]
self.keepdim = False
self.reduce_all = False
self.set_attrs()
np.random.seed(10)
x = np.random.uniform(-1, 1, self.shape).astype(self.dtype)
out = ref_logsumexp(x, self.axis, self.keepdim, self.reduce_all)
self.inputs = {'X': x}
self.outputs = {'Out': out}
self.attrs = {
'dim': self.axis,
'keep_dim': self.keepdim,
'reduce_all': self.reduce_all
}
def set_attrs(self):
pass
def test_check_output(self):
self.check_output()
def test_check_grad(self):
self.check_grad(['X'], ['Out'])
class TestLogsumexp_shape(TestLogsumexp):
def set_attrs(self):
self.shape = [4, 5, 6]
class TestLogsumexp_axis(TestLogsumexp):
def set_attrs(self):
self.axis = [0, -1]
class TestLogsumexp_axis_all(TestLogsumexp):
def set_attrs(self):
self.axis = [0, 1, 2, 3]
class TestLogsumexp_keepdim(TestLogsumexp):
def set_attrs(self):
self.keepdim = True
class TestLogsumexp_reduce_all(TestLogsumexp):
def set_attrs(self):
self.reduce_all = True
class TestLogsumexpError(unittest.TestCase):
def test_errors(self): def test_errors(self):
with paddle.static.program_guard(paddle.static.Program()): with program_guard(Program(), Program()):
self.assertRaises(TypeError, paddle.logsumexp, 1)
x1 = paddle.data(name='x1', shape=[120], dtype="int32") x1 = fluid.layers.data(name='x1', shape=[120], dtype="uint8")
self.assertRaises(TypeError, paddle.logsumexp, x1) self.assertRaises(Exception, paddle.logsumexp, x1)
x2 = fluid.layers.data(name='x2', shape=[2, 3], dtype="int")
class TestLogsumexpAPI(unittest.TestCase): self.assertRaises(Exception, paddle.logsumexp, x2)
def setUp(self):
self.shape = [2, 3, 4, 5] x3 = fluid.layers.data(name='x3', shape=[3], dtype="float16")
self.x = np.random.uniform(-1, 1, self.shape).astype(np.float32) self.assertRaises(Exception, paddle.logsumexp, x3)
self.place = paddle.CUDAPlace(0) if paddle.fluid.core.is_compiled_with_cuda() \
else paddle.CPUPlace()
class TestLogSumExpOp(unittest.TestCase):
def api_case(self, axis=None, keepdim=False): def test_dygraph(self):
out_ref = ref_logsumexp(self.x, axis, keepdim) with fluid.dygraph.guard():
with paddle.static.program_guard(paddle.static.Program()): np_x = np.random.uniform(0.1, 1, [123]).astype(np.float32)
x = paddle.data('X', self.shape) x = fluid.dygraph.to_variable(np_x)
out = paddle.logsumexp(x, axis, keepdim) self.assertTrue(
exe = paddle.static.Executor(self.place) np.allclose(
res = exe.run(feed={'X': self.x}, fetch_list=[out]) paddle.logsumexp(x).numpy(), np.log(np.sum(np.exp(np_x)))))
self.assertTrue(np.allclose(res[0], out_ref))
np_x = np.random.uniform(0.1, 1, [2, 3, 4]).astype(np.float32)
paddle.disable_static(self.place) x = fluid.dygraph.to_variable(np_x)
x = paddle.to_variable(self.x) self.assertTrue(
out = paddle.logsumexp(x, axis, keepdim) np.allclose(
self.assertTrue(np.allclose(out.numpy(), out_ref)) paddle.logsumexp(x, [1, 2]).numpy(),
paddle.enable_static() np.log(np.sum(np.exp(np_x), axis=(1, 2)))))
def test_api(self): np_x = np.random.uniform(0.1, 1, [2, 3, 4]).astype(np.float32)
self.api_case() x = fluid.dygraph.to_variable(np_x)
self.api_case(2) self.assertTrue(
self.api_case([-1]) np.allclose(
self.api_case([2, -3]) paddle.logsumexp(x, [2]).numpy(),
self.api_case((0, 1, -1)) np.log(np.sum(np.exp(np_x), axis=(2)))))
self.api_case(keepdim=True)
np_x = np.random.uniform(0.1, 1, [2, 3, 4]).astype(np.float32)
def test_alias(self): x = fluid.dygraph.to_variable(np_x)
paddle.disable_static(self.place) self.assertTrue(
x = paddle.to_variable(self.x) np.allclose(
out1 = paddle.logsumexp(x) paddle.logsumexp(
out2 = paddle.tensor.logsumexp(x) x, keepdim=True).numpy(),
out3 = paddle.tensor.math.logsumexp(x) np.log(np.sum(np.exp(np_x), keepdims=True))))
out_ref = ref_logsumexp(self.x)
for out in [out1, out2, out3]:
self.assertTrue(np.allclose(out.numpy(), out_ref))
paddle.enable_static()
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -86,7 +86,6 @@ __all__ = [ ...@@ -86,7 +86,6 @@ __all__ = [
'floor', 'floor',
'increment', 'increment',
'log', 'log',
'logsumexp',
'mul', 'mul',
'multiplex', 'multiplex',
'pow', 'pow',
...@@ -1177,35 +1176,24 @@ def logsumexp(x, axis=None, keepdim=False, name=None): ...@@ -1177,35 +1176,24 @@ def logsumexp(x, axis=None, keepdim=False, name=None):
.. code-block:: python .. code-block:: python
import paddle import paddle
import numpy as np
paddle.disable_static() paddle.disable_static()
x = paddle.to_tensor([[-1.5, 0., 2.], [3., 1.2, -2.4]]) x = np.array([[-1.5, 0., 2.], [3., 1.2, -2.4]])
x = paddle.to_tensor(x)
out1 = paddle.logsumexp(x) # [3.4691226] out1 = paddle.logsumexp(x) # [3.4691226]
out2 = paddle.logsumexp(x, 1) # [2.15317821, 3.15684602] out2 = paddle.logsumexp(x, 1) # [2.15317821, 3.15684602]
""" """
if isinstance(axis, int): if not in_dygraph_mode():
axis = [axis] check_variable_and_dtype(x, 'x',
reduce_all = True if axis is None \
or len(axis)==0 \
or len(axis) == len(x.shape) else False
if axis is None or len(axis) == 0:
axis = [0]
if in_dygraph_mode():
return core.ops.logsumexp(x, 'dim', axis, 'keep_dim', keepdim,
'reduce_all', reduce_all)
check_variable_and_dtype(x, 'x',
['float32', 'float64'], ['float32', 'float64'],
'logsumexp') 'logsumexp')
helper = LayerHelper('logsumexp', **locals()) out = paddle.exp(x, name)
attrs = {'dim': axis, 'keep_dim': keepdim, 'reduce_all': reduce_all} out = paddle.sum(out, axis=axis, keepdim=keepdim, name=name)
out = helper.create_variable_for_type_inference(x.dtype) out = paddle.log(out, name)
helper.append_op(
type='logsumexp', inputs={'X': x}, outputs={'Out': out}, attrs=attrs)
return out return out
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册