<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Maksim Sekretov</title>
    <description>The latest articles on DEV Community by Maksim Sekretov (@maktordev).</description>
    <link>https://dev.to/maktordev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4043726%2Fafb80f00-718a-4f99-a860-715037317c0b.png</url>
      <title>DEV Community: Maksim Sekretov</title>
      <link>https://dev.to/maktordev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maktordev"/>
    <language>en</language>
    <item>
      <title>ML Without Magic: Building a Tiny Language Model in Pure Node.js and Watching Every Weight Change</title>
      <dc:creator>Maksim Sekretov</dc:creator>
      <pubDate>Sat, 25 Jul 2026 09:34:59 +0000</pubDate>
      <link>https://dev.to/maktordev/ml-without-magic-building-a-tiny-language-model-in-pure-nodejs-and-watching-every-weight-change-5dfh</link>
      <guid>https://dev.to/maktordev/ml-without-magic-building-a-tiny-language-model-in-pure-nodejs-and-watching-every-weight-change-5dfh</guid>
      <description>&lt;p&gt;English Version | &lt;a href="https://github.com/sekretov/tiny-language-model-neuro-js/blob/main/ARTICLE_HABR_RU.md" rel="noopener noreferrer"&gt;Русская версия&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tokenization → embeddings → causal Transformer → LM head → softmax → loss → backpropagation. No TensorFlow, no PyTorch, and no hidden autograd.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Repository: &lt;strong&gt;&lt;a href="https://github.com/sekretov/tiny-language-model-neuro-js" rel="noopener noreferrer"&gt;tiny-language-model-neuro-js&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Most explanations of language models present correct formulas but hide the path between them inside a framework. I wanted the opposite: one small scenario where every scalar is visible and where the terminal clearly shows incorrect answers before learning and correct answers after it.&lt;/p&gt;

&lt;p&gt;The project now has one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node src/train.js &lt;span class="nt"&gt;--generalize&lt;/span&gt; &lt;span class="nt"&gt;--adaptive-teach&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It requires Node.js 18.19+ and has no dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result first
&lt;/h2&gt;

&lt;p&gt;The model is queried immediately after random initialization:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BEFORE TRAINING — random, usually wrong answers
&amp;gt; can human read ?
  model:    ? &amp;lt;unk&amp;gt; ...
  expected: human can read.  [WRONG]

&amp;gt; can fish swim ?
  model:    ? &amp;lt;unk&amp;gt; ...
  expected: fish can swim.   [WRONG]

&amp;gt; can cat read ?
  model:    ? &amp;lt;unk&amp;gt; ...
  expected: cat cannot read. [WRONG]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After pre-training, SFT, and adaptive SFT, the same model produces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FINAL ANSWERS AFTER ADAPTIVE SFT
&amp;gt; can human read ?
  model:    human can read.  [CORRECT]
&amp;gt; can fish swim ?
  model:    fish can swim.   [CORRECT]
&amp;gt; can bird fly ?
  model:    bird can fly.    [CORRECT]
&amp;gt; can cat read ?
  model:    cat cannot read. [CORRECT]

Rehearsal controls preserved: 14/14.
Stable criterion reached 11 times in a row.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The initial text varies because initialization is random. The final acceptance criterion does not: all answers must be correct, every target token must have at least 95% probability, and the complete check must pass more than ten times consecutively.&lt;/p&gt;

&lt;h2&gt;
  
  
  What remains after removing the extra modes
&lt;/h2&gt;

&lt;p&gt;The code previously contained several debug and training modes. They were useful while experimenting but obscured the main idea. The final version keeps one educational pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;text → word tokenization → token IDs
     → token + position embeddings
     → two causal Transformer blocks
        → multi-head self-attention
        → two-hidden-layer FFN
     → LM head → softmax → next-token probabilities
     → cross-entropy → backpropagation → Adam
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;train.js&lt;/code&gt; now reads as one story rather than a command-line framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  A scalar builds the computation graph
&lt;/h2&gt;

&lt;p&gt;Every number participating in learning is a &lt;code&gt;Value&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;backward&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;grad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_backward&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For multiplication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;y = a × b
dy/da = b
dy/db = a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The operation stores these local derivatives. &lt;code&gt;backward()&lt;/code&gt; sorts the graph topologically and applies the chain rule from the final loss back to embeddings and weights.&lt;/p&gt;

&lt;h2&gt;
  
  
  A neuron is literally an object
&lt;/h2&gt;

&lt;p&gt;The neuron formula is not hidden behind a tensor API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;output = activation(sum(input[i] × weight[i]) + bias)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Its implementation follows the formula:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useBias&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bias&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activation&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;relu&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;relu&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;Linear&lt;/code&gt; layer is just an array of neurons receiving the same input. This is slower than matrix multiplication but far easier to inspect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Embeddings and order
&lt;/h2&gt;

&lt;p&gt;Each token ID selects one trainable vector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;token representation = tokenEmbedding[id] + positionEmbedding[position]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Embeddings contain random values initially. They acquire useful relations only because gradients repeatedly change them in training contexts. No &lt;code&gt;meaning&lt;/code&gt; property is assigned to &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, or &lt;code&gt;cannot&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-attention without shorthand
&lt;/h2&gt;

&lt;p&gt;For every token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Q = X × Wq
K = X × Wk
V = X × Wv

