hey scott!
I’ve been working hard on various things related to this. It has wormed its way into my mind. I did fork the ear module for yall
Recently I was actually able to do a couple of cool things:
- FrankenMonty - numba jit compiled version of stock monty for robotics and low-resource computer hardware.
2. 12 column Monty in a 6 object space with a body and a “No” vote - this is something new I’ve been working on this past week. I built a tiny ant with many senses that runs around a room with 6 Monty objects and wired all the columns together.I have been running experiments and testing outputs and have been trying to not get too excited, but it is very cool. This project also uses MuJoCo to give objects more physical parameters that are testable by other, orthogonal-failing sense organs (here’s a link to my post about this in more detail).
3. In general just reading and trying to stumble upon something else like the CARFAC for all other senses.
For 2, I did actually finally get the nerve to go in and fiddle with monty. I just found that it really needed a way to say “no” itself and some kind of confidence punishment that went along with it for incorrect columns. Assuming numpy import:
from tbp.monty.frameworks.models.evidence_matching.feature_evidence.calculator import (
DefaultFeatureEvidenceCalculator,
)
class NoFeatureEvidenceCalculator(DefaultFeatureEvidenceCalculator):
NO_AT = 2.0 # x tolerance = a contradiction
NO_EVIDENCE = -1.0
@classmethod
def calculate(cls, channel_feature_array, channel_feature_order, channel_feature_weights,
channel_query_features, channel_tolerances):
evidence = super().calculate(channel_feature_array, channel_feature_order, channel_feature_weights,
channel_query_features, channel_tolerances)
# rebuild the stock per-column layout: query value + tolerance per feature column
n_cols = channel_feature_array.shape[1]
tol = np.full(n_cols, np.nan); query = np.full(n_cols, np.nan)
circ = np.zeros(n_cols, bool); cat = np.zeros(n_cols, bool)
i = 0
for f in channel_feature_order:
if f in cls.SKIP_FEATURES:
continue
q = channel_query_features[f]
n = len(q) if hasattr(q, "__len__") else 1
query[i:i + n] = q; tol[i:i + n] = channel_tolerances[f]
if f in cls.CIRCULAR_FEATURES: circ[i] = True
elif f in cls.CATEGORICAL_FEATURES: cat[i:i + n] = True
i += n
diff = np.abs(channel_feature_array - query)
if circ.any():
c = channel_feature_array[:, circ]; qc = query[circ]
diff[:, circ] = np.min([np.abs(cls.CIRCULAR_RANGE + c - qc), np.abs(c - qc),
np.abs(c - (qc + cls.CIRCULAR_RANGE))], axis=0)
diff[:, cat] = (channel_feature_array[:, cat] != query[cat]).astype(float) * 1e9
# THE NO: any feature past NO_AT x tolerance -> this node scores -1, not the diluted average
contradicts = np.nan_to_num(diff > cls.NO_AT * tol, nan=False).any(axis=1)
return np.where(contradicts, cls.NO_EVIDENCE, evidence)
To wire it in from Python (how ant_cols.py does it):
EvidenceGraphLM(...,
hypotheses_updater_args=dict(feature_evidence_calculator=NoFeatureEvidenceCalculator))
Or from a Hydra config:
hypotheses_updater_args:
feature_evidence_calculator: ${monty.class:audiomonty.no.NoFeatureEvidenceCalculator}
Monty is usually done in sessions that run and stop and report. I wanted to see what happens if we treat all senses as if they were always on and trying to contribute. Accumulation after all is something that inherently happens over time, and if it can only grow, it will saturate fast and become a useless tautology before it can become useful to an embodied AI. This is all pretty time consuming cause you need to give all of the objects in MuJoCo properties that its various sense organs can id.


graph: this shows where the bot is (orange dot) and where its vote says it is (purple star). The cloud of purple dots represent votes from various columns. Error on the top rght. Bananas are hard and get confounded with boxes.
Mainly though, I have been working on a fourth project: MEGA BUD. This is a 3 section ant with Strandbeest style legs. The “ant” I made for my 11 column Monty is a tiny version of this. I got tired of working around the tiny form factor and battery situation of OG bud and started on this insanity. I probably wont have anything super dope to show from this until next week or the week after… but when it’s up it will be cool as hell.
Lately this has all become a sort of “everything at the same time” kind of project, which is how I like em, but it means that my virtual desk is not exactly totally clean and the bench is covered in stuff. If there is anything you are particularly interested in me pushing and sharing to GitHub, im down, but it will have to come with the warning that this is the definition of a work in progress~!