initium-deeplearning 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. initium/LNN_controller/cfc_backbone_parallel.py +265 -0
  2. initium/LNN_controller/cfc_controller.py +325 -0
  3. initium/LNN_controller/chained_controller.py +83 -0
  4. initium/LNN_controller/hybrid_controller.py +90 -0
  5. initium/MoE/README.md +1 -0
  6. initium/MoE/moe_layer.py +552 -0
  7. initium/__init__.py +1 -0
  8. initium/config/controller_config.py +86 -0
  9. initium/config/train_config.py +64 -0
  10. initium/core_training.py +2182 -0
  11. initium/data/__init__.py +0 -0
  12. initium/data/audio/__init__.py +0 -0
  13. initium/data/audio/audio_dataset.py +96 -0
  14. initium/data/base_dataset.py +75 -0
  15. initium/data/common/__init__.py +0 -0
  16. initium/data/common/chain_task.py +542 -0
  17. initium/data/common/digit_codec.py +85 -0
  18. initium/data/common/graph_io.py +123 -0
  19. initium/data/common/real_data.py +747 -0
  20. initium/data/dataset_registry.py +59 -0
  21. initium/data/graph_traversal/__init__.py +0 -0
  22. initium/data/graph_traversal/graph_traversal.py +746 -0
  23. initium/data/multimodal/__init__.py +0 -0
  24. initium/data/multimodal/multimodal_dataset.py +401 -0
  25. initium/data/text/__init__.py +0 -0
  26. initium/data/text/text_dataset.py +79 -0
  27. initium/data/video/__init__.py +0 -0
  28. initium/data/video/video_dataset.py +85 -0
  29. initium/inference/__init__.py +1 -0
  30. initium/inference/cache/__init__.py +1 -0
  31. initium/inference/cache/base_cache.py +112 -0
  32. initium/inference/cache/cache_config.py +21 -0
  33. initium/inference/cache/cache_registry.py +99 -0
  34. initium/inference/cache/cached_engine.py +264 -0
  35. initium/inference/cache/keys.py +77 -0
  36. initium/inference/cache/prefix_cache.py +59 -0
  37. initium/inference/cache/result_cache.py +57 -0
  38. initium/inference/cache/state_utils.py +74 -0
  39. initium/inference/cache/stores.py +167 -0
  40. initium/inference/capabilities.py +86 -0
  41. initium/inference/checkpoint_io.py +63 -0
  42. initium/inference/engine.py +88 -0
  43. initium/inference/inference_config.py +22 -0
  44. initium/inference/metrics.py +103 -0
  45. initium/inference/model_loader.py +270 -0
  46. initium/inference/run_inference.py +526 -0
  47. initium/inference/run_logging.py +173 -0
  48. initium/inference/tasks/__init__.py +1 -0
  49. initium/inference/tasks/audio_task.py +114 -0
  50. initium/inference/tasks/base_task.py +60 -0
  51. initium/inference/tasks/graph_traversal_task.py +235 -0
  52. initium/inference/tasks/multimodal_task.py +74 -0
  53. initium/inference/tasks/task_registry.py +68 -0
  54. initium/inference/tasks/text_task.py +114 -0
  55. initium/inference/tasks/video_task.py +114 -0
  56. initium/mamba_controller/mamba2_controller.py +433 -0
  57. initium/mamba_controller/mamba3_controller.py +242 -0
  58. initium/mamba_controller/mamba_backbone_parallel.py +291 -0
  59. initium/mamba_controller/mamba_controller.py +983 -0
  60. initium/mamba_controller/split_graph_dnc.py +623 -0
  61. initium/memory_manipulation/dynamic_memory_resize.py +157 -0
  62. initium/memory_manipulation/dynamic_n_controller.py +152 -0
  63. initium/memory_manipulation/link_matrix_ablation.py +130 -0
  64. initium/memory_manipulation/nvrtc_compat.py +143 -0
  65. initium/memory_manipulation/stochastic_write_head_v2.py +545 -0
  66. initium/setup_wheels.py +175 -0
  67. initium_deeplearning-0.1.0.dist-info/METADATA +253 -0
  68. initium_deeplearning-0.1.0.dist-info/RECORD +71 -0
  69. initium_deeplearning-0.1.0.dist-info/WHEEL +4 -0
  70. initium_deeplearning-0.1.0.dist-info/entry_points.txt +3 -0
  71. initium_deeplearning-0.1.0.dist-info/licenses/LICENSE +674 -0