score = dot(Q, K) / sqrt(headSize)
attention = softmax(score)
output = attention × V
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation loops only while &lt;code&gt;past &amp;lt;= position&lt;/code&gt;. That is the causal mask: the model can attend to the current token and its history but never to a future target.&lt;/p&gt;

&lt;p&gt;After attention, every token passes through a two-hidden-layer feed-forward network:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dModel → hidden ReLU → hidden ReLU → dModel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;LayerNorm and residual paths preserve stable information flow around attention and FFN.&lt;/p&gt;

&lt;h2&gt;
  
  
  The complete learning step
&lt;/h2&gt;

&lt;p&gt;The most important code in the project is only a few lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;learnOneToken&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetId&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zeroGrad&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;optimizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The loss is ordinary next-token cross-entropy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loss = -log(P(target | previous tokens))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the correct token has low probability, loss is large. Backpropagation computes &lt;code&gt;dLoss/dWeight&lt;/code&gt;; Adam changes each parameter; the next forward pass gives a different distribution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 1: pre-training
&lt;/h2&gt;

&lt;p&gt;The tiny world contains 14 ability relations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;human can read .
fish can swim .
bird can fly .
dog cannot read .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;cat + read&lt;/code&gt; relation is missing deliberately. Pre-training samples positions from this text and learns ordinary next-token prediction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 2: SFT
&lt;/h2&gt;

&lt;p&gt;The same relations are converted into 42 prompt-answer examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;can fish swim ?
is fish able to swim ?
does fish know how to swim ?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only answer tokens contribute to SFT loss. The implementation visits every pair and every answer position on each epoch, making the training loop deterministic and readable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Phase 3: adaptive SFT
&lt;/h2&gt;

&lt;p&gt;The missing answer is represented only by target tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cannot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six question variants receive those targets. This is direct supervision: the model did not discover a zoological fact on its own. The teacher introduced the fact through loss, and backpropagation distributed that information across embeddings, attention, FFN, LayerNorm, and the LM head.&lt;/p&gt;

&lt;p&gt;Why not stop after one correct answer? Because one generation can be fragile. The loop continues until every target token exceeds 95% probability and the whole evaluation succeeds 11 times in a row.&lt;/p&gt;

&lt;h2&gt;
  
  
  Catastrophic forgetting and rehearsal
&lt;/h2&gt;

&lt;p&gt;An early implementation trained only the six new cat prompts. It successfully learned the new answer and destroyed old behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;can human read ? → cat cannot read.
can fish swim ?  → cat cannot read.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is catastrophic forgetting in miniature. The fix is rehearsal: adaptive epochs also repeat the 14 older &lt;code&gt;can ... ?&lt;/code&gt; examples. The final criterion evaluates both new and old examples, so training cannot finish by overwriting everything with one response.&lt;/p&gt;

&lt;h2&gt;
  
  
  The log is always written
&lt;/h2&gt;

&lt;p&gt;The command automatically creates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;logs/training-log.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a sequential ASCII diagram rather than a raw JSON dump. It includes every&lt;br&gt;
forward/loss/backward/update event, followed by the complete matrices at three&lt;br&gt;
checkpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;initial random matrices
        |
        v
matrices after pre-training + SFT
        |
        v
final matrices after adaptive SFT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For every transition, the log prints the AFTER matrix and its exact DELTA matrix.&lt;br&gt;
Linear rows are named &lt;code&gt;neuron[n]&lt;/code&gt;, columns are named &lt;code&gt;weight[n]&lt;/code&gt;, and biases&lt;br&gt;
are shown beside their neuron. It also points out the largest concrete change as&lt;br&gt;
&lt;code&gt;layer / neuron / weight: before -&amp;gt; after -&amp;gt; delta&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  How close is it to a production LLM?
&lt;/h2&gt;

&lt;p&gt;The architecture and learning rule are real; the scale is intentionally tiny.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;This model&lt;/th&gt;
&lt;th&gt;Production model&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;24 word tokens&lt;/td&gt;
&lt;td&gt;Large subword/byte vocabulary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2,160 parameters&lt;/td&gt;
&lt;td&gt;Millions or billions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two Transformer blocks&lt;/td&gt;
&lt;td&gt;Tens or hundreds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalar JavaScript graph&lt;/td&gt;
&lt;td&gt;Batched tensor graph on accelerators&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Small structured corpus&lt;/td&gt;
&lt;td&gt;Massive curated datasets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Narrow trained behavior&lt;/td&gt;
&lt;td&gt;Broad language and reasoning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The project is not a GPT competitor. It is a causal language model reduced until the complete path fits in one repository and one mental model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;token → embedding → attention → FFN → probability
      → loss → gradient → updated weight → changed answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That path is the point. Once it is visible, frameworks stop looking magical: they execute the same classes of operations at a scale and speed this scalar implementation deliberately avoids.&lt;/p&gt;

&lt;p&gt;Repository: &lt;strong&gt;&lt;a href="https://github.com/sekretov/tiny-language-model-neuro-js" rel="noopener noreferrer"&gt;tiny-language-model-neuro-js&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Author: &lt;strong&gt;&lt;a href="https://www.linkedin.com/in/maksim-sekretov-maktordev/" rel="noopener noreferrer"&gt;Maksim Sekretov&lt;/a&gt;&lt;/strong&gt;.&lt;br&gt;
: &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>machinelearning</category>
      <category>node</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
