Kiến trúc mạng học sâu: từ nền tảng đến LLM·Chương 2 — CNN: học từ cấu trúc không gian

Chế độ xem

CNN thực hành: từ dữ liệu ảnh đến một model có thể tin được

Hai bài trước trả lời hai câu hỏi:

  • convolution xử lý ảnh như thế nào;
  • convolution được xếp thành ConvNet (ResNet, ConvNeXt, …) để giải quyết trainability, trộn đặc trưng và chi phí ra sao.

Bài này trả lời câu hỏi thứ ba:

Làm thế nào biến một folder ảnh thành một pipeline CNN được huấn luyện, đánh giá và debug đúng cách?

Mục tiêu không phải nhồi API. Ta dùng một bài toán xuyên suốt — phân loại ảnh lá thành ba lớp — để đặt mọi quyết định thiết kế vào đúng ngữ cảnh.

healthy
class_a
class_b

Mạch thực hành:

dữ liệu + split + transform
  → cách dùng backbone pretrained
  → vòng train / eval
  → metric và error analysis
  → debug theo tầng, đổi kiến trúc sau cùng

ResNet-18 là xe tập lái: layer fc cuối dễ thay, pretrained sẵn, nhỏ đủ để iteration nhanh và đủ mạnh để kiểm tra pipeline. Khi pipeline đã đúng và ổn định, bài trước đã chỉ hướng đổi sang ConvNeXt hoặc MobileNetV4 nếu cần — nhưng không bao giờ đổi backbone để che lỗi dữ liệu.

Sau bài này, bạn cần làm được gì?

Ở mức cốt lõi, bạn cần:

  • mô tả được pipeline từ ảnh thô đến prediction;
  • phân biệt train from scratch, feature extraction và fine-tuning;
  • hiểu resize, normalize và augmentation nằm ở đâu;
  • biết dùng validation để chọn model và giữ test cho đánh giá cuối;
  • nhận ra các lỗi phổ biến khiến CNN “train được nhưng sai”.

Ở mức thực hành, bạn nên:

  • thay classification head của một backbone pretrained;
  • kiểm tra shape và label mapping trước khi train lâu;
  • đọc loss curve, confusion matrix và các failure case;
  • debug theo thứ tự rẻ → đắt, thay vì đổi model ngẫu nhiên.

Toàn bộ pipeline trước khi nhìn code

  • Ảnh thô
  • Kiểm tra dữ liệu
  • Chia train / val / test
  • Resize và preprocessing
  • Augmentation chỉ trên train
  • CNN / pretrained backbone
  • Loss
  • Backprop và optimizer
  • Validation
  • Chọn checkpoint
  • Test một lần theo protocol
  • Error analysis

Một lỗi ở đầu pipeline — sai split, sai nhãn, rò rỉ dữ liệu — có thể làm mọi bước sau mất ý nghĩa. Data leakage không sửa được bằng ConvNeXt lớn hơn.

1. Dữ liệu: sample, split, nhìn ảnh, transform

Một sample và một label

sample = một ảnh lá
label  = healthy / class_a / class_b

Model nhận tensor 3 × H × W và trả ra ba logit — điểm số thô chưa chuẩn hóa, ví dụ [1.2, -0.4, 2.1]. Lớp dự đoán là vị trí logit lớn nhất, ở đây là class_b (vị trí thứ 3).

Nếu dùng CrossEntropyLoss trong PyTorch, đưa logits thô vào loss — PyTorch tự xử lý softmax bên trong. Không softmax trước rồi mới đưa vào loss, vì sẽ tính hai lần và gây mất ổn định số học.

Chia train / val / test trước khi augmentation

Split phải mô phỏng dữ liệu mới thật sự. Với ảnh, bẫy phổ biến là ảnh gần trùng: một chiếc lá chụp 10 lần, 8 ảnh vào train và 2 ảnh vào test — model “đoán đúng” vì nhận ra ảnh gần giống, không phải vì thật sự khái quát.

