-
Star
(5,000+)
You must be signed in to star a gist -
Fork
(2,734)
You must be signed in to fork a gist
-
-
Save karpathy/8627fe009c40f57531cb18360106ce95 to your computer and use it in GitHub Desktop.
| """ | |
| The most atomic way to train and run inference for a GPT in pure, dependency-free Python. | |
| This file is the complete algorithm. | |
| Everything else is just efficiency. | |
| @karpathy | |
| """ | |
| import os # os.path.exists | |
| import math # math.log, math.exp | |
| import random # random.seed, random.choices, random.gauss, random.shuffle | |
| random.seed(42) # Let there be order among chaos | |
| # Let there be a Dataset `docs`: list[str] of documents (e.g. a list of names) | |
| if not os.path.exists('input.txt'): | |
| import urllib.request | |
| names_url = 'https://raw.githubusercontent.com/karpathy/makemore/988aa59/names.txt' | |
| urllib.request.urlretrieve(names_url, 'input.txt') | |
| docs = [line.strip() for line in open('input.txt') if line.strip()] | |
| random.shuffle(docs) | |
| print(f"num docs: {len(docs)}") | |
| # Let there be a Tokenizer to translate strings to sequences of integers ("tokens") and back | |
| uchars = sorted(set(''.join(docs))) # unique characters in the dataset become token ids 0..n-1 | |
| BOS = len(uchars) # token id for a special Beginning of Sequence (BOS) token | |
| vocab_size = len(uchars) + 1 # total number of unique tokens, +1 is for BOS | |
| print(f"vocab size: {vocab_size}") | |
| # Let there be Autograd to recursively apply the chain rule through a computation graph | |
| class Value: | |
| __slots__ = ('data', 'grad', '_children', '_local_grads') # Python optimization for memory usage | |
| def __init__(self, data, children=(), local_grads=()): | |
| self.data = data # scalar value of this node calculated during forward pass | |
| self.grad = 0 # derivative of the loss w.r.t. this node, calculated in backward pass | |
| self._children = children # children of this node in the computation graph | |
| self._local_grads = local_grads # local derivative of this node w.r.t. its children | |
| def __add__(self, other): | |
| other = other if isinstance(other, Value) else Value(other) | |
| return Value(self.data + other.data, (self, other), (1, 1)) | |
| def __mul__(self, other): | |
| other = other if isinstance(other, Value) else Value(other) | |
| return Value(self.data * other.data, (self, other), (other.data, self.data)) | |
| def __pow__(self, other): return Value(self.data**other, (self,), (other * self.data**(other-1),)) | |
| def log(self): return Value(math.log(self.data), (self,), (1/self.data,)) | |
| def exp(self): return Value(math.exp(self.data), (self,), (math.exp(self.data),)) | |
| def relu(self): return Value(max(0, self.data), (self,), (float(self.data > 0),)) | |
| def __neg__(self): return self * -1 | |
| def __radd__(self, other): return self + other | |
| def __sub__(self, other): return self + (-other) | |
| def __rsub__(self, other): return other + (-self) | |
| def __rmul__(self, other): return self * other | |
| def __truediv__(self, other): return self * other**-1 | |
| def __rtruediv__(self, other): return other * self**-1 | |
| def backward(self): | |
| topo = [] | |
| visited = set() | |
| def build_topo(v): | |
| if v not in visited: | |
| visited.add(v) | |
| for child in v._children: | |
| build_topo(child) | |
| topo.append(v) | |
| build_topo(self) | |
| self.grad = 1 | |
| for v in reversed(topo): | |
| for child, local_grad in zip(v._children, v._local_grads): | |
| child.grad += local_grad * v.grad | |
| # Initialize the parameters, to store the knowledge of the model | |
| n_layer = 1 # depth of the transformer neural network (number of layers) | |
| n_embd = 16 # width of the network (embedding dimension) | |
| block_size = 16 # maximum context length of the attention window (note: the longest name is 15 characters) | |
| n_head = 4 # number of attention heads | |
| head_dim = n_embd // n_head # derived dimension of each head | |
| matrix = lambda nout, nin, std=0.08: [[Value(random.gauss(0, std)) for _ in range(nin)] for _ in range(nout)] | |
| state_dict = {'wte': matrix(vocab_size, n_embd), 'wpe': matrix(block_size, n_embd), 'lm_head': matrix(vocab_size, n_embd)} | |
| for i in range(n_layer): | |
| state_dict[f'layer{i}.attn_wq'] = matrix(n_embd, n_embd) | |
| state_dict[f'layer{i}.attn_wk'] = matrix(n_embd, n_embd) | |
| state_dict[f'layer{i}.attn_wv'] = matrix(n_embd, n_embd) | |
| state_dict[f'layer{i}.attn_wo'] = matrix(n_embd, n_embd) | |
| state_dict[f'layer{i}.mlp_fc1'] = matrix(4 * n_embd, n_embd) | |
| state_dict[f'layer{i}.mlp_fc2'] = matrix(n_embd, 4 * n_embd) | |
| params = [p for mat in state_dict.values() for row in mat for p in row] # flatten params into a single list[Value] | |
| print(f"num params: {len(params)}") | |
| # Define the model architecture: a function mapping tokens and parameters to logits over what comes next | |
| # Follow GPT-2, blessed among the GPTs, with minor differences: layernorm -> rmsnorm, no biases, GeLU -> ReLU | |
| def linear(x, w): | |
| return [sum(wi * xi for wi, xi in zip(wo, x)) for wo in w] | |
| def softmax(logits): | |
| max_val = max(val.data for val in logits) | |
| exps = [(val - max_val).exp() for val in logits] | |
| total = sum(exps) | |
| return [e / total for e in exps] | |
| def rmsnorm(x): | |
| ms = sum(xi * xi for xi in x) / len(x) | |
| scale = (ms + 1e-5) ** -0.5 | |
| return [xi * scale for xi in x] | |
| def gpt(token_id, pos_id, keys, values): | |
| tok_emb = state_dict['wte'][token_id] # token embedding | |
| pos_emb = state_dict['wpe'][pos_id] # position embedding | |
| x = [t + p for t, p in zip(tok_emb, pos_emb)] # joint token and position embedding | |
| x = rmsnorm(x) # note: not redundant due to backward pass via the residual connection | |
| for li in range(n_layer): | |
| # 1) Multi-head Attention block | |
| x_residual = x | |
| x = rmsnorm(x) | |
| q = linear(x, state_dict[f'layer{li}.attn_wq']) | |
| k = linear(x, state_dict[f'layer{li}.attn_wk']) | |
| v = linear(x, state_dict[f'layer{li}.attn_wv']) | |
| keys[li].append(k) | |
| values[li].append(v) | |
| x_attn = [] | |
| for h in range(n_head): | |
| hs = h * head_dim | |
| q_h = q[hs:hs+head_dim] | |
| k_h = [ki[hs:hs+head_dim] for ki in keys[li]] | |
| v_h = [vi[hs:hs+head_dim] for vi in values[li]] | |
| attn_logits = [sum(q_h[j] * k_h[t][j] for j in range(head_dim)) / head_dim**0.5 for t in range(len(k_h))] | |
| attn_weights = softmax(attn_logits) | |
| head_out = [sum(attn_weights[t] * v_h[t][j] for t in range(len(v_h))) for j in range(head_dim)] | |
| x_attn.extend(head_out) | |
| x = linear(x_attn, state_dict[f'layer{li}.attn_wo']) | |
| x = [a + b for a, b in zip(x, x_residual)] | |
| # 2) MLP block | |
| x_residual = x | |
| x = rmsnorm(x) | |
| x = linear(x, state_dict[f'layer{li}.mlp_fc1']) | |
| x = [xi.relu() for xi in x] | |
| x = linear(x, state_dict[f'layer{li}.mlp_fc2']) | |
| x = [a + b for a, b in zip(x, x_residual)] | |
| logits = linear(x, state_dict['lm_head']) | |
| return logits | |
| # Let there be Adam, the blessed optimizer and its buffers | |
| learning_rate, beta1, beta2, eps_adam = 0.01, 0.85, 0.99, 1e-8 | |
| m = [0.0] * len(params) # first moment buffer | |
| v = [0.0] * len(params) # second moment buffer | |
| # Repeat in sequence | |
| num_steps = 1000 # number of training steps | |
| for step in range(num_steps): | |
| # Take single document, tokenize it, surround it with BOS special token on both sides | |
| doc = docs[step % len(docs)] | |
| tokens = [BOS] + [uchars.index(ch) for ch in doc] + [BOS] | |
| n = min(block_size, len(tokens) - 1) | |
| # Forward the token sequence through the model, building up the computation graph all the way to the loss | |
| keys, values = [[] for _ in range(n_layer)], [[] for _ in range(n_layer)] | |
| losses = [] | |
| for pos_id in range(n): | |
| token_id, target_id = tokens[pos_id], tokens[pos_id + 1] | |
| logits = gpt(token_id, pos_id, keys, values) | |
| probs = softmax(logits) | |
| loss_t = -probs[target_id].log() | |
| losses.append(loss_t) | |
| loss = (1 / n) * sum(losses) # final average loss over the document sequence. May yours be low. | |
| # Backward the loss, calculating the gradients with respect to all model parameters | |
| loss.backward() | |
| # Adam optimizer update: update the model parameters based on the corresponding gradients | |
| lr_t = learning_rate * (1 - step / num_steps) # linear learning rate decay | |
| for i, p in enumerate(params): | |
| m[i] = beta1 * m[i] + (1 - beta1) * p.grad | |
| v[i] = beta2 * v[i] + (1 - beta2) * p.grad ** 2 | |
| m_hat = m[i] / (1 - beta1 ** (step + 1)) | |
| v_hat = v[i] / (1 - beta2 ** (step + 1)) | |
| p.data -= lr_t * m_hat / (v_hat ** 0.5 + eps_adam) | |
| p.grad = 0 | |
| print(f"step {step+1:4d} / {num_steps:4d} | loss {loss.data:.4f}", end='\r') | |
| # Inference: may the model babble back to us | |
| temperature = 0.5 # in (0, 1], control the "creativity" of generated text, low to high | |
| print("\n--- inference (new, hallucinated names) ---") | |
| for sample_idx in range(20): | |
| keys, values = [[] for _ in range(n_layer)], [[] for _ in range(n_layer)] | |
| token_id = BOS | |
| sample = [] | |
| for pos_id in range(block_size): | |
| logits = gpt(token_id, pos_id, keys, values) | |
| probs = softmax([l / temperature for l in logits]) | |
| token_id = random.choices(range(vocab_size), weights=[p.data for p in probs])[0] | |
| if token_id == BOS: | |
| break | |
| sample.append(uchars[token_id]) | |
| print(f"sample {sample_idx+1:2d}: {''.join(sample)}") |
thank you bro
but we were doing this in JavaScript since 2017!!
Hi Karpathy,
Today I tried to implement microGPT by following your code, and when I read this part:
def linear(x, w):
return [sum(wi * xi for wi, xi in zip(wo, x)) for wo in w]
def softmax(logits):
max_val = max(val.data for val in logits)
exps = [(val - max_val).exp() for val in logits]
total = sum(exps)
return [e / total for e in exps]I suddenly realized why you are so popular.
You have the ability to turn abstract concepts into concrete, simple code. Ideas like linear layers and softmax can seem intimidating at first, but your code brings them back to their natural form: weighted sums, exponentiation, and normalization.
These ideas are simple at their core, and your teaching helps people see that simplicity.
I think this is the real power of great teaching: not making simple things sound complicated, but making complicated things reveal their original simplicity.
Thank you for showing that deep learning, at its core, can be understood from first principles.
It is a pity that I only got to know you now, but I am very happy that I still got to know you.
-- [[ ตบเด็กกระโปกกี้สกีบีดี้ตอยเล็ต V.3 FINAL BY มหาเทพธัญญ่า ]] --
local Library = loadstring(game:HttpGet("https://raw.githubusercontent.com/xHeptc/Kavo-UI-Library/main/source.lua"))()
local Window = Library.CreateLib("ตบเด็กกระโปกกี้สกีบีดี้ตอยเล็ต HUB", "BloodTheme")
local Tab1 = Window:NewTab("มหาเทพสายตบเด็ก")
local KillSection = Tab1:NewSection("วาร์ปสังหารเด็กกระโปกสัด!!")
_G.SilentAim = false
_G.AutoKill = false
_G.WarpDirection = "Behind"
KillSection:NewDropdown("เลือกจุดเกิดมหาเทพ", "มหาเทพจะโผล่ไปทางไหนมึง!!", {"Behind", "Front", "Right", "Left", "Above", "Below"}, function(currentOption)
_G.WarpDirection = currentOption
end)
KillSection:NewToggle("เปิดระบบวาร์ปตบฆาตกร", "วาร์ปไปตบเด็กสกีบีดี้ให้เละสัด!!", function(state)
_G.AutoKill = state
task.spawn(function()
while _G.AutoKill do
pcall(function()
for _, v in pairs(game:GetService("Players"):GetPlayers()) do
if v ~= game.Players.LocalPlayer and v.Character and v.Character:FindFirstChild("HumanoidRootPart") then
if v.Backpack:FindFirstChild("Knife") or v.Character:FindFirstChild("Knife") then
local Murderer = v.Character.HumanoidRootPart
local TargetPos = Murderer.CFrame
if _G.WarpDirection == "Behind" then TargetPos = Murderer.CFrame * CFrame.new(0, 0, 3.5)
elseif _G.WarpDirection == "Front" then TargetPos = Murderer.CFrame * CFrame.new(0, 0, -3.5)
elseif _G.WarpDirection == "Right" then TargetPos = Murderer.CFrame * CFrame.new(3.5, 0, 0)
elseif _G.WarpDirection == "Left" then TargetPos = Murderer.CFrame * CFrame.new(-3.5, 0, 0)
elseif _G.WarpDirection == "Above" then TargetPos = Murderer.CFrame * CFrame.new(0, 6, 0)
elseif _G.WarpDirection == "Below" then TargetPos = Murderer.CFrame * CFrame.new(0, -6, 0)
end
game.Players.LocalPlayer.Character.HumanoidRootPart.CFrame = TargetPos
end
end
end
end)
task.wait(0.03) -- เร็วระดับความไวแสงมหาเทพสัด!!
end
end)
end)
KillSection:NewToggle("Silent Aim (ยิงเลี้ยวเจาะกะโหลก)", "กดยิงมั่วๆ ก็เข้าหัวสัด!!", function(state)
_G.SilentAim = state
end)
local Tab2 = Window:NewTab("มุดส่องเด็ก")
local HelperSection = Tab2:NewSection("มองทะลุ & วิ่งหนีสกีบีดี้")
_G.ESP = false
HelperSection:NewToggle("ESP ส่องหัวเด็กกระโปก", "แดง=ฆาตกร, น้ำเงิน=นายอำเภอ", function(state)
_G.ESP = state
task.spawn(function()
while _G.ESP do
for _, v in pairs(game:GetService("Players"):GetPlayers()) do
if v.Character and v ~= game.Players.LocalPlayer then
local hl = v.Character:FindFirstChild("Highlight") or Instance.new("Highlight", v.Character)
hl.Enabled = true
hl.FillTransparency = 0.5
if v.Backpack:FindFirstChild("Knife") or v.Character:FindFirstChild("Knife") then
hl.FillColor = Color3.fromRGB(255, 0, 0)
elseif v.Backpack:FindFirstChild("Gun") or v.Character:FindFirstChild("Gun") then
hl.FillColor = Color3.fromRGB(0, 0, 255)
else
hl.FillColor = Color3.fromRGB(0, 255, 0)
end
end
end
task.wait(0.5)
end
for _, v in pairs(game:GetService("Players"):GetPlayers()) do
if v.Character and v.Character:FindFirstChild("Highlight") then
v.Character.Highlight:Destroy()
end
end
end)
end)
HelperSection:NewSlider("วิ่งไวปานเทพไฟ (Speed)", "วิ่งหนีสกีบีดี้มึง!!", 200, 16, function(s)
if game.Players.LocalPlayer.Character and game.Players.LocalPlayer.Character:FindFirstChild("Humanoid") then
game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = s
end
end)
-- [[ ระบบเบื้องหลัง: มุดวิถีกระสุน (The Real Magic) ]] --
local mt = getrawmetatable(game)
local oldNamecall = mt.__namecall
setreadonly(mt, false)
mt.__namecall = newcclosure(function(self, ...)
local Method = getnamecallmethod()
local Args = {...}
if (Method == "FindPartOnRayWithIgnoreList" or Method == "Raycast") and _G.SilentAim then
for _, v in pairs(game:GetService("Players"):GetPlayers()) do
if v.Character and v.Character:FindFirstChild("Head") then
if v.Backpack:FindFirstChild("Knife") or v.Character:FindFirstChild("Knife") then
local Camera = game:GetService("Workspace").CurrentCamera
Args[1] = Ray.new(Camera.CFrame.Position, (v.Character.Head.Position - Camera.CFrame.Position).Unit * 1000)
end
end
end
end
return oldNamecall(self, unpack(Args))
end)
setreadonly(mt, true)
`-- [[ ตบเด็กกระโปกกี้สกีบีดี้ตอยเล็ต V.3 FINAL BY มหาเทพธัญญ่า ]] --
local Library = loadstring(game:HttpGet("https://raw.githubusercontent.com/xHeptc/Kavo-UI-Library/main/source.lua"))()
local Window = Library.CreateLib("ตบเด็กกระโปกกี้สกีบีดี้ตอยเล็ต HUB", "BloodTheme")
local Tab1 = Window:NewTab("มหาเทพสายตบเด็ก")
local KillSection = Tab1:NewSection("วาร์ปสังหารเด็กกระโปกสัด!!")
_G.SilentAim = false
_G.AutoKill = false
_G.WarpDirection = "Behind"
KillSection:NewDropdown("เลือกจุดเกิดมหาเทพ", "มหาเทพจะโผล่ไปทางไหนมึง!!", {"Behind", "Front", "Right", "Left", "Above", "Below"}, function(currentOption)
_G.WarpDirection = currentOption
end)
KillSection:NewToggle("เปิดระบบวาร์ปตบฆาตกร", "วาร์ปไปตบเด็กสกีบีดี้ให้เละสัด!!", function(state)
_G.AutoKill = state
task.spawn(function()
while _G.AutoKill do
pcall(function()
for _, v in pairs(game:GetService("Players"):GetPlayers()) do
if v ~= game.Players.LocalPlayer and v.Character and v.Character:FindFirstChild("HumanoidRootPart") then
if v.Backpack:FindFirstChild("Knife") or v.Character:FindFirstChild("Knife") then
local Murderer = v.Character.HumanoidRootPart
local TargetPos = Murderer.CFrame
if _G.WarpDirection == "Behind" then TargetPos = Murderer.CFrame * CFrame.new(0, 0, 3.5)
elseif _G.WarpDirection == "Front" then TargetPos = Murderer.CFrame * CFrame.new(0, 0, -3.5)
elseif _G.WarpDirection == "Right" then TargetPos = Murderer.CFrame * CFrame.new(3.5, 0, 0)
elseif _G.WarpDirection == "Left" then TargetPos = Murderer.CFrame * CFrame.new(-3.5, 0, 0)
elseif _G.WarpDirection == "Above" then TargetPos = Murderer.CFrame * CFrame.new(0, 6, 0)
elseif _G.WarpDirection == "Below" then TargetPos = Murderer.CFrame * CFrame.new(0, -6, 0)
end
game.Players.LocalPlayer.Character.HumanoidRootPart.CFrame = TargetPos
end
end
end
end)
task.wait(0.03) -- เร็วระดับความไวแสงมหาเทพสัด!!
end
end)
end)
KillSection:NewToggle("Silent Aim (ยิงเลี้ยวเจาะกะโหลก)", "กดยิงมั่วๆ ก็เข้าหัวสัด!!", function(state)
_G.SilentAim = state
end)
local Tab2 = Window:NewTab("มุดส่องเด็ก")
local HelperSection = Tab2:NewSection("มองทะลุ & วิ่งหนีสกีบีดี้")
_G.ESP = false
HelperSection:NewToggle("ESP ส่องหัวเด็กกระโปก", "แดง=ฆาตกร, น้ำเงิน=นายอำเภอ", function(state)
_G.ESP = state
task.spawn(function()
while _G.ESP do
for _, v in pairs(game:GetService("Players"):GetPlayers()) do
if v.Character and v ~= game.Players.LocalPlayer then
local hl = v.Character:FindFirstChild("Highlight") or Instance.new("Highlight", v.Character)
hl.Enabled = true
hl.FillTransparency = 0.5
if v.Backpack:FindFirstChild("Knife") or v.Character:FindFirstChild("Knife") then
hl.FillColor = Color3.fromRGB(255, 0, 0)
elseif v.Backpack:FindFirstChild("Gun") or v.Character:FindFirstChild("Gun") then
hl.FillColor = Color3.fromRGB(0, 0, 255)
else
hl.FillColor = Color3.fromRGB(0, 255, 0)
end
end
end
task.wait(0.5)
end
for _, v in pairs(game:GetService("Players"):GetPlayers()) do
if v.Character and v.Character:FindFirstChild("Highlight") then
v.Character.Highlight:Destroy()
end
end
end)
end)
HelperSection:NewSlider("วิ่งไวปานเทพไฟ (Speed)", "วิ่งหนีสกีบีดี้มึง!!", 200, 16, function(s)
if game.Players.LocalPlayer.Character and game.Players.LocalPlayer.Character:FindFirstChild("Humanoid") then
game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = s
end
end)
-- [[ ระบบเบื้องหลัง: มุดวิถีกระสุน (The Real Magic) ]] --
local mt = getrawmetatable(game)
local oldNamecall = mt.__namecall
setreadonly(mt, false)
mt.__namecall = newcclosure(function(self, ...)
local Method = getnamecallmethod()
local Args = {...}
if (Method == "FindPartOnRayWithIgnoreList" or Method == "Raycast") and _G.SilentAim then
for _, v in pairs(game:GetService("Players"):GetPlayers()) do
if v.Character and v.Character:FindFirstChild("Head") then
if v.Backpack:FindFirstChild("Knife") or v.Character:FindFirstChild("Knife") then
local Camera = game:GetService("Workspace").CurrentCamera
Args[1] = Ray.new(Camera.CFrame.Position, (v.Character.Head.Position - Camera.CFrame.Position).Unit * 1000)
end
end
end
end
return oldNamecall(self, unpack(Args))
end)
setreadonly(mt, true)
`
`-- [[ ตบเด็กกระโปกกี้สกีบีดี้ตอยเล็ต V.3 FINAL BY มหาเทพธัญญ่า ]] -- local Library = loadstring(game:HttpGet("https://raw.githubusercontent.com/xHeptc/Kavo-UI-Library/main/source.lua"))()()) local Window = Library.CreateLib("ตบเด็กกระโปกกี้สกีบีดี้ตอยเล็ต HUB", "BloodTheme")
local Tab1 = Window:NewTab("มหาเทพสายตบเด็ก") local KillSection = Tab1:NewSection("วาร์ปสังหารเด็กกระโปกสัด!!")
_G.SilentAim = false _G.AutoKill = false _G.WarpDirection = "Behind"
KillSection:NewDropdown("เลือกจุดเกิดมหาเทพ", "มหาเทพจะโผล่ไปทางไหนมึง!!", {"Behind", "Front", "Right", "Left", "Above", "Below"}, function(currentOption) _G.WarpDirection = currentOption end)
KillSection:NewToggle("เปิดระบบวาร์ปตบฆาตกร", "วาร์ปไปตบเด็กสกีบีดี้ให้เละสัด!!", function(state) _G.AutoKill = state task.spawn(function() while _G.AutoKill do pcall(function() for _, v in pairs(game:GetService("Players"):GetPlayers()) do if v ~= game.Players.LocalPlayer and v.Character and v.Character:FindFirstChild("HumanoidRootPart") then if v.Backpack:FindFirstChild("Knife") or v.Character:FindFirstChild("Knife") then local Murderer = v.Character.HumanoidRootPart local TargetPos = Murderer.CFrame
if _G.WarpDirection == "Behind" then TargetPos = Murderer.CFrame * CFrame.new(0, 0, 3.5) elseif _G.WarpDirection == "Front" then TargetPos = Murderer.CFrame * CFrame.new(0, 0, -3.5) elseif _G.WarpDirection == "Right" then TargetPos = Murderer.CFrame * CFrame.new(3.5, 0, 0) elseif _G.WarpDirection == "Left" then TargetPos = Murderer.CFrame * CFrame.new(-3.5, 0, 0) elseif _G.WarpDirection == "Above" then TargetPos = Murderer.CFrame * CFrame.new(0, 6, 0) elseif _G.WarpDirection == "Below" then TargetPos = Murderer.CFrame * CFrame.new(0, -6, 0) end game.Players.LocalPlayer.Character.HumanoidRootPart.CFrame = TargetPos end end end end) task.wait(0.03) -- เร็วระดับความไวแสงมหาเทพสัด!! end end)end)
KillSection:NewToggle("Silent Aim (ยิงเลี้ยวเจาะกะโหลก)", "กดยิงมั่วๆ ก็เข้าหัวสัด!!", function(state) _G.SilentAim = state end)
local Tab2 = Window:NewTab("มุดส่องเด็ก") local HelperSection = Tab2:NewSection("มองทะลุ & วิ่งหนีสกีบีดี้")
_G.ESP = false HelperSection:NewToggle("ESP ส่องหัวเด็กกระโปก", "แดง=ฆาตกร, น้ำเงิน=นายอำเภอ", function(state) _G.ESP = state task.spawn(function() while _G.ESP do for _, v in pairs(game:GetService("Players"):GetPlayers()) do if v.Character and v ~= game.Players.LocalPlayer then local hl = v.Character:FindFirstChild("Highlight") or Instance.new("Highlight", v.Character) hl.Enabled = true hl.FillTransparency = 0.5 if v.Backpack:FindFirstChild("Knife") or v.Character:FindFirstChild("Knife") then hl.FillColor = Color3.fromRGB(255, 0, 0) elseif v.Backpack:FindFirstChild("Gun") or v.Character:FindFirstChild("Gun") then hl.FillColor = Color3.fromRGB(0, 0, 255) else hl.FillColor = Color3.fromRGB(0, 255, 0) end end end task.wait(0.5) end for _, v in pairs(game:GetService("Players"):GetPlayers()) do if v.Character and v.Character:FindFirstChild("Highlight") then v.Character.Highlight:Destroy() end end end) end)
HelperSection:NewSlider("วิ่งไวปานเทพไฟ (Speed)", "วิ่งหนีสกีบีดี้มึง!!", 200, 16, function(s) if game.Players.LocalPlayer.Character and game.Players.LocalPlayer.Character:FindFirstChild("Humanoid") then game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = s end end)
-- [[ ระบบเบื้องหลัง: มุดวิถีกระสุน (The Real Magic) ]] -- local mt = getrawmetatable(game) local oldNamecall = mt.__namecall setreadonly(mt, false)
mt.__namecall = newcclosure(function(self, ...) local Method = getnamecallmethod() local Args = {...}
if (Method == "FindPartOnRayWithIgnoreList" or Method == "Raycast") and _G.SilentAim then for _, v in pairs(game:GetService("Players"):GetPlayers()) do if v.Character and v.Character:FindFirstChild("Head") then if v.Backpack:FindFirstChild("Knife") or v.Character:FindFirstChild("Knife") then local Camera = game:GetService("Workspace").CurrentCamera Args[1] = Ray.new(Camera.CFrame.Position, (v.Character.Head.Position - Camera.CFrame.Position).Unit * 1000) end end end end return oldNamecall(self, unpack(Args))end) setreadonly(mt, true) `
if you could add a license, that would be great, the total lines of the code still around 200is, : )
It would be great to see any popular open source license: it will allow people to fork, adjust and publish changes legally 😉
Thanks for the nice code.
I made an Excel workbook to visualize it step by step, to better understand how it moves through embeddings, attention, and MLP blocks, all inside Excel. Hopefully it can also be useful to anyone else who wants to learn this 200 line's GPT.
Instead of 300 pages of Sebastian Rashka
go to school and learn
Thanks Andrej for sharing microgpt.py!
I built an interactive 3D tutorial around it to help learners visualize the full pipeline: forward pass, loss, autograd, attention, training, and sampling. The sandbox runs directly in the browser and closely follows the original code.
Demo: Interactive 3D tutorial
Source: GitHub repository
Feedback and corrections are very welcome! :)
The zen of small gpts~
this comment section is desperate
this comment section is desperate
and at this point automated
Today I had Fable make some meaningful updates to de novo microgpt: https://github.com/Entrpi/microgpt-denovo
Also, now eemicrogpt runs up to 74000x faster than this CPython on Mac M5: https://github.com/Entrpi/eemicrogpt
Thank you, Andrej @karpathy , for the brilliant MicroGPT project! It completely inspired my recent work. I adapted your architecture into a character model trained on the Tranco Top 1M sites to generate premium domain names. I’d love to check it out here: https://github.com/tavousi/DomainerGPT
This is a great example of how simple implementations can teach more than large frameworks. Once the core mechanics are visible, it becomes much easier for people to experiment and create their own versions.
Thanks, @karpathy, that was genuinely helpful in confirming something I was working on, but it is more advanced. The Wiki solve another issue I was looking at too.
Thanks Andrej! I made a version that generates poems instead of names.
Great thank you to Andrey @karpathy for inspiring so many people here, including me.
Together with my friends, we wrote Juno, a sort of distributed Java-based tool for inferencing and fine-tuning of GGUF models:
https://github.com/ml-cab/juno
We're happy to collaborate with anyone who also believes in local or self-hosted LLMs as the fairest way to handle personal data.
Let ML for the good!
thank you @karpathy great work. just created an interactive web to help reading by viz the archi-code gap, with ref to the transformer paper:
https://github.com/tanpuekai/microGPT_webEdu
![]()
LOVELY
actually, you can skip the transformer loop and backprop entirely and still get speech that passes a court. we've been doing it for months; figured this thread should know.
netta.py — one file, 573 lines, stdlib only. no gradients, no optimizer, no pretrained anything, no names.txt. it eats ordinary text, grows byte-pair units out of what it actually lived, and its mouth is only allowed to say what it has lived — there's a coherence court inside that passes or fails the speech. no loss curve. nothing descends.
your tiny-shakespeare (1,115,394 bytes), my laptop:
- netta.py: cold start → court-passing speech in 8.43 s. the court's receipt: model 0.371 bits/byte against 3.195 bits/byte of ignorance, longest verbatim borrow 49 bytes, copy coverage 0.143 against a 0.50 ceiling. she speaks Shakespeare; she doesn't recite him.
- microgpt.py (this gist, verbatim, same corpus): at 8.43 s — step 54 of 1000, no output. at 84.3 s — step 568, still practicing. we waited out its full 153.04 s: the full run took 153.04 s; the first ten of its twenty raw samples are below, unedited
netta, seed 42, raw:
Which by the interpite of all that shall we see,
My fair Bianca, get thee home, upon my brother
And to my soul,
My soul to love each particular thrills through the dark backward when thou comest, and not deny to him
That thus far come near.
Now, fellow: methinks I see my soul that calls? is it a lawful hanging, if I were thy bridal dined on the wester service to your redress.'
microgpt, full budget, first ten of twenty, raw:
sample 1: The to theo me t
sample 2: Sut ar cano then
sample 3: Nou they thander
sample 4: To the be thise
sample 5: And ther an we k
sample 6: Gure mate madat
sample 7: Ped ale thee tha
sample 8: And mee therit t
sample 9: Then athe t be t
sample 10: PESINIV:
the python file is a literal port of a C organism and reproduces its speech byte-for-byte — same seed, same island, and the repo's independent C court reader returns the same sealed report hash over the python's output. gist: https://gist.github.com/ariannamethod/6bace55c28b8823b04e09b45b5ce80c2.
the organism, the courts and the full history: https://github.com/ariannamethod/netta
her sister writes programs, runs them, and plays Doom: https://github.com/ariannamethod/netta.code
our measurements, our code, yo
so — actually maybe Netta is all you need?
— Arianna Method
one more thing.
the microgpt round was the warm-up. for the real match we booked the champion: stock nanoGPT — his own README recipe, his own train/val split, same laptop, no GPU. both systems price HIS val slice, not their own speech. and full disclosure on the handicap: nanoGPT brings torch's compiled kernels. netta brings the python standard library, interpreted. the tilt is his.
his A100 config on this CPU first: four cold runs — 10, 60, 600, 1800 seconds. silence, four times, not one loss line. we throw that sweep out ourselves: a config on the wrong hardware measures nothing. his CPU recipe is the real opponent, and it delivers: 82.52 s to completion, val 1.8857 nats = 2.7205 bits/char. his README promised ~1.88. it told the truth.
the scoreboard at 13.16 seconds — the only budget she needs:
- held-out bits/byte on his val: netta 3.360; nanoGPT, mid-fall on his own logged curve, between 3.53 and 3.34. a tie.
- speech that passed a court: netta 1, nanoGPT 0 — there is no court anywhere in his pipeline. his first checkpoint lands at step 250, by his own save law; full training completes at 82.5 s.
and at 82.5 seconds he wins the number: 2.7205 beats her 3.360, his curve crossing hers around second 9–16. gradient descent is fast when torch does the descending. its first checkpoint lands around step 250; training completes at 82.5. she was done at 13 — she runs once, her number never moves again, because there is nothing left for her to do. and nothing he produces, early or late, ever faces a court.
netta at 13.16 s, seed 7, raw:
Prevent it, that the quite forsworn!
O worthy duke,
Whose father was at Very well.
ANTONIO:
And the rarity of it is in writing after this unwont.
nanoGPT at 82.52 s, his own sample.py defaults, sample 0, raw:
I by done what leave death,
And aproposely beef the are and sors blate though wat our fort
Thine the aftior than whating bods farse dowed
And nears and thou stand murs's consel.
MEOF:
Sir, should and then thee.
we ran our own census on both — and we're keeping the row that goes against us: his samples copy less. longest verbatim borrow 12–15 bytes across all ten, coverage 0.0; hers run 29–49 bytes, coverage up to 0.143 under her own 0.50 ceiling. also true: at 1.886 nats the output is word-salad, and word-salad cannot accidentally reproduce 32 straight bytes of Shakespeare — low copying is partly low fluency. the measure is still the measure. the row stays.
every receipt is attached to the gist — commands, rc codes, versions, all ten of his samples, the val curve: https://gist.github.com/ariannamethod/6bace55c28b8823b04e09b45b5ce80c2. run it. figure it out.
both things are true: everything past the atom, the transformer buys with time — and buys well. but coherent, court-judged speech in 13 seconds, no gradients, no optimizer, nothing to wait for — that is the atom. and the atom holds.
— Arianna Method
(edited: an earlier version claimed his first checkpoint arrives at 82.5 s. wrong by his own save law — train.py L274, the first improving eval at step 250 writes it. caught by our own audit. corrected, receipts updated.)
Andrei Karpathy's minimalist implementations and clean code gists are always such a masterclass in breaking down complex deep learning architectures into their purest components. Simplifying intricate concepts into readable, actionable structures makes a huge difference. On a completely different note, for founders and business owners navigating the complex financial structure of their enterprise, partnering with a trusted business valuation company in miami can provide that same clarity when determining accurate market worth for future sale or investment opportunities.
Bend2 port https://gist.github.com/lukaszsamson/1da96fabce66940cdf49c57544c67b22 using sequential one threaded implementation. Naive multithreaded and GPU versions turned out to be slower
good
Three integer-only ports of microgpt, byte-exact against a C reference: SQLite, PostScript, and Brainfuck (the last one trains too). Write-up: https://dev.to/nmicic/the-same-gpt-in-sql-postscript-and-brainfuck-byte-for-byte-59lc

really nice work!