LLM Developer DocsLLM Docs

Loading the search index ...

↑ ↓ move, Enter open, Esc close

GitHub

Sampling

How generate.sample_next turns one row of logits into one token id, as coded.

generate.py

sample_next receives one row of logits and returns one token id. It runs these steps in this order:

  1. If temperature is below 1e-6, return the index of the largest logit and stop.
  2. Compute p, the softmax of the logits divided by temperature.
  3. If 0 < top_k < len(p), apply top-k.
  4. If top_p < 1.0, apply top-p.
  5. Draw one token from p with the generator.
Code listing: generate.sample_next
generate.pysample_nextGitHub: generate.py
def sample_next(logits, temperature, top_k, top_p, rng):    if temperature < 1e-6:        return int(np.argmax(logits))    p = softmax_forward(logits / temperature)    if 0 < top_k < len(p):        cutoff = np.sort(p)[-top_k] # # k-th largest probabilit        p = np.where(p >= cutoff, p, 0.0) # zero everything below it        p = p / p.sum() # renormalise so it sums to 1 again    if top_p < 1.0:        order = np.argsort(-p)        cum = np.cumsum(p[order])        keep = order[: np.searchsorted(cum, top_p) + 1]        q = np.zeros_like(p)        q[keep] = p[keep]        p = q / q.sum()    return int(rng.choice(len(p), p=p))

At the settings in config.py, steps 2, 4 and 5 run. Step 1 does not fire and step 3 is skipped. Autoregressive Generation lists those settings and shows how the loop calls this function.

This page has no backward pass. Sampling runs after the model and computes no loss or gradient, and nothing in generate.py calls a backward function. Every number here is an Illustrative Example, except the panel headed Actual Model Output at the end.

In this page's equations, z is the logits and the temperature is written with the Greek letter tau. T is not used for it, because on this site T is the sequence length.

Greedy guard

What is it?

Greedy guardImplemented

Sampling

The first two lines of sample_next. If temperature is below 1e-6, the function returns the index of the largest logit at once. It does not compute a softmax, and it does not read top_k, top_p or rng.

Why does the model need it?

The next line divides the logits by temperature, so a temperature of 0 cannot reach it. The guard handles that case and gives a way to get the same token every time from the same logits.

Mathematics

Greedy guard #Link to equation: Greedy guard
τ<10−6  ⟹  next=arg⁡max⁡izi\tau < 10^{-6} \implies \mathrm{next} = \arg\max_i z_i

What does each symbol mean?

SymbolMeaningIn codeShape
τ\tauThe temperature. T is not used for it on this site, because T is the sequence lengthtemperaturescalar
zzThe logits of one positionlogits(V,)
next\mathrm{next}The chosen token idthe value returned by sample_nextscalar

Tiny numerical example

The guard, on hand-picked logitsIllustrative ExampleHand-picked logits, not model output.
logitstemperatureReturned token
[0.1, 2, 1]01
[0.1, 2, 1]5e-71
[1, 3, 3, 2]01

At exactly 0.000001 the test temperature < 1e-6 is false, so the code computes a distribution: [0, 1, 0]. It is close to greedy, because dividing by so small a number leaves one exponential far above the rest, but it still draws from the generator.

np.argmax returns the first index among equal values, so a tie goes to the lowest index. That is the third row of the table.

Tensor shapes

From the model's logits to the row sample_next reads. The result is one int, with no axesgenerate.py:9
  1. logits(T, V)(16, V)
  2. logits[-1](V,)

T = seq_len = 16. T is at most seq_len: generation uses the last seq_len ids, or fewer for a short prompt. V depends on the corpus. It is not a value in config.py.

Actual implementation

generate.pysample_nextGitHub: generate.py
    if temperature < 1e-6:        return int(np.argmax(logits))

The return happens before rng is touched, so a greedy step draws nothing from the generator. Two tests check this: the same token twenty times, and the same output from two different seeds.

Code and math connection

