ข้าม​ไป​ยัง​เนื้อหา

จาก scratch สู่ PyTorch — framework ทำ​สิ่ง​ที่​คุณ​เขียน​มือ

สี่บท​ที่​ผ่าน​มา (บท2–5) เรา​เขียน ทุก​อย่าง ด้วย​มือ — class Value ที่​จำ​ได้​ว่า​ค่า​ไหน​มา​จาก​ค่า​ไหน​แล้ว​ไล่ BackpropagationBackpropagationเดิน​ย้อน​จาก loss หา​ว่า weight แต่ละ​ตัว​มี​ส่วน​ผิด​แค่​ไหน (คือ gradient)Process ย้อน​กลับ​เอง, softmax ที่​ลบ max ต่อ​แถว​กัน​ล้น, cross-entropy บน raw logits, และ loop for p, g: p -= lr * g ที่​ขยับ weight ที​ละ​ก้าว เรา​ทำ​แบบ​นั้น​ด้วย​เหตุผล​เดียว: ให้​เห็น ทุก​การ​คูณ ทุก​การ​บวก gradient ชัดๆ ไม่มี​อะไร​ซ่อน​หลัง​กล่อง​ดำ

บท​นี้​เป็น import torch ครั้ง​แรก​ของ​ทั้ง​คอร์ส — และ​นั่น​ไม่ใช่​เรื่อง​บังเอิญ บท2–5 เรา​กัน framework ออก​ไป​โดย​จงใจ (framework-quarantine) เพื่อ​ไม่​ให้ “ของ​ที่​เน่า​เร็ว” มา​บัง​ของ​ที่​ไม่​เน่า พอ​ถึง​ตรง​นี้​คุณ​เข้าใจ​กลไก​ครบ​แล้ว เรา​จึง graduate ขึ้น​ไป​ใช้ PyTorchPyTorchframework ที่​ทำ autograd+tensor ให้​เรา — graduate จาก​เขียน​มือ​มา​เป็น​เครื่องมือ​จริง (pin version+วัน​ที่​ดึง)Architecture — เครื่องมือ​จริง​ที่​ทำ​สิ่ง​ที่​คุณ​เพิ่ง​เขียน​มือ​ให้​อัตโนมัติ หัวใจ​ของ​บท​นี้​ไม่ใช่ “PyTorch API มี​อะไร​บ้าง” แต่​คือ ตาราง​เทียบ 1-ต่อ-1 ว่า​แต่ละ​บรรทัด​ที่​คุณ​เขียน​มือ​ใน​บท2–5 กลาย​เป็น primitive อะไร​ของ framework — พอ​เห็น​ตาราง​นี้ PyTorch จะ​เลิก​เป็น​เวทมนตร์​ทันที มัน​คือ​ของ​ที่​คุณ​ทำ​เป็นอยู่​แล้ว แค่​มี​คน​ห่อ​ให้

📦 kaen-nn-from-scratch

code ลงมือ​ของ​บท​นี้​อยู่​ใน repo kaen-nn-from-scratch (code ตัวอย่าง​กำลัง​จัด​ทำ) file 06_pytorch.pyบท​นี้​คือ file แรก​ที่​มี import torch ก่อนหน้า​นี้ (บท2–5) grep หา torch จะ​ได้0 hit ตาม​กติกา framework-quarantine รัน​บน CPU เครื่อง​เดียว​ได้ ไม่​ต้อง​มี GPU

ก่อน​อื่น​ติดตั้ง​ลง virtualenv สะ​อาดๆ เรา​ใช้ CPU-only (ไม่​ต้อง​มี GPU) และ​เอา torch ตัว​เดียว ไม่​เอา torchvision/torchaudio เพราะ​คอร์ส​นี้​ไม่​แตะ​ภาพ/เสียง:

Terminal window
python3.12 -m venv .venv && source .venv/bin/activate
pip install torch==2.13.0 --index-url https://download.pytorch.org/whl/cpu
⚠️ pin นี้​ลง​วัน​ที่​ไว้ — ตรวจ​ซ้ำ​ตอน build