File without changes
@@ -0,0 +1,401 @@
1
+ """
2
+ file: data/multimodal/multimodal_dataset.py
3
+
4
+ Fuses two or more of {text, audio, video} chain datasets. The SAME (key,
5
+ value) facts/queries draw is shown through EACH active modality's own
6
+ encoding channel simultaneously, concatenated into one wider per-timestep
7
+ input vector (input_dim = sum of active modalities' input_dims). This is
8
+ what makes "which modality does the model actually use" answerable via a
9
+ direct ablation: zero one modality's channel slice and re-evaluate -
10
+ Delta_<modality>, the Dependency-layer (Layer C) analogue of
11
+ evaluate_id_ablated (memory) / evaluate_id_combiner_stage_ablated
12
+ (component), for modalities.
13
+
14
+ Only the FIRST listed modality's targets are scored ("primary") - this
15
+ tests whether auxiliary modalities help/are relied upon for the primary
16
+ modality's own recall+chain task, not multi-task multi-output prediction.
17
+
18
+ Real-data wiring: each modality in the `modalities` list passed to
19
+ __init__ may be a bare name (synthetic, unchanged default) or
20
+ "modality:path" to source that modality's own real fact pool from `path`
21
+ via its existing single-modality real-data pipeline (data/common/
22
+ real_data.py) -- see _parse_modality_specs() below. Repeating the SAME
23
+ path across modalities (e.g. "video:clip.mp4+audio:clip.mp4") draws both
24
+ modalities' real content from one shared file, such as a video that also
25
+ carries an audio track -- the flagship "upload one video, learn its
26
+ picture AND its soundtrack" case. See MultimodalDataset.__init__'s
27
+ `link_role` for how training vs. inference (MultimodalTask) route a
28
+ spec's path to the right underlying *ChainDataset kwarg.
29
+ """
30
+
31
+ import random
32
+
33
+ import torch
34
+
35
+ from initium.data.audio.audio_dataset import AudioChainDataset
36
+ from initium.data.base_dataset import BaseDataset
37
+ from initium.data.common.chain_task import (
38
+ ChainCurriculum,
39
+ score_answer_steps,
40
+ value_cumsum_field_log_header,
41
+ write_value_cumsum_field_log,
42
+ )
43
+ from initium.data.text.text_dataset import TextChainDataset
44
+ from initium.data.video.video_dataset import VideoChainDataset
45
+
46
+ _MODALITY_CLASSES = {
47
+ "text": TextChainDataset,
48
+ "audio": AudioChainDataset,
49
+ "video": VideoChainDataset,
50
+ }
51
+
52
+
53
+ def _parse_modality_specs(modalities):
54
+ """Each entry of `modalities` is either a bare modality name ("text",
55
+ "audio", "video") -- synthetic facts, unchanged default -- or
56
+ "modality:path" to source that modality's OWN real (key,value) fact
57
+ pool from `path`, via the exact same per-modality real-data pipeline
58
+ single-modality datasets already use (data/common/real_data.py). The
59
+ SAME path can be given to more than one modality -- e.g.
60
+ "video:clip.mp4+audio:clip.mp4" -- to draw both modalities' real
61
+ content from one shared file, such as a video that also carries an
62
+ audio track: video_token_stream (opencv) and audio_token_stream
63
+ (torchaudio) each open the container with their own library and only
64
+ ever read the stream they care about, so pointing both at the same
65
+ path is safe and is the intended way to say "learn from this video's
66
+ picture AND its soundtrack." -> [(name, path_or_None), ...].
67
+ """
68
+ parsed = []
69
+ for spec in modalities:
70
+ spec = (spec or "").strip()
71
+ if not spec:
72
+ continue
73
+ name, _, path = spec.partition(":")
74
+ parsed.append((name.strip().lower(), path.strip() or None))
75
+ return parsed
76
+
77
+
78
+ class MultimodalDataset(BaseDataset):
79
+ # Real-data wiring: see _parse_modality_specs() above for the
80
+ # "modality[:path]" spec syntax and MultimodalTask (inference/tasks/
81
+ # multimodal_task.py) for how --dataset-link reaches here at inference.
82
+ def __init__(self, modalities, link_role: str = "dataset_link"):
83
+ """
84
+ modalities: iterable of modality specs (see _parse_modality_specs).
85
+ link_role: "dataset_link" (default; training-side) -- a spec's path
86
+ becomes that modality's OWN training source (auto-split into a
87
+ disjoint train/test pool by that modality's dataset class,
88
+ exactly like a standalone *ChainDataset(dataset_link=...)), or
89
+ "test_dataset_link" (inference-side, see MultimodalTask) -- a
90
+ spec's path becomes a fixed, already-real TEST pool directly.
91
+ """
92
+ if link_role not in ("dataset_link", "test_dataset_link"):
93
+ raise ValueError(
94
+ "MultimodalDataset: link_role must be 'dataset_link' "
95
+ f"or 'test_dataset_link', got {link_role!r}"
96
+ )
97
+ specs = _parse_modality_specs(modalities)
98
+ if len(specs) < 2:
99
+ raise ValueError(f"MultimodalDataset needs >=2 modalities, got {modalities!r}")
100
+ names = [n for n, _ in specs]
101
+ unknown = [n for n in names if n not in _MODALITY_CLASSES]
102
+ if unknown:
103
+ raise ValueError(
104
+ f"MultimodalDataset: unknown modalities {unknown}, "
105
+ f"expected a subset of {sorted(_MODALITY_CLASSES)}"
106
+ )
107
+ self.modalities = names
108
+ self.subs = [
109
+ _MODALITY_CLASSES[name](**({link_role: path} if path else {})) for name, path in specs
110
+ ]
111
+ self.primary = self.subs[0]
112
+ self.name = "multimodal[" + "+".join(names) + "]"
113
+
114
+ off = 0
115
+ self._offsets = []
116
+ for s in self.subs:
117
+ self._offsets.append((off, off + s.input_dim))
118
+ off += s.input_dim
119
+ self.input_dim = off
120
+ self.output_dim = self.primary.output_dim
121
+ self.eval_batch_size = self.primary.eval_batch_size
122
+ self.advance_threshold = self.primary.advance_threshold
123
+ self._table = self.primary._table
124
+ self._lesson_nr_cells = self.primary._lesson_nr_cells
125
+
126
+ def _facts_pool(self, use_test_pool: bool = False):
127
+ """Real (key,value) pool to draw a fused episode from, or None for
128
+ the fully-synthetic draw (unchanged default when no modality was
129
+ given a real source). use_test_pool selects each sub's held-out
130
+ `_test_fact_pool` (evaluate_ood) vs its training `_fact_pool`
131
+ (sample_batch / evaluate_id_ablated / evaluate_modality_ablated) --
132
+ same train/test convention every single-modality dataset already
133
+ uses. Values always come from the PRIMARY modality's pool (only the
134
+ primary is scored -- see class docstring); keys are restricted to
135
+ ones ALSO present in every OTHER real-sourced modality's pool, so
136
+ any channel built from real data genuinely has real content for
137
+ every key an episode can draw (e.g. a video file's frame-derived
138
+ pool intersected with that SAME file's audio-track-derived pool).
139
+ Falls back to the unrestricted primary pool if the intersection is
140
+ empty, rather than raising mid-run."""
141
+ attr = "_test_fact_pool" if use_test_pool else "_fact_pool"
142
+ primary_pool = getattr(self.primary, attr)
143
+ if primary_pool is None:
144
+ return None
145
+ other_pools = [p for p in (getattr(s, attr) for s in self.subs[1:]) if p is not None]
146
+ if not other_pools:
147
+ return primary_pool
148
+ shared_keys = set(k for k, _ in primary_pool)
149
+ for p in other_pools:
150
+ shared_keys &= set(k for k, _ in p)
151
+ restricted = [(k, v) for k, v in primary_pool if k in shared_keys]
152
+ return restricted or primary_pool
153
+
154
+ def make_curriculum(self):
155
+ return ChainCurriculum(self, self._table, self._lesson_nr_cells)
156
+
157
+ def set_output_proj(self, proj):
158
+ self._output_proj = proj
159
+
160
+ def _build_fused_episode(
161
+ self,
162
+ num_facts_range,
163
+ num_queries_range,
164
+ rng=None,
165
+ skip_modalities=None,
166
+ perturb=None,
167
+ use_test_pool=False,
168
+ ):
169
+ rng = rng if rng is not None else random
170
+ skip_modalities = skip_modalities or set()
171
+ codec, label_range = self.primary.codec, self.primary.label_range
172
+ NF = codec.num_digits
173
+
174
+ def _as_range(x):
175
+ return x if isinstance(x, tuple) else (x, x)
176
+
177
+ num_facts_range = _as_range(num_facts_range)
178
+ num_queries_range = _as_range(num_queries_range)
179
+
180
+ num_facts = rng.randint(*num_facts_range)
181
+ pool = self._facts_pool(use_test_pool=use_test_pool)
182
+ if pool is not None:
183
+ num_facts = min(num_facts, len(pool))
184
+ facts = rng.sample(pool, num_facts)
185
+ else:
186
+ keys = rng.sample(range(label_range), num_facts)
187
+ vals = [rng.randrange(label_range) for _ in range(num_facts)]
188
+ facts = list(zip(keys, vals))
189
+ rng.shuffle(facts)
190
+ keys = [k for k, _ in facts]
191
+ num_queries = rng.randint(*num_queries_range)
192
+ query_keys = [rng.choice(keys) for _ in range(num_queries)]
193
+
194
+ def fused(build_fns):
195
+ return torch.cat(
196
+ [
197
+ torch.zeros(sub.input_dim) if i in skip_modalities else build_fns[i]()
198
+ for i, sub in enumerate(self.subs)
199
+ ]
200
+ )
201
+
202
+ inputs, target_digits, answer_mask = [], [], []
203
+ for i, (k, v) in enumerate(facts):
204
+ pt = 1.0 if i == 0 else 0.0
205
+ inputs.append(
206
+ fused(
207
+ [
208
+ (lambda s=sub: s._encode_fact(k, v, pt, perturb=perturb, rng=rng))
209
+ for sub in self.subs
210
+ ]
211
+ )
212
+ )
213
+ target_digits.append([0] * (2 * NF))
214
+ answer_mask.append(0)
215
+ for i, k in enumerate(query_keys):
216
+ pt = 1.0 if i == 0 else 0.0
217
+ inputs.append(fused([(lambda s=sub: s._encode_query(k, pt)) for sub in self.subs]))
218
+ target_digits.append([0] * (2 * NF))
219
+ answer_mask.append(0)
220
+ value_of, cumsum = dict(facts), 0
221
+ for i, k in enumerate(query_keys):
222
+ cumsum = (cumsum + value_of[k]) % label_range
223
+ pt = 1.0 if i == 0 else 0.0
224
+ inputs.append(fused([(lambda s=sub: s._encode_answer(pt)) for sub in self.subs]))
225
+ target_digits.append(
226
+ codec.label_to_digit_targets(value_of[k]) + codec.label_to_digit_targets(cumsum)
227
+ )
228
+ answer_mask.append(1)
229
+ return (
230
+ torch.stack(inputs),
231
+ torch.tensor(target_digits, dtype=torch.long),
232
+ torch.tensor(answer_mask, dtype=torch.float32),
233
+ num_queries,
234
+ )
235
+
236
+ def collate(self, batch):
237
+ max_len = max(len(x[0]) for x in batch)
238
+ B = len(batch)
239
+ NF = self.primary.codec.num_digits
240
+ padded_input = torch.zeros(B, max_len, self.input_dim)
241
+ padded_targets = torch.zeros(B, max_len, 2 * NF, dtype=torch.long)
242
+ padded_mask = torch.zeros(B, max_len)
243
+ for i, (inp, tgt, mask, _) in enumerate(batch):
244
+ T = inp.size(0)
245
+ padded_input[i, :T] = inp
246
+ padded_targets[i, :T] = tgt
247
+ padded_mask[i, :T] = mask
248
+ return padded_input, padded_targets, padded_mask
249
+
250
+ def sample_batch(self, curriculum, batch_size):
251
+ episodes = []
252
+ for _ in range(batch_size):
253
+ idx = (
254
+ random.randint(0, curriculum.lesson - 1)
255
+ if curriculum.lesson > 0 and random.random() < 0.10
256
+ else curriculum.lesson
257
+ )
258
+ nf, nq = curriculum.table[idx]
259
+ episodes.append(self._build_fused_episode(nf, nq))
260
+ return self.collate(episodes) # was self.primary.collate(episodes)
261
+
262
+ def loss(self, output, target, mask):
263
+ return self.primary.loss(output, target, mask)
264
+
265
+ def diversity(self, output, target, mask):
266
+ return self.primary.diversity(output, target, mask)
267
+
268
+ def evaluate_chain(
269
+ self,
270
+ model,
271
+ device,
272
+ num_episodes,
273
+ num_facts_range=None,
274
+ num_queries_range=None,
275
+ rng=None,
276
+ ablate_memory=False,
277
+ step_breakdown=False,
278
+ skip_modalities=None,
279
+ verbose_n=0,
280
+ use_test_pool=False,
281
+ skip_stages=None,
282
+ field_log=None,
283
+ ):
284
+ model.eval()
285
+ total = correct_value = correct_cumsum = perfect_episodes = tested = 0
286
+ by_depth = {}
287
+ codec = self.primary.codec
288
+ with torch.no_grad():
289
+ while tested < num_episodes:
290
+ input_seq, target_digits, answer_mask, depth = self._build_fused_episode(
291
+ num_facts_range,
292
+ num_queries_range,
293
+ rng=rng,
294
+ skip_modalities=skip_modalities,
295
+ use_test_pool=use_test_pool,
296
+ )
297
+ input_seq = input_seq.unsqueeze(0).to(device)
298
+ output, _ = model(
299
+ input_seq,
300
+ (None, None, None),
301
+ reset_experience=True,
302
+ pass_through_memory=not ablate_memory,
303
+ **({"combiner_skip_stages": skip_stages} if skip_stages else {}),
304
+ )
305
+ output = self._output_proj(output.transpose(0, 1).contiguous().squeeze(0))
306
+ ep_total, ep_correct, episode_perfect, ep_cv, ep_cc, ep_n = score_answer_steps(
307
+ output,
308
+ target_digits,
309
+ answer_mask,
310
+ codec,
311
+ verbose=(tested < verbose_n),
312
+ field_log=field_log,
313
+ )
314
+ correct_value += ep_cv
315
+ correct_cumsum += ep_cc
316
+ total += ep_n
317
+ perfect_episodes += int(episode_perfect)
318
+ tested += 1
319
+ if step_breakdown:
320
+ acc = by_depth.setdefault(ep_total, [0, 0, 0, 0])
321
+ acc[0] += 2 * ep_total
322
+ acc[1] += ep_correct
323
+ acc[2] += 1
324
+ acc[3] += int(episode_perfect)
325
+ combined_acc = 100.0 * (correct_value + correct_cumsum) / max(2 * total, 1)
326
+ perfect_frac = 100.0 * perfect_episodes / max(tested, 1)
327
+ print(
328
+ f"Eval [{self.name}]: value {100.0 * correct_value / max(total, 1):.2f}% | "
329
+ f"cumsum {100.0 * correct_cumsum / max(total, 1):.2f}% | combined {combined_acc:.2f}% | "
330
+ f"perfect {perfect_frac:.2f}% ({tested} episodes)"
331
+ )
332
+ model.train()
333
+ if step_breakdown:
334
+ breakdown = {
335
+ d: (100.0 * c / max(t, 1), 100.0 * p / max(e, 1), e)
336
+ for d, (t, c, e, p) in sorted(by_depth.items())
337
+ }
338
+ return combined_acc, perfect_frac, breakdown
339
+ return combined_acc, perfect_frac
340
+
341
+ def evaluate_ood(self, model, device, num_episodes, rng, verbose_n=0, field_log=None):
342
+ return self.evaluate_chain(
343
+ model,
344
+ device,
345
+ num_episodes,
346
+ num_facts_range=(15, 20),
347
+ num_queries_range=self.primary.ood_query_range,
348
+ rng=rng,
349
+ step_breakdown=True,
350
+ use_test_pool=True,
351
+ verbose_n=verbose_n,
352
+ field_log=field_log,
353
+ )
354
+
355
+ def evaluate_id_ablated(self, model, device, curriculum, lesson_idx):
356
+ nf, nq = curriculum.table[lesson_idx]
357
+ return self.evaluate_chain(
358
+ model,
359
+ device,
360
+ self.eval_batch_size,
361
+ num_facts_range=nf,
362
+ num_queries_range=nq,
363
+ ablate_memory=True,
364
+ )
365
+
366
+ def evaluate_id_combiner_stage_ablated(
367
+ self, model, device, curriculum, lesson_idx, skip_stages
368
+ ):
369
+ """Combiner-stage-off eval on lesson `lesson_idx` -> (acc_pct, perfect_pct).
370
+ Mirrors data/common/chain_task.py's KVChainDataset implementation --
371
+ only meaningful when model.combiner_wrapper is a ChainedControllerWrapper
372
+ (e.g. --split-graph-combiner-variant mamba+cfc)."""
373
+ nf, nq = curriculum.table[lesson_idx]
374
+ return self.evaluate_chain(
375
+ model,
376
+ device,
377
+ self.eval_batch_size,
378
+ num_facts_range=nf,
379
+ num_queries_range=nq,
380
+ skip_stages=skip_stages,
381
+ )
382
+
383
+ def evaluate_modality_ablated(self, model, device, curriculum, lesson_idx, modality: str):
384
+ """Delta_<modality> = full_acc - ablated_acc, per the research doc's
385
+ modality-dependency proposal."""
386
+ idx = self.modalities.index(modality)
387
+ nf, nq = curriculum.table[lesson_idx]
388
+ return self.evaluate_chain(
389
+ model,
390
+ device,
391
+ self.eval_batch_size,
392
+ num_facts_range=nf,
393
+ num_queries_range=nq,
394
+ skip_modalities={idx},
395
+ )
396
+
397
+ def field_log_header(self):
398
+ return value_cumsum_field_log_header()
399
+
400
+ def write_field_log(self, writer, file, step, lesson, eval_type, field_log):
401
+ write_value_cumsum_field_log(writer, file, step, lesson, eval_type, field_log)
File without changes
@@ -0,0 +1,79 @@
1
+ """
2
+ file: data/text/text_dataset.py
3
+
4
+ Text modality dataset: TextChainDataset(KVChainDataset). Default (no
5
+ dataset_link): "facts" are token(key)->token(value) associations drawn
6
+ fresh each episode from the full label space (unchanged synthetic
7
+ behavior). With dataset_link (a path to a real text file): a byte-level
8
+ BPE tokenizer (data/common/real_data.py) is trained on the file, the
9
+ resulting token stream is turned into a real (key,value) fact pool, and
10
+ that pool is split into a disjoint TRAIN pool (used by build_episode
11
+ instead of random draws) and TEST pool (used by build_ood_facts instead of
12
+ the synthetic seeded table below) -- the text analogue of the graph
13
+ dataset's "train on synthetic graphs, test on the held-out London
14
+ Underground" split. test_dataset_link (a second, separate text file) can
15
+ be given to use an entirely different source as the test set instead of a
16
+ held-out slice of the same file.
17
+
18
+ Depth axis: number of queries (reasoning-chain-length / context-length
19
+ analogue). Fields: value (lookup), cumsum (chained state).
20
+ """
21
+
22
+ import random
23
+
24
+ from initium.data.common.chain_task import KVChainDataset
25
+ from initium.data.common.real_data import build_text_kv_pool, split_train_test_facts
26
+
27
+ TEXT_CURRICULUM = [
28
+ (3, 2),
29
+ (3, 3),
30
+ (5, 3),
31
+ (5, 4),
32
+ (8, 4),
33
+ (8, 5),
34
+ (10, 5),
35
+ (10, 6),
36
+ (12, 6),
37
+ (12, 7),
38
+ (15, 8),
39
+ (15, 9),
40
+ (20, 10),
41
+ (20, 12),
42
+ ]
43
+ TEXT_LESSON_NR_CELLS = [128, 128, 128, 128, 160, 160, 160, 160, 192, 192, 192, 192, 256, 256]
44
+ assert len(TEXT_CURRICULUM) == len(TEXT_LESSON_NR_CELLS)
45
+
46
+
47
+ class TextChainDataset(KVChainDataset):
48
+ name = "text-chain"
49
+
50
+ def __init__(self, dataset_link: str | None = None, test_dataset_link: str | None = None):
51
+ self._table = TEXT_CURRICULUM
52
+ self._lesson_nr_cells = TEXT_LESSON_NR_CELLS
53
+ self._fact_pool = None
54
+ self._test_fact_pool = None
55
+ if dataset_link is not None:
56
+ pool = build_text_kv_pool(dataset_link, self.label_range)
57
+ if test_dataset_link is not None:
58
+ self._fact_pool = pool
59
+ self._test_fact_pool = build_text_kv_pool(test_dataset_link, self.label_range)
60
+ else:
61
+ self._fact_pool, self._test_fact_pool = split_train_test_facts(pool)
62
+ print(
63
+ f"[text-chain] {len(self._fact_pool)} train facts from {dataset_link} | "
64
+ f"{len(self._test_fact_pool)} test facts"
65
+ + (f" from {test_dataset_link}" if test_dataset_link else " (held-out split)")
66
+ )
67
+ elif test_dataset_link is not None:
68
+ # Inference-only: no training pool needed, just a fixed real test
69
+ # pool -- every inference/tasks/*_task.py passes --dataset-link
70
+ # through as test_dataset_link, since inference only ever tests
71
+ # an already-trained model (see this class's own docstring).
72
+ self._test_fact_pool = build_text_kv_pool(test_dataset_link, self.label_range)
73
+ print(f"[text-chain] {len(self._test_fact_pool)} test facts from {test_dataset_link}")
74
+
75
+ def _synthetic_ood_facts(self, n_facts: int = 20):
76
+ rng = random.Random(4242) # fixed held-out vocabulary
77
+ keys = rng.sample(range(self.label_range), n_facts)
78
+ vals = [rng.randrange(self.label_range) for _ in range(n_facts)]
79
+ return list(zip(keys, vals))
File without changes
@@ -0,0 +1,85 @@
1
+ """
2
+ file: data/video/video_dataset.py
3
+
4
+ Video modality dataset: VideoChainDataset(KVChainDataset). Default (no
5
+ dataset_link): synthetic object-identity(key)->action/state-identity(value)
6
+ facts, drawn fresh each episode (unchanged behavior). With dataset_link (a
7
+ path to a real video file, needs opencv-python): each frame is downsampled
8
+ and quantized to an intensity-bin id (data/common/real_data.py
9
+ video_token_stream) and turned into a real fact pool, split into a
10
+ disjoint TRAIN/TEST pool the same way text_dataset.py does -- the video
11
+ analogue of the graph dataset's held-out London Underground graph.
12
+ test_dataset_link (a second video file) can be given to use a genuinely
13
+ different clip as the test set instead of a held-out slice of the same
14
+ one.
15
+
16
+ Depth axis: number of queried events (event-chain-length / temporal-
17
+ horizon analogue). Fields: value (object-action binding accuracy), cumsum
18
+ (chained event-ordering state).
19
+ Robustness axis: frame dropping / occlusion -- the WHOLE fact observation
20
+ (key AND value) is zeroed with prob=severity, rather than corrupted in
21
+ place (closer to "this frame was dropped/occluded" than to token noise).
22
+ """
23
+
24
+ import random
25
+
26
+ import torch
27
+
28
+ from initium.data.common.chain_task import KVChainDataset
29
+ from initium.data.common.real_data import build_video_kv_pool, split_train_test_facts
30
+
31
+ VIDEO_CURRICULUM = [
32
+ (3, 2),
33
+ (3, 3),
34
+ (5, 3),
35
+ (5, 4),
36
+ (8, 4),
37
+ (8, 5),
38
+ (10, 5),
39
+ (10, 6),
40
+ (12, 6),
41
+ (12, 7),
42
+ (15, 8),
43
+ (15, 9),
44
+ (20, 10),
45
+ (20, 12),
46
+ ]
47
+ VIDEO_LESSON_NR_CELLS = [128, 128, 128, 128, 160, 160, 160, 160, 192, 192, 192, 192, 256, 256]
48
+ assert len(VIDEO_CURRICULUM) == len(VIDEO_LESSON_NR_CELLS)
49
+
50
+
51
+ class VideoChainDataset(KVChainDataset):
52
+ name = "video-chain"
53
+
54
+ def __init__(self, dataset_link: str | None = None, test_dataset_link: str | None = None):
55
+ self._table = VIDEO_CURRICULUM
56
+ self._lesson_nr_cells = VIDEO_LESSON_NR_CELLS
57
+ self._fact_pool = None
58
+ self._test_fact_pool = None
59
+ if dataset_link is not None:
60
+ pool = build_video_kv_pool(dataset_link, self.label_range)
61
+ if test_dataset_link is not None:
62
+ self._fact_pool = pool
63
+ self._test_fact_pool = build_video_kv_pool(test_dataset_link, self.label_range)
64
+ else:
65
+ self._fact_pool, self._test_fact_pool = split_train_test_facts(pool)
66
+ print(
67
+ f"[video-chain] {len(self._fact_pool)} train facts from {dataset_link} | "
68
+ f"{len(self._test_fact_pool)} test facts"
69
+ + (f" from {test_dataset_link}" if test_dataset_link else " (held-out split)")
70
+ )
71
+ elif test_dataset_link is not None:
72
+ # Inference-only real test pool -- see text_dataset.py's twin fix.
73
+ self._test_fact_pool = build_video_kv_pool(test_dataset_link, self.label_range)
74
+ print(f"[video-chain] {len(self._test_fact_pool)} test facts from {test_dataset_link}")
75
+
76
+ def _synthetic_ood_facts(self, n_facts: int = 20):
77
+ rng = random.Random(31337) # unseen object/action table
78
+ keys = rng.sample(range(self.label_range), n_facts)
79
+ vals = [rng.randrange(self.label_range) for _ in range(n_facts)]
80
+ return list(zip(keys, vals))
81
+
82
+ def perturb_fact(self, key_vec: torch.Tensor, value_vec: torch.Tensor, rng, severity: float):
83
+ if rng.random() < severity:
84
+ return torch.zeros_like(key_vec), torch.zeros_like(value_vec)
85
+ return key_vec, value_vec
@@ -0,0 +1 @@
1
+ """Inference package: reusable, checkpoint-driven inference for the DNC project."""
@@ -0,0 +1 @@
1
+ """Inference caches (prefix state / result), modular like data/ and inference/tasks/."""
@@ -0,0 +1,112 @@
1
+ """
2
+ file: inference/cache/base_cache.py
3
+
4
+ Interface the cached engine talks to (counterpart of data/base_dataset.py). A new
5
+ cache type subclasses BaseCache, overrides only the hooks it needs, and registers
6
+ itself in cache_registry.py; the engine never imports anything cache-specific.
7
+
8
+ Two hook families:
9
+ episode-level : lookup_episode() / store_episode() (wrap the whole episode)
10
+ prefix-level : find_resume() / store_boundary() (accelerate the computation;
11
+ only used when the caches' `wants_boundaries` is True and the
12
+ episode declares cache_boundaries)
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from dataclasses import dataclass, field
18
+ from typing import Any
19
+
20
+ import torch
21
+
22
+ from initium.inference.cache.keys import digest, hash_tensor
23
+ from initium.inference.cache.state_utils import tree_nbytes
24
+ from initium.inference.cache.stores import CacheStats, TieredStore
25
+
26
+
27
+ @dataclass
28
+ class EpisodeCtx:
29
+ index: int
30
+ episode: Any # inference.tasks.base_task.Episode
31
+ reset_experience: bool
32
+ in_hash: str # hash of the episode's full input sequence
33
+ chain: str # "root" in fresh mode; history hash in persistent mode
34
+ boundaries: list[int] = field(default_factory=list) # validated cut points
35
+ _prefix_hashes: dict[int, str] = field(default_factory=dict, repr=False)
36
+
37
+ def prefix_hash(self, boundary: int) -> str:
38
+ h = self._prefix_hashes.get(boundary)
39
+ if h is None:
40
+ h = self._prefix_hashes[boundary] = hash_tensor(self.episode.input_seq[:boundary])
41
+ return h
42
+
43
+
44
+ @dataclass
45
+ class EpisodeHit:
46
+ output: torch.Tensor # (T, output_dim) CPU float
47
+ hidden: Any # restored state (persistent mode) or None
48
+ saved_ms: float
49
+
50
+
51
+ @dataclass
52
+ class ResumePoint:
53
+ position: int # steps [0, position) are already reflected in `hidden`
54
+ hidden: Any
55
+ saved_ms: float
56
+ cache_name: str
57
+
58
+
59
+ class BaseCache:
60
+ name: str = "base"
61
+ wants_boundaries: bool = False
62
+
63
+ def __init__(self, store: TieredStore, model_fp: str, device: torch.device):
64
+ self.store, self.model_fp, self.device = store, model_fp, device
65
+ self.stats = CacheStats()
66
+
67
+ # ---- hooks ----------------------------------------------------------------
68
+ def applicable(self, *, reset_experience: bool, resumable: bool) -> tuple[bool, str]:
69
+ return True, ""
70
+
71
+ def lookup_episode(self, ctx: EpisodeCtx) -> EpisodeHit | None:
72
+ return None
73
+
74
+ def store_episode(
75
+ self, ctx: EpisodeCtx, output: torch.Tensor, hidden_after: Any, compute_ms: float
76
+ ) -> None:
77
+ pass
78
+
79
+ def find_resume(self, ctx: EpisodeCtx) -> ResumePoint | None:
80
+ return None
81
+
82
+ def store_boundary(
83
+ self, ctx: EpisodeCtx, boundary: int, hidden: Any, compute_ms: float
84
+ ) -> None:
85
+ pass
86
+
87
+ # ---- helpers --------------------------------------------------------------
88
+ def report(self, reset: bool = False) -> dict:
89
+ d = self.stats.to_dict()
90
+ if reset:
91
+ self.stats = CacheStats()
92
+ return d
93
+
94
+ def _key(self, *parts: Any) -> str:
95
+ return f"{self.name}-{digest(self.model_fp, self.name, *parts)}"
96
+
97
+ def _get(self, key: str):
98
+ return self.store.get(key)
99
+
100
+ def _put(self, key: str, payload: Any, compute_ms: float) -> None:
101
+ nbytes = tree_nbytes(payload)
102
+ self.store.put(
103
+ key,
104
+ {
105
+ "payload": payload,
106
+ "compute_ms": float(compute_ms),
107
+ "nbytes": nbytes,
108
+ "kind": self.name,
109
+ },
110
+ )
111
+ self.stats.stores += 1
112
+ self.stats.bytes_stored += nbytes