summaryrefslogtreecommitdiff
path: root/sdil/core.py
diff options
context:
space:
mode:
Diffstat (limited to 'sdil/core.py')
-rw-r--r--sdil/core.py17
1 files changed, 9 insertions, 8 deletions
diff --git a/sdil/core.py b/sdil/core.py
index e66dc39..64c7c79 100644
--- a/sdil/core.py
+++ b/sdil/core.py
@@ -265,10 +265,11 @@ class SDILNet:
def vectorizer(self, l, c, h_l=None, context=None):
"""Return the learned instructional component of apical activity.
- ``soma_gated`` adds ``h_i G_i c`` independently in every cell.
- ``context_gated`` adds a linear readout of ``c outer context``. Both
- vanish when c=0, so neutral-period predictor identification remains
- unchanged.
+ ``soma_gated`` adds ``tanh(h_i) G_i c`` independently in every cell.
+ ``context_gated`` adds a linear readout of ``c outer tanh(context)``.
+ Bounding the state feature prevents a bilinear positive-feedback loop;
+ both terms vanish when c=0, so neutral-period predictor identification
+ remains unchanged.
"""
value = c @ self.A[l].t()
if self.vectorizer_mode == "linear":
@@ -276,10 +277,10 @@ class SDILNet:
if self.vectorizer_mode == "soma_gated":
if h_l is None:
raise ValueError("soma-gated vectorizer requires somatic activity")
- return value + h_l * (c @ self.A_gate[l].t())
+ return value + torch.tanh(h_l) * (c @ self.A_gate[l].t())
if context is None:
raise ValueError("context-gated vectorizer requires a context state")
- features = (c.unsqueeze(2) * context.unsqueeze(1)).flatten(1)
+ features = (c.unsqueeze(2) * torch.tanh(context).unsqueeze(1)).flatten(1)
return value + features @ self.A_gate[l].t()
def apical(self, l, c, h_l=None, context=None):
@@ -551,10 +552,10 @@ def sdil_step(net, x, y, y_onehot, cfg, step, prev_error=None):
dA = calibration_error.t() @ c / B # (n_l, n_classes)
net.A[l] += cfg.eta_A * dA
if net.vectorizer_mode == "soma_gated":
- dgate = (calibration_error * h[l + 1]).t() @ c / B
+ dgate = (calibration_error * torch.tanh(h[l + 1])).t() @ c / B
net.A_gate[l] += cfg.eta_A * dgate
elif net.vectorizer_mode == "context_gated":
- features = (c.unsqueeze(2) * context.unsqueeze(1)).flatten(1)
+ features = (c.unsqueeze(2) * torch.tanh(context).unsqueeze(1)).flatten(1)
dgate = calibration_error.t() @ features / B
net.A_gate[l] += cfg.eta_A * dgate