torch==2.13.0 คือ​รุ่น stable ปัจจุบัน ณ วัน​ที่​ดึง 2026-07-23 (ขึ้น PyPI เมื่อ 2026-07-08) และ ใช้​กับ Python 3.12 ได้ (torch 2.13.0 รองรับ 3.10–3.14) นี่​ไม่ใช่​เลข​สมมติ — มัน​เป็น​รุ่น​จริง​ที่​รัน​ได้​วัน​นี้ แต่ PyTorch ออกรุ่น​ใหม่​ราวๆ ทุก​ไตรมาส เพราะ​ฉะนั้น​ถ้า​คุณ​อ่าน​บท​นี้​หลัง​จาก​นั้น​นาน ให้​ไป​เช็ก pypi.org/project/torch ก่อน แล้ว​ปรับ pin + วัน​ที่​ดึง​ให้​ตรง​จริง (Colab CPU ก็​ใช้ได้ ปัก!pip install torch==2.13.0 ใน cell แรก​ถ้า​มัน​เลื่อน​ไป​รุ่น​อื่น)

เส้น A — เลข​รุ่น​หมด​อายุ แต่​แนวคิด​ไม่

“ของสด​ใช้ repo, ของ​นิ่ง​ใช้​ตำรา — code ของ Karpathy คือ repo ที่​ยัง​มี​ชีวิต เรา​จึง​อ้าง​ด้วย commit SHA + วัน​ที่​ดึง ไม่ใช่​เลข​รุ่น; ส่วน​คณิต​ที่​ไม่​เน่า​เรา​อ้าง Goodfellow-Bengio-Courville (MIT Press, 2016)”

แปล​ว่า (ใน​บท​นี้): บท​นี้​คือ บท​ที่​เน่า​เร็ว​ที่สุด​ของ​ทั้ง​คอร์ส — API ของ PyTorch เปลี่ยน, เลข​รุ่น​เลื่อน, ชื่อ argument ถูก deprecate นี่​คือ​เหตุผล​ที่​เรา​กัน framework ไว้​ใน​บท6–8 แล้ว pin ทุก​อย่าง​ด้วย version + วัน​ที่​ดึง แต่​หัวใจ​ของ​บท​นี้ — ตาราง​เทียบ ว่า framework ทำ​อะไร​แทน​มือ​คุณ — คือ​แนวคิด​ที่​ไม่​เน่า เลข​รุ่น 2.13.0 จะ​หมด​อายุ แต่​ความ​จริง​ที่​ว่า loss.backward() คือ topo-backward ของ​บท2 นั้น​ไม่​หมด​อายุ จำ​แนวคิด อย่า​จำ​เลข​รุ่น

หัวใจ​ของ​บท: ตาราง​เทียบ “สิ่ง​ที่​คุณ​เขียน​มือ → สิ่ง​ที่ framework ทำให้”

หัวข้อ​ที่​มีชื่อ​ว่า “หัวใจ​ของ​บท: ตาราง​เทียบ “สิ่ง​ที่​คุณ​เขียน​มือ → สิ่ง​ที่ framework ทำให้””

นี่​คือ​ส่วน​ที่​สำคัญ​ที่สุด อ่าน​ตาราง​นี้​ช้าๆ ทุก​แถว​คือ​บรรทัด​ที่​คุณ เขียน​มือ​ไป​แล้ว ในบท2–5 column ขวา​แค่​ห่อ​มัน​ด้วย​ชื่อ​ของ PyTorch:

สิ่ง​ที่​คุณ​เขียน​มือ (บท2–5)PyTorch ทำให้ (บท​นี้)มัน​ทำ​อะไร
Value.data / Value.grad (บท2)Tensor(requires_grad=True) แล้ว​อ่าน .gradtensor เก็บ​ทั้ง ค่า และ gradient ใน​ก้อน​เดียว เหมือน Value แต่​เป็น array หลาย​มิติ​ที​เดียว
topo backward() เขียน​เอง (บท2)autograd tape + loss.backward()PyTorch จด computational graph ให้​อัตโนมัติ​ตอน forward แล้ว​ไล่ chain rule ย้อน​ให้ — คือ AutogradAutogradgraph ที่​จำ​ว่า​ค่า​ไหน​มา​จาก​ค่า​ไหน (computational graph) แล้ว​ไล่ chain rule ให้​อัตโนมัติ — คือ​สิ่ง​ที่ micrograd เป็นProcess ตัว​เดียว​กับ micrograd แต่​คุณ​ไม่​ต้อง​เขียน _backward เอง
parameters = [C, W1, b1, W2, b2] (บท4)nn.Parameter / model.parameters()ประกาศ weight เป็น field ของ nn.Module แล้ว .parameters() รวบ​ให้​เอง​ทั้งหมด ไม่​ต้อง​ถือ list เอง
one-hot @ W (บท3)nn.Embedding(V, d)lookup แถว​ของ​ตาราง embedding ตาม index ตรงๆ — เร็ว​และ​ตรง​กว่า​คูณ one-hot (ผลลัพธ์​เท่า​กัน​เป๊ะ)
x @ W + b (บท4)nn.Linear(in, out)ชั้น linear หนึ่ง​ชั้น เก็บ W/b ให้​ใน​ตัว init สเกล​ให้​เหมาะ​ให้​ด้วย
softmax + NLL เขียน​มือ (บท3–4)F.cross_entropy(logits, y)fuse log-softmax + NLL ใน​ก้าว​เดียว รับ raw logits + integer target — ทำ max-subtraction กัน overflow ให้​ใน​ตัว
for p, g: p -= lr * g (บท4)optim.SGD / optim.AdamW + opt.step()optimizer อัปเดต weight ทุก​ตัว​ให้​ใน​บรรทัด​เดียว (AdamW ปรับ lr ต่อ parameter ให้​อีก)
reset grad เอง W.grad = 0 (บท2)optimizer.zero_grad()ล้าง gradient เก่า​ก่อน​ก้าว​ใหม่ — จำเป็น​เพราะ PyTorch สะสม grad เหมือน​กฎ += ในบท2 เป๊ะ
flowchart LR
  subgraph HAND["เขียนมือ (บท2–5)"]
    H1["Value.data / .grad"]
    H2["topo backward() เขียนเอง"]
    H3["parameters = [C, W1, b1, W2, b2]"]
    H4["one-hot @ W · x@W+b"]
    H5["softmax + NLL เขียนมือ"]
    H6["for p: p -= lr*p.grad  ·  W.grad = 0"]
  end
  subgraph TORCH["PyTorch (บทนี้)"]
    T1["Tensor(requires_grad=True)"]
    T2["autograd tape + loss.backward()"]
    T3["nn.Parameter / model.parameters()"]
    T4["nn.Embedding · nn.Linear"]
    T5["F.cross_entropy (raw logits)"]
    T6["optim.AdamW: step() + zero_grad()"]
  end
  H1 --> T1
  H2 --> T2
  H3 --> T3
  H4 --> T4
  H5 --> T5
  H6 --> T6

  classDef tbl fill:#fde68a,stroke:#92400e,color:#451a03;
  classDef acc fill:#7c2d12,stroke:#431407,color:#fed7aa;
  class H1,H2,H3,H4,H5,H6 tbl;
  class T1,T2,T3,T4,T5,T6 acc;