Nếu dataset có thông tin về nguồn, nên dùng group split (chia theo nhóm): tất cả ảnh từ cùng một cây / bệnh nhân / người chụp / video / địa điểm phải nằm chung một split, không được rải sang nhiều split. Ý tưởng là: test set phải chứa đối tượng mới, không chỉ ảnh mới của đối tượng cũ.

Augmentation leakage: không tạo nhiều bản biến đổi offline rồi mới random split. Các phiên bản gần giống của cùng ảnh gốc sẽ rải vào cả train lẫn test, làm test không còn độc lập.

Sai:  ảnh gốc → tạo sẵn 10 bản aug → gộp tất cả → random split 80/10/10
Đúng: ảnh gốc → split trước (theo nguồn nếu có thể) → aug online chỉ trong train loader

Nhìn dữ liệu trước khi train

Lấy ngẫu nhiên vài chục ảnh và kiểm tra:

  • Label đúng chưa? File đọc được hết không? Class mất cân bằng nhiều không?
  • Có watermark, chữ viết hoặc nền ảnh vô tình tiết lộ label không?
  • Có ảnh trùng hoặc gần trùng? Orientation bất thường?

Shortcut điển hình: class_a luôn có nền trắng phòng lab, class_b luôn chụp ngoài trời — model học phân biệt nền thay vì bệnh trên lá, đạt accuracy cao trong lab nhưng sụp đổ khi triển khai.

Resize không vô hại

Backbone thường gắn với một resolution, ví dụ 224×224.

CáchRủi ro
Kéo giãn 800×400 → 224×224vật thể méo
Resize + cropmất vùng quan trọng
Padgiữ nội dung, thêm biên giả

Không có lựa chọn đúng cho mọi dataset. Kiểm tra ảnh sau biến đổi.

Chuẩn hóa khớp pretrained weights

Ảnh 8-bit thường ở [0, 255]. Pipeline đổi sang số thực, thường về [0, 1], rồi có thể chuẩn hóa mean/std.

Nếu dùng pretrained weights, resize và chuẩn hóa phải khớp với bộ trọng số đó. Mỗi model được pretrain với pipeline preprocessing riêng — đừng nhớ cứng một cặp mean/std cho mọi model. torchvision đã gắn transform đúng với từng weights:

from torchvision.models import resnet18, ResNet18_Weights

weights = ResNet18_Weights.DEFAULT
model = resnet18(weights=weights)
eval_transform = weights.transforms()

Với train transform có augmentation, phần normalize cuối vẫn phải khớp với weight đó — chỉ các bước aug ngẫu nhiên mới thêm vào trước normalize. Preprocessing là một phần của model pipeline, không phải code phụ có thể bỏ qua: train dùng normalize A nhưng inference quên normalize, hoặc train với ảnh RGB nhưng deploy nhận ảnh BGR — model nhận đầu vào khác hoàn toàn phân phối lúc train, kết quả không thể đoán trước.

Augmentation chỉ khi nhãn vẫn đúng

Augmentation tạo biến thể trong train để model bớt phụ thuộc vào những chi tiết không quan trọng. Hợp lý với ảnh lá: crop nhẹ, flip ngang, điều chỉnh sáng/tương phản trong giới hạn, rotation nhỏ.

Nhưng cùng kỹ thuật đó có thể sai khi áp dụng vào domain khác:

  • Chữ số 6 xoay mạnh có thể trông giống 9 → label đổi.
  • X-quang flip trái-phải mất ý nghĩa về phía cơ thể.
  • Crop quá mạnh có thể cắt mất vùng tổn thương cần phát hiện.
  • Color jitter phá vỡ tín hiệu màu sắc vốn chính là dấu hiệu bệnh.

Câu hỏi đúng cần hỏi trước mọi augmentation: “Biến đổi này có giữ nguyên label trong thế giới thật không?” — không phải “aug nào đang được dùng phổ biến?”

Train có aug ngẫu nhiên. Validation/test phải ổn định và tái lập:

TRAIN:     resize/crop ngẫu nhiên, flip ngẫu nhiên, jitter nhẹ, normalize
VAL/TEST:  resize cố định, center crop hoặc policy cố định, normalize

Nếu validation cũng dùng aug ngẫu nhiên mạnh, metric sẽ dao động mỗi lần chạy — không rõ là model tốt hơn hay chỉ aug may mắn hơn lần đó.

Thêm hai bẫy màu sắc hay gặp:

  • Một số thư viện (PIL) đọc ảnh RGB, OpenCV đọc BGR. Dùng pretrained RGB nhưng input BGR sẽ hoán đổi kênh màu — model nhận ảnh “sai màu”.
  • Ảnh xám một kênh: hoặc sửa layer đầu nhận 1 channel, hoặc lặp thành 3 kênh giống nhau để dùng backbone RGB — miễn là train và inference nhất quán.

2. Ba cách dùng CNN, với ResNet-18 làm xe tập lái

Train from scratch

Khởi tạo toàn bộ weight ngẫu nhiên, train từ đầu. Phù hợp hơn khi dữ liệu đủ lớn, domain rất khác so với dữ liệu pretraining, hoặc nghiên cứu bắt buộc không dùng pretrained. Với dataset nhỏ: dễ overfit nhanh.

Feature extraction

Load pretrained backbone, đóng băng (freeze) toàn bộ backbone, chỉ train classification head mới.

Ưu điểm: train nhanh, ít tham số cập nhật, thường là baseline mạnh khi data ít.

Fine-tuning

Bắt đầu từ pretrained weights, mở (unfreeze) một phần hoặc toàn bộ backbone, cập nhật tiếp bằng dữ liệu mới. Representation có thể thích nghi tốt hơn với domain mới; nhưng cần learning rate nhỏ hơn cho backbone (tránh phá vỡ weight tốt đã có) và theo dõi overfitting cẩn thận hơn.

Thay head ResNet-18

Trong torchvision, ResNet-18 kết thúc bằng fc:

import torch.nn as nn
from torchvision.models import resnet18, ResNet18_Weights

weights = ResNet18_Weights.DEFAULT
model = resnet18(weights=weights)

num_features = model.fc.in_features
model.fc = nn.Linear(num_features, 3)

Freeze backbone rồi gắn head mới:

for param in model.parameters():
    param.requires_grad = False

model.fc = nn.Linear(num_features, 3)

Layer fc được tạo sau bước freeze nên mặc định vẫn requires_grad=True. Kiểm tra bằng cách in số tham số trainable:

trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
total = sum(p.numel() for p in model.parameters())
print("trainable:", trainable, "total:", total)

Nếu chỉ muốn train head mà trainable gần bằng total, freeze chưa đúng — backbone vẫn đang được cập nhật.

ConvNeXt trong timm thường không có tên layer là fc mà là head.fc hoặc tương tự; nhưng nguyên tắc giống nhau: thay module classifier / head, giữ nguyên normalize khớp với checkpoint. Tên API khác nhau, nguyên tắc không đổi.

Fine-tune dần với learning rate khác nhau

Khi data không đủ lớn để fine-tune toàn bộ ngay:

1. Train head trong khi backbone frozen
2. Kiểm tra pipeline và metric — đảm bảo không có lỗi cơ bản
3. Unfreeze stage cuối của backbone
4. Dùng LR nhỏ hơn cho backbone, LR lớn hơn cho head
5. Theo dõi validation loss và metric
6. Chỉ mở thêm layer nếu có lý do rõ ràng (val vẫn cải thiện)

Lý do dùng LR khác nhau: head mới khởi tạo gần ngẫu nhiên — cần học nhanh; backbone đã có weight hữu ích — cần cập nhật nhẹ nhàng, không phá vỡ:

optimizer = torch.optim.AdamW([
    {"params": model.layer4.parameters(), "lr": 1e-5},
    {"params": model.fc.parameters(), "lr": 1e-4},
])

