Skip to content

Commit b631fc0

Browse files
committed
test(vml): 8×8 grid hotspot bundling — 43.5% (local attention at 1/3 intersections)
8×8 grid of 8×8 cells. For each 1/3 intersection, find 4 neighboring cells, compute gradient energy, bundle their features (mean of 4 cells). Results (200 images, 10 classes): Hotspot bundle 768D: 43.5% (4.3× random) Compressed 17D: 29.5% (2.9× random) All approaches at 768D: Grid lines: 29.8% (diffuse full-width scan) Hotspot: 43.5% (local attention) ← 46% better than grid Centroid focus: 50.5% (single best sweet spot, 432D) At 34 bytes: Grid→17D: 14.2% Hotspot→17D: 29.5% ← 2× grid compression quality Focus→17D: 28.5% The hotspot bundling captures LOCAL composition (what's AROUND each 1/3 intersection) vs grid lines which capture GLOBAL composition (what's ALONG each 1/3 line). Local attention wins by 46%. Next: chain with NARS predicate deduction. The visual detector finds S (bird at NW) and O (fence at SE). DeepNSM's distance matrix finds the nearest linking verb → P (perch). No predicate detector needed. https://claude.ai/code/session_01Y69Vnw751w75iVSBRws7o7
1 parent ba250b2 commit b631fc0

1 file changed

Lines changed: 179 additions & 0 deletions

File tree

