Repository navigation
Add a folder index, search, and the index and search commands - #8
Merged
Merged
Conversation
jepa-scope.index is a safetensors file with a validated JSON header, like .latent. It holds every clip's window vectors in clip order, their start times, the clip each row belongs to and the window-weighted mean, plus a header with the representation block, the run settings, the root folder, skipped files and one entry per clip. Validation covers dtypes, finite values, ranges that tile the rows, strictly increasing times within a clip, portable relative paths, strict JSON and the stored mean. Saving goes through a unique temporary file beside the target. Signed-off-by: RDCLder <raymondyang.dev@gmail.com>
prepare turns an index into normalised window vectors, centred on the folder mean when the index asks for it; vectors that are zero or not finite after that are unavailable rather than ranked. nearest_moments finds windows like a given window, in other clips by default, keeping only non-overlapping hits per clip; nearest_clips compares clips by the mean of their window vectors. Candidates found with a float32 product are rescored in float64 so equal scores order by clip and window on any maths library, and overlap is decided by window number, not timestamps. Signed-off-by: RDCLder <raymondyang.dev@gmail.com>
jepa-scope index <folder> embeds every video in a folder through the result cache and writes jepa-scope.index beside the videos. A rerun keeps files whose size and modification time are unchanged without reading them, hashes the rest, and embeds only what the cache does not hold; byte-identical files share one cache file. --verify hashes everything. An index made with other settings, from another folder, or in an unreadable format is rebuilt with the reason printed. A bad file is skipped and recorded with its reason instead of stopping the run, and is not retried until it changes. The model loads only when a clip has to be embedded. jepa-scope search <folder|index> <clip|video> lists the most similar moments or clips. A video that is not in the index is embedded with the index's own model and settings and refused when this machine would produce a different representation. --source-root locates a folder that moved away from an index written elsewhere with --out. The cache rule moves from the CLI into cache.py with the same file names, so existing cache files keep hitting; a test pins the names. Signed-off-by: RDCLder <raymondyang.dev@gmail.com>
Only skips caused by a file's content (too short, too few frames per second, no video stream, not decodable) are remembered across runs, together with the jepa-scope version; read errors, running out of memory and invalid model output are retried on the next run. Two identical failing files are tried once. --centre and --recursive are remembered by the index, and the index header records recursive. --no-centre and --no-recursive turn them off. A rebuild from scratch keeps them. search takes an existing file as a file: it is an indexed clip when its path lies under the folder, or when its contents match one, and only a name that is not a file is looked up as a clip path. A query that needs embedding on a device that is not available here is refused with a message. EmbedSettings.from_index and cache.find_cache_file give one cache lookup for the indexer and search, and a local --model folder is recorded by its absolute path. A symlinked index beside the videos keeps the root ".". .latent files are written through a unique temporary file. Signed-off-by: RDCLder <raymondyang.dev@gmail.com>
The device check for a query video that is not in the index now runs only when the query must be embedded, so a query the cache already holds works on any machine. Two tests cover the remaining skip and sticky-choice rules, and the plan records T4 as complete with its measurements. Signed-off-by: RDCLder <raymondyang.dev@gmail.com>
…xperiment An opt-in real-model test indexes the 50 frozen Kinetics-mini val clips with the folder indexer and scores them with nearest_clips and nearest_moments. It reproduces the experiment exactly: 42/50 clip-level top-1, a window-level rate of 0.7427, and 16/16 localisation queries. The composite builder is shared with the experiment's own test. Signed-off-by: RDCLder <raymondyang.dev@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is the second pull request of the Weeks 3 and 4 plan (
docs/plans/2026-11-06-weeks3-4-folder-search-trajectory.md), covering tasks T2 to T5. It adds a folder index, search over it, and two commands,jepa-scope indexandjepa-scope search. The server and viewer do not use the index yet; that is the next pull request.T2: the folder index file
jepa-scope.index, is a safetensors file with a validated JSON header (src/jepa_scope/index_file.py, format version 1). Its tensors are each window's pooled vector, each window's start time, the clip each window belongs to, and the folder mean..latentfiles, the run settings (maximum seconds, device and dtype), the folder root, the clips with their SHA-256, size and modification time, the clips that were skipped and why, and whether the folder was indexed recursively.T3: search
src/jepa_scope/search.py) is a brute-force cosine search over the index, rescored in float64 so that ties and ordering are stable. It finds either the nearest moments or the nearest clips.kis capped at 1000.T4: the indexer and the commands
jepa-scope index <folder>embeds every video in the folder that is not already cached, then writes the index. A second run with nothing new reuses every cached.latentfile and does not load the model.src/jepa_scope/cache.py, so the indexer, the single-clip command and later the server share one rule for when a cached file can be reused. Cache file names are unchanged, and a test pins them.--centre(subtract the folder mean before comparing) and--recursiveare remembered in the index, so a later refresh without the flag keeps the earlier choice, even when the index has to be rebuilt.jepa-scope search <folder or index> <query>accepts a clip in the index, a relative path, or a video outside the folder. An outside video is embedded only if the cache does not already hold it, and only then does it need the index's device..latentfiles are now written to a temporary file and renamed, so an interrupted run cannot leave a half-written file.T5: search reproduces the retrieval experiment
An opt-in test (
test_search_reproduces_experimentintests/test_real_model.py) indexes the same 50 Kinetics-mini validation clips that the first pull request's experiment used, through the real indexer and search code, and compares the results with the experiment's.The test fails if any of the three results drifts. It was checked to fail when the moment search is deliberately broken.
When a search is allowed to return moments from the query's own clip (
--same-clip), 9 of the 16 composite queries find a later moment of their own video first. Within one video, the most similar moments are mostly other moments of the same scene. The default search, which leaves the query's clip out, is not affected. The README will say this when the Week 4 documentation lands.Timings on an Apple-silicon laptop (MPS)
Checks
./scripts/build.shpass.Reproduce T5
JEPA_SCOPE_MODEL_TESTS=1 uv run pytest tests/test_real_model.py -s -k "search_reproduces_experiment"