AwakeningOS's picture
Publish bilingual VISTARC research notebook and evidence-linked model explorer
07d93a3 verified
Raw History Blame Contribute Delete
14.6 kB
'use strict';
const $=s=>document.querySelector(s), $$=s=>[...document.querySelectorAll(s)];
const h=x=>String(x??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));
const lang=()=>document.documentElement.lang==='en'?'en':'ja';
const tx=(ja,en)=>lang()==='ja'?ja:en;
const fmt=(x,d=3)=>Number.isFinite(x)?x.toFixed(d):'—';
const display=x=>x===null||x===undefined||x===''?'—':typeof x==='object'?JSON.stringify(x):String(x);
const num=x=>Number.isFinite(x)?x:null;
let models=[],profiles=[],manifest={},sourceIndex={},sort='five',ascending=false,clearOnly=false,ready=false,current=null;
const cohortNames={baby:['Baby同系列','Main Baby cohort'],'legacy-dense':['旧Baby・参考','Legacy Baby reference'],'baby-boundary':['旧Baby・境界条件','Legacy Baby boundaries'],'baby-original':['旧Baby・元設定','Legacy Baby original'],'baby-inference-only':['Baby・推論時介入','Baby inference intervention'],'baby-frozen-body-continuation':['Baby・本体凍結後の追加学習','Baby frozen-body continuation'],'legacy-aro20':['ARO20M','ARO20M'],'normal-joint':['通常データ・joint探索','Normal data / joint'],'normal-threshold':['通常データ・閾値探索','Normal data / threshold'],'normal-aro-extended':['通常データ・ARO延長','Normal data / ARO extension'],'normal-reader':['通常データ・Reader','Normal data / Reader']};
const trv=x=>lang()==='ja'?display(x):({'あり':'Yes','なし':'No','未確認':'Unverified','候補の平均・分散を帰還':'Candidate mean/variance feedback','候補記憶なし/処理差分→D':'No candidate memory; processing changes → D','単一出力':'Single output','枝別に混合':'Branch-specific mixture','最終層':'Last layer','採点済み':'Evaluated','ユーザー指定で停止・削除':'Cancelled / deleted'}[x]??display(x));
function title(m){return `${m.width??'?'}${tx('幅',' wide')} · FFN${m.ffn??'?'} · ${m.depth??'?'}${tx('層',' layers')}`}
function memory(m){const a=m.architecture||{}; if(a.plastic_rank)return `F ${a.plastic_value_rank??a.plastic_rank}×${a.plastic_key_rank??a.plastic_rank}`;if(a.D_memories)return `D ${a.D_memories} × (${a.D_key??'?'}×${a.D_value??'?'})${a.C_memories?` + C ${a.C_memories}`:''}`; return ''}
function tags(m){const p=m.parts||{},a=m.architecture||{};return [p.output?trv(p.output):'',p.reader&&p.reader!=='なし'?`Reader ${p.reader}`:'',p.received==='あり'?tx('受信ゲート','Receive gate'):'',p.ffn_add==='あり'?(p.bypass_condition==='negative_sigmoid'?tx('条件付きFFN加算','Conditional FFN addition'):tx('FFN加算','FFN addition')):'',memory(m)].filter(Boolean)}
function applyLang(l){document.documentElement.lang=l;try{localStorage.setItem('research-language',l)}catch(e){}if(ready){populateCohorts();render();if(current)openModel(current,false)}}
$$('[data-language]').forEach(b=>b.addEventListener('click',()=>applyLang(b.dataset.language)));
const taskNames={blimp_filtered:'BLiMP',supplement_filtered:'Supplement',ewok_filtered:'EWoK',entity_tracking:'Entity',comps:'CoMPS',global_piqa_parallel:'PIQA parallel',global_piqa_nonparallel:'PIQA nonparallel'};
function populateCohorts(){const val=$('#cohort').value||'baby';$('#cohort').innerHTML=Object.keys(manifest.cohorts).map(k=>`<option value="${h(k)}">${h(cohortNames[k]?.[lang()==='ja'?0:1]??k)}</option>`).join('');$('#cohort').value=val;}
function scoreCell(m,k){if(k==='clear'){const p=m.clear_peak;if(!p)return '<span class="missing">—</span>';return `<span class="score"><span class="rank">${tx(String(p.rank??'—')+'位','Rank '+String(p.rank??'—'))}</span> ${fmt(p.accuracy)}%</span><span class="age">${p.age}M · ${p.correct.toLocaleString()} / ${p.total.toLocaleString()}</span>`}const p=m.peak[k];if(!Number.isFinite(p.score))return '<span class="missing">—</span>';return `<span class="score"><span class="rank">${tx(String(p.rank??'—')+'位','Rank '+String(p.rank??'—'))}</span> ${fmt(p.score)}</span><span class="age">${p.ages.join(' / ')}M</span>`}
function getSort(m){return sort==='clear'?num(m.clear_peak?.accuracy):sort==='five'||sort==='six'?num(m.peak[sort].score):num(m[sort]);}
function render(){const q=$('#search').value.trim().toLowerCase();const exact=q.match(/^#(\d+)$/);const cohort=$('#cohort').value;let found=models.filter(m=>(clearOnly?!!m.clear_peak:m.cohort===cohort)&&(!q||(exact?m.number===+exact[1]:`${m.number} ${m.original_name} ${m.title} ${m.width} ${m.ffn} ${m.seed} ${JSON.stringify(m.parts)} ${JSON.stringify(m.architecture)}`.toLowerCase().includes(q))));found.sort((a,b)=>{let x=getSort(a),y=getSort(b);if(x===null&&y===null)return a.number-b.number;if(x===null)return 1;if(y===null)return -1;return (ascending?x-y:y-x)||a.number-b.number});
$('#model-rows').innerHTML=found.length?found.map(m=>`<tr><td><button class="row-model" data-model="${m.number}">#${m.number}</button></td><td><span class="model-title">${h(title(m))}</span><div class="tags">${tags(m).map(t=>`<span class="tag">${h(t)}</span>`).join('')}</div><span class="mini">${h(tx('主要LR','Main LR'))}: ${h((m.main_lr||[]).map(x=>Number(x.toPrecision(5))).join(' → ')||tx('詳細参照','See details'))}</span></td><td>${h(m.seed??'—')}</td><td>${scoreCell(m,'five')}</td><td>${scoreCell(m,'six')}</td><td>${scoreCell(m,'clear')}</td><td><span class="mini">${m.points.length?`${m.points.length} ${tx('時点','ages')}<br>${Math.min(...m.points.map(p=>p.age))}–${Math.max(...m.points.map(p=>p.age))}M`:h(m.present===false?tx('停止・削除済み','Cancelled / deleted'):tx('未採点','Unscored'))}${m.condition_conflicts?.length?'<br>⚑ '+tx('記録の食い違いあり','Configuration conflict'):''}</span></td></tr>`).join(''):`<tr><td colspan="7">${tx('該当するモデルはありません。条件群を確認してください。','No matching models. Check the selected cohort.')}</td></tr>`;
$('#count').textContent=`${found.length} ${tx('モデル表示 / 登録302 ID','models shown / 302 registered IDs')}`;
$$('#model-table th').forEach(th=>th.removeAttribute('aria-sort'));const active=$(`[data-sort="${sort}"]`);active.closest('th').setAttribute('aria-sort',ascending?'ascending':'descending');
$$('[data-sort]').forEach(b=>{b.innerHTML=b.innerHTML.replace(/[↑↓↕]\s*$/,b.dataset.sort===sort?(ascending?'↑':'↓'):'↕')});
$$('.row-model').forEach(b=>b.addEventListener('click',()=>openModel(+b.dataset.model)));$('#clear-only').setAttribute('aria-pressed',String(clearOnly));$('#cohort').disabled=clearOnly;
}
function props(rows){return `<div class="table-wrap"><table class="props"><tbody>${rows.map(([k,v])=>`<tr><th>${h(k)}</th><td>${h(trv(v))}</td></tr>`).join('')}</tbody></table></div>`}
function raw(label,v){return `<details><summary>${h(label)}</summary><pre>${h(JSON.stringify(v??{},null,2))}</pre></details>`}
function openModel(n,changeHash=true){const m=models.find(x=>x.number===n);if(!m)return;current=n;const a=m.architecture||{},p=m.parts||{},profile=profiles[m.profile]||{};
let out=`<h2>#${n} · ${h(title(m))}</h2><p>${h(m.id)}</p><div class="tags">${tags(m).map(t=>`<span class="tag">${h(t)}</span>`).join('')}</div><p>${h(tx('固定IDは構造・設定・seedを識別します。最高点は採点した時点の中の最大値です。','The permanent ID identifies a configuration and seed. Peaks are maxima over the evaluated ages.'))}</p>`;
if(m.condition_conflicts?.length)out+=`<p class="notice">${tx('このモデルには設定記録の食い違いがあります。下の出典と記録を確認してください。','This record has configuration conflicts. Inspect the evidence and metadata below.')}</p>`;
if(!m.present)out+=`<p class="notice">${tx('停止・削除された実験の登録情報だけが残っています。得点・構成の未確認部分は補完していません。','Only the registry identity of a cancelled/deleted experiment remains. Missing scores and configuration fields have not been inferred.')}</p>`;
out+=`<h3>${tx('部品と構成','Components and architecture')}</h3>`+props([
[tx('seed','Seed'),m.seed],[tx('状態幅 / FFN中間幅 / 層数','State width / FFN intermediate width / layers'),`${m.width??'?'} / ${m.ffn??'?'} / ${m.depth??'?'}`],['Attention',p.attention],['Router',p.router],[tx('候補の扱い','Candidate handling'),p.candidate],['Candidate Reader',p.reader],[tx('Attention受信ゲート','Attention receive gate'),p.received],['QK normalization',p.qk],[tx('出力部品','Output head'),p.output],[tx('各出力枝が使う層','Layers used by output branches'),p.reference_layers],[tx('FFN加算','FFN addition'),p.ffn_add],[tx('加算条件(記録値)','Addition condition (recorded)'),p.bypass_condition],[tx('F / D / C 記憶','F / D / C memory'),memory(m)||tx('該当する明示記録なし','No explicit matching memory record')],[tx('RoPE基数を学習','Learn RoPE base'),p.rope_learned],[tx('候補分散scaleを学習','Learn candidate variance scale'),p.candidate_var_learned],[tx('距離補正','Distance correction'),p.distance],[tx('学習パス数(記録値)','Training passes (recorded)'),a.passes],[tx('幾何(記録値)','Geometry (recorded)'),a.geometry],[tx('評価条件群','Evaluation cohort'),cohortNames[m.cohort]?.[lang()==='ja'?0:1]??m.cohort]]);
out+=`<h3>${tx('各学習時点の旧評価','Legacy scores at each training age')}</h3><p>${tx('Mは累積学習語数の百万単位。PIQA二集合の平均を1軸にしたものが6軸です。','M denotes millions of words of cumulative training exposure. Six axes treat the mean of the two PIQA sets as one axis.')}</p>`;
out+=`<div class="table-wrap"><table><thead><tr><th>M</th><th>${tx('5軸','Five')}</th><th>${tx('6軸','Six')}</th>${Object.values(taskNames).map(x=>`<th>${x}</th>`).join('')}</tr></thead><tbody>${m.points.map(pt=>`<tr><td>${pt.age}</td><td>${fmt(pt.five)}</td><td>${fmt(pt.six)}</td>${Object.keys(taskNames).map(k=>`<td>${fmt(pt.tasks[k],2)}</td>`).join('')}</tr>`).join('')||`<tr><td colspan="10">${tx('未採点','Not evaluated')}</td></tr>`}</tbody></table></div>`;
out+=`<h3>${tx('明確回答:総正答率','Clear-answer: pooled accuracy')}</h3>`;
out+=m.clear_points.length?`<div class="table-wrap"><table><thead><tr><th>M</th><th>${tx('正答率','Accuracy')}</th><th>${tx('正答数 / 問題数','Correct / total')}</th><th>${tx('選択肢の得点同点数','Answer-score ties')}</th></tr></thead><tbody>${m.clear_points.map(pt=>`<tr><td>${pt.age}</td><td>${fmt(pt.accuracy)}%</td><td>${pt.correct} / ${pt.total}</td><td>${pt.ties??'—'}</td></tr>`).join('')}</tbody></table></div>`:`<p>${tx('この問題集では未採点です。','Not evaluated on this bank.')}</p>`;
out+=`<h3>${tx('学習率・重み減衰・更新条件','Learning rates, weight decay, and updates')}</h3><p>${tx('実LRを名前付きparameter群で示します。3値はscheduleに沿った各段階です。WDの「—」は未記録で、0ではありません。','Named parameter groups show effective LRs. Triplets follow the recorded schedule phases. A missing WD is unknown, not zero.')}</p>`;
out+=props([[tx('主要行列LR','Main matrix LR'),(m.main_lr||[]).map(x=>Number(x.toPrecision(7))).join(' → ')],[tx('基本LR(記録値)','Base LRs (recorded)'),profile.base_lrs],[tx('1更新の位置数(記録値)','Positions per update (recorded)'),profile.batch],[tx('系列長の巡回','Sequence-length cycle'),profile.sequence]]);
if(profile.groups?.length)out+=`<div class="table-wrap"><table><thead><tr><th>${tx('parameter群','Parameter group')}</th><th>LR</th><th>WD</th></tr></thead><tbody>${profile.groups.map(g=>`<tr><td><details><summary>${h((g.label||'').slice(0,85))}${(g.label||'').length>85?'…':''} (${g.names?.length??'?'} tensors)</summary><pre>${h((g.names||[]).join('\n'))}</pre></details></td><td>${h(Array.isArray(g.lr)?g.lr.map(x=>Number(x.toPrecision(7))).join(' → '):display(g.lr))}</td><td>${h(display(g.wd))}</td></tr>`).join('')}</tbody></table></div>`;
out+=raw('Schedule / optimizer / initialization',profile)+raw(tx('構造・データ・評価の元記録','Recorded architecture, data, and evaluation'),{architecture:m.architecture,data:m.data,tokenizer:m.tokenizer,evaluation:m.evaluation,runtime:m.runtime});
const sources=[...new Set([...(m.sources||[]),...m.points.flatMap(pt=>pt.sources||[])])].map(id=>({id,...sourceIndex[id]}));
out+=raw(tx('評価地点・checkpoint対応・出典','Checkpoint identities and source records'),{points:m.points,clear_points:m.clear_points,sources,conflicts:m.condition_conflicts});
out+=`<p><a href="data/models.json">${tx('全モデルJSON','Full model JSON')}</a> · <a href="data/profiles.json">LR / WD JSON</a> · <a href="data/sources.json">${tx('出典索引','Source index')}</a></p>`;
$('#model-detail').innerHTML=out;if(!$('#model-dialog').open)$('#model-dialog').showModal();if(changeHash)history.replaceState(null,'',`#model-${n}`);
}
function hashModel(){const match=location.hash.match(/^#model-(\d+)$/);if(match&&ready)openModel(+match[1],false)}
if($('#model-table')){
Promise.all(['models','profiles','manifest','sources'].map(n=>fetch(`data/${n}.json`).then(r=>{if(!r.ok)throw new Error(n);return r.json()}))).then(([m,p,ma,s])=>{models=m;profiles=p;manifest=ma;sourceIndex=s;ready=true;populateCohorts();render();hashModel()}).catch(e=>{$('#model-rows').innerHTML=`<tr><td colspan="7" class="error">${tx('データを読み込めませんでした。ページを再読み込みするかCSVを開いてください。','Could not load the data. Reload or use the downloadable CSV.')} ${h(e.message)}</td></tr>`});
$('#search').addEventListener('input',render);$('#cohort').addEventListener('change',render);
$$('[data-sort]').forEach(b=>b.addEventListener('click',()=>{if(sort===b.dataset.sort)ascending=!ascending;else{sort=b.dataset.sort;ascending=sort==='number'||sort==='seed'}render()}));
$('#clear-only').addEventListener('click',()=>{clearOnly=!clearOnly;sort=clearOnly?'clear':'five';ascending=false;render()});
$('#reset').addEventListener('click',()=>{$('#search').value='';$('#cohort').value='baby';clearOnly=false;sort='five';ascending=false;render()});
const close=()=>{$('#model-dialog').close();current=null;if(location.hash.startsWith('#model-'))history.replaceState(null,'','#explorer')};$('#close-dialog').addEventListener('click',close);$('#model-dialog').addEventListener('cancel',()=>{current=null;history.replaceState(null,'','#explorer')});
window.addEventListener('hashchange',hashModel);
}