Học PyTorch Qua Các Ví Dụ Thựcexperience

PyTorch cung cấp hai tính năng cốt lõi: (1) Tensor n-chiều tương tự numpy nhưng hỗ trợ tính toán trên GPU; (2) Cơ chế tự động tính đạo hàm (autograd) phục vụ huấn luyện mạng nơ-ron. Bài viết này trình bày các khái niệm nền tảng thông qua bài toán nội suy hàm \(y = \sin(x)\) bằng một đa thức bậc ba, với mục tiêu minimization khoảng cách Euclid giữa đầu ra dự đoán và giá trị thực.

Grip đầu: triển khai với NumPy

Thuật toán bắt đầu từ việc dùng NumPy — một thư viện số học性价比 cao nhưng không hỗ trợ GPU. Despite thiếu khái niệm computation graph hay gradient tự động, NumPy đủ mạnh để mô phỏng前-most và backward pass thủ công cho bài toán tối ưu hóa.

import numpy as np
import math

# Dữ liệu đầu vào và đầu ra
x = np.linspace(-math.pi, math.pi, 2000)
y = np.sin(x)

# Khởi tạo ngẫu nhiên hệ số
a = np.random.randn()
b = np.random.randn()
c = np.random.randn()
d = np.random.randn()

lr = 1e-6
for epoch in range(2000):
    # Forward pass: y = a + b*x + c*x^2 + d*x^3
    y_pred = a + b * x + c * x**2 + d * x**3
    
    # Tính loss: tổng bình phương sai số
    loss = np.sum((y_pred - y)**2)
    if epoch % 100 == 99:
        print(epoch, loss)

    # Backward pass: tính gradient thủ công
    grad_y = 2 * (y_pred - y)
    grad_a = np.sum(grad_y)
    grad_b = np.sum(grad_y * x)
    grad_c = np.sum(grad_y * x**2)
    grad_d = np.sum(grad_y * x**3)

    # Cập nhật tham số
    a -= lr * grad_a
    b -= lr * grad_b
    c -= lr * grad_c
    d -= lr * grad_d

print(f"Kết quả: y = {a} + {b}x + {c}x^2 + {d}x^3")

Chuyển sang PyTorch Tensor

PyTorch mở rộng hiện thực tensor của NumPy — không chỉ về mặt cấu trúc dữ liệu mà còn thêm khả năng tự động tính gradient, đồng thời hỗ trợ tính toán song song trên GPU bằng cách gán device=torch.device('cuda:0').

import torch
import math

dtype = torch.float
device = torch.device('cpu')  # Hoặc 'cuda:0' nếu có GPU
x = torch.linspace(-math.pi, math.pi, 2000, device=device, dtype=dtype)
y = torch.sin(x)

# Khởi tạo tham số với requires_grad=True để theo dõi gradient
a = torch.randn((), device=device, dtype=dtype, requires_grad=True)
b = torch.randn((), device=device, dtype=dtype, requires_grad=True)
c = torch.randn((), device=device, dtype=dtype, requires_grad=True)
d = torch.randn((), device=device, dtype=dtype, requires_grad=True)

lr = 1e-6
for epoch in range(2000):
    # Forward pass
    y_pred = a + b*x + c*x**2 + d*x**3
    loss = (y_pred - y).pow(2).sum()

    # Backward pass với autograd
    loss.backward()

    # Cập nhật tham số và reset gradient
    with torch.no_grad():
        [param.sub_(lr * param.grad) for param in (a, b, c, d)]
        [setattr(param, 'grad', None) for param in (a, b, c, d)]

    if epoch % 100 == 99:
        print(epoch, loss.item())

Autograd và Khai báo Đạo hàm Tự định nghĩa

Autograd trong PyTorch xây dựng đồ thị tính toán động, nơi mỗi tensor có requires_grad=True tự theo dõi gradient. Trong ví dụ trên, chỉ cần gọi loss.backward() là đủ — hệ thống sẽ tự động lan truyền gradient theo chiều ngược.

Để mở rộng khả năng, bạn có thể định nghĩa hàm tính toán riêng bằng cách kế thừa torch.autograd.Function. Dưới đây là triển khai đa thức Legendre bậc ba: \(P_3(x) = \frac{1}{2}(5x^3 - 3x)\).

class LegendrePolynomial3(torch.autograd.Function):
    @staticmethod
    def forward(ctx, input_tensor):
        ctx.save_for_backward(input_tensor)
        return 0.5 * (5 * input_tensor**3 - 3 * input_tensor)

    @staticmethod
    def backward(ctx, grad_output):
        input_tensor, = ctx.saved_tensors
        return grad_output * 1.5 * (5 * input_tensor**2 - 1)

# Sử dụng trong mô hình: y = a + b * P3(c + d*x)
P3 = LegendrePolynomial3.apply
y_pred = a + b * P3(c + d * x)
loss = (y_pred - y).pow(2).sum()
loss.backward()

Mô hình hóa với nn.Module

Để tránh lặp lại mã và dễ truy xuất tham số, PyTorch cung cấp lớp nn.Module. Dưới đây là triển khai đa thức bậc ba thành module riêng:

class PolynomialModel(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.coeffs = torch.nn.ParameterDict({
            'a': torch.nn.Parameter(torch.randn(())),
            'b': torch.nn.Parameter(torch.randn(())),
            'c': torch.nn.Parameter(torch.randn(())),
            'd': torch.nn.Parameter(torch.randn(())),
        })

    def forward(self, x):
        return (
            self.coeffs['a'] +
            self.coeffs['b'] * x +
            self.coeffs['c'] * x**2 +
            self.coeffs['d'] * x**3
        )

    def describe(self):
        return (
            f"y = {self.coeffs['a'].item():.3f} + "
            f"{self.coeffs['b'].item():.3f}x + "
            f"{self.coeffs['c'].item():.3f}x² + "
            f"{self.coeffs['d'].item():.3f}x³"
        )

model = PolynomialModel()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = torch.nn.MSELoss()

for epoch in range(2000):
    optimizer.zero_grad()
    pred = model(x)
    loss = criterion(pred, y)
    loss.backward()
    optimizer.step()

print(model.describe())

###ظم hợp động: Mô hình Đa thức Động với Trọng số Chia sẻ

Đây là ví dụ minh họa đồ thị tính toán độngtrọng số chia sẻ: mỗi lần gọi forward, mô hình chọn ngẫu nhiên bậc đa thức trong khoảng [3,5], và hệ số \(e\) được dùng chung cho cả bậc 4 và 5.

class DynamicHighOrder(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.a = torch.nn.Parameter(torch.randn(()))
        self.b = torch.nn.Parameter(torch.randn(()))
        self.c = torch.nn.Parameter(torch.randn(()))
        self.d = torch.nn.Parameter(torch.randn(()))
        self.e = torch.nn.Parameter(torch.randn(()))

    def forward(self, x):
        y = self.a + self.b * x + self.c * x**2 + self.d * x**3
        highest_degree = random.randint(4, 5)
        for exp in range(4, highest_degree + 1):
            y += self.e * x**exp  # Trọng số e dùng chung
        return y

model = DynamicHighOrder()
optimizer = torch.optim.SGD(model.parameters(), lr=1e-8, momentum=0.9)
criterion = torch.nn.MSELoss()

for epoch in range(30_000):
    optimizer.zero_grad()
    loss = criterion(model(x), y)
    loss.backward()
    optimizer.step()

Thẻ: PyTorch tensor autograd numpy gpu-acceleration

Đăng vào ngày 6 tháng 6 lúc 03:43