Các con số LR cụ thể phải tune theo bài toán. Ý quan trọng: tham số mới và tham số pretrained không nhất thiết cần cùng learning rate.

3. Vòng train / eval: shape, mode và sanity check

CNN không có cơ chế học bí mật nào khác MLP. Backprop vẫn đi qua convolution, tính gradient theo từng kernel weight và cập nhật như thường.

model.train()

for images, labels in train_loader:
    optimizer.zero_grad()
    logits = model(images)
    loss = criterion(logits, labels)
    loss.backward()
    optimizer.step()

Validation:

model.eval()

with torch.no_grad():
    for images, labels in val_loader:
        logits = model(images)

model.eval() thay đổi hành vi của BatchNorm (dùng running statistics thay vì thống kê batch) và Dropout (tắt dropout). torch.no_grad() tránh lưu computation graph không cần thiết, tiết kiệm bộ nhớ.

Hai lỗi hay gặp:

  • Đánh giá mà quên model.eval(): metric lệch so với inference thật vì BatchNorm vẫn dùng thống kê batch.
  • Quên gọi model.train() lại sau khi validation: epoch tiếp theo chạy ở chế độ eval, Dropout tắt và BatchNorm dùng running stats thay vì học từ batch.
train phase → model.train()
validation  → model.eval()
next epoch  → model.train() lại  ← đừng quên

In một batch trước khi train lâu — đây là sanity check rẻ nhất:

images, labels = next(iter(train_loader))
print(images.shape, labels.shape)
logits = model(images)
print(logits.shape)

Với batch 32, ba lớp, output kỳ vọng: images [32, 3, 224, 224], labels [32], logits [32, 3]. Nếu thấy [32, 224, 224, 3] thì ảnh đang ở format NHWC trong khi PyTorch CNN cần NCHW — cần transpose trước khi đưa vào model.

Với dataset tạo từ folder, luôn kiểm tra train_dataset.class_to_idx. Đừng giả định healthy = 0. Nếu mapping lúc inference khác lúc train, index đúng nhưng tên lớp sai — model tưởng đoán đúng nhưng thật ra nhầm hoàn toàn.

Overfit một batch nhỏ (8–32 mẫu): train model chỉ trên vài ảnh cố định, kỳ vọng loss giảm về gần 0. Nếu loss không giảm, ưu tiên debug theo thứ tự: label sai, optimizer không cập nhật, requires_grad chưa đúng, loss hoặc output shape lỗi, learning rate quá nhỏ hoặc quá lớn, data pipeline — tất cả trước khi nghĩ đến đổi architecture. Lưu ý: phép kiểm tra này không chứng minh model sẽ generalize tốt; nó chỉ xác nhận vòng train-backprop-update chạy đúng.

Log ít nhất train loss, validation loss, metric chính và learning rate sau mỗi epoch. Một số pattern giúp định hướng debug:

Triệu chứngHướng nghi ngờ trước
Cả train và val đều tệlabel sai, LR quá nhỏ, model quá yếu, preprocessing lỗi
Train tốt, val xấu dầnoverfitting; xem augmentation, regularization, dataset size, data leakage
Loss không đổi từ epoch đầudebug pipeline: gradient không đi qua, LR quá nhỏ, loss tính sai

4. Đánh giá: mất cân bằng, confusion matrix, checkpoint và test một lần

Accuracy có thể che lớp yếu. Ví dụ dataset 800 / 150 / 50 ảnh: model đoán toàn healthy sẽ ra accuracy ~80% dù không nhận ra lớp nào khác. Dùng confusion matrix, per-class recall, macro F1 để thấy từng lớp hoạt động thế nào. Nếu lớp hiếm yếu, cân nhắc thêm dữ liệu, oversampling, class weights hoặc augmentation có kiểm soát — nhưng trước hết hỏi vì sao lớp đó yếu (thiếu data, label nhất quán kém, hay task quá khó?).

Ví dụ confusion matrix:

Thật \ Dự đoánHealthyAB
Healthy9055
A8357
B31522

