Lập trình hướng đối tượng (OOP)
Mục tiêu
Phần tiêu đề “Mục tiêu”Sau bài này, bạn sẽ:
- Hiểu rõ bản chất của Lớp (Class) và Đối tượng (Object), làm chủ phương thức khởi tạo
__init__và tham số thực thểself. - Phân biệt biến thực thể (instance attribute) độc lập với biến lớp (class attribute) dùng chung để tránh lỗi rò rỉ trọng số mô hình.
- Nắm vững 4 trụ cột của lập trình hướng đối tượng (Đóng gói, Kế thừa, Đa hình, Trừu tượng) và liên hệ trực tiếp với các framework AI hàng đầu như PyTorch và Scikit-Learn.
- Sử dụng các phương thức ma thuật (dunder methods như
__len__,__getitem__,__call__) để xây dựng các lớp nạp dữ liệu và mô hình máy học chuyên nghiệp.
Cần biết trước
Phần tiêu đề “Cần biết trước”- Hàm, chuỗi, đọc/ghi file, thuộc phần Python (Đã học)
Trực giác
Phần tiêu đề “Trực giác”Hãy tưởng tượng bạn đang xây dựng một hệ thống thị giác máy tính với 50 tầng mạng nơ-ron:
- Mỗi tầng mạng có hàng nghìn tham số ma trận trọng số và hệ số chệch .
- Mỗi tầng cần lưu lại kết quả trung gian để phục vụ thuật toán lan truyền ngược (backpropagation).
- Nếu chỉ dùng các hàm rời rạc và các biến từ điển (
dict) trôi nổi, bạn sẽ phải liên tục truyền hàng chục tham số qua lại giữa các hàm. Chỉ cần sơ suất gán nhầm tên biến, toàn bộ hệ thống sẽ sụp đổ trong im lặng.
Lập trình hướng đối tượng (OOP) giải quyết triệt để bài toán này. Nó cho phép bạn coi mỗi tầng mạng như một “cỗ máy nhỏ” tự quản:
- Cỗ máy tự cất giữ trọng số riêng bên trong thân máy (Đóng gói).
- Cỗ máy có thể được nâng cấp từ một thiết kế chuẩn có sẵn mà không cần chế tạo lại từ đầu (Kế thừa).
- Bất kỳ cỗ máy nào cũng chỉ cần một nút bấm “Dự đoán” duy nhất để vận hành, dù bên trong là mạng tích chập hay mạng Transformer (Đa hình).
Lý thuyết
Phần tiêu đề “Lý thuyết”Lớp (Class), Đối Tượng (Object) và self
Phần tiêu đề “Lớp (Class), Đối Tượng (Object) và self”- Lớp (Class): Là một bản thiết kế (blueprint) định nghĩa cấu trúc dữ liệu và các thao tác có thể thực hiện.
- Đối tượng (Object / Instance): Là một thực thể cụ thể được sinh ra trong bộ nhớ từ bản thiết kế đó.
__init__: Phương thức khởi tạo đặc biệt được Python tự động kích hoạt khi một đối tượng mới được tạo ra.self: Tham số đầu tiên trong các phương thức thực thể, đại diện cho chính đối tượng đang thực hiện hành vi.
class Neuron: def __init__(self, weight: float, bias: float): # Thuộc tính thực thể (instance attributes) self.w = weight self.b = bias
def activate(self, x: float) -> float: # Phương thức thực thể (instance method) return self.w * x + self.bPhân Biệt Biến Lớp và Biến Thực Thể
Phần tiêu đề “Phân Biệt Biến Lớp và Biến Thực Thể”Một trong những cạm bẫy lớn nhất trong lập trình AI là nhầm lẫn giữa hai loại biến:
- Biến thực thể (Instance Attribute): Được gán thông qua
self.ten_bienbên trong các phương thức. Mỗi đối tượng sở hữu một vùng nhớ độc lập hoàn toàn. - Biến lớp (Class Attribute): Được định nghĩa trực tiếp trong thân
class, nằm ngoài mọi phương thức. Tất cả các đối tượng tạo từ lớp này đều trỏ chung vào cùng một vùng nhớ. Nếu biến lớp là kiểu khả biến (nhưlisthaydict), việc một đối tượng sửa đổi sẽ làm thay đổi giá trị của tất cả đối tượng còn lại!
4 Trụ Cột OOP Ứng Dụng Trong AI
Phần tiêu đề “4 Trụ Cột OOP Ứng Dụng Trong AI”1. Tính Đóng Gói (Encapsulation)
Phần tiêu đề “1. Tính Đóng Gói (Encapsulation)”Đóng gói là cơ chế gom nhóm dữ liệu (thuộc tính) và các hàm thao tác trên dữ liệu đó (phương thức) vào cùng một đơn vị, đồng thời hạn chế sự can thiệp trực tiếp từ bên ngoài.
Trong Python, ta dùng quy ước đặt tên với dấu gạch dưới:
_attribute: Biến nội bộ (protected convention), cảnh báo người dùng không nên truy cập trực tiếp từ bên ngoài.__attribute: Kích hoạt cơ chế đổi tên (name mangling) để tránh xung đột tên trong kế thừa.
2. Tính Kế Thừa (Inheritance)
Phần tiêu đề “2. Tính Kế Thừa (Inheritance)”Kế thừa cho phép một lớp mới (lớp con - child class) tiếp nhận toàn bộ thuộc tính và phương thức của một lớp đã có (lớp cha - parent class), đồng thời mở rộng hoặc định nghĩa lại (override) các hành vi cần thiết.
Trong PyTorch, mọi mô hình học sâu đều bắt buộc kế thừa từ torch.nn.Module:
# Lớp con kế thừa lớp cha nn.Moduleclass MyClassifier(nn.Module): def __init__(self, in_features: int, out_features: int): super().__init__() # Kích hoạt khởi tạo của nn.Module self.linear = nn.Linear(in_features, out_features)
def forward(self, x): return self.linear(x)Hàm super().__init__() kích hoạt hạ tầng của nn.Module, giúp mô hình tự động quản lý gradient, theo dõi thiết bị (CPU/GPU) và lưu trữ checkpoint.
3. Tính Đa Hình (Polymorphism)
Phần tiêu đề “3. Tính Đa Hình (Polymorphism)”Đa hình là khả năng các đối tượng khác nhau phản hồi theo cách riêng của mình trước cùng một lời gọi phương thức.
Hệ sinh thái Scikit-Learn là ví dụ điển hình nhất về tính đa hình:
- Mọi mô hình ước lượng (Estimator) — từ
LinearRegression,DecisionTreeClassifierđếnRandomForestRegressor— đều cung cấp hai phương thức chuẩn hóa:model.fit(X, y): Huấn luyện tìm tham số tối ưu.model.predict(X): Suy luận đưa ra kết quả dự đoán.
- Nhờ đa hình, bạn có thể viết một hàm kiểm thử duy nhất nhận bất kỳ mô hình nào vào làm tham số mà không cần sửa đổi dù chỉ một dòng code.
4. Tính Trừu Tượng (Abstraction)
Phần tiêu đề “4. Tính Trừu Tượng (Abstraction)”Trừu tượng hóa là việc ẩn đi các chi tiết cài đặt phức tạp bên dưới, chỉ cung cấp ra bên ngoài một giao diện làm việc tối giản và thiết yếu.
Python hỗ trợ tính trừu tượng thông qua module chuẩn abc (Abstract Base Classes). Lớp cơ sở trừu tượng quy định các phương thức bắt buộc bằng decorator @abstractmethod, buộc các lớp con kế thừa phải cài đặt đầy đủ logic nếu không muốn bị báo lỗi ngay khi khởi tạo.
Các Phương Thức Ma Thuật (Dunder Methods)
Phần tiêu đề “Các Phương Thức Ma Thuật (Dunder Methods)”Python sở hữu các phương thức đặc biệt có hai dấu gạch dưới ở đầu và cuối (Double Underscore - viết tắt là Dunder):
__len__(self): Cho phép gọi hàmlen(obj). Thường dùng để đếm số mẫu hoặc số batch trong tập dữ liệu.__getitem__(self, idx): Cho phép truy xuất phần tử theo cú pháp chỉ sốobj[idx].__call__(self, *args): Biến đối tượng thành một hàm có thể gọi đượcobj(x). Đây chính là cách PyTorch cho phép bạn viếtoutput = model(input)thay vì gọi tường minhmodel.forward(input).
Minh họa
Phần tiêu đề “Minh họa”Mối quan hệ kế thừa và giao diện đa hình chuẩn mực trong kiến trúc học máy:
┌────────────────────────────────────────────────────────┐ │ Lớp Trừu Tượng: BaseEstimator │ │ - Giao diện trừu tượng: fit(X, y), predict(X) │ └───────────────────────────┬────────────────────────────┘ │ ┌────────────────────┴────────────────────┐ ▼ ▼ ┌───────────────────────┐ ┌───────────────────────┐ │ Lớp LinearRegression │ │ Lớp DecisionTreeModel │ │ - self.w, self.b │ │ - self.tree_nodes │ │ - fit(): giải OLS │ │ - fit(): chia nhánh │ │ - predict(): w*x + b │ │ - predict(): duyệt cây│ └───────────────────────┘ └───────────────────────┘ │ │ └────────────────────┬────────────────────┘ │ (Tính đa hình Polymorphism) ▼ ┌──────────────────────────────────────────────────┐ │ Pipeline / cross_val_score(model, X_val, y_val) │ │ Gọi chung: model.fit(...) và model.predict(...) │ └──────────────────────────────────────────────────┘Ví dụ code
Phần tiêu đề “Ví dụ code”Các ô dưới đây chạy độc lập. Bạn có thể nhấn nút Chạy để xem ngay kết quả.
Ô thứ nhất xây dựng một lớp LinearModel hoàn chỉnh từ đầu: đóng gói trọng số self.w và độ lệch self.b, cung cấp phương thức fit() tối ưu hóa gradient descent và phương thức predict() suy luận.
Xây dựng lớp mô hình hồi quy tuyến tính với OOP
class LinearModel: def __init__(self, learning_rate: float = 0.05): self.lr = learning_rate self.w = 0.0 self.b = 0.0
def predict(self, x: float) -> float: return self.w * x + self.b
def fit(self, x_data: list[float], y_data: list[float], epochs: int = 50): m = len(x_data) for _ in range(epochs): # Tính gradient sai số MSE cho trọng số w và độ lệch b dw = sum(2 * (self.predict(x) - y) * x for x, y in zip(x_data, y_data)) / m db = sum(2 * (self.predict(x) - y) for x, y in zip(x_data, y_data)) / m self.w -= self.lr * dw self.b -= self.lr * db
# Dữ liệu huấn luyện mẫu (quan hệ thực tế: y = 2x + 1)X_train = [1.0, 2.0, 3.0, 4.0]y_train = [3.0, 5.0, 7.0, 9.0]
# Khởi tạo mô hình và tối ưu hóa tham sốmodel = LinearModel(learning_rate=0.05)model.fit(X_train, y_train, epochs=200)
print(f"Weight w: {model.w:.3f}")print(f"Bias b: {model.b:.3f}")print(f"Prediction for x=5: {model.predict(5.0):.3f}")Lần chạy đầu cần tải Python, khoảng 10 MB.
Toàn bộ quá trình tính đạo hàm riêng và cập nhật tham số được gói gọn gàng bên trong phương thức fit(). Người dùng bên ngoài chỉ cần tương tác với mô hình qua giao diện sạch sẽ, trực quan.
Ô thứ hai xây dựng lớp DataBatcher mô phỏng cơ chế mini-batching trong Deep Learning, minh họa tính đóng gói dữ liệu và phương thức ma thuật __len__.
Xây dựng lớp DataBatcher phân chia mini-batch
import math
class DataBatcher: def __init__(self, features: list[list[float]], labels: list[int], batch_size: int = 2): self._features = features self._labels = labels self.batch_size = batch_size
def __len__(self) -> int: return math.ceil(len(self._features) / self.batch_size)
def get_batch(self, index: int) -> tuple[list[list[float]], list[int]]: start = index * self.batch_size end = start + self.batch_size return self._features[start:end], self._labels[start:end]
# Dữ liệu gồm 5 mẫu với 2 đặc trưng và nhãn nhị phândata_x = [[1.2, 0.7], [-0.5, 1.4], [2.1, -1.0], [0.3, 0.9], [-1.2, -0.4]]data_y = [1, 0, 1, 1, 0]
# Khởi tạo batcher với kích thước mỗi mini-batch là 2batcher = DataBatcher(data_x, data_y, batch_size=2)print(f"Total batches: {len(batcher)}")
# Lặp qua từng batch để mô phỏng một chu kỳ huấn luyện (epoch)for i in range(len(batcher)): bx, by = batcher.get_batch(i) print(f"Batch {i}: {len(bx)} samples, labels = {by}")Lần chạy đầu cần tải Python, khoảng 10 MB.
Đối tượng batcher che giấu cấu trúc danh sách bên trong, tự động tính toán tổng số batch và chia nhỏ tập dữ liệu tương ứng với từng bước lặp huấn luyện.
Lỗi hay gặp
Phần tiêu đề “Lỗi hay gặp”Kiểm tra nhanh
Phần tiêu đề “Kiểm tra nhanh”Tóm tắt và đọc thêm
Phần tiêu đề “Tóm tắt và đọc thêm”Ý chính:
- Lớp là bản thiết kế, đối tượng là thực thể cụ thể;
selfđại diện cho chính đối tượng đang thực thi. - Luôn khởi tạo thuộc tính bên trong
__init__để bảo đảm tính độc lập dữ liệu giữa các thực thể. - 4 trụ cột OOP (Đóng gói, Kế thừa, Đa hình, Trừu tượng) là nền tảng kiến trúc của mọi thư viện AI chuyên nghiệp (PyTorch, Scikit-Learn, Hugging Face).
- Các phương thức ma thuật (
__len__,__getitem__,__call__) biến các lớp tự định nghĩa thành những đối tượng chuẩn mực của Python.
Đọc thêm:
- Python Software Foundation (2024). The Python Tutorial: Classes. Hướng dẫn chính thức về cú pháp hướng đối tượng, scope và không gian tên trong Python.
- PyTorch Team (2024). torch.nn.Module Documentation. Hướng dẫn về lớp cơ sở của mọi mạng nơ-ron trong PyTorch.
- Scikit-Learn Developers (2024). Developing Scikit-Learn Estimators. Tài liệu về quy chuẩn thiết kế lớp ước lượng máy học với các giao diện
fit,predict.
Trình duyệt đang chặn lưu dữ liệu. Tiến độ sẽ mất khi bạn tải lại trang.
Nội dung theo giấy phép CC BY-NC-SA 4.0. Mã nguồn theo giấy phép MIT.Giới thiệu