src/hpc/vml.rs

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,4 +1721,183 @@ mod tests {
17211721
"NARS revision should improve over best single: {:.1}% vs {:.1}%",
17221722
revised_accuracy * 100.0, best_single_acc * 100.0);
17231723
}
1724+
#[test]
1725+
#[ignore]
1726+
fn test_hotspot_8x8_grid_bundling() {
1727+
// 8×8 grid of 8×8 cells. For each 1/3 intersection, find the 4 hottest
1728+
// neighboring cells (by gradient energy), bundle their features.
1729+
1730+
let bytes = match std::fs::read("/tmp/tiny_imagenet_labeled.bin") {
1731+
Ok(b) => b,
1732+
Err(_) => { eprintln!("SKIP: /tmp/tiny_imagenet_labeled.bin not found"); return; }
1733+
};
1734+
1735+
let n = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as usize;
1736+
let d = u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as usize;
1737+
let n_classes = u32::from_le_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]) as usize;
1738+
let mut labels = Vec::with_capacity(n);
1739+
for i in 0..n {
1740+
let off = 12 + i * 4;
1741+
labels.push(u32::from_le_bytes([bytes[off], bytes[off+1], bytes[off+2], bytes[off+3]]) as usize);
1742+
}
1743+
let pixel_start = 12 + n * 4;
1744+
let img_w = 64usize; let img_h = 64usize; let ch = 3usize;
1745+
let n_use = n.min(200);
1746+
1747+
let pixel = |img: usize, r: usize, c: usize, channel: usize| -> f64 {
1748+
let off = pixel_start + (img * d + r * img_w * ch + c * ch + channel) * 4;
1749+
f32::from_le_bytes([bytes[off], bytes[off+1], bytes[off+2], bytes[off+3]]) as f64
1750+
};
1751+
let luma = |img: usize, r: usize, c: usize| -> f64 {
1752+
0.299 * pixel(img, r, c, 0) + 0.587 * pixel(img, r, c, 1) + 0.114 * pixel(img, r, c, 2)
1753+
};
1754+
1755+
let cell_size = 8usize; // 8×8 cells
1756+
let grid_w = img_w / cell_size; // 8 cells wide
1757+
let grid_h = img_h / cell_size; // 8 cells tall
1758+
let cell_feat_d = cell_size * cell_size * ch; // 192 features per cell
1759+
1760+
// 1/3 intersections in cell coordinates
1761+
let intersections_cell = [
1762+
(grid_h / 3, grid_w / 3), // ~(2,2)
1763+
(grid_h / 3, 2 * grid_w / 3), // ~(2,5)
1764+
(2 * grid_h / 3, grid_w / 3), // ~(5,2)
1765+
(2 * grid_h / 3, 2 * grid_w / 3), // ~(5,5)
1766+
];
1767+
1768+
// For each image: for each intersection, find 4 hottest neighboring cells, bundle
1769+
let mut features: Vec<Vec<f64>> = Vec::with_capacity(n_use);
1770+
1771+
for img in 0..n_use {
1772+
let mut img_features = Vec::new();
1773+
1774+
// Compute gradient energy for each cell
1775+
let mut cell_energy = vec![vec![0.0f64; grid_w]; grid_h];
1776+
for gr in 0..grid_h {
1777+
for gc in 0..grid_w {
1778+
let mut energy = 0.0f64;
1779+
let r0 = gr * cell_size;
1780+
let c0 = gc * cell_size;
1781+
for r in r0..(r0 + cell_size) {
1782+
for c in c0..(c0 + cell_size) {
1783+
if r > 0 && r < img_h-1 && c > 0 && c < img_w-1 {
1784+
let dx = luma(img, r, c+1) - luma(img, r, c.saturating_sub(1));
1785+
let dy = luma(img, r+1, c) - luma(img, r.saturating_sub(1), c);
1786+
energy += (dx*dx + dy*dy).sqrt();
1787+
}
1788+
}
1789+
}
1790+
cell_energy[gr][gc] = energy;
1791+
}
1792+
}
1793+
1794+
// For each intersection, get 4 hottest neighboring cells (2×2 around intersection)
1795+
for &(ir, ic) in &intersections_cell {
1796+
// Candidate cells: the 4 cells around the intersection point
1797+
let mut candidates: Vec<(usize, usize, f64)> = Vec::new();
1798+
for dr in 0..2usize {
1799+
for dc in 0..2usize {
1800+
let gr = (ir + dr).min(grid_h - 1);
1801+
let gc = (ic + dc).min(grid_w - 1);
1802+
candidates.push((gr, gc, cell_energy[gr][gc]));
1803+
}
1804+
}
1805+
// Sort by energy (hottest first) — but we take all 4 for bundling
1806+
candidates.sort_by(|a, b| b.2.partial_cmp(&a.2).unwrap());
1807+
1808+
// Bundle: average the 4 cell feature vectors (majority vote analog for f64)
1809+
let mut bundle = vec![0.0f64; cell_feat_d];
1810+
for &(gr, gc, _) in &candidates {
1811+
let r0 = gr * cell_size;
1812+
let c0 = gc * cell_size;
1813+
let mut idx = 0;
1814+
for r in r0..(r0 + cell_size) {
1815+
for c in c0..(c0 + cell_size) {
1816+
for channel in 0..ch {
1817+
bundle[idx] += pixel(img, r, c, channel);
1818+
idx += 1;
1819+
}
1820+
}
1821+
}
1822+
}
1823+
// Normalize bundle (mean of 4 cells)
1824+
for v in bundle.iter_mut() { *v /= 4.0; }
1825+
img_features.extend_from_slice(&bundle);
1826+
}
1827+
1828+
features.push(img_features);
1829+
}
1830+
1831+
let feat_d = features[0].len(); // 4 intersections × 192 = 768
1832+
1833+
// Build archetypes and classify
1834+
let mut archetypes = vec![vec![0.0; feat_d]; n_classes];
1835+
let mut counts = vec![0usize; n_classes];
1836+
for (i, &l) in labels[..n_use].iter().enumerate() {
1837+
for j in 0..feat_d { archetypes[l][j] += features[i][j]; }
1838+
counts[l] += 1;
1839+
}
1840+
for c in 0..n_classes {
1841+
if counts[c] > 0 { for j in 0..feat_d { archetypes[c][j] /= counts[c] as f64; } }
1842+
}
1843+
1844+
let mut correct = 0usize;
1845+
for (i, &true_label) in labels[..n_use].iter().enumerate() {
1846+
let mut best_c = 0;
1847+
let mut best_d = f64::MAX;
1848+
for c in 0..n_classes {
1849+
if counts[c] == 0 { continue; }
1850+
let dist: f64 = features[i].iter().zip(&archetypes[c])
1851+
.map(|(a, b)| (a-b)*(a-b)).sum::<f64>().sqrt();
1852+
if dist < best_d { best_d = dist; best_c = c; }
1853+
}
1854+
if best_c == true_label { correct += 1; }
1855+
}
1856+
let accuracy = correct as f64 / n_use as f64;
1857+
1858+
// Also: golden-step compressed
1859+
let base_dim = 17; let golden_step = 11;
1860+
let compress = |v: &[f64]| -> Vec<f64> {
1861+
let fd = v.len();
1862+
let n_oct = (fd + base_dim - 1) / base_dim;
1863+
let mut sum = vec![0.0f64; base_dim];
1864+
let mut cnt = vec![0u32; base_dim];
1865+
for oct in 0..n_oct {
1866+
for bi in 0..base_dim {
1867+
let dim = oct * base_dim + ((bi * golden_step) % base_dim);
1868+
if dim < fd { sum[bi] += v[dim]; cnt[bi] += 1; }
1869+
}
1870+
}
1871+
sum.iter().zip(&cnt).map(|(&s, &c)| if c > 0 { s / c as f64 } else { 0.0 }).collect()
1872+
};
1873+
let c_arch: Vec<Vec<f64>> = archetypes.iter().map(|a| compress(a)).collect();
1874+
let c_feat: Vec<Vec<f64>> = features.iter().map(|f| compress(f)).collect();
1875+
let mut correct_c = 0;
1876+
for (i, &tl) in labels[..n_use].iter().enumerate() {
1877+
let mut best_c = 0; let mut best_d = f64::MAX;
1878+
for c in 0..n_classes {
1879+
if counts[c] == 0 { continue; }
1880+
let dist: f64 = c_feat[i].iter().zip(&c_arch[c]).map(|(a,b)|(a-b)*(a-b)).sum::<f64>().sqrt();
1881+
if dist < best_d { best_d = dist; best_c = c; }
1882+
}
1883+
if best_c == tl { correct_c += 1; }
1884+
}
1885+
let acc_c = correct_c as f64 / n_use as f64;
1886+
1887+
eprintln!("=== 8×8 Grid Hotspot Bundling ===");
1888+
eprintln!(" {} images, {} classes", n_use, n_classes);
1889+
eprintln!(" Cell size: {}×{}, Grid: {}×{}", cell_size, cell_size, grid_w, grid_h);
1890+
eprintln!(" Features: 4 intersections × 4 hot cells bundled × {}D = {}D", cell_feat_d, feat_d);
1891+
eprintln!();
1892+
eprintln!(" Hotspot bundle 768D: {:.1}% ({}/{})", accuracy * 100.0, correct, n_use);
1893+
eprintln!(" Compressed 17D (34B): {:.1}% ({}/{})", acc_c * 100.0, correct_c, n_use);
1894+
eprintln!(" Random baseline: {:.1}%", 100.0 / n_classes as f64);
1895+
eprintln!();
1896+
eprintln!(" Compare all 768D approaches:");
1897+
eprintln!(" Grid lines: 29.8% (4 full scan lines)");
1898+
eprintln!(" Hotspot bundles: {:.1}% (4×4 hot cells at 1/3 points)", accuracy * 100.0);
1899+
eprintln!(" Centroid focus (432D): 50.5% (single best intersection patch)");
1900+
1901+
assert!(accuracy > 1.0 / n_classes as f64, "should beat random");
1902+
}
17241903
}

0 commit comments

Comments
 (0)