Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions apps/site/learn/attention/LESSON.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,16 @@ Managed Chrome desktop (1363×936) and 390×844 iframe viewport; not physical-ph
Observed: complete playback reached 48/48 and restored configuration. Backward seek 48→25→16 rebuilt earlier phases; resume/Escape pause, previous/next, Home/End, replay and reset were exercised. During playback configuration disappeared from the accessibility tree with focus on the persistent pause control. Reduced-motion toggle was enabled; t=31.1 displayed the stable full contribution bar. Query A produced 4.248; default C produced 15.752; changing future V to 1000 preserved output 15.752. The mobile quiz wrong/correct feedback and verify flow returned q=0, D=1000, output 10.000 and visible weights 1/3 each. Dialog fit in the narrow viewport.

`evals/browser/attention-lifecycle.html` tested the actual app's visibility handler using controlled document-hidden events: hidden paused at ~0.05s, configuration restored; visible did not auto-resume or jump. This is event-path testing, not actual OS hidden-tab observation. OS-level preference switching, physical devices, screen-reader devices and other engines remain untested. Full-site checks including mechanical invariants passed. Preview and actual production evidence will be recorded separately.


## Rework draft — 2026-10-29

See `docs/ai-learning/reviews/2026-10-29-attention-rework.md`. Exact operation/row pose tests passed; preliminary desktop observation only. Not visually accepted or published. Original publication evidence does not validate this new candidate.


Q/K component follow-up adds paired multiplication wells, explicit merge and routed contribution paths. Desktop7.2/8.2/8.6/9.0/reverse8.2 and selected390px inspection completed; narrow type measured15.21px after repair. Rounded arithmetic uses≈. Full release review remains pending; see the same rework record.


## Reopened craft review follow-up — 2026-10-30