Lớp B hay bị nhầm sang A. Câu hỏi tiếp theo không phải “đổi ResNet-50”: A và B có giống nhau về hình thái không? Label có nhất quán không? Vùng bệnh có quá nhỏ so với cách crop không? Resolution có đủ không? Subgroup nào lỗi nhiều nhất?

Xem ảnh đoán sai: quan sát ảnh gốc, label thật, prediction và confidence. Nhóm các lỗi theo pattern: ảnh mờ, vật thể nhỏ, nền phức tạp, ánh sáng bất thường, lớp khó vốn dĩ, label nghi ngờ, ảnh ngoài phân phối train.

Một lưu ý về confidence: softmax 0.98 không chứng minh model “chắc chắn đúng” — calibration (độ tin cậy có khớp accuracy không) là chủ đề riêng. Ở đây chỉ cần nhớ: confidence cao không có nghĩa là prediction đúng.

Checkpoint tốt nhất không nhất thiết là epoch cuối. Sau mỗi epoch, tính validation metric; nếu tốt hơn tốt nhất từ trước thì lưu checkpoint. Chốt tiêu chí lưu trước khi train: macro F1, accuracy hay val loss — tùy mục tiêu bài toán, không thay đổi tiêu chí giữa chừng.

Test set chỉ dùng cho đánh giá cuối theo protocol nghiêm ngặt:

train      → học tham số
validation → chọn cấu hình và checkpoint
test       → đánh giá một lần duy nhất ở cuối

Xem test sau mỗi lần đổi aug / LR / architecture là đang dùng test để tune — test không còn độc lập nữa. Nếu cần nhiều vòng phát triển, thêm holdout set hoặc external test set.

5. Thực nghiệm: baseline đơn giản, một thay đổi mỗi lần

Baseline cố ý đơn giản:

Backbone      : ResNet-18 pretrained (xe tập lái)
Input         : 224×224, transform khớp weights
Train         : augmentation nhẹ, nhãn vẫn đúng
Validation    : transform xác định
Loss          : CrossEntropyLoss
Optimizer     : AdamW hoặc SGD; LR head > LR backbone khi fine-tune
Model select  : validation macro F1
Test          : sau khi chốt pipeline

Baseline phải chạy ổn, tái lập được, đủ đơn giản để debug và tạo mốc so sánh. Khi pipeline đáng tin rồi, mới hỏi: có cần ConvNeXt, MobileNetV4, resolution cao hơn hay loss khác không? Chọn theo dữ liệu và phần cứng, đo latency nếu triển khai — đúng tư duy bài kiến trúc trước.

Đừng cùng lúc đổi backbone, resolution, aug, optimizer, loss và LR. Thay từng nhóm, ghi kết quả, mới thay nhóm tiếp.

Model nhỏ có ích ngay trong giai đoạn nghiên cứu: iteration nhanh, chạy nhiều seed, ablation rẻ hơn. Debug pipeline bằng model nhỏ trước, rồi mới scale lên model lớn.

Resolution không phải thay đổi nhỏ. Tăng mỗi chiều từ 224 → 448 thì số pixel tăng 4482/2242=4×448^2 / 224^2 = 4\times; tính toán và bộ nhớ activation tăng tương ứng. GPU memory lúc train còn chứa gradient, optimizer state và activation — không chỉ riêng tham số model.

Feature map và Grad-CAM giúp xem model phản ứng mạnh ở vùng nào của ảnh. Heatmap hữu ích cho phân tích và debug, nhưng không tự chứng minh model hiểu causal relationship. Dùng kết hợp với error analysis và hiểu biết domain.

Debug từ rẻ đến đắt