EquationRoleLinesCode
Greedy guardComputes itgenerate.py:8if temperature < 1e-6:
Greedy guardComputes itgenerate.py:9return int(np.argmax(logits))
Greedy guardTests ittests/test_generate.py:29assert all(sample_next(np.array([0.1, 2.0, 1.0]), 0.0, 0, 1.0, rng) == 1
Greedy guardTests ittests/test_generate.py:82assert a == b

Where is it used?

Source

generate.py, lines 7-26, sample_next

PDF reference

Section 4.7, p. 14

Used by

Called by: generate.generate

Tested by: tests.test_generate.probs_used, tests.test_generate.test_temperature_zero_is_greedy, tests.test_generate.test_top_k_one_is_greedy

Status
Implemented

Implemented in

EquationRoleFileFunctionLinesGitHub
Greedy guardComputes itgenerate.pysample_next8GitHub: generate.py, line 8
Greedy guardComputes itgenerate.pysample_next9GitHub: generate.py, line 9

Temperature

What is it?

TemperatureImplemented

Sampling

Divides the logits by temperature, then applies softmax_forward. The result is a probability for every token in the vocabulary.

Why does the model need it?

The model gives logits, and a random choice needs probabilities. Dividing first changes how far apart the logits are. Below 1 the gaps grow and the largest probability rises. Above 1 the gaps shrink and the probabilities move closer together.

Mathematics

Softmax of the logits divided by temperature #Link to equation: Softmax of the logits divided by temperature
p=softmax(zτ)p = \mathrm{softmax}\left(\frac{z}{\tau}\right)

The softmax itself is on Softmax & Cross-Entropy. It subtracts the largest value first, so large logits do not overflow.

What does each symbol mean?

SymbolMeaningIn codeShape
zzThe logits of one positionlogits(V,)
τ\tauThe temperature, at least 1e-6 on this line because of the guard above ittemperaturescalar
ppThe probabilities of the next tokenp(V,)

Tiny numerical example

One set of logits at three temperaturesIllustrative ExampleHand-picked logits [2, 1, 0], not model output.
temperaturelogits / temperaturep
0.5[4, 2, 0][0.8668, 0.1173, 0.0159]
1[2, 1, 0][0.6652, 0.2447, 0.09]
2[1, 0.5, 0][0.5065, 0.3072, 0.1863]

These inputs are the ones in test_temperature_examples. At temperature 1 the logits pass through unchanged.

Tensor shapes

Temperature keeps the shapegenerate.py:11
  1. logits(V,)
  2. p(V,)

V depends on the corpus. It is not a value in config.py.

Actual implementation

generate.pysample_nextGitHub: generate.py
    p = softmax_forward(logits / temperature)
ops.pysoftmax_forwardGitHub: ops.py
def softmax_forward(x):    e = np.exp(x - np.max(x, axis=-1, keepdims=True))    return e / e.sum(axis=-1, keepdims=True)

Code and math connection

EquationRoleLinesCode
Softmax of the logits divided by temperatureComputes itgenerate.py:11p = softmax_forward(logits / temperature)
Softmax of the logits divided by temperatureCalls itops.py:24return e / e.sum(axis=-1, keepdims=True)
Softmax of the logits divided by temperatureTests ittests/test_generate.py:22assert np.allclose(probs_used(z, 0.5), [0.867, 0.117, 0.016], atol=1e-3)

Where is it used?

Source

generate.py, lines 7-26, sample_next

PDF reference

Section 4.7, Eq. 60, p. 14

Used by

Called by: generate.generate

Tested by: tests.test_generate.probs_used, tests.test_generate.test_temperature_zero_is_greedy, tests.test_generate.test_top_k_one_is_greedy

Status
Implemented

Implemented in

EquationRoleFileFunctionLinesGitHub
Softmax of the logits divided by temperatureComputes itgenerate.pysample_next11GitHub: generate.py, line 11

Top-k

What is it?

Top-kDerived from implementation

Sampling

An optional step that runs only if 0 < top_k < len(p). It finds the k-th largest probability, sets every probability below it to zero, and renormalises. A token equal to the cut-off stays, so ties can leave more than k tokens.

Why does the model need it?

It stops the choice from landing on unlikely tokens by limiting how many tokens can be chosen. The model does not need it at the committed settings, because top_k is 0 in config.py and the step is skipped.

Mathematics

The cut-off #Link to equation: The cut-off
c=k-th largest value of p, counting repeatsc = k\text{-th largest value of } p \text{, counting repeats}
Zero everything below the cut-off #Link to equation: Zero everything below the cut-off
pi′={pipi≥c0otherwisep'_i = \begin{cases} p_i & p_i \geq c \\ 0 & \text{otherwise} \end{cases}
Renormalise #Link to equation: Renormalise
pi′′=pi′∑jpj′p''_i = \frac{p'_i}{\sum_j p'_j}

The branch runs only if 0 < top_k < len(p). So top_k = 0 skips it, a negative value skips it, and so does a value equal to or above the vocabulary size.

How the cut-off is computed. np.sort(p) sorts from smallest to largest, and [-top_k] counts back from the end (generate.py:14). Repeated values each take a place in that list. With top_k = 2 and p holding three equal largest values, the cut-off is that shared value.

What happens with ties. The test is p >= cutoff (generate.py:15), not a count. Every token equal to the cut-off stays, so more than top_k tokens can remain. Nothing breaks the tie.

The PDF gives a worked example of top-k on p. 14 and no equation, so this concept is marked as derived from the implementation.

What does each symbol mean?

SymbolMeaningIn codeShape
ppThe probabilities after temperaturep(V,)
kkHow many of the largest values to count down totop_kscalar
ccThe cut-offcutoffscalar
p′p'The probabilities with the lower values set to zerothe result of np.where(V,)
p′′p''The same values, scaled to sum to 1p, rebound(V,)

Tiny numerical example

Top-k without and with a tieIllustrative ExampleHand-picked logits at temperature 1, not model output.
QuantityValue
p[0.5, 0.3, 0.15, 0.05]
p, sorted largest first[0.5, 0.3, 0.15, 0.05]
cutoff, for top_k = 20.3
Tokens kept2
p after renormalising[0.625, 0.375, 0, 0]
QuantityValue
p[0.2855, 0.2855, 0.2855, 0.105, 0.0386]
p, sorted largest first[0.2855, 0.2855, 0.2855, 0.105, 0.0386]
cutoff, for top_k = 20.2855
Tokens kept3
p after renormalising[0.3333, 0.3333, 0.3333, 0, 0]

In the second table top_k is 2 and three tokens remain, because all three equal the cut-off.

Tensor shapes

Top-k changes values, not the shape. Removed tokens stay as zerosgenerate.py:15
  1. p before(V,)
  2. p after(V,)

V depends on the corpus. It is not a value in config.py.

Actual implementation

generate.pysample_nextGitHub: generate.py
    if 0 < top_k < len(p):        cutoff = np.sort(p)[-top_k] # # k-th largest probabilit        p = np.where(p >= cutoff, p, 0.0) # zero everything below it        p = p / p.sum() # renormalise so it sums to 1 again

Code and math connection

EquationRoleLinesCode
The cut-offComputes itgenerate.py:13if 0 < top_k < len(p):
The cut-offComputes itgenerate.py:14cutoff = np.sort(p)[-top_k] # # k-th largest probabilit
Zero everything below the cut-offComputes itgenerate.py:15p = np.where(p >= cutoff, p, 0.0) # zero everything below it
Zero everything below the cut-offTests ittests/test_generate.py:41assert all(sample_next(z, 1.0, 1, 1.0, rng) == 1 for _ in range(30))
RenormaliseComputes itgenerate.py:16p = p / p.sum() # renormalise so it sums to 1 again
RenormaliseTests ittests/test_generate.py:35assert np.allclose(probs_used(z, top_k=2), [0.625, 0.375, 0, 0])

Where is it used?

Source

generate.py, lines 7-26, sample_next

PDF reference

Not stated in the PDF

Used by

Called by: generate.generate

Tested by: tests.test_generate.probs_used, tests.test_generate.test_temperature_zero_is_greedy, tests.test_generate.test_top_k_one_is_greedy

Status
Derived from implementation

Implemented in

EquationRoleFileFunctionLinesGitHub
The cut-offComputes itgenerate.pysample_next13GitHub: generate.py, line 13
The cut-offComputes itgenerate.pysample_next14GitHub: generate.py, line 14
Zero everything below the cut-offComputes itgenerate.pysample_next15GitHub: generate.py, line 15
RenormaliseComputes itgenerate.pysample_next16GitHub: generate.py, line 16

Top-p

What is it?

Top-pDerived from implementation

Sampling

An optional step that runs only if top_p < 1.0. It sorts the tokens from most to least likely, adds up their probabilities, keeps the shortest run from the top whose sum reaches top_p, and renormalises. The token that crosses top_p is kept.

Why does the model need it?

It removes the unlikely tail. The number of tokens kept follows the distribution, so a confident distribution keeps few and an unsure one keeps many. It is on in config.py.

Mathematics

Sort #Link to equation: Sort
π=token indices sorted by p, largest first\pi = \text{token indices sorted by } p \text{, largest first}
Cumulative sum #Link to equation: Cumulative sum
Cm=∑j=0mpπjC_m = \sum_{j=0}^{m} p_{\pi_j}
The smallest prefix that reaches top_p #Link to equation: The smallest prefix that reaches top_p
s=min⁡{m:Cm≥ρ},keep π0,…,πss = \min \{ m : C_m \geq \rho \}, \qquad \text{keep } \pi_0, \dots, \pi_s
Renormalise #Link to equation: Renormalise
qi=pi∑m=0spπm for kept i,qi=0 otherwiseq_i = \frac{p_i}{\sum_{m=0}^{s} p_{\pi_m}} \text{ for kept } i, \qquad q_i = 0 \text{ otherwise}

The prefix rule. np.searchsorted(cum, top_p) returns the first position where cum is at least top_p, counting from 0. The slice then adds 1, so the token at that position is kept (generate.py:21). The kept tokens are always a run from the top of the sorted order, and the sum of what is kept is at least top_p, not at most.

  • If cum lands exactly on top_p, the prefix ends at that token.
  • If top_p is 0 or below, position 0 already qualifies, so one token is kept.
  • If cum never reaches top_p, for example through rounding at a value just below 1, searchsorted returns len(cum), and the slice keeps every token.
  • If top-k ran first, its removed tokens are in the sort as zeros. They sit at the end of the order and add nothing to cum.

Ties at the cut. The code does not treat ties specially here, unlike top-k. If the cut falls inside a group of equal probabilities, some of them stay and some go. np.argsort(-p) (generate.py:19) uses NumPy's default sort, which does not promise an order for equal values, so the code does not define which ones stay. The number of tokens kept does not depend on that order.

The PDF gives a worked example of top-p on p. 15 and no equation, so this concept is marked as derived from the implementation.

What does each symbol mean?

SymbolMeaningIn codeShape
ppThe probabilities after temperature and top-kp(V,)
ρ\rhoThe thresholdtop_pscalar
π\piToken indices, largest probability firstorder(V,)
CCRunning sum of the sorted probabilitiescum(V,)
ssThe first position where C reaches the threshold, counting from 0np.searchsorted(cum, top_p)scalar
qqThe kept probabilities, scaled to sum to 1q / q.sum()(V,)

Tiny numerical example

Top-p: the token that crosses is keptIllustrative ExampleHand-picked logits at temperature 1, not model output.
Sorted positionTokenpcumKeptAfter renormalising
000.50.5Yes0.5263
110.30.8Yes0.3158
220.150.95Yes0.1579
330.051No0
Sorted positionTokenpcumKeptAfter renormalising
000.250.25Yes0.5
110.250.5Yes0.5
220.250.75No0
330.251No0

In the first table cum is below top_p at position 1 and above it at position 2, so position 2 is the crossing token and it is kept. These are the inputs of test_top_p_example. In the second table cum equals top_p at position 1, so the prefix stops there.

Tensor shapes

Top-p sorts and sums over all V tokens. Only keep is shorter, and p keeps its shapegenerate.py:21
  1. order(V,)
  2. cum(V,)
  3. p(V,)

V depends on the corpus. It is not a value in config.py.

keep is the one shorter array, with length s + 1. q has the full length, so removed tokens remain as zeros.

Actual implementation

generate.pysample_nextGitHub: generate.py
    if top_p < 1.0:        order = np.argsort(-p)        cum = np.cumsum(p[order])        keep = order[: np.searchsorted(cum, top_p) + 1]        q = np.zeros_like(p)        q[keep] = p[keep]        p = q / q.sum()

Code and math connection

EquationRoleLinesCode
SortComputes itgenerate.py:18if top_p < 1.0:
SortComputes itgenerate.py:19order = np.argsort(-p)
Cumulative sumComputes itgenerate.py:20cum = np.cumsum(p[order])
The smallest prefix that reaches top_pComputes itgenerate.py:21keep = order[: np.searchsorted(cum, top_p) + 1]
The smallest prefix that reaches top_pTests ittests/test_generate.py:47assert np.allclose(probs_used(z, top_p=0.9), [0.526, 0.316, 0.158, 0], atol=1e-3)
The smallest prefix that reaches top_pTests ittests/test_generate.py:54assert (probs_used(unsure, top_p=0.9) > 0).sum() == 4
RenormaliseComputes itgenerate.py:23q[keep] = p[keep]
RenormaliseComputes itgenerate.py:24p = q / q.sum()

Where is it used?

Source

generate.py, lines 7-26, sample_next

PDF reference

Not stated in the PDF

Used by

Called by: generate.generate

Tested by: tests.test_generate.probs_used, tests.test_generate.test_temperature_zero_is_greedy, tests.test_generate.test_top_k_one_is_greedy

Status
Derived from implementation

Implemented in

EquationRoleFileFunctionLinesGitHub
SortComputes itgenerate.pysample_next18GitHub: generate.py, line 18
SortComputes itgenerate.pysample_next19GitHub: generate.py, line 19
Cumulative sumComputes itgenerate.pysample_next20GitHub: generate.py, line 20
The smallest prefix that reaches top_pComputes itgenerate.pysample_next21GitHub: generate.py, line 21
RenormaliseComputes itgenerate.pysample_next23GitHub: generate.py, line 23
RenormaliseComputes itgenerate.pysample_next24GitHub: generate.py, line 24

Random choice

What is it?

Random choiceImplemented

Sampling

The last line of sample_next. It draws one token id with the probabilities left after the earlier steps, using the generator it was given. A token with probability zero cannot be drawn.

Why does the model need it?

Generation needs one token to append. Drawing at random lets the same logits give different tokens. The generator is seeded, so a run with the same seed and the same calls repeats the same draws.

Mathematics

One draw from the final probabilities #Link to equation: One draw from the final probabilities
P(next=i)=piP(\mathrm{next} = i) = p_i

What does each symbol mean?

SymbolMeaningIn codeShape
ppThe final probabilitiesp(V,)
next\mathrm{next}The chosen token idthe value returned by sample_nextscalar
VVThe number of tokens to choose fromlen(p)scalar

Tiny numerical example

1000 draws from one distributionIllustrative ExampleHand-picked logits, not model output. The settings are those in config.py. The draws were recorded by calling the real sample_next with np.random.default_rng(42), because that generator is not reproduced in this site's engine. p comes from the engine.

First draws: [1, 0, 1, 1, 0, 2, 1, 1, 0, 0, 0, 2]

TokenpTimes drawn
00.6945689
10.199206
20.1065105
300
400

Tokens 3 and 4 have probability 0 and are never drawn. Running the same calls again from the same seed gave the same draws.

Tensor shapes

The array before the draw. The draw itself returns one int, with no axesgenerate.py:26
  1. p after top-k(V,)
  2. p after top-p(V,)

V depends on the corpus. It is not a value in config.py.

The draw returns one number, and int(...) makes it a plain Python integer.

Actual implementation

generate.pysample_nextGitHub: generate.py
    return int(rng.choice(len(p), p=p))

sample_next does not create the generator. Its caller passes one in, and both callers create it from 42:

train.pymainGitHub: train.py
    rng = np.random.default_rng(config.seed)
talk.pymainGitHub: talk.py
    rng = np.random.default_rng(config.seed)

Code and math connection

EquationRoleLinesCode
One draw from the final probabilitiesComputes itgenerate.py:26return int(rng.choice(len(p), p=p))
One draw from the final probabilitiesCalls ittrain.py:37rng = np.random.default_rng(config.seed)
One draw from the final probabilitiesCalls ittalk.py:9rng = np.random.default_rng(config.seed)
One draw from the final probabilitiesTests ittests/test_generate.py:10self.p = np.asarray(p)

Where is it used?

Source

generate.py, lines 7-26, sample_next

PDF reference

Section 4.7, p. 15

Used by

Called by: generate.generate

Tested by: tests.test_generate.probs_used, tests.test_generate.test_temperature_zero_is_greedy, tests.test_generate.test_top_k_one_is_greedy

Status
Implemented

Implemented in

EquationRoleFileFunctionLinesGitHub
One draw from the final probabilitiesComputes itgenerate.pysample_next26GitHub: generate.py, line 26

Probability lab

Edit the logits, temperature, top_k and top_p, or start from a preset. The first preset uses the settings in config.py. Every result comes from this site's mirror of sample_next. The presets' results are compared with the real function by the golden tests.

The lab stops at the distribution. It does not draw, because NumPy's generator is not reproduced in this site's engine.

logits
token 0token 1token 2token 3token 4
logits

  1. p = softmax_forward(logits / 0.8).
  2. top_k = 0: 0 < top_k < len(p) is false, so top-k is skipped.
  3. top_p = 0.9: the sum first reaches it within the first 3 sorted tokens, and the token that crosses it is kept.
  4. rng.choice would then draw from the 3 kept tokens.
Before truncation: softmax of logits / temperatureIllustrative ExampleHand-picked logits, not model output. Accent bars are the kept set. Grey bars are the tokens the later steps remove.
Data table
LabelProbability
token 00.6471
token 10.1854
token 20.0992
token 30.0531 removed
token 40.0152 removed
After truncation: what rng.choice receivesIllustrative ExampleThe kept probabilities, scaled to sum to 1. Both charts run from 0 to 1, so the bars can be compared.
Data table
LabelProbability
token 00.6945
token 10.1990
token 20.1065
token 30.0000 removed
token 40.0000 removed
TokenlogitsAfter temperatureAfter top-kSort positioncumFinal pKept
token 020.64710.647100.64710.6945Yes
token 110.18540.185410.83240.199Yes
token 20.50.09920.099220.93170.1065Yes
token 300.05310.053130.98480No
token 4-10.01520.0152410No

Actual Model Output

The distributions of a real model, for one prompt. The lab above does not read these numbers, and these panels do not read the lab.

Next-token probabilities, softmax of the last logitsActual Model OutputCommit 66da45b. Checkpoint model.npz sha256 74de2ec88a63. Seed 42, from config.py, since a checkpoint does not record its own. Read from checkpoints/model, an ignored local file, trained on data/corpus.csv (git-ignored, and not at the pinned commit), with training settings that by inference differ from config.py.The prompt is hand-picked: "Once there was a little ", which encodes to 12 tokens. The probabilities are what the model returned for this one prompt. The 10 most likely tokens are listed, and the other 565 tokens share one bar.
Data table
LabelProbability
p0.0700
b0.0575
s0.0492
f0.0451
boy0.0357
c0.0342
g0.0245
d0.0222
th0.0153
little0.0130
all other tokens0.6333
What sample_next draws from, at the config.py settingsActual Model OutputCommit 66da45b. Checkpoint model.npz sha256 74de2ec88a63. Seed 42, from config.py, since a checkpoint does not record its own. Read from checkpoints/model, an ignored local file, trained on data/corpus.csv (git-ignored, and not at the pinned commit), with training settings that by inference differ from config.py.The same prompt, with temperature 0.8, top_k 0 and top_p 0.9, read from the real sample_next before it draws. 84 tokens keep a non-zero probability.
Data table
LabelProbability
p0.1213
b0.0949
s0.0781
f0.0699
boy0.0523
c0.0496
g0.0327
d0.0288
th0.0182
little0.0148
all other tokens0.4395
Where these numbers came from
Repository commit66da45bea72176fa5d2f8dba2ea1c7e597e30dd3
model.npz sha25674de2ec88a63ceb131a27e03cc63070c6d8c4174cc78bc189195e9356e84550e
model.json sha256f93002949162068d573aab9b38990b12aec7f32b468ec9eaaef986075df7d3b4
model.tok.json sha256bf874ab4e4de2b61cb936f38635a7c589c5c0d29879947a5b45d13be2456b17d
Corpus data/corpus.csv sha256c1bec80f274294e6ce989fcc63fd7022a206f415e7d3df85e82c410e56dc4f4f
Tokenizer rebuilt from this corpus equals the checkpoint'sYes
Model shape, from the checkpoint{"context_len":32,"emb_dim":32,"ff_dim":128,"ln_eps":0.00001,"num_heads":2,"num_layers":2,"vocab_size":575}
config.py, when this was exported{"adam_eps":1e-8,"batch_size":16,"beta1":0.9,"beta2":0.999,"context_len":32,"corpus_column":"text","corpus_path":"data/corpus.csv","emb_dim":32,"epochs":20,"ff_dim":128,"grad_clip":1,"head_dim":16,"ln_eps":0.00001,"lr_max":0.001,"lr_min":0.0001,"max_new_tokens":50,"max_rows":2000,"num_heads":2,"num_layers":2,"num_merges":500,"seed":42,"seq_len":16,"stride":1,"temperature":0.8,"top_k":0,"top_p":0.9,"val_fraction":0.1,"warmup_steps":50,"weight_decay":0.01}
Seed42
EnvironmentPython 3.14.4, NumPy 2.5.2, pandas 3.1.0