Assumptions: - fastpragma.data already exports DataSource, Tokenizer, and PRAGMADataset. - We use MovieLens 100k as a small stand-in for banking event histories. - User rows provide profile/static state, and rating rows provide timestamped events.
Assumptions: - users_src is profile state because it has one row per user and no event timestamp. - ratings_src is the event stream because each row is timestamped. - eval_time is fixed for this toy dataset so logsec features are deterministic. - Tokenized shards plus tokenizer.json are saved under out.
out = Path('data/ml100k_pragma')ds = PRAGMADataset(profile=users_src, events=[ratings_src], entity_col='user_id', out_path=out)ds.show_summary()
Assumptions: - The dataloader should consume saved parquet shards, not the original raw MovieLens files. - Each shard contains rows from multiple users, with profile rows marked by event_idx == -1 and event rows by event_idx >= 0. - We first inspect one shard and one user before building batching logic.
tok = Tokenizer.load(out/'tokenizer.json')shard = pl.read_parquet(out/'shard_0.parquet')shard.shape, shard.columns, shard.head()
Assumptions: - Each key-value token is represented as (key_id, val_id, val_pos). - Profile and lifelong tensors can be padded per batch. - Event tokens will be packed flat with offsets instead of padded to a large rectangle. - Cutoffs mirror the PRAGMA paper defaults where practical: profile tokens, lifelong tokens, events per user, and tokens per event.
Convert one user into a record
Assumptions: - Static profile rows have event_idx < 0 and time == 0. - Lifelong rows have event_idx < 0 and non-zero time. - Event rows are sorted by event_idx, truncated to the latest max_events, and each event is capped at max_event_toks. - Calendar features are stored once per event.
Pack a batch
Assumptions: - Profiles and lifelong rows are small enough to pad within a batch. - Event field tokens are packed into one flat tensor. - event_offsets maps flat tokens to events. - event_user maps events to users. - history_offsets reserves one history position per user for [USR], plus one per event.
Entity ids
entity_col is preserved as uids in each batch.
uids contains the original entity ids, e.g. user ids.
The model usually should not embed or consume uids.
Use uids for debugging, evaluation joins, predictions, and traceability.
The model should use event_user and history_offsets for batch-local entity structure.
detailed plan
The current fitting convention is:
PRAGMADataset.write_kv(...) is the preprocessing/fitting stage.
It fits or loads the tokenizer, tokenizes profile and event sources, assigns each entity to a shard, and writes saved parquet shards plus tokenizer.json.
The dataloader does not refit anything. It only consumes the saved files.
Assumptions: - MLM labels reconstruct value IDs only, using event_tokens[:,1]. - Non-masked labels use -100 so PyTorch loss can ignore them. - Batches are built by token budget rather than fixed user count. - Multi-worker loading splits shard paths across workers to avoid duplicate data.
MLM masking assumptions
We mask only event value tokens, not profile or lifelong tokens.
For each user record, selected mask positions come from the union of three sources:
Token-level masking: each event token is selected independently with probability p_tok.
Event-level masking: each event is selected independently with probability p_event, and all value tokens in that event are selected.
Semantic key-level masking: keys are selected independently per user with probability p_key, and all event values for those keys are selected for that user.
After positions are selected:
selected positions become MLM targets using their original val_id
most selected input values are replaced with [MASK]
a small fraction are replaced with [UNK]
[UNK] positions are excluded from the loss by setting their label to -100
So the effective target mask is:
This follows the paper’s intent while treating key-level masking as sample-local: selected keys affect only the user record where they were sampled, not other users in the same batch.
The model receives padded profile/lifelong tensors and packed event tensors.
Special tokens are added by the model, not the dataloader: - profile encoder prepends [USR] - event encoder prepends [EVT] to each event - history encoder receives [USR] + [EVT] event representations
event_offsets maps packed event tokens to events. event_user maps events to batch users. history_offsets maps history tokens to users.
MLM labels reconstruct event value IDs only. Non-masked labels are -100.