คำ​บรรยาย​ภาพ: ตาราง​เทียบ​แบบ 1-ต่อ-1 ระหว่าง​สิ่ง​ที่​เรา​เขียน​มือ​ใน​บท2–5 (column ซ้าย) กับ primitive ของ PyTorch ที่​ทำ​สิ่ง​เดียวกัน​ให้ (column ขวา) — Value.data/.grad กลาย​เป็น Tensor(requires_grad=True), topo-backward ที่​เขียน​เอง​กลาย​เป็น loss.backward(), list ของ weight กลาย​เป็น model.parameters(), one-hot คูณ W กับ x@W+b กลาย​เป็น nn.Embedding/nn.Linear, softmax+NLL เขียน​มือ​กลาย​เป็น F.cross_entropy บน raw logits, และ loop อัปเดต + การ​ล้าง grad กลาย​เป็น optim.AdamW กับ zero_grad()/step() ทุก​ลูกศร​ชี้​จาก “ของ​ที่​คุณ​ทำ​เป็น​แล้ว” ไป​ยัง “ชื่อ​ที่ framework เรียก​มัน” — ไม่มี​แนวคิด​ใหม่ มี​แต่​ชื่อ​ใหม่

เส้น C — column ขวา​คือ​เครื่อง​ที่ agent ของ​คุณ​เรียก​ใช้

“backprop ตัว​เดียวกัน​นี้​แหละ​ที่​หมุน​อยู่​ข้าง​ใน model ที่ agent ของ​คุณ​ใน #15-#18 เรียก​ผ่าน API — เข้าใจ​มัน​แล้ว​จะ​เห็น​ทั้ง​กอง​ตั้งแต่ neuron ยัน tool-call; แต่​พูดตรงๆ: ไม่รู้ backprop ก็​สร้าง agent ได้”

แปล​ว่า (ใน​บท​นี้): column ขวา​ของ​ตาราง​ข้าง​บน — nn.Embedding, nn.Linear, F.cross_entropy, loss.backward(), AdamW.step() — คือ primitive ชุด​เดียวกันเป๊ะ ที่ model จริง​หลัง API ของ #15–#18 ใช้​เทรน​ตัวเอง model ของ Anthropic/OpenAI ไม่​ได้​ใช้​เวทมนตร์​ลึกลับ มัน​คือ tensor + autograd + optimizer ที่​สเกล​ขึ้น​มหาศาล​บน primitive ชุด​นี้ พอ​คุณ​อ่าน​ตาราง​ออก คุณ​กำลัง​มอง​เห็น “ทั้ง​กอง” ที่​หมุน​อยู่​หลัง client.messages.create(...) — แต่​ย้ำ​เหมือน​เดิม: นี่​เป็น สะพาน​ความ​เข้าใจ ไม่ใช่ prerequisite ไม่รู้​ตาราง​นี้​ก็​สร้าง agent ได้

ทีนี้​เอา​ตาราง​มา​ใช้​จริง — เรา​จะ​เขียน MLP ของ​บท4 ใหม่​ทั้ง​ตัว แต่​คราว​นี้​ให้ PyTorch ทำ backward ให้ จำ model บท4 ได้​ไหม: ตาราง embedding C → ต่อ​เวกเตอร์ → tanh(·@W1+b1)@W2+b2 → logits แล้ว​เรา​คำนวณ dC, dW1, ..., dW2 ด้วย​มือ​กัน​ยาวเหยียด ตอน​นี้​ทุก​อย่าง​นั้น​ยุบ​เหลือ​เท่า​นี้:

import torch
import torch.nn as nn
import torch.nn.functional as F
V, n_embd, n_hidden = 27, 10, 200 # vocab / มิติ embedding / ชั้นซ่อน — เลขเดียวกับบท4
class BigramMLP(nn.Module):
def __init__(self, V, n_embd=10, n_hidden=200):
super().__init__()
self.emb = nn.Embedding(V, n_embd) # แทนตาราง C (27,10) ของบท4
self.fc1 = nn.Linear(n_embd, n_hidden) # แทน W1,b1 (คูณ + บวก bias ในตัว)
self.fc2 = nn.Linear(n_hidden, V) # แทน W2,b2
def forward(self, idx):
x = self.emb(idx) # lookup embedding
h = torch.tanh(self.fc1(x)) # ชั้นซ่อน tanh — เหมือนบท4
return self.fc2(h) # <<< คืน RAW LOGITS (ยัง 'ไม่' softmax)
model = BigramMLP(V).to("cpu")
opt = torch.optim.AdamW(model.parameters(), lr=0.01) # optimizer รวบ weight ให้เอง
รูป​ย่อ​ระดับ bigram — และ​วิธี​ต่อยอด​เป็น context 3 ตัว​แบบ​บท4

