/
sigmoid.py
120 lines (93 loc) · 3.44 KB
/
sigmoid.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import numpy
import chainer
from chainer.backends import cuda
from chainer import function_node
from chainer import utils
from chainer.utils import type_check
if cuda.cudnn_enabled:
cudnn = cuda.cudnn
libcudnn = cuda.cuda.cudnn
_mode = libcudnn.CUDNN_ACTIVATION_SIGMOID
class Sigmoid(function_node.FunctionNode):
"""Logistic sigmoid function."""
def check_type_forward(self, in_types):
type_check.expect(in_types.size() == 1)
type_check.expect(in_types[0].dtype.kind == 'f')
def forward_cpu(self, inputs):
x = inputs[0]
half = x.dtype.type(0.5)
y = utils.force_array(numpy.tanh(x * half) * half + half)
self.retain_outputs((0,))
self._use_cudnn = False
return y,
def forward_gpu(self, inputs):
x = inputs[0]
if chainer.should_use_cudnn('==always') and x.flags.c_contiguous:
y = cudnn.activation_forward(x, _mode)
self.retain_inputs((0,))
self._use_cudnn = True
else:
y = cuda.elementwise(
'T x', 'T y', 'y = tanh(x * 0.5) * 0.5 + 0.5',
'sigmoid_fwd')(x)
self._use_cudnn = False
self.retain_outputs((0,))
return y,
def backward(self, indexes, grad_outputs):
if self._use_cudnn:
x = self.get_retained_inputs()[0].data
else:
x = None
y = self.get_retained_outputs()[0]
gy, = grad_outputs
return SigmoidGrad((x,)).apply((y, gy))
class SigmoidGrad(function_node.FunctionNode):
"""Logistic sigmoid gradient function."""
def __init__(self, inputs):
super(SigmoidGrad, self).__init__()
self.x = inputs[0]
def check_type_forward(self, in_types):
type_check.expect(in_types.size() == 2)
type_check.expect(in_types[0].dtype.kind == 'f')
type_check.expect(in_types[1].dtype.kind == 'f')
def forward_cpu(self, inputs):
self.retain_inputs((0, 1))
y, gy = inputs
one = y.dtype.type(1)
return utils.force_array(gy * y * (one - y)),
def forward_gpu(self, inputs):
self.retain_inputs((0, 1))
y, gy = inputs
if (chainer.should_use_cudnn('==always') and gy.flags.c_contiguous and
self.x is not None and self.x.flags.c_contiguous):
gx = cudnn.activation_backward(self.x, y, gy, _mode)
else:
gx = cuda.elementwise(
'T y, T gy', 'T gx',
'gx = gy * y * (1 - y)',
'sigmoid_bwd')(y, gy)
return gx,
def backward(self, indexes, grad_outputs):
y, gy = self.get_retained_inputs()
g, = grad_outputs
return g * gy * (1 - 2 * y), g * y * (1 - y)
def sigmoid(x):
"""Element-wise sigmoid logistic function.
.. math:: f(x)=(1 + \\exp(-x))^{-1}.
Args:
x (:class:`~chainer.Variable` or :class:`numpy.ndarray` or \
:class:`cupy.ndarray`):
Input variable. A :math:`(s_1, s_2, ..., s_N)`-shaped float array.
Returns:
~chainer.Variable: Output variable. A
:math:`(s_1, s_2, ..., s_N)`-shaped float array.
.. admonition:: Example
It maps the input values into the range of :math:`[0, 1]`.
>>> x = np.arange(-2, 3, 2).astype('f')
>>> x
array([-2., 0., 2.], dtype=float32)
>>> F.sigmoid(x)
variable([0.11920291, 0.5 , 0.8807971 ])
"""
y, = Sigmoid().apply((x,))
return y