Skip to content

Commit fa80c06

Browse files
committed
Merge branch 'master' of https://github.com/explosion/thinc
2 parents 0528e13 + 1233d0b commit fa80c06

File tree

7 files changed

+107
-9
lines changed

7 files changed

+107
-9
lines changed

thinc/api.py

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from .layers import Dropout, Embed, expand_window, HashEmbed, LayerNorm, Linear
2323
from .layers import Maxout, Mish, MultiSoftmax, Relu, softmax_activation, Softmax, LSTM
2424
from .layers import CauchySimilarity, ParametricAttention, Logistic
25+
from .layers import sigmoid_activation, Sigmoid
2526
from .layers import SparseLinear
2627
from .layers import PyTorchWrapper, PyTorchRNNWrapper, PyTorchLSTM
2728
from .layers import TensorFlowWrapper, keras_subclass, MXNetWrapper

thinc/backends/ops.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
ArrayT = TypeVar("ArrayT", bound=ArrayXd)
1414
FloatsT = TypeVar("FloatsT", bound=_Floats)
15+
FloatsType = TypeVar("FloatsType", bound=FloatsXd)
1516

1617

1718
class Ops:
@@ -558,16 +559,16 @@ def as_contig(self, data: ArrayT, dtype: Optional[DTypes] = None) -> ArrayT:
558559
kwargs = {"dtype": dtype} if dtype is not None else {}
559560
return self.xp.ascontiguousarray(data, **kwargs)
560561

561-
def sigmoid(self, X: FloatsT, *, inplace: bool = False) -> FloatsT:
562+
def sigmoid(self, X: FloatsType, *, inplace: bool = False) -> FloatsType:
562563
if inplace:
563564
self.xp.exp(-X, out=X)
564-
X += 1.0
565-
X **= -1.0
566-
return X
565+
X += 1.0 # type: ignore
566+
X **= -1.0 # type: ignore
567+
return cast(FloatsType, X)
567568
else:
568-
return 1.0 / (1.0 + self.xp.exp(-X))
569+
return cast(FloatsType, 1.0 / (1.0 + self.xp.exp(-X)))
569570

570-
def dsigmoid(self, Y: FloatsT, *, inplace: bool = False) -> FloatsT:
571+
def dsigmoid(self, Y: FloatsType, *, inplace: bool = False) -> FloatsType:
571572
if inplace:
572573
Y *= 1 - Y
573574
return Y

thinc/layers/__init__.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@
66
from .hashembed import HashEmbed
77
from .layernorm import LayerNorm
88
from .linear import Linear
9+
from .lstm import LSTM, PyTorchLSTM
910
from .logistic import Logistic
1011
from .maxout import Maxout
1112
from .mish import Mish
1213
from .multisoftmax import MultiSoftmax
1314
from .parametricattention import ParametricAttention
1415
from .pytorchwrapper import PyTorchWrapper, PyTorchRNNWrapper
1516
from .relu import Relu
17+
from .sigmoid_activation import sigmoid_activation
18+
from .sigmoid import Sigmoid
1619
from .softmax_activation import softmax_activation
1720
from .softmax import Softmax
1821
from .sparselinear import SparseLinear
19-
from .lstm import LSTM, PyTorchLSTM
2022
from .tensorflowwrapper import TensorFlowWrapper, keras_subclass
2123
from .mxnetwrapper import MXNetWrapper
2224

@@ -69,18 +71,20 @@
6971
"expand_window",
7072
"HashEmbed",
7173
"LayerNorm",
74+
"LSTM",
7275
"Maxout",
7376
"Mish",
7477
"MultiSoftmax",
7578
"ParametricAttention",
79+
"PyTorchLSTM",
7680
"PyTorchWrapper",
7781
"PyTorchRNNWrapper",
7882
"Relu",
83+
"sigmoid_activation",
84+
"Sigmoid"
7985
"softmax_activation",
8086
"Softmax",
8187
"SparseLinear",
82-
"LSTM",
83-
"PyTorchLSTM",
8488
"TensorFlowWrapper",
8589
"add",
8690
"bidirectional",

thinc/layers/logistic.py

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
@registry.layers("Logistic.v1")
1313
def Logistic() -> Model[InT, OutT]:
14+
"""Deprecated in favor of `sigmoid_activation` layer, for more consistent
15+
naming.
16+
"""
1417
return Model("logistic", forward)
1518

