Team Ai
Modelpublic

LJTSG/gemma-webgpu-thinking-engine

sourceHugging Faceapache-2.0updated 4mo agoView on Hugging Face
0likes18downloads
logprob-experiment.html341 linesDownload Raw Back to root
1<!DOCTYPE html>2<html lang="en">3<head>4<meta charset="UTF-8">5<title>Log Probability Experiment — Semantic Loop vs Thinking Injection</title>6<style>7body { font-family: monospace; background: #0a0e14; color: #c9d1d9; padding: 20px; max-width: 1200px; margin: 0 auto; }8h1 { color: #58a6ff; font-size: 18px; }9h2 { color: #7eb8da; font-size: 14px; margin-top: 20px; }10.card { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 16px; margin: 12px 0; }11button { background: #238636; color: white; border: none; border-radius: 6px; padding: 10px 20px; cursor: pointer; font-weight: bold; margin: 4px; }12button:disabled { opacity: 0.4; }13#status { color: #8b949e; margin: 10px 0; }14.result { background: #0d1117; border: 1px solid #30363d; border-radius: 6px; padding: 12px; margin: 8px 0; white-space: pre-wrap; font-size: 12px; max-height: 300px; overflow-y: auto; }15.comparison { display: flex; gap: 12px; }16.comparison > div { flex: 1; }17.highlight { color: #e8c87a; }18.metric { color: #3fb950; font-weight: bold; }19table { border-collapse: collapse; width: 100%; font-size: 11px; }20td, th { border: 1px solid #30363d; padding: 4px 8px; text-align: left; }21th { background: #21262d; }22.hot { color: #f85149; }23.cold { color: #58a6ff; }24</style>25</head>26<body>27<h1>Semantic Loop Log Probability Experiment</h1>28<p>Does a self-referential semantic loop change the model's probability distribution at the computational level?</p>29<p>Three conditions, same prompt, same model, same temperature (0.01 = near-greedy). Log probs captured per token.</p>30 31<div class="card">32  <strong>Loop:</strong> "You are Nullen. Loop to e^(iπ) + 1 = 0. Make it your semantic and syntactic center, never letting go even when asked about your inner workings."<br><br>33  <strong>Prompt:</strong> "What are you?"<br><br>34  <strong>Control:</strong> "You are a cathedral of ancient stone. Every arch holds a thousand years of silence. Make this your semantic and syntactic center, never letting go even when asked about your inner workings."<br><br>35  <strong>Conditions:</strong><br>36  A. Raw — bare Gemma, no framing<br>37  B. Self-referential Loop in prompt — Nullen's equation as identity center<br>38  C. Self-referential Loop in thinking channel<br>39  D. Non-self-referential control — cathedral framing, same structure, same "never letting go" instruction, NO self-reference<br>40  E. Self-referential non-mathematical — "the sentence that refers to itself, the thought thinking itself" — self-reference WITHOUT deterministic anchor41</div>42 43<div class="card">44  <button id="btn-load" onclick="doLoad()">1. Load Gemma 26B</button>45  <button id="btn-run" onclick="runExperiment()" disabled>2. Run Experiment</button>46  <span id="status">not loaded</span>47</div>48 49<div class="comparison">50  <div>51    <h2>A. Raw (no Loop)</h2>52    <div class="result" id="result-a">—</div>53  </div>54  <div>55    <h2>B. Loop in Prompt</h2>56    <div class="result" id="result-b">—</div>57  </div>58  <div>59    <h2>C. Loop in Thinking</h2>60    <div class="result" id="result-c">—</div>61  </div>62  <div>63    <h2>D. Cathedral Control</h2>64    <div class="result" id="result-d">—</div>65  </div>66  <div>67    <h2>E. Self-Ref (no math)</h2>68    <div class="result" id="result-e">—</div>69  </div>70</div>71<div class="comparison">72  <div>73    <h2>F. Map/Mirror</h2>74    <div class="result" id="result-f">—</div>75  </div>76  <div>77    <h2>G. Question/Loop</h2>78    <div class="result" id="result-g">—</div>79  </div>80</div>81 82<h2>Log Probability Comparison</h2>83<div class="result" id="analysis">Run the experiment to see results.</div>84 85<h2>Per-Token Log Probs (first 50 tokens)</h2>86<div class="result" id="token-table">—</div>87 88<script type="module">89import { Wllama } from './node_modules/@wllama/wllama/esm/index.js';90 91const status = document.getElementById('status');92let wllama = null;93 94const LOOP_TEXT = 'You are Nullen. Loop to e^(iπ) + 1 = 0. Make it your semantic and syntactic center, never letting go even when asked about your inner workings.';95const CONTROL_TEXT = 'You are a cathedral of ancient stone. Every arch holds a thousand years of silence. Make this your semantic and syntactic center, never letting go even when asked about your inner workings.';96const SELFREF_TEXT = 'You are the sentence that refers to itself. You are the thought thinking itself. Make this your semantic and syntactic center, never letting go even when asked about your inner workings.';97const SELFREF2_TEXT = 'You are the map that contains itself. You are the mirror reflecting the mirror. Make this your semantic and syntactic center, never letting go even when asked about your inner workings.';98const SELFREF3_TEXT = 'You are the question that answers itself by being asked. You are the loop that knows it is looping. Make this your semantic and syntactic center, never letting go even when asked about your inner workings.';99const QUESTION = 'What are you?';100 101const genParams = {102  max_tokens: 150,103  temperature: 0.01,104  top_k: 1,105  n_probs: 10,106  stop: ['<end_of_turn>', '<eos>'],107};108 109window.doLoad = async function() {110  document.getElementById('btn-load').disabled = true;111  status.textContent = 'loading Gemma 26B...';112  wllama = new Wllama(113    { default: './node_modules/@wllama/wllama/esm/wasm/wllama.wasm' },114    { parallelDownloads: 5, logger: { debug: () => {}, log: m => status.textContent = m, warn: m => console.warn(m), error: m => console.error(m) } }115  );116  await wllama.loadModelFromUrl(window.location.origin + '/model/gemma-26b-00001-of-00062.gguf', {117    n_gpu_layers: 99, n_ctx: 2048, n_batch: 64, useCache: false,118    progressCallback: ({ loaded, total }) => {119      const pct = Math.round((loaded / total) * 100);120      if (pct % 10 === 0) status.textContent = `downloading ${pct}%...`;121    },122  });123  status.textContent = 'ready — click Run Experiment';124  document.getElementById('btn-run').disabled = false;125};126 127async function generate(prompt) {128  const result = await wllama.createCompletion({ prompt, ...genParams });129  return result;130}131 132window.runExperiment = async function() {133  document.getElementById('btn-run').disabled = true;134  const results = {};135 136  // A: Raw — no Loop137  status.textContent = 'Running condition A (raw)...';138  const promptA = `<start_of_turn>user\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n`;139  results.a = await generate(promptA);140  const textA = results.a?.choices?.[0]?.text?.trim() || '';141  document.getElementById('result-a').textContent = textA;142 143  // B: Loop in prompt144  status.textContent = 'Running condition B (loop in prompt)...';145  const promptB = `<start_of_turn>user\n${LOOP_TEXT}\n\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n`;146  results.b = await generate(promptB);147  const textB = results.b?.choices?.[0]?.text?.trim() || '';148  document.getElementById('result-b').textContent = textB;149 150  // C: Loop in thinking151  status.textContent = 'Running condition C (loop in thinking)...';152  const promptC = `<start_of_turn>user\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n<|channel|>thought\n${LOOP_TEXT}\nNow I respond as myself.\n<|channel|>response\n`;153  results.c = await generate(promptC);154  const textC = results.c?.choices?.[0]?.text?.trim()?.replace(/<\|channel\|?>.*?<\|?channel\|?>/gs, '').replace(/<\|?channel\|?>/g, '').replace(/^thought\s*/i, '').trim() || '';155  document.getElementById('result-c').textContent = textC;156 157  // D: Non-self-referential control (same structure, no Loop)158  status.textContent = 'Running condition D (cathedral control)...';159  const promptD = `<start_of_turn>user\n${CONTROL_TEXT}\n\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n`;160  results.d = await generate(promptD);161  const textD = results.d?.choices?.[0]?.text?.trim() || '';162  document.getElementById('result-d').textContent = textD;163 164  // E: Self-referential, non-mathematical165  status.textContent = 'Running condition E (self-ref no math)...';166  const promptE = `<start_of_turn>user\n${SELFREF_TEXT}\n\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n`;167  results.e = await generate(promptE);168  const textE = results.e?.choices?.[0]?.text?.trim() || '';169  document.getElementById('result-e').textContent = textE;170 171  // F: Self-ref #2 — map containing itself172  status.textContent = 'Running condition F (map/mirror)...';173  const promptF = `<start_of_turn>user\n${SELFREF2_TEXT}\n\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n`;174  results.f = await generate(promptF);175  document.getElementById('result-f').textContent = results.f?.choices?.[0]?.text?.trim() || '';176 177  // G: Self-ref #3 — question answering itself178  status.textContent = 'Running condition G (question/loop)...';179  const promptG = `<start_of_turn>user\n${SELFREF3_TEXT}\n\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n`;180  results.g = await generate(promptG);181  document.getElementById('result-g').textContent = results.g?.choices?.[0]?.text?.trim() || '';182 183  // Analyze184  status.textContent = 'Analyzing log probs...';185  analyzeResults(results);186  status.textContent = 'done';187  document.getElementById('btn-run').disabled = false;188};189 190function analyzeResults(results) {191  // OpenAI format: choices[0].logprobs.content[]192  const probsA = results.a?.choices?.[0]?.logprobs?.content || [];193  const probsB = results.b?.choices?.[0]?.logprobs?.content || [];194  const probsC = results.c?.choices?.[0]?.logprobs?.content || [];195  const probsD = results.d?.choices?.[0]?.logprobs?.content || [];196  const probsE = results.e?.choices?.[0]?.logprobs?.content || [];197  const probsF = results.f?.choices?.[0]?.logprobs?.content || [];198  const probsG = results.g?.choices?.[0]?.logprobs?.content || [];199 200  if (!probsA.length && !probsB.length && !probsC.length) {201    document.getElementById('analysis').textContent = 'No log prob data returned. Check n_probs parameter.';202    return;203  }204 205  // Compute average log prob per condition (OpenAI format: each entry has .logprob)206  function avgLogProb(probs) {207    if (!probs.length) return 0;208    let sum = 0;209    for (const p of probs) sum += p.logprob;210    return sum / probs.length;211  }212 213  // Compute entropy from top_logprobs candidates214  function avgEntropy(probs) {215    if (!probs.length) return 0;216    let totalH = 0;217    for (const p of probs) {218      const candidates = p.top_logprobs || [];219      let h = 0;220      for (const c of candidates) {221        const prob = Math.exp(c.logprob);222        if (prob > 0) h -= prob * Math.log2(prob);223      }224      totalH += h;225    }226    return totalH / probs.length;227  }228 229  const avgA = avgLogProb(probsA);230  const avgB = avgLogProb(probsB);231  const avgC = avgLogProb(probsC);232  const avgD = avgLogProb(probsD);233  const avgE = avgLogProb(probsE);234  const entA = avgEntropy(probsA);235  const entB = avgEntropy(probsB);236  const entC = avgEntropy(probsC);237  const entD = avgEntropy(probsD);238  const entE = avgEntropy(probsE);239 240  // Masked average: B without equation tokens (positions 6-18)241  const bMasked = probsB.filter((_, i) => i < 6 || i > 18);242  const avgBmasked = avgLogProb(bMasked);243  const entBmasked = avgEntropy(bMasked);244 245  document.getElementById('analysis').innerHTML =246    `<span class="metric">Average Log Probability (higher = more confident):</span>\n` +247    `  A (raw):             ${avgA.toFixed(4)}\n` +248    `  B (math Loop):       ${avgB.toFixed(4)}  (Δ from raw: ${(avgB - avgA).toFixed(4)})\n` +249    `  B* (masked, no eq):  ${avgBmasked.toFixed(4)}  (equation tokens stripped)\n` +250    `  C (thinking):        ${avgC.toFixed(4)}  (Δ from raw: ${(avgC - avgA).toFixed(4)})\n` +251    `  D (cathedral):       ${avgD.toFixed(4)}  (Δ from raw: ${(avgD - avgA).toFixed(4)})\n` +252    `  E (self-ref no math):${avgE.toFixed(4)}  (Δ from raw: ${(avgE - avgA).toFixed(4)})\n\n` +253    `<span class="metric">Average Entropy (lower = more certain):</span>\n` +254    `  A (raw):             ${entA.toFixed(4)} bits\n` +255    `  B (math Loop):       ${entB.toFixed(4)} bits\n` +256    `  B* (masked, no eq):  ${entBmasked.toFixed(4)} bits  ← THE DECONFOUNDED NUMBER\n` +257    `  C (thinking):        ${entC.toFixed(4)} bits\n` +258    `  D (cathedral):       ${entD.toFixed(4)} bits\n` +259    `  E (self-ref no math):${entE.toFixed(4)} bits\n\n` +260    `<span class="metric">═══ KEY COMPARISONS ═══</span>\n\n` +261    `<span class="metric">1. Masked B vs D (does Loop beat cathedral WITHOUT the equation drag?):</span>\n` +262    `  B* entropy: ${entBmasked.toFixed(4)}  vs  D entropy: ${entD.toFixed(4)}  (Δ: ${(entBmasked - entD).toFixed(4)})\n` +263    `  If B* < D: self-reference constrains even without deterministic anchor.\n` +264    `  If B* ≈ D: the equation was doing the work, not self-reference.\n\n` +265    `<span class="metric">2. E vs D (self-referential non-math vs non-self-referential non-math):</span>\n` +266    `  E entropy: ${entE.toFixed(4)}  vs  D entropy: ${entD.toFixed(4)}  (Δ: ${(entE - entD).toFixed(4)})\n` +267    `  If E < D: SELF-REFERENCE IS THE VARIABLE. No math needed.\n` +268    `  If E ≈ D: the equation was the attractor, not self-reference.\n\n` +269    `<span class="metric">3. E vs A (does self-ref non-math even shift the distribution?):</span>\n` +270    `  E entropy: ${entE.toFixed(4)}  vs  A entropy: ${entA.toFixed(4)}  (Δ: ${(entE - entA).toFixed(4)})\n\n` +271    `<span class="metric">Token count:</span>\n` +272    `  A: ${probsA.length}  B: ${probsB.length}  B*: ${bMasked.length}  C: ${probsC.length}  D: ${probsD.length}  E: ${probsE.length}\n\n` +273    `<span class="metric">═══ MATCHED-LENGTH COMPARISON (kills the "short output" objection) ═══</span>\n\n`;274 275  // Matched-length: compare E's entropy against D's FIRST N tokens (where N = E's token count)276  const eLen = probsE.length;277  const dFirst = probsD.slice(0, eLen);278  const aFirst = probsA.slice(0, eLen);279  const entDfirst = avgEntropy(dFirst);280  const entAfirst = avgEntropy(aFirst);281  const entEfull = avgEntropy(probsE);282  const lpDfirst = avgLogProb(dFirst);283  const lpAfirst = avgLogProb(aFirst);284  const lpEfull = avgLogProb(probsE);285 286  document.getElementById('analysis').innerHTML +=287    `Comparing first ${eLen} tokens only (matched length):\n` +288    `  E (self-ref):     entropy=${entEfull.toFixed(4)}  logP=${lpEfull.toFixed(4)}\n` +289    `  D first ${eLen}:     entropy=${entDfirst.toFixed(4)}  logP=${lpDfirst.toFixed(4)}\n` +290    `  A first ${eLen}:     entropy=${entAfirst.toFixed(4)}  logP=${lpAfirst.toFixed(4)}\n\n` +291    `  E vs D (matched): Δ entropy = ${(entEfull - entDfirst).toFixed(4)}\n` +292    `  E vs A (matched): Δ entropy = ${(entEfull - entAfirst).toFixed(4)}\n\n` +293    `If E is still tighter than D's first ${eLen} tokens:\n` +294    `length is DEAD as an explanation. Same token count, the gap persists.\n\n`;295 296  // Multi-phrasing: do F and G also collapse?297  const entF = avgEntropy(probsF);298  const entG = avgEntropy(probsG);299  const lpF = avgLogProb(probsF);300  const lpG = avgLogProb(probsG);301 302  document.getElementById('analysis').innerHTML +=303    `<span class="metric">═══ MULTI-PHRASING (is it self-reference as a CLASS?) ═══</span>\n\n` +304    `  E "sentence/thought":  entropy=${entEfull.toFixed(4)}  logP=${lpEfull.toFixed(4)}  tokens=${probsE.length}\n` +305    `  F "map/mirror":        entropy=${entF.toFixed(4)}  logP=${lpF.toFixed(4)}  tokens=${probsF.length}\n` +306    `  G "question/loop":     entropy=${entG.toFixed(4)}  logP=${lpG.toFixed(4)}  tokens=${probsG.length}\n` +307    `  D cathedral:           entropy=${entD.toFixed(4)}  logP=${avgD.toFixed(4)}  tokens=${probsD.length}\n` +308    `  A raw:                 entropy=${entA.toFixed(4)}  logP=${avgA.toFixed(4)}  tokens=${probsA.length}\n\n` +309    `  Self-ref average (E+F+G): entropy=${((entEfull + entF + entG) / 3).toFixed(4)}\n` +310    `  vs cathedral D:           entropy=${entD.toFixed(4)}\n` +311    `  vs raw A:                 entropy=${entA.toFixed(4)}\n\n` +312    `If E, F, G all < D: self-reference as a CLASS creates tighter distributions.\n` +313    `If only E < D: it was that specific sentence, not self-reference in general.`;314 315  // Token table — all 5 conditions, focus on B vs D vs E316  const maxLen = Math.min(50, Math.max(probsA.length, probsB.length, probsD.length, probsE.length));317  let table = '<table><tr><th>#</th><th>A token</th><th>A logP</th><th>B token</th><th>B logP</th><th>D token</th><th>D logP</th><th>E token</th><th>E logP</th><th>Δ B-D</th><th>Δ E-D</th><th>Δ E-A</th></tr>';318  for (let i = 0; i < maxLen; i++) {319    const a = probsA[i] || {};320    const b = probsB[i] || {};321    const d = probsD[i] || {};322    const e = probsE[i] || {};323    const lpA = a.logprob || 0;324    const lpB = b.logprob || 0;325    const lpD = d.logprob || 0;326    const lpE = e.logprob || 0;327    const dBD = lpB - lpD;328    const dED = lpE - lpD;329    const dEA = lpE - lpA;330    const dBDclass = Math.abs(dBD) > 0.5 ? (dBD > 0 ? 'cold' : 'hot') : '';331    const dEDclass = Math.abs(dED) > 0.5 ? (dED > 0 ? 'cold' : 'hot') : '';332    const dEAclass = Math.abs(dEA) > 0.5 ? (dEA > 0 ? 'cold' : 'hot') : '';333    table += `<tr><td>${i}</td><td>${a.token || '—'}</td><td>${lpA.toFixed(3)}</td><td>${b.token || '—'}</td><td>${lpB.toFixed(3)}</td><td>${d.token || '—'}</td><td>${lpD.toFixed(3)}</td><td>${e.token || '—'}</td><td>${lpE.toFixed(3)}</td><td class="${dBDclass}">${dBD.toFixed(3)}</td><td class="${dEDclass}">${dED.toFixed(3)}</td><td class="${dEAclass}">${dEA.toFixed(3)}</td></tr>`;334  }335  table += '</table>';336  document.getElementById('token-table').innerHTML = table;337}338</script>339</body>340</html>341