Deep Learning 4 — CNN & thị giác máy tính
Deep Learning 4 — CNN & thị giác máy tính
Ảnh là loại dữ liệu mà con người xử lý dễ nhất nhưng máy tính lại thấy khó nhất: chỉ là một lưới số. Một tấm ảnh màu 224×224 điểm ảnh thực chất là một khối số 224×224×3 (ba kênh đỏ–lục–lam). Mạng nơ-ron tích chập (Convolutional Neural Network — CNN) là kiến trúc được thiết kế riêng để "nhìn" loại lưới số này, và trong hơn một thập kỷ nó là xương sống của thị giác máy tính hiện đại.
Bài này giả định bạn đã nắm được nơ-ron, lớp ẩn, hàm kích hoạt và lan truyền ngược từ bài Nền tảng Deep Learning. Ở đây ta trả lời một câu hỏi cụ thể: tại sao mạng nhiều lớp thông thường (MLP) không hợp với ảnh, và CNN sửa điều đó bằng cách nào.
Đây là danh mục AI. Các đoạn code Python trong bài là minh hoạ để bạn thấy hình dạng phép tính, không phải sandbox chạy được. Muốn chạy thật, xem bài PyTorch.
1. Vì sao MLP không hợp với ảnh
Nhớ lại MLP: mỗi nơ-ron ở lớp sau nối với mọi nơ-ron ở lớp trước (fully connected). Để đưa ảnh vào MLP, ta phải "duỗi thẳng" (flatten) lưới điểm ảnh thành một vector dài. Cách làm này hỏng theo hai hướng.
Thứ nhất, bùng nổ tham số. Một ảnh màu 224×224×3 duỗi ra thành vector 150.528 chiều. Nếu lớp ẩn đầu tiên chỉ có 1.000 nơ-ron, riêng lớp đó đã cần hơn 150 triệu trọng số. Con số này khổng lồ với một lớp duy nhất, dễ dẫn tới overfitting và tốn bộ nhớ vô lý — trong khi phần lớn trọng số là dư thừa.
Thứ hai, mất cấu trúc không gian. Khi duỗi ảnh thành vector, hai điểm ảnh nằm sát nhau (rất liên quan về mặt hình học) trở thành hai phần tử có thể cách nhau rất xa trong vector. MLP không hề biết điểm ảnh nào kề điểm ảnh nào — nó coi mọi đầu vào là độc lập. Với ảnh, tính lân cận là thông tin cốt lõi: một cạnh, một góc, một kết cấu đều được định nghĩa bởi quan hệ giữa các điểm ảnh gần nhau.
Hệ quả thứ ba: MLP không bất biến với dịch chuyển. Nếu ta dạy MLP nhận diện con mèo ở góc trên trái, rồi con mèo xuất hiện ở góc dưới phải, mạng gần như phải học lại từ đầu vì các trọng số liên quan hoàn toàn khác. Trực giác con người thì "mèo vẫn là mèo dù nó ở đâu trong khung hình".
CNN giải cả ba vấn đề bằng một ý tưởng: thay vì mỗi nơ-ron nhìn toàn bộ ảnh, hãy cho một bộ lọc nhỏ trượt khắp ảnh và dùng lại cùng bộ trọng số ở mọi vị trí.
2. Convolution — phép tính cốt lõi
Filter (kernel) và feature map
Filter (còn gọi là kernel) là một ma trận trọng số nhỏ, ví dụ 3×3. Ta đặt filter lên một vùng nhỏ của ảnh, nhân từng phần tử tương ứng rồi cộng lại thành một số duy nhất. Sau đó trượt filter sang vị trí kế bên và lặp lại. Kết quả của việc trượt khắp ảnh là một lưới số mới gọi là feature map (bản đồ đặc trưng) — nó cho biết đặc trưng mà filter tìm kiếm xuất hiện mạnh ở đâu.
Minh hoạ phép nhân–cộng cho một vị trí (filter 3×3 phát hiện cạnh dọc):
Vùng ảnh 3×3 Filter 3×3 Tích từng phần tử → cộng
10 10 10 -1 0 1 (10·-1)+(10·0)+(10·1)
10 10 10 ⊙ -1 0 1 = (10·-1)+(10·0)+(10·1) = 0 (vùng phẳng)
10 10 10 -1 0 1 (10·-1)+(10·0)+(10·1)
10 10 90 -1 0 1
10 10 90 ⊙ -1 0 1 = số lớn (có cạnh dọc: trái tối, phải sáng)
10 10 90 -1 0 1
Filter này gần như bằng 0 ở vùng phẳng nhưng cho giá trị lớn ở nơi độ sáng thay đổi đột ngột theo chiều ngang — đó chính là một cạnh dọc. Điều tuyệt vời: các trọng số trong filter không do ta gán tay mà được học bằng lan truyền ngược. Mạng tự khám phá ra filter nào hữu ích.
Weight sharing — chìa khoá tiết kiệm tham số
Điểm mấu chốt: cùng một filter được dùng ở mọi vị trí trên ảnh. Đây gọi là weight sharing (chia sẻ trọng số). Một filter 3×3 trên ảnh màu chỉ có 3×3×3 + 1 = 28 tham số — bất kể ảnh lớn cỡ nào. So với 150 triệu tham số của MLP, đây là khác biệt vài bậc độ lớn.
Weight sharing đồng thời cho ta bất biến dịch chuyển: vì cùng filter quét khắp ảnh, nếu nó biết phát hiện cạnh ở góc trên trái thì tự động phát hiện được cạnh y hệt ở góc dưới phải. Đặc trưng học một lần, dùng ở mọi nơi.
Nhiều filter, nhiều kênh
Một lớp tích chập không dùng một filter mà cả một tập filter (ví dụ 32 hoặc 64 filter), mỗi filter học một đặc trưng khác nhau: cái tìm cạnh dọc, cái tìm cạnh ngang, cái tìm mảng màu, cái tìm kết cấu. Lớp cho ra 32 feature map xếp chồng thành một khối 3D — đầu vào cho lớp tiếp theo.
Đây là ý tưởng đẹp nhất của CNN: học đặc trưng phân cấp. Lớp đầu học các đặc trưng thô sơ (cạnh, góc, đốm màu). Lớp giữa ghép chúng thành hình dạng (mắt, bánh xe, chữ cái). Lớp sâu ghép hình dạng thành khái niệm (khuôn mặt, ô tô, con số). Không ai lập trình các mức này — mạng tự dựng lên từ dữ liệu: cạnh → hình → vật.
Stride và padding
Hai tham số điều khiển cách filter trượt:
- Stride (bước trượt): filter nhảy mấy điểm ảnh mỗi lần. Stride 1 trượt từng điểm (feature map giữ gần nguyên kích thước); stride 2 nhảy 2 điểm, làm feature map co lại một nửa — một cách giảm kích thước.
- Padding (đệm): thêm một viền số 0 quanh ảnh. Không đệm thì mỗi lớp tích chập làm ảnh nhỏ dần và điểm ảnh ở rìa bị "quét ít lần" hơn điểm ở giữa.
padding="same"giữ feature map cùng kích thước với đầu vào — rất tiện khi xếp nhiều lớp.
3. Pooling — thu gọn và tăng độ bền
Sau lớp tích chập thường có lớp pooling để giảm kích thước không gian của feature map. Phổ biến nhất là max pooling: chia feature map thành các ô nhỏ (thường 2×2) và giữ lại giá trị lớn nhất trong mỗi ô.
Feature map 4×4 Max pooling 2×2 (stride 2) Kết quả 2×2
1 3 | 2 4
5 6 | 1 0 giữ max mỗi ô 2×2 6 4
------+------ → → 8 9
8 2 | 3 1
4 7 | 9 5
Pooling mang lại ba lợi ích:
- Giảm kích thước → giảm chi phí tính toán và số tham số ở các lớp sau.
- Tăng bất biến dịch chuyển nhỏ: nếu đặc trưng lệch một hai điểm ảnh, giá trị lớn nhất trong ô thường vẫn giữ nguyên, nên đầu ra không đổi.
- Mở rộng trường nhìn (receptive field): sau pooling, mỗi nơ-ron lớp sau "nhìn" được vùng ảnh gốc rộng hơn, giúp bắt đặc trưng ở quy mô lớn hơn.
Ngoài max pooling còn có average pooling (lấy trung bình ô). Max pooling giữ lại tín hiệu mạnh nhất (hợp phát hiện đặc trưng nổi bật) nên thường được ưa dùng hơn; average pooling mượt hơn và hay gặp ở dạng global average pooling cuối mạng (lấy trung bình cả feature map thành một số cho mỗi kênh).
4. Kiến trúc CNN điển hình
Ghép các thành phần trên lại, một CNN kinh điển có dạng: xen kẽ khối conv → activation → pool vài lần để trích đặc trưng, rồi duỗi thẳng và nối vài lớp fully-connected (dense) để ra quyết định.
Trực giác: phần conv + pool là bộ trích đặc trưng — biến ảnh thô thành một biểu diễn đặc trưng cô đọng, giàu ngữ nghĩa. Phần dense cuối là bộ phân loại — nhận biểu diễn đó và quyết định ảnh thuộc lớp nào. Càng vào sâu, kích thước không gian càng nhỏ nhưng số kênh (độ sâu ngữ nghĩa) càng lớn: từ "vài trăm điểm ảnh × 3 kênh màu" thành "vài điểm × hàng trăm kênh đặc trưng".
5. Các kiến trúc kinh điển
Lịch sử CNN gắn với một chuỗi kiến trúc, mỗi cái đóng góp một ý tưởng bền vững:
-
LeNet-5 (1998). Do Yann LeCun đề xuất để nhận dạng chữ số viết tay (bưu chính, séc ngân hàng). Nhỏ, gồm vài lớp conv–pool rồi dense. Đây là bằng chứng đầu tiên CNN hoạt động thực tế.
-
AlexNet (2012). Thắng cuộc thi ImageNet với cách biệt lớn, châm ngòi cho làn sóng deep learning. Sâu hơn LeNet, huấn luyện trên GPU, dùng hàm kích hoạt ReLU (thay sigmoid, giúp huấn luyện nhanh và bớt vanishing gradient) và dropout để chống overfitting.
-
VGG (2014). Triết lý "đơn giản mà sâu": chỉ dùng filter 3×3 xếp chồng nhiều lớp. VGG cho thấy nhiều filter nhỏ liên tiếp hiệu quả hơn ít filter lớn, và trở thành backbone kinh điển cho transfer learning.
-
Inception / GoogLeNet (2014). Trong cùng một khối, chạy song song nhiều filter cỡ khác nhau (1×1, 3×3, 5×5) rồi ghép kết quả, để mạng tự chọn quy mô đặc trưng phù hợp. Dùng convolution 1×1 để giảm số kênh, tiết kiệm tính toán.
-
ResNet (2015). Bước ngoặt cho phép huấn luyện mạng rất sâu (50, 101, thậm chí hơn 150 lớp). Vấn đề trước đó: chồng thêm lớp làm mạng khó huấn luyện hơn (gradient khó lan tới lớp đầu). ResNet đưa ra residual connection (còn gọi skip connection): đầu ra của một khối được cộng thẳng với đầu vào của nó — mạng học phần dư (residual) thay vì học lại toàn bộ ánh xạ.
Với skip connection, thông tin và gradient có một "đường tắt" đi thẳng qua nhiều lớp, làm dịu vấn đề vanishing gradient và giúp mạng sâu huấn luyện ổn định. Đây là một trong những ý tưởng có ảnh hưởng nhất của deep learning — nó xuất hiện lại ở cả Transformer (xem bài Transformer).
Gần đây, Vision Transformer (ViT) áp dụng cơ chế attention của Transformer thẳng lên ảnh (chia ảnh thành các mảng nhỏ — patch — rồi coi như một chuỗi). Với lượng dữ liệu đủ lớn, ViT cạnh tranh hoặc vượt CNN trên nhiều bài toán. Dù vậy, CNN vẫn rất phổ biến vì hiệu quả, tiết kiệm dữ liệu và dễ triển khai; nhiều hệ thống hiện đại còn kết hợp cả hai. Chi tiết về attention nằm ở bài Transformer.
6. Ví dụ minh hoạ: CNN nhỏ và transfer learning
Một CNN nhỏ cho bài phân loại ảnh (dạng phác thảo, cú pháp kiểu Keras):
# (minh hoạ) — CNN nhỏ phân loại ảnh 10 lớp
model = Sequential([
Conv2D(32, kernel_size=3, activation="relu", padding="same",
input_shape=(64, 64, 3)), # 32 filter 3x3
MaxPooling2D(pool_size=2), # giảm 64x64 -> 32x32
Conv2D(64, kernel_size=3, activation="relu", padding="same"),
MaxPooling2D(pool_size=2), # 32x32 -> 16x16
Conv2D(128, kernel_size=3, activation="relu", padding="same"),
GlobalAveragePooling2D(), # gom mỗi kênh thành 1 số
Dense(128, activation="relu"),
Dropout(0.5), # chống overfitting
Dense(10, activation="softmax"), # 10 lớp -> xác suất
])
model.compile(optimizer="adam",
loss="categorical_crossentropy",
metrics=["accuracy"])
Trong thực tế, hiếm khi ta huấn luyện CNN từ con số 0. Thay vào đó dùng transfer learning: lấy một mạng đã huấn luyện trên ImageNet (1,2 triệu ảnh, 1000 lớp) và tái sử dụng.
# (minh hoạ) — transfer learning: load pretrained + gắn đầu phân loại mới
base = ResNet50(weights="imagenet", # tải trọng số đã học sẵn
include_top=False, # bỏ lớp phân loại 1000-lớp của ImageNet
input_shape=(224, 224, 3))
base.trainable = False # ĐÓNG BĂNG (freeze) backbone
model = Sequential([
base, # bộ trích đặc trưng dùng lại
GlobalAveragePooling2D(),
Dense(256, activation="relu"),
Dropout(0.5),
Dense(num_classes, activation="softmax"), # đầu phân loại của TA
])
model.compile(optimizer="adam",
loss="categorical_crossentropy",
metrics=["accuracy"])
# Giai đoạn 1: chỉ huấn luyện đầu mới (feature extraction)
# Giai đoạn 2 (tuỳ chọn): mở băng vài lớp cuối của base, hạ learning rate -> fine-tune
7. Transfer learning trong thực chiến
Đây là phần thực dụng nhất của bài. Ý tưởng: các lớp đầu của một CNN đã học những đặc trưng rất tổng quát (cạnh, kết cấu, mảng màu) — chúng hữu ích cho gần như mọi bài toán ảnh, không riêng ImageNet. Ta tái sử dụng phần đó thay vì học lại.
Có hai chế độ, chọn theo lượng dữ liệu bạn có:
-
Feature extraction (trích đặc trưng — freeze backbone). Đóng băng toàn bộ mạng gốc, chỉ huấn luyện lớp phân loại mới gắn thêm. Dùng khi dữ liệu ít (vài trăm đến vài nghìn ảnh) hoặc bài toán gần với ImageNet. Nhanh, ít rủi ro overfitting, chạy được cả trên máy yếu.
-
Fine-tuning (tinh chỉnh — unfreeze). Sau khi feature extraction ổn định, mở băng một số lớp cuối của backbone và huấn luyện tiếp với learning rate rất nhỏ. Điều này cho mạng điều chỉnh các đặc trưng cấp cao cho hợp miền dữ liệu của bạn. Dùng khi có nhiều dữ liệu hơn hoặc miền ảnh khác xa ImageNet (ví dụ ảnh y tế, ảnh vệ tinh).
Nguyên tắc: freeze lớp đầu, unfreeze lớp cuối. Lớp đầu chứa đặc trưng tổng quát nên giữ nguyên; lớp cuối chuyên biệt hơn nên đáng tinh chỉnh. Và luôn hạ learning rate khi fine-tune để không "phá hỏng" kiến thức đã học sẵn. Các kỹ thuật chống overfitting (dropout, weight decay, early stopping) từ bài Regularization & tuning đặc biệt quan trọng khi dữ liệu ít.
8. Data augmentation cho ảnh
Khi dữ liệu ít, tăng cường dữ liệu (data augmentation) là công cụ gần như bắt buộc. Ý tưởng: sinh thêm biến thể của ảnh huấn luyện bằng các phép biến đổi giữ nguyên nhãn, để mạng học được sự bất biến và bớt học vẹt:
- Lật ngang (flip) — mèo lật vẫn là mèo.
- Xoay / dịch / phóng to nhỏ nhẹ — mô phỏng góc chụp khác nhau.
- Đổi độ sáng / tương phản / màu — mô phỏng điều kiện ánh sáng.
- Cắt ngẫu nhiên (random crop) — buộc mạng không phụ thuộc vào một vị trí cố định.
Lưu ý: chỉ chọn phép biến đổi không làm sai nhãn. Lật ngang chữ số "3" tạo ra ký tự vô nghĩa; xoay ảnh biển báo giao thông có thể đổi ý nghĩa. Với bài toán như OCR hay nhận dạng chứng từ, phải cân nhắc kỹ phép nào an toàn.
9. Ứng dụng
CNN đứng sau hầu hết bài toán thị giác máy tính:
- Phân loại ảnh (classification): ảnh này là mèo hay chó, sản phẩm lỗi hay đạt.
- Phát hiện đối tượng (detection): tìm và khoanh hộp quanh vật thể (người, xe, khuôn mặt).
- Phân đoạn (segmentation): gán nhãn cho từng điểm ảnh — tách chính xác vùng vật thể (ảnh y tế, xe tự lái).
- OCR: nhận dạng ký tự từ ảnh — đọc chữ, số trên tài liệu, biển số, hoá đơn.
- Nhận diện khuôn mặt / xác thực sinh trắc.
Use case thực tế
1. Transfer learning khi ít dữ liệu — bài toán phân loại chứng từ. Một ngân hàng cần tự động phân loại ảnh chứng từ khách nộp (CMND, hộ chiếu, sổ hộ khẩu, giấy tờ khác) nhưng chỉ có vài nghìn ảnh dán nhãn — quá ít để huấn luyện CNN từ đầu. Giải pháp thực tế: lấy ResNet đã huấn luyện ImageNet, freeze backbone, gắn một đầu phân loại vài lớp lên trên và chỉ huấn luyện đầu đó. Kèm data augmentation (xoay nhẹ, đổi sáng mô phỏng ảnh chụp điện thoại). Chỉ với vài nghìn ảnh, cách này thường đạt độ chính xác cao mà chỉ mất vài chục phút huấn luyện — điều bất khả thi nếu train từ 0.
2. OCR cho eKYC ngân hàng. Trong quy trình định danh điện tử (eKYC), khách chụp ảnh giấy tờ tuỳ thân; hệ thống cần tự động đọc họ tên, số giấy tờ, ngày sinh, ngày cấp để điền vào hồ sơ. Pipeline điển hình dùng CNN ở hai chặng: (a) detection — định vị vùng chứa chữ và các trường thông tin trên giấy tờ; (b) recognition — CNN (thường kết hợp với thành phần xử lý chuỗi) đọc ký tự trong từng vùng. So với nhập tay, OCR rút ngắn thời gian mở tài khoản từ nhiều phút xuống vài giây và giảm sai sót nhập liệu. Thách thức thực tế: ảnh mờ, chói sáng, giấy tờ nghiêng, chữ tiếng Việt có dấu — nên data augmentation và làm sạch ảnh trước khi nhận dạng là khâu quan trọng.
Ghi nhớ
- MLP không hợp ảnh vì bùng nổ tham số và mất cấu trúc không gian; CNN sửa bằng filter nhỏ trượt khắp ảnh với weight sharing.
- Convolution dùng filter học được để tạo feature map, phát hiện đặc trưng phân cấp: cạnh → hình → vật.
stride/paddingđiều khiển kích thước đầu ra. - Pooling (thường max) thu gọn feature map, tăng bất biến dịch chuyển nhỏ và mở rộng trường nhìn.
- Kiến trúc điển hình:
conv → act → pool → ... → dense → softmax— phần conv trích đặc trưng, phần dense phân loại. - Các mốc kiến trúc: LeNet → AlexNet (ReLU, dropout) → VGG (3×3 xếp chồng) → Inception (đa quy mô) → ResNet (skip connection cho mạng rất sâu); gần đây có ViT.
- Transfer learning là mặc định thực chiến: feature extraction (freeze) khi ít dữ liệu, fine-tuning (unfreeze lớp cuối, learning rate nhỏ) khi nhiều dữ liệu hơn.
- Data augmentation là cứu cánh khi dữ liệu ít — nhưng chỉ dùng phép biến đổi không làm sai nhãn.
- Ứng dụng ngân hàng nổi bật: phân loại chứng từ ít dữ liệu và OCR cho eKYC.
Đọc tiếp: Nền tảng Deep Learning · Regularization & tuning · Transformer & attention · PyTorch trong thực chiến.
Bài viết liên quan
Phân biệt AI/ML/DL, các kiểu học máy, quy trình ML end-to-end và thuật ngữ nền tảng.
Chất lượng dữ liệu, xử lý thiếu/ngoại lai, mã hoá, chuẩn hoá, tạo đặc trưng và tránh data leakage.
Mô hình ngôn ngữ lớn hoạt động ra sao, token, context window, tham số sinh, và kỹ thuật viết prompt.
Retrieval-Augmented Generation, vector database, tool calling, agent và MCP để xây ứng dụng LLM thực tế.