Persistent mathematical rows now carry exact values between chapters; Q/K component multiplication, denominator collection, normalized fractions, same-scaleV/pV and cumulative contributions are inspectable in intermediate frames.18-unit narrow SVG type, explicit front-face ports and consistent carrier depth were checked with native4× and390px browser evidence. Full tests and affected UI lifecycle/quiz checks passed; see [review with actual images, raw DOM records and limits](../../../../docs/ai-learning/reviews/2026-10-29-attention-rework.md#follow-up-2026-10-30--reviewed-candidate-release-verification-pending). Controlled hidden-event handling is covered; real background scheduling, physical devices and measured learning gains are not. This entry is candidate acceptance, not yet a production receipt. Skill/host compatibility is not newly claimed.
82 changes: 81 additions & 1 deletion apps/site/learn/attention/SCENE_SPEC.json
Original file line number Diff line number Diff line change
@@ -1 +1,81 @@
{"id":"attention","question":"当前查询如何把可见位置的 V 汇成一个输出?","durationSeconds":48,"inputs":{"alpha":[-1,0,1],"futureV":{"min":0,"max":1000,"step":10}},"queryPosition":2,"keyDimension":2,"valueDimension":1,"keys":[[-1,0],[0,0],[1,0],[2,0]],"values":[0,10,20,"futureV"],"relations":["q=[sqrt(2)*alpha,0]","s=qK^T/sqrt(2)","mask j>2 to -Infinity before Softmax","p=Softmax(masked scores)","o=sum(p_j*V_j)"],"mapping":{"color":"position identity","probabilityBar":"0..1 within each channel","contributionBar":"length of p_j*V_j; shared total scale 0..20","connections":"dependencies, not physical motion or measured timing"},"experiment":"Keep K/V fixed and change q; then vary masked future V and show output invariance.","transfer":"q=0, futureV=1000 gives mean of visible 0,10,20 = 10, not max or four-way mean.","sources":["https://arxiv.org/abs/1706.03762","https://docs.pytorch.org/docs/2.14/generated/torch.nn.functional.scaled_dot_product_attention.html"],"simplifications":["Authored Q/K/V, no model or semantic interpretation","One causal row and head; V scalar","No learned projection, positions, dropout, output projection, residual, training or token sampling","SVG teaching geometry, not actual model hardware"]}
{
"id": "attention",
"question": "当前查询如何把可见位置的 V 汇成一个输出?",
"durationSeconds": 48,
"inputs": {
"alpha": [
-1,
0,
1
],
"futureV": {
"min": 0,
"max": 1000,
"step": 10
}
},
"queryPosition": 2,
"keyDimension": 2,
"valueDimension": 1,
"keys": [
[
-1,
0
],
[
0,
0
],
[
1,
0
],
[
2,
0
]
],
"values": [
0,
10,
20,
"futureV"
],
"relations": [
"q=[sqrt(2)*alpha,0]",
"s=qK^T/sqrt(2)",
"mask j>2 to -Infinity before Softmax",
"p=Softmax(masked scores)",
"o=sum(p_j*V_j)"
],
"mapping": {
"color": "position identity",
"probabilityBar": "0..1 within each channel",
"contributionBar": "length of p_j*V_j; shared total scale 0..20",
"connections": "dependencies, not physical motion or measured timing",
"valueRead": "Dashed V and filled pV share a0..20 front-plane scale; masked D original V is not drawn beyond that range"
},
"experiment": "Keep K/V fixed and change q; then vary masked future V and show output invariance.",
"transfer": "q=0, futureV=1000 gives mean of visible 0,10,20 = 10, not max or four-way mean.",
"sources": [
"https://arxiv.org/abs/1706.03762",
"https://docs.pytorch.org/docs/2.14/generated/torch.nn.functional.scaled_dot_product_attention.html"
],
"simplifications": [
"Authored Q/K/V, no model or semantic interpretation",
"One causal row and head; V scalar",
"No learned projection, positions, dropout, output projection, residual, training or token sampling",
"SVG teaching geometry, not actual model hardware"
],
"reworkReview": {
"date": "2026-10-30",
"status": "reviewed-candidate-pending-release",
"record": "docs/ai-learning/reviews/2026-10-29-attention-rework.md",
"layout": "Persistent rows, exact chapter carriers, paired QK wells/merge, common denominator collection, traced shared-scale fractions, V/pV comparison and nonzero routed contributions",
"limits": [
"No physical phone/other engine/learner study",
"Controlled hidden event tested; native background scheduling not independently verified",
"Skill distribution alignment pending"
]
}
}
14 changes: 13 additions & 1 deletion apps/site/learn/attention/app.mjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import {TOKENS,STARTS,DURATION,sample,narration} from './model.mjs';
import {createStage} from './stage.mjs';
import {lessonPose,handoff} from './pose.mjs';
const $=s=>document.querySelector(s),$$=s=>[...document.querySelectorAll(s)],motion=matchMedia('(prefers-reduced-motion: reduce)');
let reduced=motion.matches;
const stage=createStage($('#artwork'),{reducedMotion:()=>reduced});
let id=1,future=100,time=0,playing=false,raf=0,last=0,lastCopy='',dead=false;
const names=['输入 Q/K/V','匹配分数','因果遮罩','分配权重','加权内容','求和与实验'];
function focus(on){$('#app').classList.toggle('is-playing',on);$$('.secondary').forEach(x=>{x.inert=on;x.setAttribute('aria-hidden',String(on));});}
function anchor(){const box=$('.exhibit').getBoundingClientRect(),bubble=$('#callout').getBoundingClientRect(),art=$('#artwork');art.style.top=Math.max(185,bubble.bottom-box.top+13)+'px';const a=art.getBoundingClientRect(),point=stage.projectAnchor();if(!point)return;const x=a.left-box.left+point.x*a.width,y=a.top-box.top+point.y*a.height,cx=Math.max(bubble.width/2+17,Math.min(box.width-bubble.width/2-17,x));$('#callout').style.left=cx+'px';$('#leader').setAttribute('viewBox',`0 0 ${box.width} ${box.height}`);const sy=bubble.bottom-box.top;const side=a.left-box.left+point.bendX*a.width,start=cx-bubble.width/2+10;$('#leader-line').setAttribute('d',point.routeLeft?`M${start} ${sy}C${side} ${sy+12},${side} ${sy+12},${side} ${sy+27}V${y-8}Q${side} ${y},${side+8} ${y}H${x-8}`:`M${cx} ${sy}C${cx} ${sy+20},${x} ${y-25},${x} ${y-8}`);$('#leader-dot').setAttribute('cx',x);$('#leader-dot').setAttribute('cy',y);}
function render(){if(dead)return;const f=sample(time,{id,future}),c=narration(f),key=JSON.stringify(c);stage.render(f);if(key!==lastCopy){lastCopy=key;$('#copy-eyebrow').textContent=c.eyebrow;$('#copy-title').textContent=c.title;$('#copy-body').textContent=c.body;}$('#phase-label').textContent=`0${f.phase+1} / 06 · ${names[f.phase]}`;$('#counts').textContent=`当前位置 C · 单头单行`;$$('[data-id]').forEach(b=>b.setAttribute('aria-pressed',String(+b.dataset.id===id)));$('#future').value=future;$('#future-value').textContent=future;$('#timeline').value=time;$('#timeline').style.setProperty('--fill',`${time/DURATION*100}%`);$('#time').textContent=`00:${String(Math.floor(time)).padStart(2,'0')} / 00:48`;$('#play-label').textContent=playing?'暂停':time>=DURATION?'再看一遍':time?'继续讲解':'播放讲解';$('#play-icon').textContent=playing?'Ⅱ':'▶';$('#play').setAttribute('aria-pressed',String(playing));$('#back').disabled=time===0;$('#next').disabled=time===DURATION;$('#play-note').textContent=playing?'配置已收起 · 空格暂停':'六个步骤 · 从查询到加权和';$('#challenge').hidden=time<DURATION;anchor();}
function teachingCopy(f){
const c=narration(f),p=lessonPose(f,reduced),h=handoff(f,reduced);
if(h?.inTransit){c.title='同一数值,进入下一步';c.body=['','','保留每行的匹配分数,先送入因果遮罩。','把遮罩后的分数送入指数运算;未来 D 仍为 −∞。','把每行的权重送入乘法,接下来读取对应的 V。','把各位置贡献送入加法;不是只选最大的一项。'][f.phase];}
else if(f.phase===2){c.body='D 的分数变为 −∞,exp(−∞)=0。无论未来 V 多大,它都不进入当前的输出。';}
else if(f.phase===3){
c.title=p.collect<1?'先求一个共同分母':`${TOKENS[p.active]} 的份额,除以同一分母`;
c.body=p.collect<1?'把各行的指数权重相加。未来 D 的指数为 0,不进入分母。':'短条按 0→100% 的共同刻度描出份额。这是混合信息的权重,不是抽取下一个 Token。';
}else if(f.phase===4){c.title=`读取 ${TOKENS[p.active]} 的 V,再汇入结果`;c.body='虚线是 V,实色是读出的份额,同一刻度。非零贡献沿连线汇入底部;零值与未来位置不发出贡献。';}
if(f.phase===5&&!h?.inTransit)c.body='保持 K/V 不变,试着切换查询方向。再只改未来 D 的 V:输出为何不变?查询归零后又是多少?';
return c;
}
function render(){if(dead)return;const f=sample(time,{id,future}),c=teachingCopy(f),key=JSON.stringify(c);stage.render(f);if(key!==lastCopy){lastCopy=key;$('#copy-eyebrow').textContent=c.eyebrow;$('#copy-title').textContent=c.title;$('#copy-body').textContent=c.body;}$('#phase-label').textContent=`0${f.phase+1} / 06 · ${names[f.phase]}`;$('#counts').textContent=`当前位置 C · 单头单行`;$$('[data-id]').forEach(b=>b.setAttribute('aria-pressed',String(+b.dataset.id===id)));$('#future').value=future;$('#future-value').textContent=future;$('#timeline').value=time;$('#timeline').style.setProperty('--fill',`${time/DURATION*100}%`);$('#time').textContent=`00:${String(Math.floor(time)).padStart(2,'0')} / 00:48`;$('#play-label').textContent=playing?'暂停':time>=DURATION?'再看一遍':time?'继续讲解':'播放讲解';$('#play-icon').textContent=playing?'Ⅱ':'▶';$('#play').setAttribute('aria-pressed',String(playing));$('#back').disabled=time===0;$('#next').disabled=time===DURATION;$('#play-note').textContent=playing?'配置已收起 · 空格暂停':'六个步骤 · 从查询到加权和';$('#challenge').hidden=time<DURATION;anchor();}
function advance(now){if(playing){time=Math.min(DURATION,time+Math.max(0,now-last)/1000);last=now;}}
function stop(capture=true){if(capture)advance(performance.now());playing=false;cancelAnimationFrame(raf);focus(false);render();}
function tick(now){if(!playing)return;advance(now);render();if(time===DURATION)stop(false);else raf=requestAnimationFrame(tick);}
Expand Down
Loading
Loading