File size: 2,240 Bytes
ca2a6e7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
export function seededRandom(seed) {
  let state = Number(seed) >>> 0;
  return () => {
    state = (state + 0x6D2B79F5) >>> 0;
    let x = Math.imul(state ^ (state >>> 15), state | 1);
    x ^= x + Math.imul(x ^ (x >>> 7), x | 61);
    return ((x ^ (x >>> 14)) >>> 0) / 4294967296;
  };
}

export function validateSettings(settings) {
  const { seed, temperature, topP, topK, maxTokens } = settings;
  if (!Number.isInteger(seed) || seed < 0 || seed > 0xffffffff) throw new Error('Seed must be an integer from 0 to 4,294,967,295.');
  if (!Number.isFinite(temperature) || temperature < 0 || temperature > 2) throw new Error('Temperature must be between 0 and 2.');
  if (!Number.isFinite(topP) || topP <= 0 || topP > 1) throw new Error('Top-p must be between 0 (exclusive) and 1.');
  if (!Number.isInteger(topK) || topK < 0 || topK > 378) throw new Error('Top-k must be an integer from 0 to 378.');
  if (!Number.isInteger(maxTokens) || maxTokens < 1 || maxTokens > 2047) throw new Error('Token limit must be an integer from 1 to 2,047.');
}

export function sample(logits, settings, random) {
  const { temperature, topP, topK } = settings;
  if (temperature === 0) {
    let best = 0;
    for (let i = 1; i < logits.length; i++) if (logits[i] > logits[best]) best = i;
    return best;
  }
  let candidates = Array.from(logits, (value, id) => ({ id, value })).sort((a, b) => b.value - a.value);
  // Same order as Transformers: temperature, top-k, then nucleus filtering.
  if (topK > 0 && topK < candidates.length) {
    const cutoff = candidates[topK - 1].value;
    candidates = candidates.filter(c => c.value >= cutoff);
  }
  const maximum = candidates[0].value;
  let total = 0;
  for (const c of candidates) { c.prob = Math.exp((c.value - maximum) / temperature); total += c.prob; }
  let cumulative = 0;
  let keep = candidates.length;
  for (let i = 0; i < candidates.length; i++) {
    cumulative += candidates[i].prob / total;
    if (cumulative >= topP) { keep = i + 1; break; }
  }
  candidates = candidates.slice(0, keep);
  total = candidates.reduce((sum, c) => sum + c.prob, 0);
  let draw = random() * total;
  for (const c of candidates) { draw -= c.prob; if (draw < 0) return c.id; }
  return candidates.at(-1).id;
}