Key Concept: Neural Network คือการนำ Layer มาต่อกัน
โครงข่ายประสาทเทียม (Neural Networks) สร้างขึ้นจากการนำ เลเยอร์ (Layers) หรือโมดูลต่างๆ มาต่อเข้าด้วยกันเพื่อทำการคำนวณ
ใน PyTorch เนมสเปซ torch.nn ได้เตรียมเลเยอร์พื้นฐานทั้งหมดที่คุณต้องใช้ในการสร้างโครงข่ายของคุณเองไว้ให้หมดแล้ว ทุกๆ โมดูลใน PyTorch จะสืบทอดมาจากคลาส nn.Module
1. Flatten
คลี่ข้อมูล 2D เป็น 1D Vector
2. Linear
คูณน้ำหนัก (Weights) + Bias
3. ReLU (Activation)
แปลงค่าติดลบให้เป็นศูนย์
import os
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
การเลือกอุปกรณ์สำหรับ Training
เราต้องการเทรนโมเดลบนตัวเร่งความเร็วฮาร์ดแวร์ (hardware accelerator) เช่น GPU หรือ MPS (Mac) หากมีให้ใช้งาน โค้ดด้านล่างใช้สำหรับตรวจสอบอุปกรณ์ที่มีและตั้งค่า
device = (
"cuda"
if torch.cuda.is_available()
else "mps"
if torch.backends.mps.is_available()
else "cpu"
)
print(f"Using {device} device")
Using cuda device
การกำหนดคลาสโมเดล (Define the Class)
เราจะกำหนดโครงสร้างของโมเดลโดยสร้างคลาสใหม่ที่สืบทอดมาจาก nn.Module:
__init__: กำหนดเลเยอร์ต่างๆ ที่จะนำมาใช้งานในโมเดลforward: กำหนดขั้นตอนการไหลของข้อมูล (Data flow) ว่าเมื่อข้อมูลเข้าสู่โมเดลแล้วจะผ่านเลเยอร์ใดบ้างตามลำดับ
class NeuralNetwork(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(
nn.Linear(28*28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
)
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
model = NeuralNetwork().to(device)
print(model)
NeuralNetwork(
(flatten): Flatten(start_dim=1, end_dim=-1)
(linear_relu_stack): Sequential(
(0): Linear(in_features=784, out_features=512, bias=True)
(1): ReLU()
(2): Linear(in_features=512, out_features=512, bias=True)
(3): ReLU()
(4): Linear(in_features=512, out_features=10, bias=True)
)
)
การใช้งานโมเดล
หากเราต้องการใช้งานโมเดล เราเพียงแค่ส่งข้อมูลป้อนเข้าไป (ตัวอย่างเช่น model(X))
ระบบจะทำการเรียกใช้งานฟังก์ชัน forward ให้อัตโนมัติ (ห้ามเรียก model.forward(X) โดยตรง)
X = torch.rand(1, 28, 28, device=device)
logits = model(X)
# ผลลัพธ์จะเป็นคะแนนดิบ เราใช้ Softmax เพื่อแปลงเป็นความน่าจะเป็น
pred_probab = nn.Softmax(dim=1)(logits)
y_pred = pred_probab.argmax(1)
print(f"Predicted class: {y_pred.item()}")
Predicted class: 7
เจาะลึกการทำงานของ Model Layers
มาดูกันว่าเมื่อเราส่งรูปภาพเสื้อผ้าขนาด 28x28 พิกเซลจำนวน 3 รูปแบบมินิแบทช์ (shape: [3, 28, 28]) ข้อมูลจะถูกแปลงรูปร่างไปอย่างไรบ้าง
1. nn.Flatten
แปลงภาพ 2D ให้กลายเป็น 1D array โดยในที่นี้ ภาพ 28x28 จะถูกคลี่ออกกลายเป็นข้อมูล 784 ค่าเรียงกัน (3 คือจำนวนภาพใน batch คงไว้เหมือนเดิม)
input_image = torch.rand(3,28,28)
flatten = nn.Flatten()
flat_image = flatten(input_image)
print(flat_image.size()) # torch.Size([3, 784])
2. nn.Linear
คือเลเยอร์ที่ทำการ คูณเมทริกซ์และบวกค่า Bias (y = xA^T + b) มันรับข้อมูลขนาด 784 และแปลงออกเป็นขนาด 512
layer1 = nn.Linear(in_features=28*28, out_features=512)
hidden1 = layer1(flat_image)
print(hidden1.size()) # torch.Size([3, 512])
3. nn.ReLU
Activation Function ที่จัดการความไม่เป็นเชิงเส้น (Non-linearity) ให้โมเดลเรียนรู้ฟังก์ชันซับซ้อนได้ โดย ReLU จะกำหนดค่าที่ติดลบให้กลายเป็นศูนย์ทั้งหมด
hidden1 = nn.ReLU()(hidden1)
Model Parameters (พารามิเตอร์ของโมเดล)
หลายเลเยอร์ใน Neural Network มี พารามิเตอร์ (Weights และ Biases) ที่จะถูกปรับเปลี่ยนระหว่างการเทรน
เราสามารถดูพารามิเตอร์ทั้งหมดในโมเดลได้ผ่าน model.parameters()
print(f"Model structure: {model}\n\n")
for name, param in model.named_parameters():
print(f"Layer: {name} | Size: {param.size()} | Values : {param[:2]} \n")
Layer: linear_relu_stack.0.weight | Size: torch.Size([512, 784]) | Values : tensor([[ 0.0273, 0.0296, -0.0084, ... Layer: linear_relu_stack.0.bias | Size: torch.Size([512]) | Values : tensor([-0.0142, 0.0093]) ... Layer: linear_relu_stack.4.weight | Size: torch.Size([10, 512]) | Values : tensor([[-0.0415, -0.0204, 0.0101,...