XSLmodels 0.4.0
New Features
- Added
uncfam_elimination(), a variant of
uncfam() with learning by elimination (mutual exclusivity).
Each on-trial pair’s mutual confidence P(o|w) * P(w|o) is
computed from the current associations, and a pair gets elimination
support to the extent that the trial’s other words and objects are
already accounted for by each other. That support, weighted by a free
parameter eps, is added to uncfam()’s
familiarity-and-uncertainty share of the trial’s associative weight
before renormalizing; eps = 0 reproduces
uncfam() exactly. In uncfam(), an
already-known pair on a trial draws weight away from the
trial’s other pairs; with elimination, knowing one word directs learning
to the remaining word-object pairing. Motivated by the initial-accuracy
experiment, where learners were more accurate on an initially mis-paired
word the more of its study trials it shared with an initially accurate
word. Registered in
show_models()/xsl_model_registry()
- Added
uncfam_gamma(), a variant of
uncfam() that decouples familiarity’s contribution to a
trial’s attentional allocation from uncertainty’s.
uncfam()’s allocation weight is
exp(B * entropy) * assocs – entropy gets a free exponent
(B), but familiarity (assocs) enters linearly
with an implicit weight of 1 and no free parameter of its own.
uncfam_gamma() adds one parameter, gamma,
raising familiarity to a free power instead (assocs^gamma);
gamma = 1 reproduces uncfam() exactly.
Cross-validated against all of xsl_datasets, it beats plain
uncfam() in every fold of a 5-fold split (mean test SSE
0.48 vs. 0.56), with a best-fit gamma around 0.3
(familiarity’s pull dampens with diminishing returns). A
separate analysis fitting this same free-gamma substrate to
active cross-situational word learning (learners choosing which items to
see named next, rather than a fixed passive sequence) instead found a
best-fit gamma around 2 (amplified, not dampened) – see
?uncfam_gamma for the full comparison
- Added
minerva2(), todam(), and
rem(), three distributed/episodic memory models ported from
standalone prototypes that predated this package (Hintzman’s MINERVA2,
1984/1986; Murdock’s TODAM, 1982; Shiffrin & Steyvers’ REM, 1997)
and were never wired into it or tested. All three represent
words/objects as random feature vectors rather than tallying a single
word-by-object association, and turn their native similarity/odds score
into a Luce-choice-ready matrix via an exponentiated
(X-temperature) or likelihood-ratio-based choice rule so
they plug into get_perf()/mafc_test() like
every other model here. Porting surfaced real bugs in the prototypes,
fixed along the way (see each model’s @details/source
comments): minerva2()‘s prototype compared a 2D
echo-content vector against D-dim object vectors (silent recycling, not
an error) instead of just the echo’s object half; todam()’s
prototype computed trial-1 attention weights as
cos_sim(item, 0) = NaN, poisoning memory from the first
trial on, and both todam() prototypes called the
long-removed as.real(); rem()’s prototype
never actually implemented REM at all (it declared a geometric
feature-vector generator but its model/test functions were an unmodified
copy of the MINERVA2 prototype’s continuous-Gaussian code) –
rem() here is a fresh adaptation of Shiffrin &
Steyvers’ storage/odds equations to this package’s associative task.
Benchmarking (see
?minerva2/?todam/?rem performance
notes) found rem()’s raw per-simulation likelihood-ratio
odds span several orders of magnitude (a lucky match on one rare feature
value can dominate), which would otherwise let a single lucky simulation
hijack xsl_run()’s sum-across-simulations aggregation;
rem() now row-normalizes each simulation’s choice weights
before returning them. All three are registered in
show_models()/xsl_model_registry(), fitting
only their choice-rule temperature (X) or storage
parameters (g, u, c) by default –
D/w (feature-vector dimensionality) are fixed
representational hyperparameters, not free cognitive parameters. Speed
varies widely: on the full xsl_datasets (53 conditions) at
n_sim = 500, minerva2() takes ~30s,
todam() ~8 min, and rem() ~20 min –
todam()/rem() are impractical to
xsl_fit() at full DEoptim settings
(NP = 100, itermax = 100 would be tens of thousands of
evaluations) without sharply reducing
n_sim/NP/itermax, as the
package’s own fitting examples already do for slow models
- Added 3 more temporal-contiguity conditions to
xsl_datasets from Kachergis, Yu, & Shiffrin (2009) –
the same paper behind the existing
1_max_temp_spat_cont_orig/4_no_spat_orig_max_tc
conditions. data-raw/XSL-dataset-fields.csv documented 6
“overlap” conditions (3 matched pairs of a control and non-control order
at the same overlap degree) that were never pulled in; only the 3
control-order ones (1olap3tr_contr,
temp_cont_1olap2tr_contr,
temp_cont_2olap2tr_contr) have real subject-level accuracy
data findable anywhere in the repo (in
data-raw/agg_data/x13_1-21.txt, per
export_data.R’s own comments mapping its generic condition
labels to these named orders). The other 3 have order files but no
discoverable human data, and are deliberately left out rather than
guessed. See
data-raw/add_temporal_contiguity_overlap.R
- Added a fifth standalone dataset,
benitez2020 (a named
list of 7 xslData objects, one per condition x age-group
combination) from Benitez et al. (2020), “The temporal structure of
naming events differentially affects children’s and adults’
cross-situational word learning” (data: osf.io/2hmxr).
data-raw/Benitez2020-rep/Benitez2020_XSLdata_extraction.R
already extracted training orders, 2AFC test trials, and response-count
matrices from the raw OSF data but stopped short of building
xslData objects (a literal # ToDo in the
file); data-raw/add_benitez2020.R picks up from there. 8
symmetric word-object pairs, 12 training trials, 8-item 2AFC test;
unlike the other standalone datasets, real per-word accuracy is
recoverable directly from the provided response matrices (not just an
overall mean) – structurally it could join xsl_datasets
directly, but is kept standalone by choice, as held-out
generalization-test data (see xsl_holdout_datasets)
- Added
xsl_holdout_datasets, a registry of every dataset
in the package that is not part of xsl_datasets
and therefore never seen by
get_group_model_fit()/get_crossvalidated_model_fit()
– i.e. everything available for testing a fitted model’s generalization
to genuinely held-out data, along with how to score each one (most need
a different scoring approach than xsl_datasets’s standard
diagonal convention, which is exactly why they’re standalone;
benitez2020 and kachergis_initial_accuracy are
the two directly-scorable exceptions, kept out of the fitting pool
specifically to serve as held-out data)
- Added a fourth standalone dataset,
vlach_debrock2017
(Vlach & DeBrock, 2017, Journal of Memory and Language,
“Remember dax? Relations between children’s cross-situational word
learning, memory, and language abilities”). 12 symmetric word-object
pairs, 2 pairs per training trial, 36 trials, with pairs varying in
whether their 6 repetitions are massed or spaced (n = 47 children, ages
2-5). The source only reports an overall mean/SD across all pairs and
participants, not a per-word breakdown, so accuracy is
NA throughout rather than fabricated – kept standalone (not
part of xsl_datasets) for the same reason as
kachergis2012_highlighting/gangwani2011_category.
See ?vlach_debrock2017 and
data-raw/add_vlach_debrock2017.R
- Added a third standalone dataset,
gangwani2011_category
(Experiment 1 of Gangwani, Kachergis & Yu, “Simultaneous
Cross-situational Learning of Category and Object Names”; an
undergraduate-journal version is Gangwani & Kachergis, Indiana
Undergraduate Journal of Cognitive Science 5, 2010). A hierarchical
design: each training trial shows 2 objects and names 3 words – the two
objects’ own 1-to-1 names plus one 1-to-many “category” label naming
those two objects and two others seen on other trials – so every object
carries both a basic name and a category label, and the paper’s finding
is that learners violate mutual exclusivity by learning both. A named
list of three xslData objects (one per training block: ad
hoc / natural / ad hoc), sharing one 36-trial co-occurrence schedule.
Its 15 x 12 (word x object) association matrix breaks
xslData’s diagonal-scoring convention the same way
kachergis2012_highlighting does, so it is kept standalone;
score it with score_gangwani2011_category() in the new
tests/bakeoff_comparison/gangwani2011_category_fit.R, which
reads 12-AFC name accuracy, 3-AFC category accuracy, and the paper’s
headline ME-violation measure straight off any model’s matrix. See
?gangwani2011_category and
data-raw/add_gangwani2011_category.R
Other changes
control$start_matrix is no longer silently ignored.
Only some models initialized from it; the rest dropped it without
warning (so e.g. a familiarization phase passed as a start matrix simply
vanished for them). Models now declare
supports_start_matrix in xslMod(), and
xsl_run() errors if a start matrix is given to one that
doesn’t, or if it doesn’t match the training data’s dimensions.
baseline(), decay(),
rescorla_wagner(), softmax_rl(),
uncfam_sampling(), and multi_sampling() now
support it, joining the uncfam() family,
propose_but_verify(), and pursuit(). The
remaining models (fazly(), guess_and_test(),
tilles(), bayesian_decay(),
kalman_filter(),
fgt2009()/fgt2009_rsa(),
minerva2()/todam()/rem()) have no
single association matrix a start matrix maps onto (or would need a
model-specific convention, e.g. a variance as well as a mean), so prior
learning should be passed to them as training trials, as
kachergis_initial_accuracy does. A custom model built with
xslMod() must set supports_start_matrix = TRUE
to receive one. Runs without a start matrix are unchanged
Documentation
- The main vignette now covers every model and dataset added since
0.3.0 (
uncfam_gamma(), uncfam_elimination(),
minerva2()/todam()/rem();
vlach_debrock2017, benitez2020,
xsl_holdout_datasets), and adds two sections: passing prior
learning to a model as training trials vs. a start_matrix,
and testing a fitted model’s generalization on the held-out datasets.
Its description of the dataset structure used field names
(trials, objs, perf) that no
longer exist – so its create_cooc_matrix() example was
silently printing an empty matrix – and said words/objects must be
referred to by index, which no longer holds
Bug Fixes
xsl_fit() with a parallel DEoptim backend
(DEoptim.control(parallelType = "parallel")) silently
returned bestval = Inf when control was passed
as a variable
(e.g. ctrl <- xslControl(n_sim = 100); xsl_fit(..., control = ctrl)):
control was never forced, so the objective shipped to the
worker processes carried an unevaluated promise that each worker tried
to evaluate in its own empty global environment, every evaluation
errored, and the error was converted to Inf.
control is now forced before fitting, and
xsl_fit() warns when every evaluation of a fit failed
instead of returning an all-Inf result silently. Serial
fits were unaffected.
create_cooc_matrix() looped over the number of distinct
words rather than the number of trials: with more words than
trials it errored, and with fewer (e.g. its own documented example,
xsl_datasets[[1]]: 18 words, 36 trials) it silently tallied
only the first trials. It also indexed by raw label (the same issue as
#14). Both fixed; plot_training_trials() now indexes by
label too. No model uses either function, so no fits change
propose_but_verify() and pursuit() drew
new hypotheses with sample(tr_o, ...). On a trial with a
single object, tr_o is one value, and when that value is an
integer k, R’s sample(k, n) draws from
1:k rather than returning k – so a word seen
alone with an object usually hypothesized a different object,
one not even on the trial (propose_but_verify()
hypothesized the right object ~1/8 of the time in an 8-object toy). Both
now index into tr_o
(tr_o[sample.int(length(tr_o), n, replace = TRUE)], as
guess_and_test() already did). No xsl_datasets
condition has single-object trials, so fits to it are unchanged;
kachergis_initial_accuracy (18 single-object
familiarization trials per condition),
kachergis2012_highlighting’s words-as-cues condition (28
trials naming two words with one object), and the naturalistic corpora
(rollins_corpus, fm_corpus) are affected.
Integer-labelled data (e.g. kachergis_initial_accuracy) was
affected before this release too; the corpora were not – they reached
these models as string labels, for which sample() behaves
as intended – until #14 began handing models integer positions, so for
the corpora this is a regression in 0.4.0.
- Models indexed their association matrices by raw word/object value
(
m[tr_w, tr_o]) rather than by position in the sorted
vocabulary, which is only correct for labels that are exactly
1..N (#14): a vocabulary with a gap crashed (“subscript out
of bounds”), and a raw value that still fell in range silently updated
the wrong row. Fixed once, in xsl_run(): models now receive
each dataset’s words/objects as positions, and the original labels are
restored on the returned matrix, perf, and trajectory. Test
trials are scored by label, and a start_matrix with
dimnames is aligned to the data by label. Checked against every registry
model on every bundled dataset (23 models x 75 datasets, fixed seed):
1721 of 1725 runs are bit-identical, including all of
xsl_datasets and the standalone datasets, whose labels are
already 1..N. The 4 that differ are
propose_but_verify() and pursuit() on
rollins_corpus/fm_corpus, where the fix
corrects a real error: both compared a column position against
the trial’s object labels, which can never match for character
labels, so on the corpora every hypothesis was treated as disconfirmed
and none was ever verified. (Handing these models integer positions also
exposed the single-object sample() bug above on the same
corpora; both fixes are needed for correct corpus results.) The
propose_but_verify and pursuit results
previously in tests/bakeoff_comparison/corpus_report.md
were therefore invalid (including pursuit’s reported collapse on FM);
the report and vignette("corpora") have been rerun on the
fixed code
uncfam_predictive() now caps associations at
beta (1), its stated maximum, as well as flooring them at
0. Its unnormalized update could overshoot far above beta
on a word’s first exposure: the prediction error is then
~beta, and it is scaled by exp(B * entropy) of
the word’s row, which update_known() spreads over every
object seen so far – so a word first seen after many others could reach
an association in the thousands in a single trial (e.g. ~4600 for the
18th of 18 sequentially introduced words at X = .8, B = 1.6, C = .7).
That association then dominated the word’s row and collapsed its
entropy, locking in the first pairing it was seen with; in the
initial-accuracy study this made the model predict learners would choose
an initially inaccurate word’s familiarization referent 3-4x as often as
they did. This changes uncfam_predictive()’s
fits wherever the overshoot occurred, including the corpus-fit
gains reported for it in
tests/bakeoff_comparison/corpus_report.md (not rerun
here)
get_perf() now treats negative associations as 0 before
applying the Luce choice rule (as predict_referent()
already did), and answers a word whose associations are then all 0 at
chance (1 / ncol(m)) rather than returning
NaN. Error-driven models (rescorla_wagner(),
kalman_filter()) can learn negative associations, for which
diag(m) / rowSums(m) gave per-item “probabilities” outside
[0, 1] – which DEoptim could exploit when fitting. In the
initial-accuracy study, fitted rescorla_wagner() had
negative associations for about half of participants and out-of-range
predictions for 25 of 61. This changes those models’
fits wherever negative associations occurred
kachergis_initial_accuracy put the
familiarization pairing on the diagonal (the
xslData “correct referent” slot), but the experiment’s
test-correct answer is always the study pairing. For every
initially inaccurate item these differ, so any model’s accuracy on those
items was actually its probability of choosing the wrong,
familiarization object. Its per-item accuracy was also
keyed by init_word_ind (the word originally familiarized
with the tested word’s correct object) rather than by the tested word.
Both are fixed: objects are now indexed by the word they are studied
with, so the study pairing is the diagonal and an initially inaccurate
word’s familiarization object is off-diagonal, and accuracy
is keyed by the tested word. It now also excludes the 4 participants
whose median test response time was under 400 ms (as the accompanying
manuscript does), leaving 34 High IA and 27 Low IA participants.
tests/bakeoff_comparison/kachergis_initial_accuracy_fit.R
and kachergis_initial_accuracy_persubject_fit.R are updated
and rerun accordingly
kachergis_initial_accuracy’s familiarization trials
were in word-index order; they now follow the order participants
actually saw them (the same for every participant, recovered from the
raw familiarization records). Order matters for the
uncfam() family, whose first-exposure update depends on how
many objects have already been seen via update_known() –
for uncfam_predictive() it determined how far a word’s
familiarization association overshot beta before the cap
above. The bakeoff scripts are rerun accordingly
XSLmodels 0.3.0
New Features
- Added two new model variants of
uncfam():
uncfam_attention() (BAM+Attention), which scales a trial’s
learning rate by that trial’s object uncertainty relative to the running
mean (implementing Fitneva & Christiansen 2015’s system-level
attention account), and uncfam_predictive()
(BAM+Prediction), which replaces the normalized update rule with an
item-level, Rescorla-Wagner-style prediction-error term (floored at 0 to
prevent the unnormalized update from diverging over trials)
- Added two standalone datasets, documented but deliberately not
appended to
xsl_datasets:
kachergis2012_highlighting (Kachergis, 2012, CogSci) and
kachergis_initial_accuracy (an unpublished MTurk
initial-accuracy manipulation).
kachergis2012_highlighting‘s training trials are genuine
simultaneous 2-cue trials (2 words + 1 object, or 2 objects + 1 word,
per trial, matching the paper’s Figure 2), read directly from the real
per-trial ordering file for the real N=67 dataset behind the paper’s
published statistics – confirmed by reproducing its exact reported
response proportions and chi-square values (an earlier version of this
dataset, built from a different, superficially similar file before that
real data was located, did not reproduce them, and has been replaced).
Each condition replicates the classic 3-role highlighting structure (PE,
PL, I) twice; words-as-cues’ PL items have their real target at a
different index than their own word index, and its I items have two
legitimate targets – neither fits xslData’s
one-correct-object-per-word accuracy convention, so only
its two PE items get a real accuracy value (the rest are
NA). Objects-as-cues has no such issue and gets a real
accuracy value for all 4 of its items. Because of the partial-NA
accuracy vector, kachergis2012_highlighting is kept
standalone: an NA would silently poison every other
dataset’s aggregate fit in
get_group_model_fit()/get_crossvalidated_model_fit(),
which sum/average SSE across all of xsl_datasets.
kachergis_initial_accuracy has no such blocker but is kept
standalone for now. See their ?help pages and
data-raw/add_kachergis2012_highlighting.R/add_kachergis_initial_accuracy.R
for full construction details, and
tests/bakeoff_comparison/kachergis2012_highlighting_fit.R
for a custom scorer that fits a model against all four of the paper’s
reported proportions (PE-E, PL-L, I-E, I-L) directly off the association
matrix, the way the paper’s own (non-package) fitting procedure did
- Added
kalman_filter(), a Kalman-filter generalization
of rescorla_wagner()’s error-driven update: each
word-object association is tracked as a Gaussian belief (mean and
variance), giving an adaptive learning rate that starts high under
uncertainty and shrinks with confidence, rather than a fixed rate (Dayan
& Kakade, 2000; Kruschke, 2008)
- Added
softmax_rl(), a Q-learning-style reinforcement
learning model. Unlike every other model in the package (which updates
every word-object pair presented together on a trial), it makes a
discrete choice per word – sampling a candidate referent from a softmax
policy over its current values, then updating only that guess via a
TD/delta-rule reward (1 if the guess was present in the scene, 0
otherwise). This mirrors
propose_but_verify()/pursuit()’s
propose-and-verify logic but replaces their threshold-based keep/discard
rules with graded value learning and explicit softmax exploration
- Added two naturalistic corpora imported from the wurwur package
(github.com/mcfrank/wurwur), as standalone objects (not appended to
xsl_datasets, which is scored by SSE against a human
accuracy vector these don’t have): rollins_corpus – the
CHILDES/Rollins corpus the Frank, Goodman & Tenenbaum (2009) model
was fit to (619 mother-infant utterances, 416 words, 22 objects) – and
fm_corpus – the larger Frank, Tenenbaum & Fernald
corpus (4763 utterances, 1122 words, 30 objects), which additionally
carries the speaker’s hand-coded referential intention per utterance
(fm_corpus$intents). Each is a list bundling the training
xslData ($data) with a gold-standard lexicon
($gold, plus $gold_variants for FM) to be
scored with
get_fscore()/get_roc()/get_tp()
rather than SSE. Gaze/hand attentional cues in the FM source are not
imported. See data-raw/add_wurwur_corpora.R
- Added
predict_referent(), a model-agnostic trial-level
prediction: given any model’s word-object matrix, a heard word, and the
objects present, it returns the probability distribution over those
objects
(P(object | word) proportional to m[word, object] * prior(object),
normalized over the objects present) – the quantity to compare against a
participant’s choice on a referent-selection trial. Supports a
non-uniform prior (set an entry to 0 to remove an object
the speaker has no epistemic access to) and a
pragmatic = TRUE mode that resolves the objects with a
one-step Rational Speech Act pragmatic listener
(rsa_listener()/rsa_speaker(), also exported),
yielding strong mutual exclusivity when a heard word is lexically
ambiguous and a competitor word names one of the candidates.
mafc_test() is now a thin wrapper over it (behavior
unchanged; gains a ... passthrough for
pragmatic/threshold)
- Added
fgt2009() and fgt2009_rsa(), a
pure-R port of the intentional Bayesian word-learning model of Frank,
Goodman & Tenenbaum (2009) and its Rational Speech Act (RSA)
pragmatic extension, from the Python package wordlearn
(github.com/mcfrank/wurwur). Unlike every other model in the package –
which tally word-object associations incrementally, trial by trial –
this is a batch model: it does joint MCMC inference
(blocked per-object Gibbs plus MI-biased single-edge Metropolis moves)
over the whole corpus at once, asking which lexicon best explains
all the data, so xslFit$matrix holds posterior
edge marginals P(word names object | corpus) rather than a
running tally. It therefore has no learning trajectory and ignores
control$reps. The scoring kernel is verified to match the
Python reference to numerical precision.
gamma/kappa default to the values used for the
analogous cross-situational simulation in the source package
(gamma = 1, since every word in a controlled XSL experiment
is a referential label). The lexicon-size prior alpha
scales with corpus size and its fit-vs-alpha curve is
single-peaked, so it is not wired into
xsl_model_registry()’s DEoptim bounds like the other
models; use the new fgt2009_sweep_alpha() helper instead
(which takes an optional gold argument to report the
best-threshold F-score against a gold lexicon at each
alpha, for corpora with no human accuracy vector)
- Added a vignette, “Running and fitting models on naturalistic
corpora”, covering how to run any model on
rollins_corpus/fm_corpus, score the learned
matrix against a gold lexicon with
get_fscore()/get_roc()/get_roc_max(),
and choose fgt2009()’s alpha by sweeping. It
ends with a quick model comparison (bayesian_decay and
fazly recover the gold lexicon best on both corpora, with
fgt2009 close behind and highest-precision). The comparison
script and its outputs are in
tests/bakeoff_comparison/corpus_gold_comparison.R (every
model at registry defaults); a companion,
corpus_gold_fits.R, fits each model’s parameters to each
corpus (parallel DEoptim maximizing gold-lexicon F, since these corpora
have no accuracy vector; fgt2009() by an alpha
sweep). Fitting lifts every model – dramatically for the ones whose
registry defaults were tuned on controlled experiments
(tilles +0.34, uncfam_predictive +0.15/+0.32)
– and bayesian_decay fit to the FM corpus reaches F = 0.56.
tests/bakeoff_comparison/corpus_report.md is a rendered
write-up of all of this
Other changes
xsl_run() is now far more memory-frugal on long inputs
(corpora). Previously it built the full list of every simulation’s
xslFit – each carrying a word-by-object matrix per
training trial – and only reduced them at the end, so a stochastic
model on the 4763-utterance FM corpus at n_sim = 50 needed
tens of GB and simply failed. Now: (1) the per-trial trajectory
(xslFit$traj) is only recorded when
xslControl(keep_traj = TRUE) – it is off by default and is
not used by any function in the package; (2) xsl_run()
accumulates the summed matrix one simulation at a time rather than
holding all n_sim at once; (3) the full per-simulation list
(fits[[i]]$sims) is dropped unless
xslControl(keep_sims = TRUE), replaced by
fits[[i]]$responses, a compact n_sim x n-words
matrix of each simulated participant’s final per-word accuracy.
matrix, perf, and sse are
numerically unchanged.
uncfam_sampling()/multi_sampling(): every
trial was allocating two full voc_sz x ref_sz matrices and
computing a full outer product, even though only the handful of cells at
[tr_w, tr_o] are ever nonzero. Entropy, weighting, and the
update are now computed on that small per-trial submatrix instead.
Behaviour-preserving – the sample() call’s probability
vector is still built at full ref_sz length (zero outside
tr_o), so the RNG draw sequence, and therefore every
existing fit, is unchanged. 1.17x faster on a small lab condition, 1.97x
on rollins_corpus (bigger vocabularies benefit more, since
that’s the dimension the fix targets)
shannon_entropy() computed sum(p) twice
(once for the <= 0 check, again for normalization); now
computed once and reused
update_known()’s which(...)-based
zero-filling replaced with direct logical-vector indexing, removing five
which() calls per trial
Bug Fixes
update_known() computed
which(m[w, fam_objects] == 0) – positions within
the fam_objects-filtered subset – and then indexed
m[w, zeros] as if those were absolute column positions,
silently filling startval into the wrong cell whenever
fam_objects (or fam_words, for the symmetric
object-side fill) was a proper subset of all columns/rows –
i.e. whenever some word or object was still wholly unfamiliar. Affects
all 5 models that call it (uncfam(),
uncfam_attention(), uncfam_predictive(),
uncfam_sampling(), multi_sampling()). In
practice this only ever mis-set a handful of near-zero cells during
early training that get overwritten by real learning signal soon after –
verified to make no difference to the final matrix on any of
xsl_datasets’ 53 conditions or fm_corpus, and
a single cell’s startval on rollins_corpus.
Fixed as part of the logical-indexing rewrite above.
guess_and_test() errored (if with a zero-
or multiple-length condition at the disconfirmation step) on any
utterance that repeats a word – common in a naturalistic corpus,
impossible in a controlled trial – because the repeated word was visited
twice and the first pass could clear or double-set its hypothesis. It
now de-duplicates a trial’s words and objects. Its disconfirmation check
also compared a column position to the object labels
(only equivalent when objects are labelled 1..N), and it
applied new hypotheses to need_hypoths[w] rather than the
actual stored word store[w] (setting hypotheses for the
wrong words whenever only a subset rolled below the storage threshold);
both are fixed.
tilles() coerced each trial’s words/objects with
as.integer() (it indexes its state by position), turning
any non-integer label into NA and leaving the matrix
all-zero; it also never set dimnames on its matrix, so the
result could not be scored against a gold lexicon by label. It now maps
labels to positions with match() and names its matrix.
xsl_datasets results are unchanged (the labels there are
already 1..N).
softmax_rl() checked its sampled guess against the
trial’s objects with proposal %in% tr_o, comparing a column
position (1..ref_sz) against the objects’
labels. For xsl_datasets the object labels are
1..N so it happened to work, but on any dataset whose
objects have non-integer (or non-contiguous) labels – e.g. either
bundled corpus – every reward was 0 and the learned Q-matrix stayed
identically zero. It now maps the objects present to positions
(match(tr_o, ref)) before the check, and skips a trial with
no objects present. xsl_datasets results are
unchanged.
uncfam_sampling() and multi_sampling()
errored (sample(): “too few positive probabilities”) on any
dataset containing an utterance with no objects present – e.g. the ~320
non-referential utterances in fm_corpus, which made both
models unable to run on a naturalistic corpus. Such a trial now leaves
the association matrix unchanged apart from decay (as
uncfam() already did), by skipping the per-word sampling
when its weights are all zero and only applying the normalized update
when something was sampled. Behaviour on datasets without objectless
trials (all of xsl_datasets) is unchanged.
tilles() was essentially unfittable – three separate
bugs (not the single one originally suspected) made a quick DEoptim
search return Inf for every draw: (1) its
alpha term was recomputed fresh every trial instead of
persisting per-word across trials, so words absent from the current
trial (needed by the “other old words” update) always had
alpha = NA; (2) an internal matrix was sized
voc_sz x voc_sz instead of voc_sz x ref_sz, a
copy-paste bug that only breaks on asymmetric datasets (word count !=
object count); (3) a flux computation divided by a quantity that can
legitimately be zero (a previously-seen word paired with an entirely
new-to-it set of objects), producing Inf * 0 = NaN. One
dataset failed on 100% of a 40-draw sweep regardless of parameters
before these fixes; after them, a 100-draw sweep shows a residual ~2%
failure rate confined to extreme parameter-space tails, on par with
other models’ known numerical edges
XSLmodels 0.2.0
New Features
- Added helper functions
show_models(),
show_datasets(), get_group_model_fit(), and
get_crossvalidated_model_fit() (now actually exported and
working)
- Re-implemented k-fold cross-validation
(
cross_validated_group_fits(),
get_train_test_split()) for the current
xslMod/xslData architecture
- Added 9 new conditions to
xsl_datasets (44 -> 53): 2
from Kachergis, Yu, & Shiffrin (2009) (temporal contiguity), 3 from
Suanda, Mugwanya, & Namy (2014), and 4 from Koehne, Trueswell, &
Gleitman (2013)
Bug Fixes
xslData() no longer rejects data with no
response_matrix supplied – this was breaking the vignette,
most function examples, and
get_example_ambiguous_condition()/get_example_unambiguous_condition()
get_group_model_fit()/get_crossvalidated_model_fit()
called uncfam_sampling(), multi_sampling(),
tilles(), and fazly() with incorrect parameter
names, causing them to error for those models
update_params() was dropping the parameter list’s
names/type, which made xsl_run() error for every model
except bayesian_decay() whenever it was called after
fitting (e.g. from xsl_fit() or cross-validation)
xsl_fit() now treats a model erroring or returning
NA/NaN SSE for a given parameter draw as an
infinitely bad fit instead of aborting the whole optimization run
- Fixed
tilles() mislabeling its model name as
"rescorla_wagner"
create_cooc_matrix() test had an incorrect expected
value
plot_training_trials() now gives an informative error
if the optional viridis/gganimate packages
aren’t installed, instead of a raw namespace-loading error
xsl_run() checked !is.null(dat$test) to
decide whether to use mafc_test(), but
xslData()’s test defaults to
list() (not NULL), so any dataset built
without explicit test trials – including the package’s own
get_example_ambiguous_condition()/get_example_unambiguous_condition()
– was silently routed through mafc_test(mat, list()). That
returned numeric(0) rather than erroring (an R quirk:
1:0 counts down instead of being empty, and
vec[i] <- numeric(0) truncates the vector rather than
erroring), producing a false sse = 0 “perfect fit” with no
warning. Now checks length(dat$test) > 0.
guess_and_test() had an inverted guard clause
(if (length(which(m[w,]==1))) next) that made its
hypothesis-disconfirmation step permanently unreachable, since it was
only reached for words that already have a stored hypothesis
(guaranteeing the guard’s condition was always true). Hypotheses were
therefore never disconfirmed once formed, silently disabling a core part
of the model (“…on later encounters, learners attempt to retrieve this
hypothesis from memory and test it against a new context, updating it
only if it is disconfirmed”). Found by comparing the package’s fits
against the original pre-package research code’s fits for the same
44-condition dataset.
Documentation
- Enhanced README with working examples
- Updated vignette with proper model categorization
- Added comprehensive function documentation
- Documented models and datasets