ReLU (Rectified Linear Unit)
ReLU (đơn vị tuyến tính chỉnh lưu) trả về max(0, x), giữ nguyên đầu vào dương và đưa đầu vào âm về 0. Bài viết đề cập đến gradient, ReLU chết, các biến thể và mã nguồn PyTorch.
Rectified linear unit (ReLU) là hàm kích hoạt f(x) = max(0, x): hàm giữ nguyên đầu vào dương và trả về 0 với mọi giá trị còn lại. Phép so sánh đơn giản này cung cấp tính phi tuyến cần thiết để mạng nơ-ron (NN) học các mẫu cong, với chi phí tính toán gần như bằng không. ReLU trở thành hàm kích hoạt mặc định cho lớp ẩn trong deep learning sau khi Vinod Nair và Geoffrey Hinton sử dụng nó vào năm 2010, rồi AlexNet—một mạng nơ-ron tích chập (CNN) xây dựng trên ReLU—chiến thắng thử thách ImageNet năm 2012. ReLU vẫn là mốc chuẩn để so sánh các hàm kích hoạt mới hơn như SiLU và GELU.
Cách ReLU hoạt động#
Đạo hàm của ReLU bằng 1 với đầu vào dương và bằng 0 với đầu vào âm. Tại đúng 0, đạo hàm không xác định; các framework như PyTorch dùng giá trị 0. Hai giá trị này giải thích những đặc tính chính của ReLU:
- Tính toán rẻ: Lượt truyền xuôi chỉ cần so sánh với 0, còn lượt truyền ngược chỉ cần tạo mask; không cần tính hàm mũ như sigmoid hoặc tanh.
- Không bão hòa với đầu vào dương: Gradient bằng đúng 1 truyền qua mọi đơn vị đang hoạt động mà không đổi, vì vậy tín hiệu lỗi không suy giảm khi lan ngược qua nhiều lớp; điều này khắc phục vấn đề vanishing gradient do các hàm bão hòa gây ra.
- Kích hoạt thưa: Mọi đầu vào âm đều trở thành giá trị 0 chính xác, vì vậy tại mỗi thời điểm chỉ một phần lớp hoạt động. Với trọng số được khởi tạo ngẫu nhiên, khoảng một nửa số đơn vị trong một lớp trả về 0 với một đầu vào nhất định.
- Tuyến tính từng đoạn: Mạng xây dựng từ ReLU tính hàm tuyến tính từng đoạn theo đầu vào, gồm nhiều miền tuyến tính nối với nhau tại các điểm mà đơn vị bật hoặc tắt.
Ví dụ PyTorch bên dưới áp dụng nn.ReLU và dùng autograd để tính gradient tại các điểm tương ứng:
import torch
from torch import nn
relu = nn.ReLU()
# Inputs on both sides of zero, tracked so PyTorch can compute gradients
x = torch.tensor([-2.0, -0.5, 0.0, 0.5, 2.0], requires_grad=True)
y = relu(x)
# Backpropagate a gradient of 1 from each output to its input
y.sum().backward()
print(f"Output: {y.tolist()}")
print(f"Gradient: {x.grad.tolist()}")Đoạn code in ra các đầu ra [0.0, 0.0, 0.0, 0.5, 2.0] và gradient [0.0, 0.0, 0.0, 1.0, 1.0]. Đầu vào dương được truyền qua cùng gradient nguyên vẹn; đầu vào âm và giá trị 0 đều không nhận gradient, tạo nên cả tính thưa lẫn nhược điểm chính của ReLU.
Vấn đề ReLU chết#
Một đơn vị ReLU có đầu vào âm với mọi ví dụ trong dữ liệu huấn luyện sẽ trả về 0 và nhận gradient bằng 0, khiến trọng số không bao giờ thay đổi nữa; đơn vị đó xem như đã chết. Đơn vị thường chết khi một lần cập nhật trọng số lớn—thường do learning rate cao—đẩy bias của chúng xuống rất âm. Một vài đơn vị chết gây ít ảnh hưởng, nhưng một lượt chạy được tinh chỉnh kém có thể làm chết phần lớn một lớp. Khởi tạo He, điều chỉnh tỷ lệ trọng số ban đầu cho các lớp ReLU, cùng learning rate vừa phải và batch normalization giúp duy trì hầu hết đơn vị; các biến thể leaky loại bỏ vấn đề này bằng cách không bao giờ để gradient về 0.
Các biến thể ReLU#
- Leaky ReLU: Nhân đầu vào âm với một độ dốc nhỏ cố định, thường là 0,01, để các đơn vị không hoạt động vẫn nhận được gradient.
- PReLU: Học độ dốc phía âm trong quá trình huấn luyện. Kaiming He và các cộng sự giới thiệu hàm này năm 2015 trong cùng bài báo đề xuất khởi tạo He.
- ReLU6: Giới hạn đầu ra ở mức 6, min(max(0, x), 6), giúp giữ activation trong khoảng mà phép toán độ chính xác thấp có thể biểu diễn tốt. MobileNetV1 và MobileNetV2 sử dụng hàm này.
- ELU: Thay phần âm bằng đường cong hàm mũ trơn bão hòa ở −1, giúp đưa activation trung bình về gần 0 hơn.
- SiLU và GELU: Các đường cong trơn x · σ(x) và x · Φ(x), hoạt động như ReLU với đầu vào lớn nhưng vẫn truyền các giá trị âm nhỏ và không có điểm gấp khúc tại 0. Chúng tốn nhiều phép tính hơn cho mỗi phần tử; bài báo về GELU ghi nhận mức cải thiện so với ReLU trên mọi tác vụ thị giác, ngôn ngữ và tiếng nói được thử nghiệm.
ReLU, sigmoid và tanh#
Trước khi có ReLU, các lớp ẩn dùng sigmoid hoặc tanh. Cả hai đều bão hòa: với đầu vào dương hoặc âm lớn, đường cong trở nên phẳng và đạo hàm tiến về 0; ngay cả tại điểm dốc nhất, đạo hàm của sigmoid cũng không vượt quá 0,25. Việc nhân các đạo hàm này qua nhiều lớp làm các lớp đầu thiếu gradient. Trong bài báo AlexNet, một CNN bốn lớp dùng ReLU đạt lỗi huấn luyện 25% trên CIFAR-10 nhanh gấp sáu lần so với cùng mạng dùng các đơn vị tanh. Sigmoid và tanh vẫn được dùng khi cần dải giá trị bị giới hạn: sigmoid trong lớp đầu ra để biểu diễn xác suất và trong các cổng của ô hồi quy, còn tanh dùng trong trạng thái ẩn hồi quy.
ReLU trong các model hiện đại#
ResNet và hầu hết CNN cùng thời sử dụng ReLU xuyên suốt; transformer nguyên bản năm 2017 cũng dùng hàm này trong các lớp truyền thẳng. Nhiều model mới chuyển sang hàm trơn hơn: GELU trong BERT và vision transformer, còn SwiGLU được dùng trong nhiều large language model hiện nay; ReLU vẫn phổ biến khi tốc độ và khả năng hỗ trợ phần cứng là ưu tiên hàng đầu. YOLO26 mặc định dùng SiLU trong các khối Conv; một dòng activation: nn.ReLU() trong YAML của model thay ReLU vào mọi khối Conv trước khi huấn luyện, phù hợp với các accelerator như AMD Zynq UltraScale+ DPU vốn hỗ trợ ReLU nguyên bản nhưng không hỗ trợ SiLU. Trong PyTorch, nn.ReLU(inplace=True) ghi đè tensor đầu vào bằng kết quả, tiết kiệm bộ nhớ cần thiết cho tensor đầu ra riêng.