Architecture là tầng cuối cùng cần xem — vì đổi backbone tốn nhiều thời gian nhất. Thứ tự debug theo chi phí tăng dần:

  1. Dữ liệu: file hỏng, label sai, split bị leakage, ảnh trùng.
  2. Shape và preprocessing: NCHW/NHWC, RGB/BGR bị hoán đổi, resize sai, normalize thiếu hoặc sai giá trị, aug phá nhãn.
  3. Forward và loss: logits shape đúng chưa, target dtype đúng chưa, có softmax nhầm trước CrossEntropyLoss không.
  4. Gradient và optimizer: requires_grad có đúng chỗ không, parameter có được thêm vào optimizer không, LR có hợp lý không.
  5. Generalization: train/val gap, class imbalance, subgroup yếu, resolution thấp, capacity model.
  6. Architecture: đổi backbone chỉ khi pipeline đã đáng tin và vấn đề đã được xác định rõ.
Triệu chứngKiểm tra trước
Loss không giảmlabel, optimizer, requires_grad, LR, loss/input shape
Train rất cao, val thấpoverfit, split, aug, domain gap
Val dao động mạnhrandom transform trên val, data nhỏ, seed, BatchNorm, sampling
Một lớp gần như không được dự đoánimbalance, mapping, label, task setup
App tệ hơn notebookpreprocess, RGB/BGR, resize, eval(), file weight
CUDA OOMbatch, resolution, activation, model size
Train chậmloader, resolution, aug CPU, device
Accuracy cao nhưng ứng dụng tệmetric sai mục tiêu, slice yếu, leakage, shift

Mini-protocol tái lập

Dataset ba lớp ảnh lá — đây là trình tự đề xuất khi làm một bài toán phân loại ảnh mới:

Bước 1 — Trước khi train:

  • Đếm ảnh mỗi lớp, kiểm tra file hỏng và duplicate.
  • Group split nếu có rủi ro ảnh gần trùng.
  • Chia train / val / test.
  • Visualize 16–32 ảnh sau transform để xác nhận preprocessing đúng.

Bước 2 — Baseline:

  • ResNet-18 pretrained, thay head 3 lớp.
  • Freeze backbone, train head.
  • Lưu checkpoint tốt nhất theo val metric.

Bước 3 — Fine-tuning (nếu cần):

  • Unfreeze stage cuối backbone.
  • LR backbone nhỏ hơn head.
  • Log train/val loss + macro F1.
  • Dừng sớm nếu val xấu dần liên tục.

Bước 4 — Đánh giá:

  • Load best checkpoint, test đúng preprocess.
  • Tính accuracy, macro F1, confusion matrix, per-class recall.
  • Xem failure cases.

Bước 5 — Chỉ sau đó mới hỏi: cần backbone lớn hơn / hiện đại hơn không? Resolution? Loss khác? Thêm dữ liệu loại nào?

Bài thực hành hoàn thành khi chứng minh được tất cả: split không leakage rõ ràng; train và val/test transform tách biệt; một batch shape đúng; logits đúng số lớp; loss giảm trên sanity check nhỏ; lưu best val checkpoint; chạy test đúng protocol một lần; có confusion matrix hoặc per-class metric; đã xem prediction sai và ghi ít nhất một failure mode. Accuracy đẹp không thay thế được các kiểm tra này.

Bài tập thực hành

1. Dự đoán shape

Input 16 × 3 × 224 × 224 qua Conv 7×7, stride=2, padding=3, out=64 rồi MaxPool 3×3, stride=2, padding=1.

Kết quả theo công thức bài convolution:

16 × 64 × 112 × 112
16 × 64 × 56  × 56

Đây là stem kiểu ResNet: giảm resolution trước khi vào residual stage.

2. Tìm lỗi pipeline

1. Tạo 8 bản augmentation offline từ mỗi ảnh gốc
2. Gộp tất cả ảnh (8 × N ảnh)
3. Random split 80/10/10
4. Train CNN
5. Test accuracy = 99%

Vấn đề lớn nhất: các bản aug của cùng ảnh gốc nằm cả trong train lẫn test — model “ghi nhớ” ảnh gốc, không khái quát. Accuracy 99% phản ánh leakage, không phản ánh khả năng thật.

3. Chọn chiến lược transfer

