Custom paradigms¶
Your own items¶
The learning paradigms take their items as a task. cg.tasks.Mapping holds any items,
described by numbers or by words, with a fixed set of labels, so iterated learning runs
on your own category system or function without a new class, as the
learning paradigms page shows.
A paradigm you write can read rows from a file instead. Set item_columns to the columns
it needs, and stimuli= then takes a path to a CSV, JSON, JSON Lines or Parquet file, a
pandas table, a Dataset or a list of mappings. self.item_rows(rng) gives the rows. A
missing column or an empty cell raises an error naming the row.
import cognarium as cg
import pandas as pd
subject = cg.load("gpt2", device="auto")
class Acceptability(cg.Paradigm):
"""Choose the acceptable sentence of a pair that differs in one place."""
item_columns = ("good", "bad")
effects = (cg.Effect("preference", "answer_probability", against=0.5),)
def trials(self, rng):
for index, row in enumerate(self.item_rows(rng)):
first, second = (row["good"], row["bad"]) if index % 2 == 0 else (row["bad"], row["good"])
yield cg.Trial(
cg.Stimulus(text=f"A: {first}\nB: {second}\nWhich sentence is acceptable?"),
options=["A", "B"],
answer="A" if first == row["good"] else "B",
item=index
)
pairs = pd.DataFrame({
"good": ["The keys are on the table.", "She has eaten.", "Who did you see?"],
"bad": ["The keys is on the table.", "She have eaten.", "Who did you see him?"]
})
pairs.to_csv("pairs.csv", index=False)
results = cg.run(Acceptability(stimuli="pairs.csv"), subject)
results.to_pandas()[["item", "answer", "response"]]
Results record where the stimuli came from.
A new paradigm¶
A paradigm is a subclass of cg.Paradigm with a trials method. Keyword arguments
become attributes, so the paradigm below reads self.pairs. Effects are declared as
data: each names a measure, the column whose levels it compares, and the two levels.
class Priming(cg.Paradigm):
"""Decide whether a target is a word, after a related or an unrelated prime."""
context = cg.context.isolated
effects = (
cg.Effect("priming", "answer_surprisal", by="relatedness", levels=("unrelated", "related")),
)
def trials(self, rng):
for prime, target, relatedness in self.pairs:
yield cg.Trial(
cg.Stimulus(text=f"Prime: {prime}. Target: {target}. Is the target a word?"),
options=["word", "nonword"],
answer="word",
condition={"relatedness": relatedness},
item=target
)
pairs = [
("doctor", "nurse", "related"),
("table", "nurse", "unrelated"),
("bread", "butter", "related"),
("cloud", "butter", "unrelated"),
("cat", "dog", "related"),
("lamp", "dog", "unrelated")
]
results = cg.run(Priming(pairs=pairs), subject)
results.score()
rng is a NumPy generator seeded for each participant, for anything random in the trials.
For more control, set template to a cg.PromptTemplate to change how trials are
written, group_by to the columns metrics are reported by, or override
score to compute effects some other way.
Measures for effects¶
| Measure | One value per row |
|---|---|
answer_probability |
The probability of the correct answer |
answer_surprisal |
The surprisal of the correct answer, in bits, a proxy for reaction time |
answer_margin |
How far, in nats, the correct answer's log probability is above the best other option's |
option_probability |
The probability of one option, named with options={"option": ...} |
expected_option |
The probability-weighted position among ordered options |
entropy |
The entropy of the response distribution |
accuracy, surprisal |
Whether the response was correct, and the surprisal of the response, in bits |
A numeric column the paradigm writes, such as a count it parses, works as a measure too.
Surprisal, entropy and the margin stand in for reaction time, and score() says so in
proxy_for. When a measure stands in for something else, name it on the effect, as in
cg.Effect("errors", "answer_margin", ..., proxy_for="error rate").