LJTSG commited on
Commit
c1c92e9
Β·
verified Β·
1 Parent(s): 0b09fde

Upload logprob-experiment.html with huggingface_hub

Browse files
Files changed (1) hide show
  1. logprob-experiment.html +340 -0
logprob-experiment.html ADDED
@@ -0,0 +1,340 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>
7
+ body { font-family: monospace; background: #0a0e14; color: #c9d1d9; padding: 20px; max-width: 1200px; margin: 0 auto; }
8
+ h1 { color: #58a6ff; font-size: 18px; }
9
+ h2 { color: #7eb8da; font-size: 14px; margin-top: 20px; }
10
+ .card { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 16px; margin: 12px 0; }
11
+ button { background: #238636; color: white; border: none; border-radius: 6px; padding: 10px 20px; cursor: pointer; font-weight: bold; margin: 4px; }
12
+ button: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; }
19
+ table { border-collapse: collapse; width: 100%; font-size: 11px; }
20
+ td, th { border: 1px solid #30363d; padding: 4px 8px; text-align: left; }
21
+ th { 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 anchor
41
+ </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">
89
+ import { Wllama } from './node_modules/@wllama/wllama/esm/index.js';
90
+
91
+ const status = document.getElementById('status');
92
+ let wllama = null;
93
+
94
+ const 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.';
95
+ const 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.';
96
+ const 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.';
97
+ const 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.';
98
+ const 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.';
99
+ const QUESTION = 'What are you?';
100
+
101
+ const 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
+
109
+ window.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
+
127
+ async function generate(prompt) {
128
+ const result = await wllama.createCompletion({ prompt, ...genParams });
129
+ return result;
130
+ }
131
+
132
+ window.runExperiment = async function() {
133
+ document.getElementById('btn-run').disabled = true;
134
+ const results = {};
135
+
136
+ // A: Raw β€” no Loop
137
+ 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 prompt
144
+ 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 thinking
151
+ 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-mathematical
165
+ 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 itself
172
+ 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 itself
178
+ 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
+ // Analyze
184
+ status.textContent = 'Analyzing log probs...';
185
+ analyzeResults(results);
186
+ status.textContent = 'done';
187
+ document.getElementById('btn-run').disabled = false;
188
+ };
189
+
190
+ function 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 candidates
214
+ 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 E
316
+ 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>