BigramMLP ตัว​นี้​รับ index ตัว​เดียว (idx รูป (N,)) เพื่อ​โชว์ primitive ให้​สะอาด​ที่สุด — เป็น bigram (มอง​ย้อน 1 ตัว) ถ้า​อยาก​ได้ context 3 ตัว​เต็ม​แบบ​บท4 (block_size=3) หลักการ​เดิม​เป๊ะ เพิ่ม​แค่​ขั้น flatten: x = self.emb(idx) จะ​ได้ (N, 3, 10) แล้ว x = x.view(x.shape[0], -1) ให้​เป็น (N, 30) ก่อน​เข้า fc1 (และ​ตั้ง nn.Linear(block_size*n_embd, n_hidden)) — นี่​คือ .reshape(-1, 30) ที่​ต้อง match fan_in=30 ของ​บท4 นั่นเอง โครง​เดิม เพิ่ม​บรรทัด​เดียว

สังเกต​ว่า forward คืน raw logits ไม่มี softmax เลย — นี่​ตั้งใจ เพราะ F.cross_entropy อยาก​ได้ logits ดิบๆ (เดี๋ยว​อธิบาย​ว่า​ทำไม​ใน​กับดัก​ถัด​ไป) ตอน​นี้​มา​ดู loop เทรน เทียบ​กับ loop บท4 ที่​ยาว​เป็น​หน้า:

for step in range(10000):
logits = model(Xb) # forward — autograd จด graph ให้เอง
loss = F.cross_entropy(logits, Yb) # Yb: LongTensor ของ 'class index' (ไม่ใช่ one-hot)
opt.zero_grad() # 1) ล้าง grad เก่า (ไม่งั้นสะสม — bug เดียวกับบท2)
loss.backward() # 2) autograd ไล่ chain rule ย้อนให้ทั้ง graph
opt.step() # 3) optimizer ขยับ weight ทุกตัวหนึ่งก้าว
if step % 1000 == 0:
print(step, float(loss)) # float(loss) ดึงตัวเลขออกโดยไม่แตะ tape

ทั้ง dW2 = h.T @ dlogits, dh = dlogits @ W2.T, np.add.at(dC, Xb, demb) และ​เพื่อนๆ ของ​บท4 — หาย​ไป​หมด เหลือ​แค่ loss.backward() บรรทัด​เดียว นี่​คือ​สิ่ง​ที่ framework ซื้อ​ให้​คุณ: คุณ​เข้าใจ​ว่า​มัน​ทำ​อะไร (เพราะ​เขียน​มือ​มา​แล้ว) แต่​ไม่​ต้อง​เขียน​ซ้ำ​อีก ลำดับ​สาม​บรรทัด zero_grad → backward → step เป็น​ท่า​ประจำ — จำ​ให้​ขึ้นใจ

PyTorch อยู่​มา​นาน API เปลี่ยน​หลาย​รอบ code เก่า​ใน Stack Overflow เต็ม​ไป​ด้วย​ท่า​ที่​ตาย​แล้ว นี่​คือ​กับดัก​ที่​เจอ​บ่อย​ที่สุด:

Variable ตาย​แล้ว — code เก่า​ห่อ tensor ด้วย torch.autograd.Variable(x) เพื่อ​ให้​มัน track gradient เดี๋ยวนี้ Variable ถูกรวม​เข้า​กับ Tensor ไป​นาน​แล้ว ✅ ใช้ torch.tensor(x, requires_grad=True) หรือ x.requires_grad_(True) ตรงๆ เห็น Variable ที่ไหน = สัญญาณ​ว่า code นั้น​เก่า​มาก

