You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

65 lines
1.7 KiB

from typing import Callable, Optional, Tuple, cast
from ..config import registry
from ..model import Model
from ..types import Floats1d, Floats2d
from ..util import get_width
InT = Tuple[Floats2d, Floats2d]
OutT = Floats1d
@registry.layers("CauchySimilarity.v1")
def CauchySimilarity(nI: Optional[int] = None) -> Model[InT, OutT]:
"""Compare input vectors according to the Cauchy similarity function proposed by
Chen (2013). Primarily used within Siamese neural networks.
"""
return Model(
"cauchy_similarity",
forward,
init=init,
dims={"nI": nI, "nO": 1},
params={"W": None},
)
def forward(
model: Model[InT, OutT], X1_X2: InT, is_train: bool
) -> Tuple[OutT, Callable]:
X1, X2 = X1_X2
W = cast(Floats2d, model.get_param("W"))
diff = X1 - X2
square_diff = diff**2
total = (W * square_diff).sum(axis=1)
sim, bp_sim = inverse(total)
def backprop(d_sim: OutT) -> InT:
d_total = bp_sim(d_sim)
d_total = model.ops.reshape2f(d_total, -1, 1)
model.inc_grad("W", (d_total * square_diff).sum(axis=0))
d_square_diff = W * d_total
d_diff = 2 * d_square_diff * diff
return (d_diff, -d_diff)
return sim, backprop
def init(
model: Model[InT, OutT], X: Optional[InT] = None, Y: Optional[OutT] = None
) -> None:
if X is not None:
model.set_dim("nI", get_width(X[0]))
# Initialize weights to 1
W = model.ops.alloc1f(model.get_dim("nI"))
W += 1
model.set_param("W", W)
def inverse(total: OutT) -> Tuple[OutT, Callable]:
inv = 1.0 / (1 + total)
def backward(d_inverse: OutT) -> OutT:
return d_inverse * (-1 / (total + 1) ** 2)
return inv, backward