rishabhsai commited on
Commit
9d91b1d
·
verified ·
1 Parent(s): 141be62

Publish Cache Atlas static site

Browse files
.gitattributes CHANGED
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ public/media/minicache-depth-axis.mp4 filter=lfs diff=lfs merge=lfs -text
37
+ public/media/minicache-layer-merge.mp4 filter=lfs diff=lfs merge=lfs -text
38
+ public/media/minicache-retention.mp4 filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # build output
2
+ dist/
3
+
4
+ # generated types
5
+ .astro/
6
+
7
+ # dependencies
8
+ node_modules/
9
+
10
+ # logs
11
+ npm-debug.log*
12
+ yarn-debug.log*
13
+ yarn-error.log*
14
+ pnpm-debug.log*
15
+
16
+ # environment variables
17
+ .env
18
+ .env.production
19
+
20
+ # macOS-specific files
21
+ .DS_Store
22
+ __pycache__/
23
+ *.pyc
24
+
25
+ # jetbrains setting folder
26
+ .idea/
27
+
28
+ # internal planning notes
29
+ PROJECT_DIRECTION.md
30
+ research/
.vscode/extensions.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "recommendations": ["astro-build.astro-vscode"],
3
+ "unwantedRecommendations": []
4
+ }
.vscode/launch.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "0.2.0",
3
+ "configurations": [
4
+ {
5
+ "command": "./node_modules/.bin/astro dev",
6
+ "name": "Development server",
7
+ "request": "launch",
8
+ "type": "node-terminal"
9
+ }
10
+ ]
11
+ }
README.md CHANGED
@@ -1,10 +1,33 @@
1
  ---
2
  title: Cache Atlas
3
- emoji: 🚀
4
- colorFrom: gray
5
  colorTo: indigo
6
  sdk: static
 
 
7
  pinned: false
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  title: Cache Atlas
3
+ emoji: 🧠
4
+ colorFrom: blue
5
  colorTo: indigo
6
  sdk: static
7
+ app_build_command: npm run build
8
+ app_file: dist/index.html
9
  pinned: false
10
+ license: mit
11
  ---
12
 