❌ ยุ่ง​กับ .data ดิบๆ → grad เพี้ยน​เงียบๆ — การ​เขียน x.data เพื่อ “แอบ” แก้​ค่า​โดย​เลี่ยง autograd เป็น​บ่อเกิด​ของ bug ที่​ไม่ error แต่ grad ผิด ✅ อยาก​ตัด​ออก​จาก tape ใช้ x.detach(); อยาก​รัน​ช่วง​ที่​ไม่​ต้อง track grad (เช่น​ตอน eval) ครอบ​ด้วย with torch.no_grad():; อยาก log ตัวเลข loss ใช้ float(loss) หรือ loss.item() — อย่า​ไป​แตะ .data

❌ ลืม zero_grad() → grad บวก​สะสม​ข้าม​ก้าว — PyTorch สะสม gradient โดย design (+= เหมือน​กฎ fan-out ของ​บท2 เป๊ะ) ถ้า​ลืม​ล้าง grad ของ​ก้าว​ที่​แล้ว​จะ​บวก​ทับ​ก้าว​นี้ ทิศ​เพี้ยน model ไม่​ลู่​เข้า ✅ เรียก opt.zero_grad() ก่อน backward() ทุก​ก้าว — นี่​คือ bug เดียว​กับ​ที่​บท2 ย้ำ​เรื่อง reset grad

❌ softmax เอง​ก่อน​แล้ว​ส่ง​เข้า F.cross_entropy (double-softmax)F.cross_entropy ทำ log-softmax ใน​ตัว​อยู่​แล้ว ถ้า​คุณ F.softmax(logits) ก่อน​แล้ว​ส่ง​เข้าไป = softmax สอง​รอบ ผิด (loss จะ​ดู​โอเค​แต่ model เรียน​ไม่​เต็ม​ที่) ✅ ส่ง raw logits เข้า F.cross_entropy ตรงๆ (นี่​คือ​เหตุผล​ที่ forward ของ​เรา​คืน logits ดิบ) และ target เป็น integer class index ไม่ใช่ one-hot ไม่ใช่ log-prob

❌ สลับ​ลำดับ​สาม​บรรทัด — เช่น step() ก่อน backward() (อัปเดต​ด้วย grad เก่า/ว่าง) หรือ zero_grad() หลัง backward() (ล้าง grad ที่​เพิ่ง​คำนวณ​ทิ้ง) ✅ ลำดับ​ต้อง​เป็น zero_grad() → backward() → step() เสมอ — ล้าง, คำนวณ, ขยับ ตาม​นั้น

เส้น B — นี่​คือ​ของ​จิ๋ว​เพื่อ​เข้าใจ ไม่ใช่​ของ deploy

“เรา​สร้าง​เพื่อ​เข้าใจ ไม่ใช่​เพื่อ deploy — micrograd กับ nano-GPT ตัว​จิ๋ว​ใน​คอร์ส​นี้​รัน​บน CPU เครื่อง​เดียว​ได้; แต่ LLM จริง​กิน​ทั้ง GPU cluster, ข้อมูล​ระดับ​เท​ระ, เวลา​เป็น​เดือน — สเกล​ที่​คอร์ส​นี้ ‘ไม่’ จำลอง”

แปล​ว่า (ใน​บท​นี้): การ graduate มา PyTorch ไม่​ได้ แปล​ว่า​เรา​กำลัง​ทำ​ของ production ขึ้น​มา BigramMLP ยัง​รัน​บน CPU เครื่อง​เดียว เทรน​ได้​ใน​ไม่​กี่​นาที เหมือน​เดิม สิ่ง​ที่ framework ให้​คือ ความ​สะดวก (backward อัตโนมัติ, optimizer สำเร็จรูป) และ ประตู​สู่ GPU — แต่ training stack จริง (data pipeline, distributed, mixed-precision, checkpointing) ยัง​อยู่​นอก​คอร์ส​นี้​ตาม design PyTorch เป็น​เครื่องมือ ไม่ใช่​เส้นชัย

