--- title: "Getting started with leakaudit" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting started with leakaudit} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ## The problem When building an image classification dataset, near-duplicate images (the same photo re-saved, resized, lightly cropped, or recompressed) commonly end up split across train and test. This silently inflates test-set performance, since the model has effectively already seen a near-identical copy of the "unseen" example. leakaudit finds these near-duplicates, reports how much they contaminate each split, and can produce a corrected split assignment. ## Workflow The typical pipeline has four steps: hash, group, audit, and clean. ```{r, eval = FALSE} library(leakaudit) # 1. Hash every image and record which split it currently belongs to hashes <- compute_hashes( paths = image_paths, split = split_labels ) # 2. Cluster images into near-duplicate groups grouped <- find_duplicate_groups(hashes, threshold = 5) # 3. Audit: how much leakage is there? report <- dhash_audit(grouped) print(report) # 4. Clean: reassign leaked groups to a single split clean <- clean_splits(grouped, priority = c("train", "val", "test")) ``` ## A minimal, reproducible example `dhash_audit()` and `clean_splits()` only need a data frame with `path`, `hash`/`group_id`, and `split` columns, so they can be demonstrated without real image files: ```{r} library(leakaudit) groups <- data.frame( path = c("a.jpg", "b.jpg", "c.jpg", "d.jpg", "e.jpg"), split = c("train", "test", "train", "val", "test"), group_id = c(1, 1, 2, 3, 3), stringsAsFactors = FALSE ) report <- dhash_audit(groups) report ``` Group 1 spans `train` and `test`, and group 3 spans `val` and `test`, so both are flagged as leaked. Group 2 stays within `train` and is left alone. `clean_splits()` resolves the leaked groups by reassigning every member to a single split, chosen by priority (default: keep duplicates in `train`): ```{r} clean_splits(groups) ``` ## Choosing a threshold `find_duplicate_groups()` clusters images whose dHash values are within `threshold` Hamming distance (out of 64 bits). The default of `5` is a reasonably conservative value: lower it for stricter, closer-to-exact matching, or raise it to catch more aggressive near-duplicates at the cost of more false positives.