返回

文章详情

LLM回应的交叉熵比较揭示Kimi与Claude的相似性

Hacker News2026年7月23日 15:05

哪些LLM模型的写作风格类似?仅通过它们的词语构建的热图。--- 格式:typebulb/v1 名称:“你相对正确!” --- **code.tsx** ```tsx import React, { useEffect, useMemo, useState } from "react"; import { createRoot } from "react-dom/client"; import { encode } from "gpt-tokenizer/encoding/cl100k_base"; // ── 类型 ──────────────────────────────────────────────────────── 类型 RawResult = { testId: string; testName: string; subject: string; score: number; response: string; response2?: string; reasoning: string; error?: string; }; 类型 RawData = { timestamp?: string; judge?: string; results: RawResult[] }; 类型 MetaRow = { match: string; lab: string; released: string | null }; 类型 Counts = { map: Map<string, number>; n: number }; 类型 Bg = { words: Counts; phrases: Counts; common: Set<string> }; 类型 ModelRow = { name: string; disp: string; // "<真实实验室>: <模型>" — OpenRouter条目解析为其真实实验室 lab: string; released: string | null; // YYYY-MM,来自数据块;在提供之前为null chars: number; // 语料库大小 grams: Counts; // 字符三元组 words: Counts; // 单词单元格(用于显示) phrases: Counts; // 单词双元组(用于显示) wordDf: Map<string, number>; // 每个单词的答案数量 phraseDf: Map<string, number>; // 每个双元组的答案数量 docs: number; // 语料库中的答案 H: number; // 当前的熵,每个三元组的位数(原始MLE) }; // ── 文本统计 ─────────────────────────────────────────────────── const LAMBDA = 0.8; // 插值:λ·模型 + (1−λ)·汇总背景 const lg = (x: number) => Math.log(x) / Math.LN2; function countGrams(text: string, k: number): Counts { const map = new Map<string, number>(); for (let i = 0; i + k <= text.length; i++) { const g = text.slice(i, i + k); map.set(g, (map.get(g) ?? 0) + 1); } return { map, n: Math.max(1, text.length - k + 1) }; } function countList(items: string[]): Counts { const map = new Map<string, number>(); for (const it of items) map.set(it, (map.get(it) ?? 0) + 1); return { map, n: Math.max(1, items.length) }; } function pool(all: Counts[]): Counts { const map = new Map<string, number>(); let n = 0; for (const c of all) { for (const [g, v] of c.map) map.set(g, (map.get(g) ?? 0) + v); n += c.n; } return { map, n }; } // 在模型q下对gram g的插值概率,回退到汇总bg const prob = (g: string, q: Counts, bg: Counts) => LAMBDA * ((q.map.get(g) ?? 0) / q.n) + (1 - LAMBDA) * ((bg.map.get(g) ?? 0) / bg.n); // 作为稀有筛选的BPE令牌计数:分词器经过频率训练,因此“the”花费1个令牌,而“congratulatory”花费4个代币。每个特殊必须花费的令牌多于字数(字数≥2,短语≥3)。 const tokCache = new Map<string, number>(); function tokenCount(w: string): number { let c = tokCache.get(w); if (c === undefined) { c = encode(w).length; tokCache.set(w, c); } return c; } function rareEnough(term: string, extra = 1): boolean { const parts = term.split(" "); return parts.reduce((s, w) => s + tokenCount(w), 0) >= parts.length + extra; } // log10 P(X ≥ c) for X ~ Poisson(λ): 在该领域的比率下产生c或更多使用的可能性函数 log10PoissonTail(c: number, lambda: number): number { if (c <= 0 || lambda <= 0) return 0; let lnTerm = c * Math.log(lambda) - lambda; for (let k = 2; k <= c; k++) lnTerm -= Math.log(k); let sum = 1, term = 1; for (let k = c; k < c + 200; k++) { term *= lambda / (k + 1); sum += term; if (term < 1e-12 * sum) break; } return Math.min(0, (lnTerm + Math.log(sum)) / Math.LN10); } function crossEntropy(a: Counts, b: Counts, bg: Counts): number { let s = 0; for (const [g, c] of a.map) s -= (c / a.n) * lg(prob(g, b, bg)); return s; } function entropy(a: Counts): number { let s = 0; for (const c of a.map.values()) { const p = c / a.n; s -= p * lg(p); } return s; } 类型 Tale = { term: string; ratio: number; bCount: number; tokens: number; surprise: number; dfA: number; dfB: number }; // 两个模型依赖的术语,而其余领域很少使用 — 亲和证据。 // 每个幸存者携带一个修正的惊喜:−log10 联合泊松机会,同时符合两个模型在该领域的比率,减去每个扫描的术语的寻找开销。 function sharedTales(a: ModelRow, b: ModelRow, bg: Bg, top: number): Tale[] { const minus = (pool: Counts, ...subs: Counts[]): Counts => { const map = new Map(pool.map); let n = pool.n; for (const s of subs) { for (const [g, v] of s.map) { const r = (map.get(g) ?? 0) - v; if (r > 0) map.set(g, r); else map.delete(g); } n -= s.n; } return { map, n: Math.max(1, n) }; }; const restWords = minus(bg.words, a.words, b.words); const restPhrases = minus(bg.phrases, a.phrases, b.phrases); let scanned = 0; const cand: Tale[] = []; const consider = (term: string, aC: Counts, bC: Counts, rest: Counts, boring: boolean, dfA: number, dfB: number) => { scanned++; const ca = aC.map.get(term) ?? 0, cb = bC.map.get(term) ?? 0; if (ca < 3 || cb < 3 || boring || !rareEnough(term)

赞助内容

NordVPN Next-gen Antivirus

本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。

请我喝杯咖啡