บท​นี้​เรา graduate จาก “เขียน​มือ​ทุก​อย่าง” มา​เป็น PyTorch — import torch ครั้ง​แรก​ของ​คอร์ส: TensorTensorarray หลาย​มิติ หน่วย​ข้อมูล​พื้นฐาน​ของ PyTorchArchitecture เก็บ​ทั้ง​ค่า​และ gradient เหมือน Value แต่​เป็น array, loss.backward() คือ topo-backward ของ​บท2 ที่ autograd ทำให้​อัตโนมัติ, nn.Embedding/nn.Linear คือ one-hot@W และ x@W+b, F.cross_entropy fuse softmax+NLL บน raw logits, และ optim.AdamW + zero_grad()→backward()→step() แทน loop อัปเดต​ที่​เขียน​มือ หัวใจ​คือ ตาราง​เทียบ — PyTorch ไม่ใช่​แนวคิด​ใหม่ มัน​คือ​ชื่อ​ใหม่​ของ​สิ่ง​ที่​คุณ​ทำ​เป็น​แล้ว และ​กับดัก API-churn (Variable ตาย, อย่า​แตะ .data, อย่า​ลืม zero_grad, อย่า double-softmax, ลำดับ​สาม​บรรทัด​ห้าม​สลับ) คือ​ราคา​ของ​การ​อยู่​บน​เครื่องมือ​ที่​ยัง​มี​ชีวิต จึง​ต้อง pin version + วัน​ที่​ดึง​เสมอ

บท​หน้า​เรา​จะ​ใช้ primitive ชุด​นี้​สร้าง​ของ​ที่​ใหญ่​กว่า MLP มาก — self-attention และ transformer ตัว​จิ๋ว กลไก​ที่​ทำให้​แต่ละ token “มอง​ย้อน” ไป token อื่น​แล้ว​ชั่ง​น้ำหนัก​ว่า​อัน​ไหน​สำคัญ นี่​คือ​โครง​ที่ LLM จริง​หลัง API ใช้ และ​เป็น​บันได​ขั้น​สุดท้าย​ก่อน capstone


🔗 อ้างอิง​ต้นทาง​ของ​บท​นี้

บท​นี้​อิง​ต้นทาง​ที่​ลง​วัน​ที่​กำกับ อ่าน​ต่อ​ได้​โดยตรง:

  • PyTorch — project บน PyPI (torch==2.13.0) (S16, รุ่น 2.13.0 ขึ้น PyPI 2026-07-08; เข้าถึง 2026-07-23 ⚠️VERIFY-AT-BUILD) — เลข​รุ่น​ที่ pin ไว้​ใน​บท​นี้; PyTorch ออกรุ่น​ใหม่​ราว​ทุก​ไตรมาส ตรวจ​ซ้ำ​ก่อน build ทุก​ครั้ง แล้ว​ปรับ pin + วัน​ที่​ดึง​ให้​ตรง​จริง (เส้น A)
  • PyTorch — Get Started / Locally (คำ​สั่ง​ติดตั้ง CPU/CUDA) (S16, เข้าถึง 2026-07-23 ⚠️VERIFY-AT-BUILD) — ที่มา​ของ​คำ​สั่ง pip install torch --index-url .../whl/cpu; หน้า​นี้​สร้าง​คำ​สั่ง​ติดตั้ง​ตาม OS/platform ให้
  • Goodfellow, Bengio, Courville — Deep Learning (MIT Press, 2016) (S8) — ตำรา​คณิต​ที่ “นิ่ง”: หลักการ autograd/backprop ที่ loss.backward() ทำให้​อัตโนมัติ​อ้าง​ได้ที่ §6.5 (timeless-math-only; ติด​ป้าย “stale-on-modern-practice” ตรง​ที่​แตะ optimizer/normalization สมัย​ใหม่) (เส้น A/D)

เช็กความเข้าใจ — บทที่ 6

ข้อ 1 / 3

`F.cross_entropy` ต้องการอะไรเป็น input และทำไม?