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

add activation ops under paddle.nn and paddle.nn.functional: ReLU, LogSoftmax (#23258)

上级 03073937
...@@ -21,6 +21,8 @@ from op_test import OpTest ...@@ -21,6 +21,8 @@ from op_test import OpTest
from scipy.special import expit, erf from scipy.special import expit, erf
import paddle import paddle
import paddle.fluid as fluid import paddle.fluid as fluid
import paddle.nn as nn
import paddle.nn.functional as functional
from paddle.fluid import compiler, Program, program_guard from paddle.fluid import compiler, Program, program_guard
...@@ -759,9 +761,6 @@ class TestPow_factor_tensor(TestActivation): ...@@ -759,9 +761,6 @@ class TestPow_factor_tensor(TestActivation):
self.check_grad(['X'], 'Out') self.check_grad(['X'], 'Out')
def test_api(self): def test_api(self):
import paddle
import paddle.fluid as fluid
input = np.random.uniform(1, 2, [11, 17]).astype("float32") input = np.random.uniform(1, 2, [11, 17]).astype("float32")
x = fluid.layers.data( x = fluid.layers.data(
name="x", shape=[11, 17], append_batch_size=False, dtype="float32") name="x", shape=[11, 17], append_batch_size=False, dtype="float32")
...@@ -1003,5 +1002,74 @@ create_test_act_fp16_class(TestHardSigmoid) ...@@ -1003,5 +1002,74 @@ create_test_act_fp16_class(TestHardSigmoid)
create_test_act_fp16_class(TestSwish) create_test_act_fp16_class(TestSwish)
create_test_act_fp16_class(TestHardSwish) create_test_act_fp16_class(TestHardSwish)
class TestNNReluAPI(unittest.TestCase):
def setUp(self):
self.init_data()
def init_data(self):
self.x_shape = [10, 12]
self.x = np.random.uniform(-1, 1, self.x_shape).astype(np.float32)
self.y = self.ref_forward(self.x)
def ref_forward(self, x):
return np.maximum(x, 0)
def ref_backward(self, y, dy):
y_t = y.copy()
y_t[y_t > 0] = 1
return y_t * dy
def check_api(self, place=fluid.CPUPlace(), inplace=False):
main_program = Program()
myrelu = nn.ReLU(inplace)
with fluid.program_guard(main_program):
x = fluid.data(name='x', shape=self.x_shape)
x.stop_gradient = False
y = myrelu(x)
fluid.backward.append_backward(fluid.layers.mean(y))
exe = fluid.Executor(place)
out = exe.run(main_program,
feed={'x': self.x},
fetch_list=[y, y.grad_name, x.grad_name])
self.assertTrue(np.allclose(out[0], self.y))
self.assertTrue(np.allclose(out[2], self.ref_backward(self.y, out[1])))
with fluid.dygraph.guard(place):
x = fluid.dygraph.to_variable(self.x)
y = myrelu(x)
self.assertTrue(np.allclose(y.numpy(), self.y))
def test_check_api(self):
places = [fluid.CPUPlace()]
if core.is_compiled_with_cuda():
places.append(fluid.CUDAPlace(0))
for place in places:
for inplace in [True, False]:
self.check_api(place, inplace)
class TestNNFunctionalReluAPI(unittest.TestCase):
def setUp(self):
self.init_data()
def init_data(self):
self.x_shape = [10, 12]
self.x = np.random.uniform(-1, 1, self.x_shape).astype(np.float32)
self.y = self.ref_forward(self.x)
def ref_forward(self, x):
return np.maximum(x, 0)
def test_check_api(self):
main_program = Program()
with fluid.program_guard(main_program):
x = fluid.data(name='x', shape=self.x_shape)
y = functional.relu(x)
exe = fluid.Executor(fluid.CPUPlace())
out = exe.run(main_program, feed={'x': self.x}, fetch_list=[y])
self.assertTrue(np.allclose(out[0], self.y))
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()
# 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 numpy as np
import paddle.fluid as fluid
import paddle.fluid.core as core
import paddle.nn as nn
import paddle.nn.functional as functional
def stable_softmax(x):
shiftx = (x - np.max(x))
exps = np.exp(shiftx)
return exps / np.sum(exps)
def ref_log_softmax(x, axis=None, dtype=None):
x_t = x.copy()
if dtype is not None:
x_t = x_t.astype(dtype)
if axis is None:
axis = -1
out = np.apply_along_axis(stable_softmax, axis, x_t)
return np.log(out)
class TestNNLogSoftmaxAPI(unittest.TestCase):
def setUp(self):
self.init_data()
def init_data(self):
self.x_shape = [2, 3, 4, 5]
self.x = np.random.uniform(-1, 1, self.x_shape).astype(np.float32)
def check_api(self, place=fluid.CPUPlace(), axis=None):
ref_out = ref_log_softmax(self.x, axis)
main_program = fluid.Program()
mylogsoftmax = nn.LogSoftmax(axis)
with fluid.program_guard(main_program):
x = fluid.data(name='x', shape=self.x_shape)
y = mylogsoftmax(x)
exe = fluid.Executor(place)
out = exe.run(main_program, feed={'x': self.x}, fetch_list=[y])
self.assertTrue(np.allclose(out[0], ref_out))
with fluid.dygraph.guard(place):
x = fluid.dygraph.to_variable(self.x)
y = mylogsoftmax(x)
self.assertTrue(np.allclose(y.numpy(), ref_out))
def test_check_api(self):
places = [fluid.CPUPlace()]
if core.is_compiled_with_cuda():
places.append(fluid.CUDAPlace(0))
for place in places:
for axis in [None, 2]:
self.check_api(place, axis)
class TestNNFunctionalLogSoftmaxAPI(unittest.TestCase):
def setUp(self):
self.init_data()
def init_data(self):
self.x_shape = [2, 3, 4, 5]
self.x = np.random.uniform(-1, 1, self.x_shape).astype(np.float32)
def check_api(self, place=fluid.CPUPlace(), axis=None, dtype=None):
ref_out = ref_log_softmax(self.x, axis, dtype)
main_program = fluid.Program()
mylogsoftmax = nn.LogSoftmax(axis)
with fluid.program_guard(main_program):
x = fluid.data(name='x', shape=self.x_shape)
y = functional.log_softmax(x, axis, dtype)
exe = fluid.Executor(place)
out = exe.run(main_program, feed={'x': self.x}, fetch_list=[y])
self.assertTrue(np.allclose(out[0], ref_out))
with fluid.dygraph.guard(place):
x = fluid.dygraph.to_variable(self.x)
y = functional.log_softmax(x, axis, dtype)
self.assertTrue(np.allclose(y.numpy(), ref_out))
def test_check_api(self):
places = [fluid.CPUPlace()]
if core.is_compiled_with_cuda():
places.append(fluid.CUDAPlace(0))
for place in places:
self.check_api(place, None, None)
self.check_api(place, None, np.float64)
if __name__ == "__main__":
unittest.main()
...@@ -81,10 +81,10 @@ from .layer.conv import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose #DEFIN ...@@ -81,10 +81,10 @@ from .layer.conv import Conv2D, Conv2DTranspose, Conv3D, Conv3DTranspose #DEFIN
from .layer.norm import InstanceNorm #DEFINE_ALIAS from .layer.norm import InstanceNorm #DEFINE_ALIAS
# from .layer.norm import SpectralNorm #DEFINE_ALIAS # from .layer.norm import SpectralNorm #DEFINE_ALIAS
# from .layer.activation import PReLU #DEFINE_ALIAS # from .layer.activation import PReLU #DEFINE_ALIAS
# from .layer.activation import ReLU #DEFINE_ALIAS from .layer.activation import ReLU #DEFINE_ALIAS
# from .layer.activation import Sigmoid #DEFINE_ALIAS # from .layer.activation import Sigmoid #DEFINE_ALIAS
# from .layer.activation import Softmax #DEFINE_ALIAS # from .layer.activation import Softmax #DEFINE_ALIAS
# from .layer.activation import LogSoftmax #DEFINE_ALIAS from .layer.activation import LogSoftmax #DEFINE_ALIAS
# from .layer.rnn import RNNCell #DEFINE_ALIAS # from .layer.rnn import RNNCell #DEFINE_ALIAS
# from .layer.rnn import GRUCell #DEFINE_ALIAS # from .layer.rnn import GRUCell #DEFINE_ALIAS
# from .layer.rnn import LSTMCell #DEFINE_ALIAS # from .layer.rnn import LSTMCell #DEFINE_ALIAS
...@@ -189,7 +189,7 @@ from .functional.conv import conv3d_transpose #DEFINE_ALIAS ...@@ -189,7 +189,7 @@ from .functional.conv import conv3d_transpose #DEFINE_ALIAS
# from .functional.activation import logsigmoid #DEFINE_ALIAS # from .functional.activation import logsigmoid #DEFINE_ALIAS
# from .functional.activation import maxout #DEFINE_ALIAS # from .functional.activation import maxout #DEFINE_ALIAS
# from .functional.activation import prelu #DEFINE_ALIAS # from .functional.activation import prelu #DEFINE_ALIAS
# from .functional.activation import relu #DEFINE_ALIAS from .functional.activation import relu #DEFINE_ALIAS
# from .functional.activation import relu6 #DEFINE_ALIAS # from .functional.activation import relu6 #DEFINE_ALIAS
# from .functional.activation import selu #DEFINE_ALIAS # from .functional.activation import selu #DEFINE_ALIAS
# from .functional.activation import sigmoid #DEFINE_ALIAS # from .functional.activation import sigmoid #DEFINE_ALIAS
...@@ -201,7 +201,7 @@ from .functional.conv import conv3d_transpose #DEFINE_ALIAS ...@@ -201,7 +201,7 @@ from .functional.conv import conv3d_transpose #DEFINE_ALIAS
# from .functional.activation import swish #DEFINE_ALIAS # from .functional.activation import swish #DEFINE_ALIAS
# from .functional.activation import tanh_shrink #DEFINE_ALIAS # from .functional.activation import tanh_shrink #DEFINE_ALIAS
# from .functional.activation import thresholded_relu #DEFINE_ALIAS # from .functional.activation import thresholded_relu #DEFINE_ALIAS
# from .functional.activation import log_softmax #DEFINE_ALIAS from .functional.activation import log_softmax #DEFINE_ALIAS
# from .functional.extension import add_position_encoding #DEFINE_ALIAS # from .functional.extension import add_position_encoding #DEFINE_ALIAS
# from .functional.extension import autoincreased_step_counter #DEFINE_ALIAS # from .functional.extension import autoincreased_step_counter #DEFINE_ALIAS
# from .functional.extension import continuous_value_model #DEFINE_ALIAS # from .functional.extension import continuous_value_model #DEFINE_ALIAS
......
...@@ -102,6 +102,7 @@ from .conv import conv3d_transpose #DEFINE_ALIAS ...@@ -102,6 +102,7 @@ from .conv import conv3d_transpose #DEFINE_ALIAS
# from .vision import space_to_depth #DEFINE_ALIAS # from .vision import space_to_depth #DEFINE_ALIAS
# from .vision import yolo_box #DEFINE_ALIAS # from .vision import yolo_box #DEFINE_ALIAS
# from .vision import yolov3_loss #DEFINE_ALIAS # from .vision import yolov3_loss #DEFINE_ALIAS
from . import activation
# from .activation import brelu #DEFINE_ALIAS # from .activation import brelu #DEFINE_ALIAS
# from .activation import elu #DEFINE_ALIAS # from .activation import elu #DEFINE_ALIAS
# from .activation import erf #DEFINE_ALIAS # from .activation import erf #DEFINE_ALIAS
...@@ -114,7 +115,7 @@ from .conv import conv3d_transpose #DEFINE_ALIAS ...@@ -114,7 +115,7 @@ from .conv import conv3d_transpose #DEFINE_ALIAS
# from .activation import logsigmoid #DEFINE_ALIAS # from .activation import logsigmoid #DEFINE_ALIAS
# from .activation import maxout #DEFINE_ALIAS # from .activation import maxout #DEFINE_ALIAS
# from .activation import prelu #DEFINE_ALIAS # from .activation import prelu #DEFINE_ALIAS
# from .activation import relu #DEFINE_ALIAS from .activation import relu #DEFINE_ALIAS
# from .activation import relu6 #DEFINE_ALIAS # from .activation import relu6 #DEFINE_ALIAS
# from .activation import selu #DEFINE_ALIAS # from .activation import selu #DEFINE_ALIAS
# from .activation import sigmoid #DEFINE_ALIAS # from .activation import sigmoid #DEFINE_ALIAS
...@@ -126,7 +127,7 @@ from .conv import conv3d_transpose #DEFINE_ALIAS ...@@ -126,7 +127,7 @@ from .conv import conv3d_transpose #DEFINE_ALIAS
# from .activation import swish #DEFINE_ALIAS # from .activation import swish #DEFINE_ALIAS
# from .activation import tanh_shrink #DEFINE_ALIAS # from .activation import tanh_shrink #DEFINE_ALIAS
# from .activation import thresholded_relu #DEFINE_ALIAS # from .activation import thresholded_relu #DEFINE_ALIAS
# from .activation import log_softmax #DEFINE_ALIAS from .activation import log_softmax #DEFINE_ALIAS
# from .extension import add_position_encoding #DEFINE_ALIAS # from .extension import add_position_encoding #DEFINE_ALIAS
# from .extension import autoincreased_step_counter #DEFINE_ALIAS # from .extension import autoincreased_step_counter #DEFINE_ALIAS
# from .extension import continuous_value_model #DEFINE_ALIAS # from .extension import continuous_value_model #DEFINE_ALIAS
......
...@@ -12,29 +12,167 @@ ...@@ -12,29 +12,167 @@
# 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.
import warnings
from ...fluid.layer_helper import LayerHelper
from ...fluid.framework import in_dygraph_mode, convert_np_dtype_to_dtype_
from ...fluid import core
# TODO: define activation functions of neural network # TODO: define activation functions of neural network
# __all__ = ['brelu', __all__ = [
# 'elu', # 'brelu',
# 'erf', # 'elu',
# 'gelu', # 'erf',
# 'hard_shrink', # 'gelu',
# 'hard_sigmoid', # 'hard_shrink',
# 'hard_swish', # 'hard_sigmoid',
# 'hsigmoid', # 'hard_swish',
# 'leaky_relu', # 'hsigmoid',
# 'logsigmoid', # 'leaky_relu',
# 'maxout', # 'logsigmoid',
# 'prelu', # 'maxout',
# 'relu', # 'prelu',
# 'relu6', 'relu',
# 'selu', # 'relu6',
# 'sigmoid', # 'selu',
# 'soft_relu', # 'sigmoid',
# 'softmax', # 'soft_relu',
# 'softplus', # 'softmax',
# 'softshrink', # 'softplus',
# 'softsign', # 'softshrink',
# 'swish', # 'softsign',
# 'tanh_shrink', # 'swish',
# 'thresholded_relu', # 'tanh_shrink',
# 'log_softmax'] # 'thresholded_relu',
'log_softmax',
]
def relu(input, inplace=False, name=None):
"""
ReLU Activation.
.. math:
out = max(x, 0)
Parameters:
input (Variable): The input variable. A multi-dimension Tensor with type float16, float32, or float64.
inplace (bool, optional): If inplace is True, the input and output of ``ReLU`` are the same variable.
Otherwise, the input and output of ``ReLU`` are different variables. Default: False. Note that if x is
more than one OPs' input, inplace must be False.
name (str, optional): The default value is None. Normally there is no need for user to set this property.
For more information, please refer to :ref:`api_guide_Name` .
Returns:
Output of relu operator, a Tensor with shape same as input
Examples:
.. code-block:: python
import paddle.fluid as fluid
import paddle.nn.functional as functional
import numpy as np
data = np.array([-2, 0, 1]).astype('float32')
with fluid.dygraph.guard():
data = fluid.dygraph.to_variable(data)
res = functional.relu(data) # [0, 0, 1]
"""
if in_dygraph_mode():
if inplace:
warnings.warn(
"Inplace on ReLU is not allowed and will be discarded in dygraph mode currently."
)
return core.ops.relu(input)
helper = LayerHelper('relu', **locals())
outs = input if inplace else helper.create_variable_for_type_inference(
input.dtype)
helper.append_op(type='relu', inputs={'X': [input]}, outputs={'Out': outs})
return outs
def log_softmax(input, axis=None, dtype=None, name=None):
"""
This operator implements the log_softmax layer. The calculation process is as follows:
.. math::
Out[i, j] = log(softmax(x))
= log(\\frac{\exp(X[i, j])}{\sum_j(exp(X[i, j])})
Parameters:
input (Variable): The input variable. A multi-dimension Tensor with type float32, or float64.
axis (int, optional): The index of dimension to perform softmax calculations, it should be in
range :math:`[-1, rank-1]`, while :math:`rank` is the rank of input variable. Default: None.
None and -1 means the last dimension.
dtype (np.dtype|core.VarDesc.VarType|str): The desired data type of returned tensor. If specified,
the input tensor is casted to dtype before the operation is performed. This is useful for
preventing data type overflows. Default: None. Supported dtype: float32 or float64
name (str, optional): The default value is None. Normally there is no need for user to set this property.
For more information, please refer to :ref:`api_guide_Name` .
Returns:
Variable: ``Tensor`` indicates the output of softmax. The data type and shape are the same as ``input``.
Examples:
.. code-block:: python
import paddle.fluid as fluid
import paddle.nn.functional as F
import numpy as np
data = np.array([[[-2.0, 3.0, -4.0, 5.0],
[3.0, -4.0, 5.0, -6.0],
[-7.0, -8.0, 8.0, 9.0]],
[[1.0, -2.0, -3.0, 4.0],
[-5.0, 6.0, 7.0, -8.0],
[6.0, 7.0, 8.0, 9.0]]]).astype('float32')
with fluid.dygraph.guard():
data = fluid.dygraph.to_variable(data)
res = F.log_softmax(data, -1)
# [[[ -7.1278396 -2.1278396 -9.127839 -0.12783948]
# [ -2.1270514 -9.127051 -0.12705144 -11.127051 ]
# [-16.313261 -17.313261 -1.3132617 -0.31326184]]
# [[ -3.0518122 -6.051812 -7.051812 -0.051812 ]
# [-12.313267 -1.3132664 -0.3132665 -15.313267 ]
# [ -3.4401896 -2.4401896 -1.4401896 -0.44018966]]]
"""
axis = -1 if axis is None else axis
dtype = convert_np_dtype_to_dtype_(dtype) if dtype is not None else dtype
if in_dygraph_mode():
outs_cast = input if dtype is None \
else core.ops.cast(input, 'in_dtype', input.dtype, 'out_dtype', dtype)
outs_softmax = core.ops.softmax(outs_cast, 'axis', axis, 'use_cudnn',
False)
return core.ops.log(outs_softmax)
helper = LayerHelper("log_softmax", **locals())
outs_cast = input
if dtype is not None:
outs_cast = helper.create_variable_for_type_inference(dtype)
helper.append_op(
type='cast',
inputs={'X': input},
outputs={'Out': outs_cast},
attrs={'in_dtype': input.dtype,
'out_dtype': dtype})
outs_softmax = helper.create_variable_for_type_inference(outs_cast.dtype)
helper.append_op(
type='softmax',
inputs={'X': outs_cast},
outputs={'Out': outs_softmax},
attrs={'axis': axis,
'use_cudnn': False})
outs_log = helper.create_variable_for_type_inference(outs_softmax.dtype)
helper.append_op(
type='log', inputs={'X': outs_softmax}, outputs={'Out': outs_log})
return outs_log
...@@ -14,10 +14,12 @@ ...@@ -14,10 +14,12 @@
# TODO: define activation functions of neural network # TODO: define activation functions of neural network
from . import activation
from . import loss from . import loss
from . import conv from . import conv
from . import norm from . import norm
from .activation import *
from .loss import * from .loss import *
from .conv import * from .conv import *
from .norm import * from .norm import *
...@@ -12,5 +12,108 @@ ...@@ -12,5 +12,108 @@
# 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 ...fluid.dygraph import layers
from ...fluid import core
from ...fluid.framework import in_dygraph_mode
from .. import functional
# TODO: define activation functions of neural network # TODO: define activation functions of neural network
# __all__ = ['PReLU', 'ReLU', 'Sigmoid', 'Softmax', 'LogSoftmax'] __all__ = [
# 'PReLU',
'ReLU',
# 'Sigmoid',
# 'Softmax',
'LogSoftmax',
]
class ReLU(layers.Layer):
"""
ReLU Activation.
.. math:
out = max(x, 0)
Parameters:
inplace (bool, optional): If inplace is True, the input and output of
``ReLU`` are the same variable. Otherwise, the input and output of
``ReLU`` are different variables. Default False. Note that if x is
more than one OPs' input, inplace must be False.
Returns:
None
Examples:
.. code-block:: python
import paddle.fluid as fluid
import paddle.nn as nn
import numpy as np
data = np.array([-2, 0, 1]).astype('float32')
my_relu = nn.ReLU()
with fluid.dygraph.guard():
data = fluid.dygraph.to_variable(data)
res = my_relu(data) # [0, 0, 1]
"""
def __init__(self, inplace=False):
super(ReLU, self).__init__()
self._inplace = inplace
def forward(self, input):
return functional.relu(input, self._inplace)
class LogSoftmax(layers.Layer):
"""
This operator implements the log_softmax layer. The calculation process is as follows:
.. math::
Out[i, j] = log(softmax(x))
= log(\\frac{\exp(X[i, j])}{\sum_j(exp(X[i, j])})
Parameters:
axis (int, optional): The index of dimension to perform softmax calculations, it should be in
range :math:`[-1, rank-1]`, while :math:`rank` is the rank of input variable. Default: None.
None and -1 means the last dimension.
dtype (np.dtype|core.VarDesc.VarType|str): The desired data type of returned tensor. If specified,
the input tensor is casted to dtype before the operation is performed. This is useful for
preventing data type overflows. Default: None. Supported dtype: float32 or float64
Returns:
None
Examples:
.. code-block:: python
import paddle.fluid as fluid
import paddle.nn as nn
import numpy as np
data = np.array([[[-2.0, 3.0, -4.0, 5.0],
[3.0, -4.0, 5.0, -6.0],
[-7.0, -8.0, 8.0, 9.0]],
[[1.0, -2.0, -3.0, 4.0],
[-5.0, 6.0, 7.0, -8.0],
[6.0, 7.0, 8.0, 9.0]]]).astype('float32')
my_log_softnmax = nn.LogSoftmax()
with fluid.dygraph.guard():
data = fluid.dygraph.to_variable(data)
res = my_log_softnmax(data)
# [[[ -7.1278396 -2.1278396 -9.127839 -0.12783948]
# [ -2.1270514 -9.127051 -0.12705144 -11.127051 ]
# [-16.313261 -17.313261 -1.3132617 -0.31326184]]
# [[ -3.0518122 -6.051812 -7.051812 -0.051812 ]
# [-12.313267 -1.3132664 -0.3132665 -15.313267 ]
# [ -3.4401896 -2.4401896 -1.4401896 -0.44018966]]]
"""
def __init__(self, axis=None):
super(LogSoftmax, self).__init__()
self._axis = axis
def forward(self, input):
return functional.log_softmax(input, self._axis)
...@@ -105,8 +105,6 @@ write_version_py(filename='@PADDLE_BINARY_DIR@/python/paddle/version.py') ...@@ -105,8 +105,6 @@ write_version_py(filename='@PADDLE_BINARY_DIR@/python/paddle/version.py')
packages=['paddle', packages=['paddle',
'paddle.nn',
'paddle.nn.layer',
'paddle.libs', 'paddle.libs',
'paddle.utils', 'paddle.utils',
'paddle.dataset', 'paddle.dataset',
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册