3 lớp, mỗi lớp ~300 ảnh, GPU hạn chế, ảnh khá giống ảnh tự nhiên
A. Train ResNet-50 từ đầu
B. ResNet-18 pretrained, train head rồi fine-tune stage cuối
C. MLP flatten toàn bộ ảnh
D. ConvNeXt-Tiny from scratch

B là baseline hợp lý để bắt đầu: pretrained backbone giúp feature extraction tốt ngay từ đầu, model nhỏ dễ debug và iteration nhanh. A và D tốn tài nguyên lớn và dễ overfit nghiêm trọng với chỉ ~900 ảnh. C bỏ đi đặc tính không gian — thứ vừa được học ở hai bài trước — không có lý do hợp lý. Sau khi B chạy đúng và ổn định, mới xem xét ConvNeXt pretrained — không train from scratch — nếu accuracy vẫn còn cần cải thiện.

Nếu chỉ nhớ 10 ý

  • Split theo nguồn trước khi augmentation khi có nguy cơ ảnh gần trùng.
  • Nhìn dữ liệu và ảnh sau transform trước khi train.
  • Preprocessing là một phần của model; pretrained weights cần đúng normalize.
  • Augmentation chỉ hợp lý nếu sau biến đổi nhãn vẫn đúng.
  • Dataset nhỏ: pretrained backbone, không train from scratch một họ SOTA.
  • Feature extraction chỉ train head; fine-tuning cập nhật thêm backbone với LR nhỏ hơn.
  • model.train() / model.eval() đổi BatchNorm và Dropout.
  • Loss không giảm: debug data, shape, loss, gradient trước khi đổi architecture.
  • Validation chọn cấu hình; test đánh giá cuối.
  • Confusion matrix và failure cases nói nhiều hơn một accuracy tổng.

Câu hỏi tự kiểm tra

  1. Vì sao các ảnh từ cùng một đối tượng thật nên thường nằm cùng split?
  2. Resize kéo giãn có thể gây vấn đề gì?
  3. Vì sao validation không nên dùng augmentation ngẫu nhiên mạnh như train?
  4. Feature extraction khác fine-tuning ở parameter nào được cập nhật?
  5. Vì sao pretrained backbone thường dùng learning rate nhỏ hơn head mới?
  6. CrossEntropyLoss trong PyTorch thường nhận logits hay softmax đã tính sẵn?
  7. model.eval() ảnh hưởng loại layer nào đáng chú ý?
  8. Overfit một batch nhỏ giúp debug điều gì?
  9. Vì sao test set không nên được xem sau mỗi thay đổi hyperparameter?
  10. Nếu notebook tốt nhưng app inference tệ, ba lỗi preprocessing nào nên kiểm tra đầu tiên?

Kết thúc Chương 2

Ba bài CNN tạo thành một khung hoàn chỉnh:

Cấu trúc ảnh
→ convolution khai thác tính cục bộ và chia sẻ trọng số
→ các block ghép thành ConvNet phân cấp
→ backbone pretrained được fine-tune trong pipeline dữ liệu
→ metric + error analysis + debug có hệ thống

Bốn câu hỏi xuyên suốt ba bài:

  1. Dữ liệu có cấu trúc gì? — ảnh có tính cục bộ và có thể dùng lại pattern.
  2. Architecture khai thác cấu trúc đó bằng cách nào? — kết nối cục bộ, chia sẻ trọng số, xếp stage.
  3. Thông tin và shape thay đổi ra sao qua các layer? — resolution giảm, channel tăng, vùng tiếp nhận mở rộng.
  4. Ta biết model tốt hay lỗi dựa trên bằng chứng nào? — split đúng, metric có ý nghĩa, failure cases đã xem.

Chương tiếp theo chuyển sang dữ liệu tuần tự — nơi quan hệ trước–sau theo thời gian quan trọng hơn vị trí trong không gian, và Vanilla RNN là kiến trúc đầu tiên mang thông tin qua hidden state.

Tài liệu tham khảo và đọc thêm