YOLO
YOLO: You Only Look Once
YOLO (You Only Look Once) là một trong những thuật toán phát hiện đối tượng hiệu quả và phổ biến nhất hiện nay. Nổi tiếng với tốc độ cao và khả năng xử lý thời gian thực, YOLO đã cách mạng hóa lĩnh vực phát hiện đối tượng kể từ khi ra mắt vào năm 2015.

Nguyên lý cơ bản của YOLO
Điểm khác biệt chính của YOLO so với các thuật toán phát hiện đối tượng truyền thống là cách tiếp cận "một lần nhìn" (one-look). YOLO xử lý toàn bộ hình ảnh trong một lần truyền qua mạng nơ-ron, đồng thời dự đoán nhiều bounding box và xác suất lớp cho các box này.
Cách hoạt động:
Phân chia lưới (Grid Division): Chia hình ảnh thành lưới S×S (ví dụ: 7×7 trong YOLOv1, 13×13 trong YOLOv3)
Dự đoán đồng thời: Mỗi ô lưới dự đoán:
B bounding boxes (thường là 2-3 boxes)
Độ tin cậy (confidence) cho mỗi box
C xác suất lớp (với C là số lượng lớp cần phát hiện)
Thông tin dự đoán box: Mỗi bounding box bao gồm:
Tọa độ trung tâm (x, y) - tương đối trong ô lưới
Chiều rộng và chiều cao (w, h) - tương đối với kích thước hình ảnh
Confidence score biểu thị khả năng box chứa đối tượng
Lọc kết quả: Áp dụng ngưỡng confidence và Non-Maximum Suppression (NMS) để loại bỏ các box dư thừa
Tiến hóa của YOLO
YOLO đã trải qua nhiều cải tiến qua các phiên bản, mỗi phiên bản đều nâng cao hiệu suất và tốc độ:
YOLOv1 (2015)
Phiên bản đầu tiên do Joseph Redmon giới thiệu
Mạng CNN đơn giản với 24 lớp tích chập và 2 lớp fully connected
Tốc độ 45 FPS, không đủ chính xác cho các đối tượng nhỏ
YOLOv2/YOLO9000 (2016)
Thêm Batch Normalization
Sử dụng Anchor Boxes (điểm neo) thay vì dự đoán trực tiếp
Darknet-19 backbone nhẹ hơn
YOLO9000 có thể phát hiện hơn 9000 lớp đối tượng
YOLOv3 (2018)
Sử dụng Darknet-53 làm backbone
Dự đoán ở ba tỷ lệ khác nhau (scales) giúp phát hiện đối tượng ở nhiều kích cỡ
Feature pyramid network để kết hợp thông tin từ các tỷ lệ khác nhau
Thay thế Softmax bằng hàm Sigmoid để hỗ trợ phân loại đa nhãn
YOLOv4 (2020)
Phát triển bởi Alexey Bochkovskiy, không phải nhóm ban đầu
Sử dụng CSPDarknet53 làm backbone
Thêm nhiều kỹ thuật augmentation như Mosaic, CutMix
Bag of Freebies và Bag of Specials để cải thiện độ chính xác
Path Aggregation Network (PAN) để kết hợp feature maps
YOLOv5 (2020)
Phát triển bởi Ultralytics, viết bằng PyTorch
Nhiều kích cỡ mô hình: nano, small, medium, large, xlarge
Tích hợp tốt vào các pipeline triển khai
YOLOv6 (2022)
Phát triển bởi Meituan
Sử dụng RepVGG cho backbone
Thiết kế đầu phát hiện đối xứng hiệu quả
YOLOv7 (2022)
Cải tiến bởi WongKinYiu và Alexey Bochkovskiy
Tập trung vào hiệu suất trên nhiều phần cứng khác nhau
E-ELAN (Extended Efficient Layer Aggregation Network)
Auxiliary head và lead head đặc biệt
YOLOv8 (2023)
Phiên bản mới nhất từ Ultralytics
Anchorless detection
Cải tiến head detection với C2f module
Hỗ trợ nhiều nhiệm vụ: Detection, Segmentation, Classification, Pose
Hiệu suất cao nhất trong các phiên bản YOLO
Kiến trúc chi tiết
Hãy xem xét kiến trúc của YOLOv8, phiên bản mới nhất và phổ biến hiện nay:
1. Backbone
YOLOv8 sử dụng CSPDarknet làm backbone, với cấu trúc được cải tiến:
Lớp tích chập (Convolution) → Batch Normalization → SiLU activation
C2f block (Cross Stage Partial với nhiều bottleneck)
Kết nối tắt (skip connections) giữa các khối
# Ví dụ về C2f block trong YOLOv8
class C2f(nn.Module):
# CSP Bottleneck with 2 convolutions
def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):
super().__init__()
self.c = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, 2 * self.c, 1, 1)
self.cv2 = Conv((2 + n) * self.c, c2, 1) # optional act=FReLU(c2)
self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))
def forward(self, x):
y = list(self.cv1(x).split((self.c, self.c), 1))
y.extend(m(y[-1]) for m in self.m)
return self.cv2(torch.cat(y, 1))2. Neck
YOLOv8 sử dụng cấu trúc neck dạng SPPF (Spatial Pyramid Pooling - Fast) và PAN (Path Aggregation Network):
SPPF: Tổng hợp thông tin không gian ở các tỷ lệ khác nhau
PAN: Kết hợp thông tin từ feature map có độ phân giải thấp với độ phân giải cao
# SPPF block trong YOLOv8
class SPPF(nn.Module):
# Spatial Pyramid Pooling - Fast (SPPF) layer
def __init__(self, c1, c2, k=5):
super().__init__()
c_ = c1 // 2 # hidden channels
self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv(c_ * 4, c2, 1, 1)
self.m = nn.MaxPool2d(kernel_size=k, stride=1, padding=k // 2)
def forward(self, x):
x = self.cv1(x)
y1 = self.m(x)
y2 = self.m(y1)
return self.cv2(torch.cat((x, y1, y2, self.m(y2)), 1))3. Head
YOLOv8 sử dụng Decoupled Head, tách biệt dự đoán phân loại và dự đoán bounding box:
Một nhánh cho phân loại (classification)
Một nhánh cho định vị (bbox regression)
Dự đoán không sử dụng anchor boxes (anchorless)
# Head detection của YOLOv8
class Detect(nn.Module):
# YOLOv8 Detect head
def __init__(self, nc=80, ch=()):
super().__init__()
self.nc = nc # number of classes
self.nl = len(ch) # number of detection layers
self.reg_max = 16 # DFL channels (ch[0] // 16 to scale 4/8/12/16/20 for n/s/m/l/x)
self.no = nc + self.reg_max * 4 # number of outputs per anchor
self.stride = torch.zeros(self.nl) # strides computed during build
# Classification and Box Regression heads
c2, c3 = max((16, ch[0] // 4, self.reg_max * 4)), max(ch[0], self.nc)
self.cv2 = nn.ModuleList(nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch)
self.cv3 = nn.ModuleList(nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch)
def forward(self, x):
for i in range(self.nl):
x[i] = torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)
return xCác ưu điểm của YOLO
1. Tốc độ cao
YOLOv8-nano: 155+ FPS trên GPU RTX 3090
YOLOv8-small: 100+ FPS
Phù hợp cho các ứng dụng thời gian thực
2. Cân bằng tốc độ và độ chính xác
YOLOv8-small: 37.4% mAP trên COCO val2017
YOLOv8-large: 43.4% mAP trên COCO val2017
3. Khả năng triển khai đa nền tảng
Dễ dàng triển khai trên nhiều thiết bị: GPU, CPU, edge devices
Hỗ trợ ONNX, TensorRT, CoreML, TFLite
4. Cộng đồng mạnh mẽ
Mã nguồn mở
Tài liệu và hướng dẫn phong phú
Nhiều pre-trained models
5. Đa nhiệm vụ
Object Detection
Instance Segmentation
Pose Estimation
Classification
Triển khai YOLO trong thực tế
1. Cài đặt và sử dụng YOLOv8
# Cài đặt
pip install ultralytics
# Sử dụng cơ bản
from ultralytics import YOLO
# Tải mô hình pre-trained
model = YOLO('yolov8n.pt') # nano model
# Các lựa chọn khác: yolov8s.pt, yolov8m.pt, yolov8l.pt, yolov8x.pt
# Inference
results = model('path/to/image.jpg')
# Xử lý kết quả
for r in results:
boxes = r.boxes # Bounding boxes
for box in boxes:
x1, y1, x2, y2 = box.xyxy[0] # Lấy tọa độ box (format xyxy)
confidence = box.conf[0] # Độ tin cậy
class_id = box.cls[0] # ID lớp
class_name = model.names[int(class_id)] # Tên lớp
print(f"Phát hiện {class_name} với độ tin cậy {confidence:.2f}")2. Huấn luyện YOLO với dữ liệu tùy chỉnh
# Định nghĩa file cấu hình (data.yaml)
"""
path: /path/to/dataset
train: train/images
val: val/images
# Định nghĩa các lớp
names:
0: person
1: car
2: bicycle
"""
# Bắt đầu huấn luyện
from ultralytics import YOLO
# Tải mô hình cơ sở
model = YOLO('yolov8n.pt')
# Huấn luyện
results = model.train(
data='data.yaml',
epochs=100,
imgsz=640,
batch=16,
patience=50,
device=0 # GPU id
)
# Đánh giá sau huấn luyện
metrics = model.val()3. Ví dụ ứng dụng thời gian thực với webcam
from ultralytics import YOLO
import cv2
import numpy as np
import time
# Tải mô hình
model = YOLO('yolov8n.pt') # yolov8 nano
# Mở webcam
cap = cv2.VideoCapture(0)
# Thiết lập kích thước khung hình
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
# Danh sách màu cho các lớp khác nhau
colors = np.random.uniform(0, 255, size=(80, 3))
while True:
# Đọc frame từ webcam
ret, frame = cap.read()
if not ret:
break
# Bắt đầu đo thời gian
start_time = time.time()
# Thực hiện phát hiện
results = model(frame)
# Đo thời gian hoàn thành phát hiện
fps = 1.0 / (time.time() - start_time)
# Vẽ kết quả lên frame
for r in results:
boxes = r.boxes
for box in boxes:
# Lấy tọa độ
x1, y1, x2, y2 = map(int, box.xyxy[0])
# Lấy thông tin lớp và độ tin cậy
conf = float(box.conf[0])
cls_id = int(box.cls[0])
cls_name = model.names[cls_id]
# Chỉ hiển thị kết quả có độ tin cậy > 0.5
if conf > 0.5:
# Vẽ bounding box
color = colors[cls_id]
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
# Vẽ nhãn
label = f'{cls_name}: {conf:.2f}'
t_size = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)[0]
c2 = x1 + t_size[0], y1 - t_size[1] - 3
cv2.rectangle(frame, (x1, y1), c2, color, -1)
cv2.putText(frame, label, (x1, y1 - 2), cv2.FONT_HERSHEY_SIMPLEX, 0.5, [255, 255, 255], 1)
# Hiển thị FPS
cv2.putText(frame, f'FPS: {fps:.2f}', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# Hiển thị frame
cv2.imshow('YOLOv8 Detection', frame)
# Thoát khi nhấn phím 'q'
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Giải phóng tài nguyên
cap.release()
cv2.destroyAllWindows()4. Tinh chỉnh và tối ưu hóa
# Ví dụ tinh chỉnh tham số khi huấn luyện
from ultralytics import YOLO
model = YOLO('yolov8s.pt')
# Tinh chỉnh tham số nâng cao
results = model.train(
data='data.yaml',
epochs=300,
imgsz=640,
batch=16,
patience=50,
optimizer='AdamW', # Optimizer
lr0=0.001, # Tốc độ học ban đầu
weight_decay=0.0005, # Weight decay
warmup_epochs=3, # Warmup epochs
cos_lr=True, # Cosine LR scheduler
augment=True, # Augmentation
mixup=0.1, # MixUp augmentation
degrees=0.1, # Xoay ảnh
translate=0.1, # Dịch chuyển ảnh
scale=0.1, # Thay đổi tỷ lệ ảnh
fliplr=0.5, # Lật ngang
mosaic=1.0, # Mosaic augmentation
device=0 # GPU id
)5. Triển khai trên thiết bị nhúng (Raspberry Pi, Jetson Nano)
# Cài đặt trên Raspberry Pi/Jetson Nano
# 1. Cài đặt dependencies
# $ sudo apt update
# $ sudo apt install python3-pip libopenblas-dev libopenmpi-dev libomp-dev
# 2. Cài đặt PyTorch phiên bản dành cho thiết bị ARM
# $ pip3 install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/cpu
# 3. Cài đặt Ultralytics
# $ pip3 install ultralytics
# Sử dụng
from ultralytics import YOLO
import cv2
# Tải mô hình nhỏ nhất (nano)
model = YOLO('yolov8n.pt')
# Chạy inference với cấu hình thấp
# - Giảm kích thước ảnh
# - Sử dụng độ chính xác thấp hơn (FP16)
results = model('test.jpg', imgsz=320, half=True) # half=True cho FP16
# Xử lý kết quả
for r in results:
boxes = r.boxes
for box in boxes:
if box.conf[0] > 0.3: # Ngưỡng thấp hơn
print(f"Phát hiện {model.names[int(box.cls[0])]} với độ tin cậy {box.conf[0]:.2f}")Nâng cao hiệu suất YOLO
1. Tối ưu hóa tốc độ
# Chuyển đổi model sang ONNX để tăng tốc độ
from ultralytics import YOLO
model = YOLO('yolov8n.pt')
model.export(format='onnx', dynamic=True, simplify=True) # Xuất ra yolov8n.onnx
# Sử dụng model ONNX
import onnxruntime as ort
import numpy as np
import cv2
# Tải model ONNX
session = ort.InferenceSession('yolov8n.onnx', providers=['CUDAExecutionProvider', 'CPUExecutionProvider'])
# Xử lý ảnh đầu vào
img = cv2.imread('test.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (640, 640))
img = img.transpose((2, 0, 1)).astype(np.float32) / 255.0
img = np.expand_dims(img, axis=0)
# Lấy tên input/output
input_name = session.get_inputs()[0].name
output_names = [output.name for output in session.get_outputs()]
# Thực hiện inference
outputs = session.run(output_names, {input_name: img})
# Xử lý kết quả
# ...2. Cải thiện độ chính xác
# 1. Ensemble - Kết hợp nhiều mô hình
from ultralytics import YOLO
# Tải nhiều mô hình
model1 = YOLO('yolov8n.pt')
model2 = YOLO('yolov8s.pt')
model3 = YOLO('yolov8m.pt')
# Thực hiện phát hiện với từng mô hình
results1 = model1('test.jpg')
results2 = model2('test.jpg')
results3 = model3('test.jpg')
# Kết hợp kết quả bằng Weighted Box Fusion (WBF)
# (Cần sử dụng thư viện ensemble-boxes)
from ensemble_boxes import weighted_boxes_fusion
# 2. Test Time Augmentation (TTA)
results = model('test.jpg', augment=True) # Bật TTA3. Theo dõi đối tượng (Object Tracking)
from ultralytics import YOLO
import cv2
from collections import defaultdict
# Tải mô hình
model = YOLO('yolov8n.pt')
# Mở video
cap = cv2.VideoCapture('video.mp4')
# Theo dõi đối tượng
track_history = defaultdict(lambda: [])
while cap.isOpened():
success, frame = cap.read()
if not success:
break
# Chạy YOLOv8 tracking với các lớp người và xe
results = model.track(frame, persist=True, classes=[0, 2]) # 0: person, 2: car
# Nếu có kết quả
if results[0].boxes.id is not None:
boxes = results[0].boxes
for box in boxes:
# Lấy ID
track_id = int(box.id[0])
# Lấy tọa độ tâm
x1, y1, x2, y2 = box.xyxy[0]
x_center = (x1 + x2) / 2
y_center = (y1 + y2) / 2
center = (int(x_center), int(y_center))
# Lưu vị trí vào lịch sử
track_history[track_id].append(center)
# Giữ kích thước lịch sử hợp lý
if len(track_history[track_id]) > 30:
track_history[track_id].pop(0)
# Vẽ bounding box và ID
cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
cv2.putText(frame, f"ID: {track_id}", (int(x1), int(y1) - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# Vẽ quỹ đạo
points = track_history[track_id]
for i in range(1, len(points)):
cv2.line(frame, points[i - 1], points[i], (0, 255, 0), 2)
# Hiển thị
cv2.imshow("YOLOv8 Tracking", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()YOLO so với các thuật toán khác
1. YOLO vs SSD
Tốc độ
Cao hơn (45-155 FPS)
Trung bình (22-46 FPS)
Độ chính xác
Cải thiện qua các phiên bản
Tốt cho đối tượng nhiều kích cỡ
Cách tiếp cận
Lưới phân chia
Feature maps đa tỷ lệ
Dễ triển khai
Đơn giản, nhiều framework
Phức tạp hơn một chút
2. YOLO vs Faster R-CNN
Tốc độ
Rất nhanh (45-155 FPS)
Chậm (5-8 FPS)
Độ chính xác
Tốt (33-44% mAP)
Xuất sắc (42-48% mAP)
Kiến trúc
Một bước
Hai bước (RPN + Classifier)
Ứng dụng
Thời gian thực
Độ chính xác cao
Ứng dụng thực tế của YOLO
1. Giám sát an ninh
Phát hiện xâm nhập
Theo dõi người và phương tiện
Phát hiện hành vi bất thường
2. Xe tự lái
Phát hiện người đi bộ, xe cộ, biển báo
Hỗ trợ lái xe
Phát hiện và tránh vật cản
3. Bán lẻ
Theo dõi hàng hóa trong kệ
Phân tích luồng khách hàng
Hệ thống thanh toán tự động
4. Nông nghiệp
Theo dõi vật nuôi
Phát hiện bệnh cây trồng
Đếm và phân loại sản phẩm
5. Y tế
Phân tích chuyển động
Hỗ trợ phẫu thuật
Theo dõi bệnh nhân
Những thách thức và hạn chế
1. Đối tượng nhỏ
YOLO gặp khó khăn với các đối tượng nhỏ và đông đúc
YOLOv8 đã cải thiện đáng kể vấn đề này, nhưng vẫn chưa hoàn hảo
2. Yêu cầu tài nguyên
Mô hình lớn như YOLOv8-X yêu cầu GPU mạnh
Các phiên bản nhỏ hơn có hiệu suất thấp hơn
3. Tính tổng quát
Cần huấn luyện lại cho các miền dữ liệu đặc biệt
Hiệu suất phụ thuộc vào chất lượng dữ liệu huấn luyện
Tương lai của YOLO
1. Kết hợp với Transformer
Hướng đi mới là kết hợp CNN và Transformer
YOLOv8 đã bắt đầu tích hợp các ý tưởng từ Transformer
2. Mở rộng đa nhiệm vụ
Phát triển thêm các tác vụ như phân đoạn 3D
Kết hợp với xử lý ngôn ngữ tự nhiên
3. Tối ưu hóa thiết bị nhúng
Tiếp tục tối ưu cho thiết bị có tài nguyên hạn chế
Mô hình lượng tử hóa (quantized) và nhẹ hơn
Kết luận
YOLO đã và đang là một trong những thuật toán phát hiện đối tượng có ảnh hưởng lớn nhất trong thị giác máy tính. Từ YOLOv1 đến YOLOv8, mỗi phiên bản đều mang đến những cải tiến đáng kể về tốc độ và độ chính xác. Sự đơn giản, hiệu quả và cộng đồng hỗ trợ mạnh mẽ đã giúp YOLO trở thành lựa chọn hàng đầu cho các ứng dụng phát hiện đối tượng thời gian thực.
Với tốc độ phát triển nhanh chóng của lĩnh vực học sâu, chúng ta có thể mong đợi các phiên bản YOLO trong tương lai sẽ tiếp tục phá vỡ những ranh giới về hiệu suất và khả năng ứng dụng. Đồng thời, việc tiếp tục tối ưu hóa cho các thiết bị có tài nguyên hạn chế sẽ mở rộng phạm vi ứng dụng của YOLO đến nhiều lĩnh vực hơn nữa.
Last updated