13
+ # Cache Atlas
14
+
15
+ Public notes and demos for learning modern inference systems by implementing the core pieces.
16
+
17
+ This repo holds:
18
+
19
+ - paper notes written as implementation writeups
20
+ - diagrams and Manim renders
21
+ - inline demos embedded in articles
22
+ - links to standalone implementation repos
23
+ - reproduction notes for the code paths I build
24
+
25
+ Current paper track:
26
+
27
+ 1. <https://arxiv.org/abs/2405.14366> — MiniCache
28
+ 2. <https://arxiv.org/abs/2412.03409> — PrefixKV
29
+
30
+ ## Commands
31
+
32
+ - `npm run dev`
33
+ - `npm run build`
animations/scenes/minicache_intro.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from manim import *
2
+
3
+
4
+ config.background_color = BLACK
5
+
6
+ INK = "#E7EDF4"
7
+ MUTED = "#9AA6B2"
8
+ ACCENT = "#79D2FF"
9
+ GREEN = "#7DF0C8"
10
+ RED = "#FF8B84"
11
+ CARD = "#0B0E12"
12
+
13
+
14
+ def box(width, height, stroke=INK, fill=CARD, opacity=1.0):
15
+ return RoundedRectangle(
16
+ width=width,
17
+ height=height,
18
+ corner_radius=0.08,
19
+ stroke_color=stroke,
20
+ stroke_width=2,
21
+ fill_color=fill,
22
+ fill_opacity=opacity,
23
+ )
24
+
25
+
26
+ class MiniCacheDepthAxis(Scene):
27
+ def construct(self):
28
+ title = Text("KV cache papers attack different axes", color=INK, font_size=40)
29
+ title.to_edge(UP)
30
+
31
+ left_frame = box(4.8, 3.8, stroke=ACCENT)
32
+ right_frame = box(4.8, 3.8, stroke=GREEN)
33
+ frames = VGroup(left_frame, right_frame).arrange(RIGHT, buff=0.5).shift(DOWN * 0.15)
34
+
35
+ left_title = Text("token-axis", color=ACCENT, font_size=26).next_to(left_frame, UP, buff=0.18)
36
+ right_title = Text("depth-axis", color=GREEN, font_size=26).next_to(right_frame, UP, buff=0.18)
37
+
38
+ token_grid = VGroup()
39
+ for _ in range(5):
40
+ row = VGroup(*[Square(side_length=0.38, stroke_color=ACCENT, fill_color=ACCENT, fill_opacity=0.08) for _ in range(7)])
41
+ row.arrange(RIGHT, buff=0.04)
42
+ token_grid.add(row)
43
+ token_grid.arrange(DOWN, buff=0.06).move_to(left_frame)
44
+
45
+ keep = SurroundingRectangle(VGroup(token_grid[0], token_grid[1], token_grid[2]), color=ACCENT, buff=0.08)
46
+ drop = Cross(VGroup(token_grid[3], token_grid[4]), stroke_color=RED, stroke_width=4).scale(1.1)
47
+
48
+ layers = VGroup()
49
+ for idx in range(6):
50
+ rect = box(3.4, 0.38, stroke=GREEN, fill=GREEN, opacity=0.1)
51
+ rect.add(Text(f"layer {idx + 1}", color=INK, font_size=18).move_to(rect))
52
+ layers.add(rect)
53
+ layers.arrange(DOWN, buff=0.12).move_to(right_frame)
54
+
55
+ merge_a = SurroundingRectangle(VGroup(layers[2], layers[3]), color=GREEN, buff=0.08)
56
+ merge_b = SurroundingRectangle(VGroup(layers[4], layers[5]), color=GREEN, buff=0.08)
57
+ arrow = Arrow(LEFT * 0.9, RIGHT * 0.9, color=GREEN).move_to(right_frame.get_bottom() + UP * 0.38)
58
+ note = Text("MiniCache compresses across depth", color=MUTED, font_size=24).to_edge(DOWN)
59
+
60
+ self.play(Write(title))
61
+ self.play(FadeIn(frames), FadeIn(left_title), FadeIn(right_title))
62
+ self.play(LaggedStart(*[FadeIn(row, shift=UP * 0.08) for row in token_grid], lag_ratio=0.08))
63
+ self.play(Create(keep), Create(drop))
64
+ self.play(LaggedStart(*[FadeIn(layer, shift=RIGHT * 0.08) for layer in layers], lag_ratio=0.08))
65
+ self.play(Create(merge_a), Create(merge_b), GrowArrow(arrow))
66
+ self.play(FadeIn(note))
67
+ self.wait(1)
68
+
69
+
70
+ class MiniCacheLayerMerge(Scene):
71
+ def construct(self):
72
+ title = Text("Middle and deep layers may be redundant", color=INK, font_size=40)
73
+ title.to_edge(UP)
74
+
75
+ layer_stack = VGroup()
76
+ colors = [ACCENT, ACCENT, GREEN, GREEN, GREEN, GREEN]
77
+ for idx, color in enumerate(colors):
78
+ rect = box(4.4, 0.46, stroke=color, fill=color, opacity=0.12)
79
+ rect.add(Text(f"layer {idx + 1}", color=INK, font_size=18).move_to(rect))
80
+ layer_stack.add(rect)
81
+ layer_stack.arrange(DOWN, buff=0.16).shift(LEFT * 1.7 + DOWN * 0.15)
82
+
83
+ similar_a = SurroundingRectangle(VGroup(layer_stack[2], layer_stack[3]), color=GREEN, buff=0.08)
84
+ similar_b = SurroundingRectangle(VGroup(layer_stack[4], layer_stack[5]), color=GREEN, buff=0.08)
85
+
86
+ compressed = VGroup()
87
+ for label in ["compressed pair", "compressed pair"]:
88
+ rect = box(2.8, 0.62, stroke=GREEN, fill=GREEN, opacity=0.12)
89
+ rect.add(Text(label, color=INK, font_size=18).move_to(rect))
90
+ compressed.add(rect)
91
+ compressed.arrange(DOWN, buff=0.36).shift(RIGHT * 2.4)
92
+
93
+ arrows = VGroup(
94
+ Arrow(similar_a.get_right(), compressed[0].get_left(), color=GREEN, buff=0.2),
95
+ Arrow(similar_b.get_right(), compressed[1].get_left(), color=GREEN, buff=0.2),
96
+ )
97
+
98
+ memory_before = Text("memory before", color=MUTED, font_size=20).next_to(layer_stack, DOWN, buff=0.28)
99
+ memory_after = Text("memory after", color=MUTED, font_size=20).next_to(compressed, DOWN, buff=0.28)
100
+ bars_before = VGroup(*[Rectangle(width=0.42, height=0.18, stroke_width=0, fill_color=ACCENT, fill_opacity=1) for _ in range(6)]).arrange(RIGHT, buff=0.06).next_to(memory_before, DOWN, buff=0.16)
101
+ bars_after = VGroup(*[Rectangle(width=0.42, height=0.18, stroke_width=0, fill_color=GREEN, fill_opacity=1) for _ in range(4)]).arrange(RIGHT, buff=0.06).next_to(memory_after, DOWN, buff=0.16)
102
+
103
+ note = Text("compress the cache without only dropping tokens", color=MUTED, font_size=24).to_edge(DOWN)
104
+
105
+ self.play(Write(title))
106
+ self.play(LaggedStart(*[FadeIn(layer, shift=UP * 0.08) for layer in layer_stack], lag_ratio=0.08))
107
+ self.play(Create(similar_a), Create(similar_b))
108
+ self.play(GrowArrow(arrows[0]), FadeIn(compressed[0]))
109
+ self.play(GrowArrow(arrows[1]), FadeIn(compressed[1]))
110
+ self.play(FadeIn(memory_before), FadeIn(bars_before))
111
+ self.play(FadeIn(memory_after), FadeIn(bars_after))
112
+ self.play(FadeIn(note))
113
+ self.wait(1)
114
+
115
+
116
+ class MiniCacheRetention(Scene):
117
+ def construct(self):
118
+ title = Text("Retention keeps the sharp mismatches", color=INK, font_size=40)
119
+ title.to_edge(UP)
120
+
121
+ tokens = VGroup()
122
+ fills = [GREEN, GREEN, GREEN, RED, GREEN, RED, GREEN, GREEN]
123
+ labels = ["0.98", "0.97", "0.99", "0.71", "0.96", "0.68", "0.98", "0.99"]
124
+ for fill, label in zip(fills, labels):
125
+ square = RoundedRectangle(
126
+ width=0.78,
127
+ height=0.78,
128
+ corner_radius=0.08,
129
+ stroke_color=fill,
130
+ stroke_width=2,
131
+ fill_color=fill,
132
+ fill_opacity=0.12,
133
+ )
134
+ number = Text(label, color=INK, font_size=18).move_to(square)
135
+ tokens.add(VGroup(square, number))
136
+ tokens.arrange(RIGHT, buff=0.14).shift(UP * 0.35)
137
+
138
+ caption = Text("cross-layer similarity per token", color=MUTED, font_size=24).next_to(tokens, UP, buff=0.24)
139
+ threshold = DashedLine(
140
+ start=tokens.get_left() + DOWN * 0.85,
141
+ end=tokens.get_right() + DOWN * 0.85,
142
+ color=MUTED,
143
+ dash_length=0.1,
144
+ )
145
+ threshold_label = Text("similar enough -> merge", color=GREEN, font_size=22).next_to(threshold, DOWN, buff=0.16)
146
+
147
+ kept = VGroup(
148
+ SurroundingRectangle(tokens[3], color=RED, buff=0.08),
149
+ SurroundingRectangle(tokens[5], color=RED, buff=0.08),
150
+ )
151
+ kept_label = Text("retain the unusually distinct pairs", color=RED, font_size=24).to_edge(DOWN)
152
+
153
+ self.play(Write(title))
154
+ self.play(FadeIn(caption))
155
+ self.play(LaggedStart(*[FadeIn(token, shift=UP * 0.08) for token in tokens], lag_ratio=0.08))
156
+ self.play(Create(threshold), FadeIn(threshold_label))
157
+ self.play(Create(kept[0]), Create(kept[1]))
158
+ self.play(FadeIn(kept_label))
159
+ self.wait(1)
astro.config.mjs ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ // @ts-check
2
+ import { defineConfig } from 'astro/config';
3
+
4
+ import mdx from '@astrojs/mdx';
5
+ import react from '@astrojs/react';
6
+
7
+ // https://astro.build/config
8
+ export default defineConfig({
9
+ integrations: [mdx(), react()]
10
+ });
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
package.json ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "cache-atlas",
3
+ "type": "module",
4
+ "version": "0.0.1",
5
+ "engines": {
6
+ "node": ">=22.12.0"
7
+ },
8
+ "scripts": {
9
+ "dev": "astro dev",
10
+ "build": "astro build",
11
+ "preview": "astro preview",
12
+ "astro": "astro"
13
+ },
14
+ "dependencies": {
15
+ "@astrojs/mdx": "^5.0.4",
16
+ "@astrojs/react": "^5.0.4",
17
+ "@types/react": "^19.2.14",
18
+ "@types/react-dom": "^19.2.3",
19
+ "astro": "^6.1.9",
20
+ "react": "^19.2.5",
21
+ "react-dom": "^19.2.5"
22
+ }
23
+ }
public/favicon.ico ADDED
public/favicon.svg ADDED
public/media/minicache-depth-axis.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7ccd98f2c8dc35b850e72befd292cba69cb3a340345fbeb658e95dbb6bcda3fa
3
+ size 175526
public/media/minicache-layer-merge.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:730416da0386dc6627faea6fad19c81c314c717aaba29c4f424842499be22207
3
+ size 165670
public/media/minicache-retention.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:48d94ebcd3c115cd0e52e3408780f2b721b00cbc663bf4a6b0fdf960b7e489ba
3
+ size 131083
research/FIRST_PAPER_DECISION.md ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # First Paper Decision
2
+
3
+ ## Decision
4
+
5
+ We should **write generally first, implement narrowly first**.
6
+
7
+ That means:
8
+
9
+ ## First post
10
+
11
+ **Why KV cache papers matter**
12
+
13
+ This is the right first post because it does three things:
14
+
15
+ 1. explains the space before we commit to one paper
16
+ 2. gives us a reusable framing for later posts
17
+ 3. supports the first interactive demo naturally
18
+
19
+ It should answer:
20
+
21
+ - what the KV cache is
22
+ - why decode becomes memory-bound
23
+ - why people keep proposing compression / eviction / budget allocation
24
+ - why this repo is focusing on cache-efficiency papers
25
+
26
+ ## First implementation
27
+
28
+ **MiniCache**
29
+
30
+ ## Why MiniCache first
31
+
32
+ MiniCache is not the flashiest option, but it is the best first implementation target.
33
+
34
+ Reasons:
35
+
36
+ 1. **Cleaner scope**
37
+ - training-free
38
+ - no heavy VLM integration needed on day one
39
+ - easier to isolate the core method
40
+
41
+ 2. **Better odds of shipping**
42
+ - more self-contained than PrefixKV
43
+ - less adapter pain
44
+ - easier to make a concise repo that feels complete
45
+
46
+ 3. **Good visuals anyway**
47
+ - cross-layer redundancy
48
+ - kept vs compressed cache state
49
+ - depth-wise compression
50
+ - memory / quality tradeoffs
51
+
52
+ 4. **Sets up the rest of the series**
53
+ - once we have one clean cache-efficiency implementation, later papers like PrefixKV and CAKE become easier to explain
54
+
55
+ ## Why not PrefixKV first
56
+
57
+ PrefixKV is still a strong paper.
58
+
59
+ But it is better as the **second** project, not the first.
60
+
61
+ Reasons:
62
+
63
+ - more adapter complexity
64
+ - more tied to vision-language model internals
65
+ - higher chance of getting stuck in model integration before the repo identity is established
66
+
67
+ PrefixKV is still the better paper if the top priority becomes:
68
+
69
+ - image-based demos
70
+ - VLM-specific cache allocation
71
+ - a stronger visual public artifact
72
+
73
+ But for the first clean implementation repo, MiniCache has better odds.
74
+
75
+ ## Recommended sequence
76
+
77
+ ### Step 1
78
+
79
+ Write:
80
+
81
+ - `Why KV cache papers matter`
82
+
83
+ ### Step 2
84
+
85
+ Implement:
86
+
87
+ - `MiniCache`
88
+
89
+ ### Step 3
90
+
91
+ Write:
92
+
93
+ - `MiniCache from first principles`
94
+
95
+ ### Step 4
96
+
97
+ Then move to:
98
+
99
+ - `PrefixKV`
100
+
101
+ That gives the project both:
102
+
103
+ - one clean systems implementation first
104
+ - one more visual VLM-oriented paper second
105
+
106
+ ## What to build with MiniCache
107
+
108
+ For the implementation repo:
109
+
110
+ - minimal standalone cache-compression module
111
+ - one benchmark script
112
+ - one toy memory simulator
113
+ - one clean README
114
+
115
+ For the blog:
116
+
117
+ - one diagram showing depth-wise redundancy
118
+ - one memory budget chart
119
+ - one inline demo showing how cache size changes under different compression settings
120
+
121
+ ## Current call
122
+
123
+ If we start now, the best immediate move is:
124
+
125
+ > finish the first post and build MiniCache first
research/blog-patterns.md ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Blog and repo patterns
2
+
3
+ Internal note. This file is intentionally hidden from the public repo.
4
+
5
+ ## References checked
6
+
7
+ - `mni-ml`
8
+ - Distill
9
+ - `lucidrains/x-transformers`
10
+ - `huggingface/ml-intern`
11
+ - Lil'Log
12
+
13
+ ## What to borrow
14
+
15
+ ### mni-ml
16
+
17
+ - extremely sparse home page
18
+ - curriculum / table-of-contents structure
19
+ - article-first navigation
20
+ - short explanatory paragraphs
21
+ - direct, not academic, tone
22
+
23
+ ### Distill
24
+
25
+ - visuals do explanatory work, not decorative work
26
+ - interaction appears exactly where the reader needs it
27
+ - one section, one mental model
28
+ - explanations progress from intuition to mechanism
29
+
30
+ ### lucidrains
31
+
32
+ - README is the product
33
+ - install and usage appear immediately
34
+ - small runnable examples beat long prose
35
+ - public package surface stays focused
36
+
37
+ ### ml-intern
38
+
39
+ - repo structure is disciplined
40
+ - setup path is explicit
41
+ - use `uv` and make local development obvious
42
+
43
+ For this project, borrow the discipline, not the agent architecture.
44
+
45
+ ### Lil'Log
46
+
47
+ - table of contents helps long posts
48
+ - strong use of sectioning and references
49
+ - good for survey-style notes
50
+
51
+ ## Practical synthesis
52
+
53
+ ### Hub repo
54
+
55
+ - `mni-ml` home page
56
+ - Distill-style inline demos
57
+ - concise system writing
58
+
59
+ ### Implementation repos
60
+
61
+ - lucidrains-style README
62
+ - `ml-intern`-style setup discipline
63
+ - tight public API
src/components/CacheBudgetDemo.tsx ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { type CSSProperties, useMemo, useState } from "react";
2
+
3
+ export default function CacheBudgetDemo() {
4
+ const [layers, setLayers] = useState(24);
5
+ const [prefix, setPrefix] = useState(256);
6
+ const [tokenCost, setTokenCost] = useState(2.4);
7
+
8
+ const totalMb = useMemo(() => {
9
+ return (layers * prefix * tokenCost) / 1024;
10
+ }, [layers, prefix, tokenCost]);
11
+
12
+ return (
13
+ <div style={styles.card}>
14
+ <div style={styles.label}>inline demo</div>
15
+ <p style={styles.copy}>
16
+ Tiny proxy for why cache-budget papers exist at all. Push layer count, kept prefix length, or per-token memory cost,
17
+ and the memory bill climbs fast.
18
+ </p>
19
+
20
+ <div style={styles.grid}>
21
+ <label style={styles.control}>
22
+ <span>layers</span>
23
+ <strong>{layers}</strong>
24
+ <input type="range" min="8" max="48" step="4" value={layers} onChange={(e) => setLayers(Number(e.target.value))} />
25
+ </label>
26
+ <label style={styles.control}>
27
+ <span>kept prefix</span>
28
+ <strong>{prefix}</strong>
29
+ <input type="range" min="64" max="1024" step="64" value={prefix} onChange={(e) => setPrefix(Number(e.target.value))} />
30
+ </label>
31
+ <label style={styles.control}>
32
+ <span>mb / token / layer</span>
33
+ <strong>{tokenCost.toFixed(1)}</strong>
34
+ <input type="range" min="0.5" max="4" step="0.1" value={tokenCost} onChange={(e) => setTokenCost(Number(e.target.value))} />
35
+ </label>
36
+ </div>
37
+
38
+ <div style={styles.result}>
39
+ <span>estimated cache memory</span>
40
+ <strong>{totalMb.toFixed(1)} MB</strong>
41
+ </div>
42
+ </div>
43
+ );
44
+ }
45
+
46
+ const styles: Record<string, CSSProperties> = {
47
+ card: {
48
+ border: "1px solid rgba(231,237,244,0.14)",
49
+ background: "rgba(11,14,18,0.92)",
50
+ padding: "18px",
51
+ margin: "24px 0",
52
+ },
53
+ label: {
54
+ color: "#9aa6b2",
55
+ fontSize: "12px",
56
+ textTransform: "uppercase",
57
+ },
58
+ copy: {
59
+ color: "#9aa6b2",
60
+ lineHeight: 1.8,
61
+ },
62
+ grid: {
63
+ display: "grid",
64
+ gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
65
+ gap: "12px",
66
+ marginTop: "12px",
67
+ },
68
+ control: {
69
+ display: "grid",
70
+ gap: "8px",
71
+ border: "1px solid rgba(231,237,244,0.14)",
72
+ padding: "12px",
73
+ background: "rgba(8,10,12,0.92)",
74
+ color: "#e7edf4",
75
+ },
76
+ result: {
77
+ display: "grid",
78
+ gap: "6px",
79
+ marginTop: "14px",
80
+ padding: "12px",
81
+ border: "1px solid rgba(231,237,244,0.14)",
82
+ background: "rgba(8,10,12,0.92)",
83
+ color: "#e7edf4",
84
+ },
85
+ };
src/layouts/Layout.astro ADDED
@@ -0,0 +1,287 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ const { title = "Cache Atlas" } = Astro.props;
3
+ const path = Astro.url.pathname;
4
+ ---
5
+
6
+ <!doctype html>
7
+ <html lang="en">
8
+ <head>
9
+ <meta charset="UTF-8" />
10
+ <meta name="viewport" content="width=device-width" />
11
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
12
+ <link rel="icon" href="/favicon.ico" />
13
+ <meta name="generator" content={Astro.generator} />
14
+ <title>{title}</title>
15
+ </head>
16
+ <body>
17
+ <header class="site-header">
18
+ <div class="header-inner">
19
+ <a class="brand" href="/">Cache Atlas</a>
20
+ <nav>
21
+ <a class:list={{ active: path === "/" }} href="/">Home</a>
22
+ <a class:list={{ active: path.startsWith("/notes") }} href="/notes">Notes</a>
23
+ </nav>
24
+ </div>
25
+ </header>
26
+ <slot />
27
+ </body>
28
+ </html>
29
+
30
+ <style>
31
+ :root {
32
+ color-scheme: dark;
33
+ font-family: "IBM Plex Mono", "SF Mono", Menlo, monospace;
34
+ --bg: #000;
35
+ --ink: #e7edf4;
36
+ --muted: #9aa6b2;
37
+ --line: rgba(231, 237, 244, 0.14);
38
+ --card: rgba(11, 14, 18, 0.92);
39
+ --accent: #79d2ff;
40
+ }
41
+
42
+ * {
43
+ box-sizing: border-box;
44
+ }
45
+
46
+ html,
47
+ body {
48
+ margin: 0;
49
+ width: 100%;
50
+ min-height: 100%;
51
+ background: var(--bg);
52
+ color: var(--ink);
53
+ }
54
+
55
+ a {
56
+ color: inherit;
57
+ text-decoration: none;
58
+ }
59
+
60
+ body {
61
+ font-size: 16px;
62
+ }
63
+
64
+ .site-header {
65
+ position: sticky;
66
+ top: 0;
67
+ z-index: 10;
68
+ border-bottom: 1px solid var(--line);
69
+ background: rgba(0, 0, 0, 0.9);
70
+ backdrop-filter: blur(14px);
71
+ }
72
+
73
+ .header-inner {
74
+ display: flex;
75
+ align-items: center;
76
+ justify-content: space-between;
77
+ gap: 16px;
78
+ width: min(1040px, calc(100% - 32px));
79
+ margin: 0 auto;
80
+ padding: 18px 0;
81
+ }
82
+
83
+ .brand {
84
+ font-weight: 600;
85
+ letter-spacing: 0;
86
+ }
87
+
88
+ nav {
89
+ display: flex;
90
+ align-items: center;
91
+ gap: 14px;
92
+ }
93
+
94
+ nav a {
95
+ color: var(--muted);
96
+ font-size: 12px;
97
+ text-transform: uppercase;
98
+ }
99
+
100
+ nav a.active,
101
+ nav a:hover {
102
+ color: var(--ink);
103
+ }
104
+
105
+ :global(main.page) {
106
+ width: min(980px, calc(100% - 32px));
107
+ margin: 0 auto;
108
+ padding: 48px 0 44px;
109
+ }
110
+
111
+ :global(main.article-shell) {
112
+ width: min(900px, calc(100% - 32px));
113
+ margin: 0 auto;
114
+ padding: 38px 0 42px;
115
+ }
116
+
117
+ :global(.eyebrow),
118
+ :global(.label) {
119
+ color: var(--muted);
120
+ font-size: 12px;
121
+ text-transform: uppercase;
122
+ }
123
+
124
+ :global(h1) {
125
+ margin: 12px 0 20px;
126
+ font-size: clamp(40px, 7vw, 82px);
127
+ line-height: 0.96;
128
+ font-weight: 600;
129
+ }
130
+
131
+ :global(.article-shell h1) {
132
+ max-width: 860px;
133
+ font-size: clamp(34px, 5vw, 62px);
134
+ }
135
+
136
+ :global(h2) {
137
+ margin: 40px 0 14px;
138
+ font-size: clamp(24px, 3vw, 38px);
139
+ line-height: 1.02;
140
+ }
141
+
142
+ :global(p),
143
+ :global(li) {
144
+ color: var(--muted);
145
+ line-height: 1.8;
146
+ }
147
+
148
+ :global(.lede) {
149
+ max-width: 820px;
150
+ font-size: 19px;
151
+ color: var(--ink);
152
+ }
153
+
154
+ :global(blockquote) {
155
+ margin: 22px 0;
156
+ padding: 14px 18px;
157
+ border-left: 2px solid var(--accent);
158
+ background: rgba(11, 14, 18, 0.92);
159
+ }
160
+
161
+ :global(code) {
162
+ font-family: inherit;
163
+ }
164
+
165
+ :global(pre) {
166
+ overflow-x: auto;
167
+ padding: 16px;
168
+ border: 1px solid var(--line);
169
+ background: var(--card);
170
+ }
171
+
172
+ :global(.note-card) {
173
+ margin: 22px 0;
174
+ padding: 18px;
175
+ border: 1px solid var(--line);
176
+ background: var(--card);
177
+ }
178
+
179
+ :global(.meta-grid) {
180
+ display: grid;
181
+ grid-template-columns: repeat(3, minmax(0, 1fr));
182
+ gap: 12px;
183
+ margin: 20px 0 26px;
184
+ }
185
+
186
+ :global(.meta-cell) {
187
+ padding: 14px;
188
+ border: 1px solid var(--line);
189
+ background: var(--card);
190
+ }
191
+
192
+ :global(.meta-cell strong) {
193
+ display: block;
194
+ margin-bottom: 6px;
195
+ font-size: 12px;
196
+ color: var(--muted);
197
+ text-transform: uppercase;
198
+ }
199
+
200
+ :global(.source-list),
201
+ :global(.bullet-list) {
202
+ padding-left: 18px;
203
+ }
204
+
205
+ :global(.source-list a),
206
+ :global(.inline-link) {
207
+ color: var(--accent);
208
+ }
209
+
210
+ :global(.category-list) {
211
+ display: grid;
212
+ grid-template-columns: repeat(2, minmax(0, 1fr));
213
+ gap: 12px;
214
+ margin: 14px 0 0;
215
+ padding: 0;
216
+ list-style: none;
217
+ }
218
+
219
+ :global(.category-list li) {
220
+ padding: 14px;
221
+ border: 1px solid var(--line);
222
+ background: var(--card);
223
+ }
224
+
225
+ :global(.category-list strong) {
226
+ display: block;
227
+ margin-bottom: 4px;
228
+ color: var(--ink);
229
+ }
230
+
231
+ :global(.article-nav) {
232
+ display: grid;
233
+ grid-template-columns: repeat(2, minmax(0, 1fr));
234
+ gap: 12px;
235
+ margin-top: 34px;
236
+ padding-top: 18px;
237
+ border-top: 1px solid var(--line);
238
+ }
239
+
240
+ :global(.article-nav a) {
241
+ display: block;
242
+ min-height: 86px;
243
+ padding: 14px;
244
+ border: 1px solid var(--line);
245
+ background: var(--card);
246
+ }
247
+
248
+ :global(.article-nav span) {
249
+ display: block;
250
+ margin-bottom: 6px;
251
+ color: var(--muted);
252
+ font-size: 12px;
253
+ text-transform: uppercase;
254
+ }
255
+
256
+ :global(.article-nav strong) {
257
+ color: var(--ink);
258
+ line-height: 1.35;
259
+ }
260
+
261
+ :global(.video-figure) {
262
+ margin: 24px 0;
263
+ }
264
+
265
+ :global(.video-figure video) {
266
+ display: block;
267
+ width: 100%;
268
+ border: 1px solid var(--line);
269
+ background: #050607;
270
+ }
271
+
272
+ :global(.video-figure figcaption) {
273
+ margin-top: 10px;
274
+ color: var(--muted);
275
+ }
276
+
277
+ @media (max-width: 860px) {
278
+ :global(.meta-grid) {
279
+ grid-template-columns: 1fr;
280
+ }
281
+
282
+ :global(.category-list),
283
+ :global(.article-nav) {
284
+ grid-template-columns: 1fr;
285
+ }
286
+ }
287
+ </style>
src/pages/index.astro ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ import Layout from "../layouts/Layout.astro";
3
+ ---
4
+
5
+ <Layout title="Cache Atlas">
6
+ <main class="page">
7
+ <div class="eyebrow">research implementation lab</div>
8
+ <h1>KV-cache and inference papers, studied through code.</h1>
9
+ <p class="lede">
10
+ Cache Atlas is my public notebook for learning modern inference systems by implementing the core mechanics.
11
+ Each note explains what I read, what I built, and how to reproduce the experiment instead of treating the paper
12
+ as a black box.
13
+ </p>
14
+
15
+ <section class="toc">
16
+ <div class="label">notes</div>
17
+ <ol>
18
+ <li>
19
+ <a href="/notes/why-kv-cache-papers-matter">Why KV cache papers matter</a>
20
+ <p>A map of the memory problem that motivated the first implementation.</p>
21
+ </li>
22
+ <li>
23
+ <a href="/notes/minicache-paper-notes">MiniCache paper notes</a>
24
+ <p>Depth-axis compression, the implementation boundary, and the pieces I reproduced in PyTorch.</p>
25
+ </li>
26
+ </ol>
27
+ </section>
28
+
29
+ <section class="toc">
30
+ <div class="label">categories</div>
31
+ <ul class="category-list">
32
+ <li>
33
+ <strong>KV-cache memory</strong>
34
+ <p>Cache growth, compression axes, retention policies, and decode-time memory pressure.</p>
35
+ </li>
36
+ <li>
37
+ <strong>Paper reproductions</strong>
38
+ <p>Small implementation tracks that turn one paper mechanism into runnable code.</p>
39
+ </li>
40
+ <li>
41
+ <strong>Visual demos</strong>
42
+ <p>Animations and interactive components that make the systems behavior easier to inspect.</p>
43
+ </li>
44
+ <li>
45
+ <strong>Benchmarks</strong>
46
+ <p>Minimal scripts that measure the implemented path before scaling up the experiment.</p>
47
+ </li>
48
+ </ul>
49
+ </section>
50
+
51
+ <section class="toc">
52
+ <div class="label">repos</div>
53
+ <ul>
54
+ <li>
55
+ <a href="https://github.com/rishabhsai/minicache-pytorch" target="_blank" rel="noreferrer">minicache-pytorch</a>
56
+ <p>Standalone PyTorch package with clean-room primitives, tests, examples, and benchmark scripts.</p>
57
+ </li>
58
+ <li>
59
+ <strong>prefixkv-pytorch</strong>
60
+ <p>Planned next track for token and layer budget allocation in vision-language generation.</p>
61
+ </li>
62
+ </ul>
63
+ </section>
64
+
65
+ <section class="toc">
66
+ <div class="label">next note</div>
67
+ <p>
68
+ The next note should be a reproduction report for <strong>minicache-pytorch</strong>: the API, the tensor
69
+ tests, a small benchmark result, and the exact commands needed to reproduce the implementation locally.
70
+ </p>
71
+ </section>
72
+ </main>
73
+ </Layout>
74
+
75
+ <style>
76
+ h1 {
77
+ margin: 12px 0 20px;
78
+ max-width: 900px;
79
+ font-size: clamp(40px, 7vw, 82px);
80
+ line-height: 0.96;
81
+ font-weight: 600;
82
+ }
83
+
84
+ .lede,
85
+ .card p {
86
+ color: var(--muted);
87
+ line-height: 1.8;
88
+ }
89
+
90
+ .lede {
91
+ max-width: 820px;
92
+ font-size: 19px;
93
+ color: var(--ink);
94
+ }
95
+
96
+ .toc {
97
+ margin-top: 28px;
98
+ padding-top: 18px;
99
+ border-top: 1px solid var(--line);
100
+ }
101
+
102
+ .toc ol,
103
+ .toc ul {
104
+ margin: 12px 0 0;
105
+ padding-left: 20px;
106
+ }
107
+
108
+ .toc li {
109
+ margin: 0 0 14px;
110
+ }
111
+
112
+ .toc a,
113
+ .toc strong {
114
+ color: var(--ink);
115
+ }
116
+
117
+ .toc a {
118
+ text-decoration: underline;
119
+ text-decoration-color: rgba(121, 210, 255, 0.45);
120
+ text-underline-offset: 3px;
121
+ }
122
+
123
+ .toc p {
124
+ margin: 6px 0 0;
125
+ }
126
+ </style>
src/pages/notes/index.astro ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ import Layout from "../../layouts/Layout.astro";
3
+ ---
4
+
5
+ <Layout title="Notes - Cache Atlas">
6
+ <main class="page">
7
+ <div class="eyebrow">notes</div>
8
+ <h1>Paper notes and implementation writeups.</h1>
9
+ <p class="lede">
10
+ These notes track my learning process in public: one mechanism at a time, with enough implementation detail,
11
+ visuals, and reproduction notes to make the code path inspectable.
12
+ </p>
13
+
14
+ <section class="toc">
15
+ <ol>
16
+ <li>
17
+ <a href="/notes/why-kv-cache-papers-matter">Why KV cache papers matter</a>
18
+ <p>The opening map of the memory problem behind modern inference serving.</p>
19
+ </li>
20
+ <li>
21
+ <a href="/notes/minicache-paper-notes">MiniCache paper notes</a>
22
+ <p>The first paper-specific implementation note, centered on <a href="https://arxiv.org/abs/2405.14366" target="_blank" rel="noreferrer">arXiv:2405.14366</a>.</p>
23
+ </li>
24
+ </ol>
25
+ </section>
26
+
27
+ <section class="toc">
28
+ <div class="label">categories</div>
29
+ <ul class="category-list">
30
+ <li>
31
+ <strong>KV-cache memory</strong>
32
+ <p>Cache footprint, decode bottlenecks, and compression strategies.</p>
33
+ </li>
34
+ <li>
35
+ <strong>Implementation notes</strong>
36
+ <p>Reproducible code paths with tests, examples, and benchmark commands.</p>
37
+ </li>
38
+ </ul>
39
+ </section>
40
+
41
+ <section class="toc">
42
+ <div class="label">next note</div>
43
+ <p>
44
+ Next up: a short reproduction report for <strong>minicache-pytorch</strong>, including the public API,
45
+ the current test coverage, and a first benchmark table.
46
+ </p>
47
+ </section>
48
+ </main>
49
+ </Layout>
50
+
51
+ <style>
52
+ .toc {
53
+ margin-top: 28px;
54
+ padding-top: 18px;
55
+ border-top: 1px solid var(--line);
56
+ }
57
+
58
+ .toc ol {
59
+ margin: 12px 0 0;
60
+ padding-left: 20px;
61
+ }
62
+
63
+ .toc li {
64
+ margin: 0 0 14px;
65
+ }
66
+
67
+ .toc a {
68
+ color: var(--ink);
69
+ }
70
+
71
+ .toc p {
72
+ margin: 6px 0 0;
73
+ }
74
+ </style>
src/pages/notes/minicache-paper-notes.mdx ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ layout: ../../layouts/Layout.astro
3
+ title: MiniCache paper notes - Cache Atlas
4
+ ---
5
+
6
+ <main class="article-shell">
7
+
8
+ <div class="eyebrow">note 02</div>
9
+
10
+ # MiniCache paper notes
11
+
12
+ The first implementation target is:
13
+
14
+ > <a class="inline-link" href="https://arxiv.org/abs/2405.14366" target="_blank" rel="noreferrer">MiniCache: KV Cache Compression in Depth Dimension for Large Language Models</a>
15
+
16
+ The paper is interesting for one simple reason: it attacks the cache along a less crowded axis.
17
+
18
+ Most cache papers make an argument about **which tokens** to keep. MiniCache instead starts from the observation that adjacent middle-to-deep layers can carry highly similar KV state, then asks whether that redundancy can be compressed directly.
19
+
20
+ <div class="meta-grid">
21
+ <div class="meta-cell">
22
+ <strong>arxiv</strong>
23
+ <a class="inline-link" href="https://arxiv.org/abs/2405.14366" target="_blank" rel="noreferrer">2405.14366</a>
24
+ </div>
25
+ <div class="meta-cell">
26
+ <strong>official project</strong>
27
+ <a class="inline-link" href="https://minicache.vmv.re/" target="_blank" rel="noreferrer">minicache.vmv.re</a>
28
+ </div>
29
+ <div class="meta-cell">
30
+ <strong>official repo</strong>
31
+ <a class="inline-link" href="https://github.com/AkideLiu/MiniCache" target="_blank" rel="noreferrer">AkideLiu/MiniCache</a>
32
+ </div>
33
+ </div>
34
+
35
+ ## Paper snapshot
36
+
37
+ From the abstract, the public claim is:
38
+
39
+ - KV cache states show high similarity between adjacent layers in the middle-to-deep part of the network
40
+ - disentangling magnitude and direction makes merging easier
41
+ - a token retention strategy can avoid merging the most distinct pairs
42
+ - the method is training-free and complementary to quantization and sparsity
43
+
44
+ The specific abstract lines that matter for implementation are in the paper itself:
45
+
46
+ - <a class="inline-link" href="https://arxiv.org/abs/2405.14366" target="_blank" rel="noreferrer">arXiv:2405.14366</a>
47
+
48
+ For this reproduction, I am not rebuilding the entire official evaluation stack. I am isolating the core tensor behavior so the method is easy to read, test, and extend.
49
+
50
+ ## What I implemented first
51
+
52
+ The first pass keeps the scope tight instead of recreating the full paper stack at once.
53
+
54
+ `minicache-pytorch` focuses on:
55
+
56
+ - magnitude / direction decomposition
57
+ - adjacent-layer direction interpolation
58
+ - reconstruction with preserved magnitude
59
+ - a simple token-retention primitive based on inter-layer similarity
60
+ - tight unit tests around those behaviors
61
+ - one benchmark script for the pairwise compression path
62
+
63
+ That is already enough to make the method inspectable.
64
+
65
+ <figure class="video-figure">
66
+ <video autoPlay loop muted playsInline controls preload="metadata">
67
+ <source src="/media/minicache-layer-merge.mp4" type="video/mp4" />
68
+ </video>
69
+ <figcaption>
70
+ The merge intuition: if nearby layers are partially redundant, the compression path can live between layers rather than only across tokens.
71
+ </figcaption>
72
+ </figure>
73
+
74
+ ## What we are adding beyond the official repo
75
+
76
+ There is already an official MiniCache repo. That means the standalone implementation needs a different job.
77
+
78
+ The added value is:
79
+
80
+ - smaller surface area
81
+ - easier install and packaging
82
+ - a public API instead of only evaluation glue
83
+ - tests around the math primitives
84
+ - examples that fit in a README
85
+ - diagrams and animations that explain the method
86
+
87
+ That is the same pattern that makes a lot of lucidrains repos useful: not necessarily beating the official codebase, but turning an idea into something easier to inspect and reuse.
88
+
89
+ ## Retention is where the method gets more interesting
90
+
91
+ The part that makes MiniCache feel less like “just average layers” is the retention step.
92
+
93
+ If two adjacent layers are already similar for a token, merging them should be cheap. If they diverge sharply for a token, blindly merging them is where quality loss is most likely to appear.
94
+
95
+ That makes the core retention primitive:
96
+
97
+ 1. compute a similarity score between adjacent layer states
98
+ 2. keep a mask for the highly distinct token positions
99
+ 3. only merge the easy cases
100
+
101
+ That gives the implementation repo something concrete and testable to grow around.
102
+
103
+ <figure class="video-figure">
104
+ <video autoPlay loop muted playsInline controls preload="metadata">
105
+ <source src="/media/minicache-retention.mp4" type="video/mp4" />
106
+ </video>
107
+ <figcaption>
108
+ A simple retention picture: tokens with unusually low cross-layer similarity are kept out of the merge path.
109
+ </figcaption>
110
+ </figure>
111
+
112
+ ## Sources
113
+
114
+ <ul class="source-list">
115
+ <li><a href="https://arxiv.org/abs/2405.14366" target="_blank" rel="noreferrer">MiniCache paper (arXiv:2405.14366)</a></li>
116
+ <li><a href="https://minicache.vmv.re/" target="_blank" rel="noreferrer">MiniCache project page</a></li>
117
+ <li><a href="https://github.com/AkideLiu/MiniCache" target="_blank" rel="noreferrer">Official MiniCache GitHub repo</a></li>
118
+ <li><a href="https://mni-ml.github.io/" target="_blank" rel="noreferrer">mni-ml</a></li>
119
+ <li><a href="https://distill.pub/2020/communicating-with-interactive-articles/" target="_blank" rel="noreferrer">Distill: Communicating with Interactive Articles</a></li>
120
+ <li><a href="https://github.com/lucidrains/x-transformers" target="_blank" rel="noreferrer">lucidrains/x-transformers</a></li>
121
+ </ul>
122
+
123
+ <nav class="article-nav" aria-label="Article navigation">
124
+ <a href="/notes/why-kv-cache-papers-matter">
125
+ <span>Previous</span>
126
+ <strong>Why KV cache papers matter</strong>
127
+ </a>
128
+ <a href="https://github.com/rishabhsai/minicache-pytorch" target="_blank" rel="noreferrer">
129
+ <span>Next</span>
130
+ <strong>Open minicache-pytorch</strong>
131
+ </a>
132
+ </nav>
133
+
134
+ </main>
src/pages/notes/why-kv-cache-papers-matter.mdx ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ layout: ../../layouts/Layout.astro
3
+ title: Why KV cache papers matter - Cache Atlas
4
+ ---
5
+
6
+ import CacheBudgetDemo from "../../components/CacheBudgetDemo";
7
+
8
+ <main class="article-shell">
9
+
10
+ <div class="eyebrow">note 01</div>
11
+
12
+ # Why KV cache papers matter
13
+
14
+ The important shift is this:
15
+
16
+ > as context windows grow, cache memory becomes a product constraint, not just a systems detail
17
+
18
+ That is why the last stretch of serving papers keeps circling the same family of ideas:
19
+
20
+ - compress the cache
21
+ - evict part of the cache
22
+ - allocate the cache unevenly across layers
23
+ - specialize the policy for vision-language models
24
+
25
+ I started with this map because the individual papers make more sense once the cache itself is treated as a product constraint.
26
+
27
+ <div class="meta-grid">
28
+ <div class="meta-cell">
29
+ <strong>first implementation</strong>
30
+ MiniCache
31
+ </div>
32
+ <div class="meta-cell">
33
+ <strong>paper</strong>
34
+ <a class="inline-link" href="https://arxiv.org/abs/2405.14366" target="_blank" rel="noreferrer">arXiv:2405.14366</a>
35
+ </div>
36
+ <div class="meta-cell">
37
+ <strong>next note</strong>
38
+ <a class="inline-link" href="/notes/minicache-paper-notes">MiniCache paper notes</a>
39
+ </div>
40
+ </div>
41
+
42
+ <figure class="video-figure">
43
+ <video autoPlay loop muted playsInline controls preload="metadata">
44
+ <source src="/media/minicache-depth-axis.mp4" type="video/mp4" />
45
+ </video>
46
+ <figcaption>
47
+ One way to read the space: most cache work compresses or drops tokens along sequence length, while MiniCache asks what can be compressed across depth.
48
+ </figcaption>
49
+ </figure>
50
+
51
+ ## The KV cache is not optional
52
+
53
+ Autoregressive decoding without a cache is the obvious baseline and the wrong product system.
54
+
55
+ Every generated token would force the model to recompute key and value state for the entire existing prefix. That makes decode cost grow with sequence length even when almost all of the old state is unchanged.
56
+
57
+ The cache fixes that by storing old key and value tensors so later decode steps mainly append new state instead of rebuilding the past. The result is the modern serving stack:
58
+
59
+ - prefill builds cache state from the prompt
60
+ - decode reuses that state one token at a time
61
+
62
+ The catch is that the cache itself gets expensive fast.
63
+
64
+ ## Why the memory bill gets ugly
65
+
66
+ Cache size grows with several things at once:
67
+
68
+ - number of layers
69
+ - number of heads or KV groups
70
+ - hidden dimensions
71
+ - sequence length
72
+ - batch size
73
+
74
+ That is why serving teams keep running into the same practical problem:
75
+
76
+ > the model still fits, but throughput collapses because memory traffic and cache footprint dominate decode
77
+
78
+ This is also why there is not one single “KV cache paper.” There is a whole cluster of them.
79
+
80
+ ## The main paper buckets
81
+
82
+ The easiest way to organize the space is by the axis they attack.
83
+
84
+ ### 1. Token-axis compression and eviction
85
+
86
+ These papers ask:
87
+
88
+ > which old tokens are worth keeping?
89
+
90
+ Examples:
91
+
92
+ - <a class="inline-link" href="https://arxiv.org/abs/2412.03409" target="_blank" rel="noreferrer">PrefixKV</a>
93
+ - <a class="inline-link" href="https://arxiv.org/abs/2503.12491" target="_blank" rel="noreferrer">CAKE</a>
94
+
95
+ This is especially natural for long prompts and vision-language models, where different parts of the prefix are not equally valuable.
96
+
97
+ ### 2. Depth-axis compression
98
+
99
+ These papers ask:
100
+
101
+ > how much redundancy exists across layers?
102
+
103
+ This is the lane that made MiniCache interesting enough to start with. Instead of only asking which tokens to keep, it asks whether nearby layers carry overlapping information that can be compressed more directly.
104
+
105
+ ### 3. Architecture-specific cache policies
106
+
107
+ These papers ask:
108
+
109
+ > if the model is multimodal or has uneven layer behavior, should the cache budget be allocated differently?
110
+
111
+ That is why PrefixKV is compelling even though it is not my first implementation target. It sits right at the intersection of cache policy and vision-language generation.
112
+
113
+ ## Why I started with MiniCache
114
+
115
+ MiniCache is a good first implementation target because the core mechanic can be isolated without reproducing an entire serving stack.
116
+
117
+ The paper:
118
+
119
+ - <a class="inline-link" href="https://arxiv.org/abs/2405.14366" target="_blank" rel="noreferrer">MiniCache: KV Cache Compression in Depth Dimension for Large Language Models</a>
120
+
121
+ Supporting links:
122
+
123
+ - <a class="inline-link" href="https://minicache.vmv.re/" target="_blank" rel="noreferrer">official project page</a>
124
+ - <a class="inline-link" href="https://github.com/AkideLiu/MiniCache" target="_blank" rel="noreferrer">official GitHub repo</a>
125
+
126
+ Why it works as a first reproduction:
127
+
128
+ - cleaner scope than PrefixKV
129
+ - does not require starting in VLM adapter hell
130
+ - easier to isolate the method itself
131
+ - still rich enough for diagrams, demos, and benchmarks
132
+
133
+ Tradeoffs:
134
+
135
+ - it is less visually flashy than PrefixKV
136
+ - it is not the strongest “image demo” paper
137
+
138
+ That tradeoff is acceptable for this project because the goal is to publish code that is readable, testable, and easy to extend.
139
+
140
+ <figure class="video-figure">
141
+ <video autoPlay loop muted playsInline controls preload="metadata">
142
+ <source src="/media/minicache-layer-merge.mp4" type="video/mp4" />
143
+ </video>
144
+ <figcaption>
145
+ The implementation intuition: if middle and deep layers are partially redundant, there is room to compress cache state across depth instead of only pruning tokens.
146
+ </figcaption>
147
+ </figure>
148
+
149
+ ## What the public artifacts add
150
+
151
+ The explanation site and implementation package have different jobs.
152
+
153
+ ### Hub repo: Cache Atlas
154
+
155
+ Cache Atlas adds:
156
+
157
+ - the explanation
158
+ - the diagrams
159
+ - the animation
160
+ - the interactive demo
161
+ - the paper comparison layer
162
+
163
+ ### Standalone repo: minicache-pytorch
164
+
165
+ `minicache-pytorch` adds:
166
+
167
+ - a clean-room reference implementation
168
+ - a usable API
169
+ - tight tests
170
+ - benchmark scripts
171
+ - a README that reads like a good lucidrains repo, not like a paper appendix
172
+ - enough structure to grow cleanly, borrowing the packaging discipline of repos like `ml-intern` without copying its agent architecture
173
+
174
+ That split keeps the notes readable while keeping the package focused on code, tests, and reproduction.
175
+
176
+ ## Example interactive demo
177
+
178
+ The first demo does not need to be perfect. It just needs to make the memory problem obvious.
179
+
180
+ <CacheBudgetDemo client:load />
181
+
182
+ ## What comes after this
183
+
184
+ After MiniCache, the next paper track is PrefixKV.
185
+
186
+ That gives the overall project a clean progression:
187
+
188
+ 1. general note on why cache papers matter
189
+ 2. depth-axis compression with MiniCache
190
+ 3. token / layer budget allocation with PrefixKV
191
+
192
+ That order gives the project both:
193
+
194
+ - a clean systems implementation first
195
+ - a more visual VLM-oriented paper second
196
+
197
+ ## Sources
198
+
199
+ <ul class="source-list">
200
+ <li><a href="https://arxiv.org/abs/2405.14366" target="_blank" rel="noreferrer">MiniCache paper (arXiv:2405.14366)</a></li>
201
+ <li><a href="https://minicache.vmv.re/" target="_blank" rel="noreferrer">MiniCache project page</a></li>
202
+ <li><a href="https://github.com/AkideLiu/MiniCache" target="_blank" rel="noreferrer">MiniCache GitHub repo</a></li>
203
+ <li><a href="https://arxiv.org/abs/2412.03409" target="_blank" rel="noreferrer">PrefixKV paper (arXiv:2412.03409)</a></li>
204
+ <li><a href="https://arxiv.org/abs/2503.12491" target="_blank" rel="noreferrer">CAKE paper (arXiv:2503.12491)</a></li>
205
+ <li><a href="https://distill.pub/" target="_blank" rel="noreferrer">Distill</a> for article structure and visual explanation style</li>
206
+ <li><a href="https://mni-ml.github.io/articles/inference/" target="_blank" rel="noreferrer">mni-ml inference article</a> for compact systems writing</li>
207
+ <li><a href="https://github.com/lucidrains" target="_blank" rel="noreferrer">lucidrains GitHub profile</a> for implementation-repo discipline and README style</li>
208
+ </ul>
209
+
210
+ <nav class="article-nav" aria-label="Article navigation">
211
+ <a href="/notes">
212
+ <span>Previous</span>
213
+ <strong>All notes</strong>
214
+ </a>
215
+ <a href="/notes/minicache-paper-notes">
216
+ <span>Next</span>
217
+ <strong>MiniCache paper notes</strong>
218
+ </a>
219
+ </nav>
220
+
221
+ </main>
tsconfig.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "extends": "astro/tsconfigs/strict",
3
+ "include": [
4
+ ".astro/types.d.ts",
5
+ "**/*"
6
+ ],
7
+ "exclude": [
8
+ "dist"
9
+ ],
10
+ "compilerOptions": {
11
+ "jsx": "react-jsx",
12
+ "jsxImportSource": "react"
13
+ }
14
+ }