1619

thinc/layers/sigmoid.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from typing import Tuple, Callable, Optional, cast
2+
3+
from ..model import Model
4+
from ..config import registry
5+
from ..types import Floats2d, Floats1d
6+
from ..initializers import zero_init
7+
from ..util import get_width, partial
8+
9+
10+
InT = Floats2d
11+
OutT = Floats2d
12+
13+
14+
@registry.layers("Sigmoid.v1")
15+
def Sigmoid(
16+
nO: Optional[int] = None,
17+
nI: Optional[int] = None,
18+
*,
19+
init_W: Callable = zero_init,
20+
init_b: Callable = zero_init
21+
) -> Model[InT, OutT]:
22+
"""A dense layer, followed by a sigmoid (logistic) activation function. This
23+
is usually used instead of the Softmax layer as an output for multi-label
24+
classification.
25+
"""
26+
return Model(
27+
"sigmoid",
28+
forward,
29+
init=partial(init, init_W, init_b),
30+
dims={"nO": nO, "nI": nI},
31+
params={"W": None, "b": None},
32+
)
33+
34+
35+
def forward(model: Model[InT, OutT], X: InT, is_train: bool) -> Tuple[OutT, Callable]:
36+
W = cast(Floats2d, model.get_param("W"))
37+
b = cast(Floats1d, model.get_param("b"))
38+
Y = model.ops.affine(X, W, b)
39+
Y = model.ops.sigmoid(Y)
40+
41+
def backprop(dY: InT) -> OutT:
42+
dY = dY * model.ops.dsigmoid(Y, inplace=False)
43+
model.inc_grad("b", dY.sum(axis=0))
44+
model.inc_grad("W", model.ops.gemm(dY, X, trans1=True))
45+
return model.ops.gemm(dY, W)
46+
47+
return Y, backprop
48+
49+
50+
def init(
51+
init_W: Callable,
52+
init_b: Callable,
53+
model: Model[InT, OutT],
54+
X: Optional[InT] = None,
55+
Y: Optional[OutT] = None,
56+
) -> Model[InT, OutT]:
57+
if X is not None and model.has_dim("nI") is None:
58+
model.set_dim("nI", get_width(X))
59+
if Y is not None and model.has_dim("nO") is None:
60+
model.set_dim("nO", get_width(Y))
61+
model.set_param("W", init_W(model.ops, (model.get_dim("nO"), model.get_dim("nI"))))
62+
model.set_param("b", init_b(model.ops, (model.get_dim("nO"),)))
63+
return model

thinc/layers/sigmoid_activation.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from typing import TypeVar, Tuple, Callable, cast
2+
3+
from ..model import Model
4+
from ..config import registry
5+
from ..types import FloatsXd
6+
7+
8+
InT = TypeVar("InT", bound=FloatsXd)
9+
10+
11+
@registry.layers("sigmoid_activation.v1")
12+
def sigmoid_activation() -> Model[InT, InT]:
13+
return Model("sigmoid_activation", forward)
14+
15+
16+
def forward(model: Model[InT, InT], X: InT, is_train: bool) -> Tuple[InT, Callable]:
17+
Y = model.ops.sigmoid(X, inplace=False)
18+
19+
def backprop(dY: InT) -> InT:
20+
return dY * model.ops.dsigmoid(Y, inplace=False) # type: ignore
21+
22+
return Y, backprop

thinc/tests/layers/test_layers_api.py

+4
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ def assert_data_match(Y, out_data):
6969
("Mish.v1", {"normalize": True, "dropout": 0.2}, array2d, array2d),
7070
("Relu.v1", {}, array2d, array2d),
7171
("Relu.v1", {"normalize": True, "dropout": 0.2}, array2d, array2d),
72+
("Sigmoid.v1", {}, array2d, array2d),
73+
("Sigmoid.v1", {"nO": 4, "nI": 4}, array2d, array2d),
74+
("sigmoid_activation.v1", {}, array2d, array2d),
75+
("softmax_activation.v1", {}, array2d, array2d),
7276
("Softmax.v1", {}, array2d, array2d),
7377
("Softmax.v1", {"nO": 4, "nI": 4}, array2d, array2d),
7478
# fmt: off

0 commit comments

Comments
 (0)