Kiến trúc mạng học sâu: từ nền tảng đến LLM·Chương 12 — Pretraining, transfer learning và fine-tuning

Chế độ xem

Pretraining, transfer learning và fine-tuning: học một lần, thích nghi nhiều lần

Trong phần lớn các bài toán học máy thực tế, bạn sẽ không bắt đầu từ các ma trận trọng số ngẫu nhiên. Huấn luyện một mạng neural lớn từ con số 0 đòi hỏi hàng triệu mẫu dữ liệu được gán nhãn chuẩn xác, hàng trăm nghìn giờ tính toán của GPU và ngân sách khổng lồ — những thứ mà hầu hết các dự án vừa và nhỏ không bao giờ có.

Thay vào đó, ngành học sâu hiện đại vận hành dựa trên một triết lý khác: học một lần trên dữ liệu lớn, rồi tái sử dụng và thích nghi nhiều lần cho các bài toán chuyên biệt. Đó là sợi dây liên kết chặt chẽ giữa ba khái niệm nền tảng: Pretraining, Transfer Learning và Fine-tuning.

Nếu chỉ giữ lại một câu, có thể dùng câu sau:

Pretraining tạo ra một xuất phát điểm mang sẵn tri thức biểu diễn từ dữ liệu lớn; transfer learning là ý tưởng tái sử dụng tri thức đó; còn fine-tuning là phương thức thích nghi có kiểm soát cho bài toán đích.

Vì sao không phải lúc nào cũng train từ đầu?

Giả sử bạn cần xây dựng một mô hình phân loại bệnh lá cây với tập dữ liệu chỉ vỏn vẹn 500 bức ảnh. Bạn đứng trước hai lựa chọn:

  1. Khởi tạo ngẫu nhiên toàn bộ trọng số (Train from scratch): Mô hình buộc phải tự mò mẫm học lại từ những chi tiết sơ cấp nhất như cạnh biên, đường cong, góc nhọn, mảng màu, chất cảm bề mặt, rồi mới chắp vá thành gân lá và đốm bệnh. Với 500 ảnh, mô hình gần như chắc chắn sẽ bị quá khớp (overfitting) nặng nề: nó học thuộc lòng từng pixel của tập train và mất hoàn toàn khả năng dự đoán ảnh mới.
  2. Kế thừa một mô hình đã học trước (Transfer Learning): Bạn lấy một mạng ResNet hoặc Vision Transformer đã được huấn luyện trên 14 triệu ảnh của ImageNet. Mạng này đã “nhìn thấy cả thế giới” và sở hữu sẵn bộ lọc nhận diện hình khối cực kỳ tinh vi. Bạn chỉ cần thay lớp phân loại cuối cùng và tinh chỉnh nhẹ để nó nhận biết đốm bệnh cụ thể.

Minh họa khái niệm về hiệu quả của transfer learning

Hình 1. So sánh khái niệm giữa học từ đầu (đường dưới) và transfer learning (đường trên). Đường có transfer khởi đầu ở mức chất lượng cao hơn, dốc hơn và thường đạt trần hiệu năng tốt hơn.

Điều thực sự được “chuyển giao” là gì?

Khi nói về transfer learning, ta không mang các bức ảnh từ bài toán cũ sang bài toán mới. Điều thực sự được chuyển giao qua các ranh giới bài toán bao gồm:

  • Các ma trận trọng số đã học (Learned Weights): Điểm khởi đầu tham số θ0\theta_0 nằm rất gần với vùng cực tiểu tối ưu thay vì trôi nổi ngẫu nhiên trong không gian nhiều triệu chiều.
  • Biểu diễn trung gian (Feature Representations): Các feature map ở các tầng sâu đã biết cách trừu tượng hóa thế giới thị giác hoặc ngữ nghĩa ngôn ngữ thành các vector cô đọng.
  • Quy trình tiền xử lý đi kèm (Preprocessing & Tokenizer): Bộ tách từ (tokenizer) của mô hình ngôn ngữ hoặc các tham số chuẩn hóa mean/std của ảnh chụp cũng là một phần không thể tách rời của checkpoint.

Một checkpoint pretrained không chỉ là “kiến trúc mạng”. Hai mô hình có cùng kiến trúc ResNet-50 nhưng một bên mang trọng số ImageNet và một bên khởi tạo ngẫu nhiên là hai thực thể hoàn toàn khác nhau về năng lực.

Pretraining: học tri thức tổng quát trước bài toán đích

Pretraining là bước huấn luyện mô hình trên một nguồn dữ liệu khổng lồ DsourceD_{\text{source}} nhằm tối ưu một hàm mất mát tổng quát:

θ0=arg⁡min⁡θLpre(θ;Dsource)\theta_0 = \arg\min_{\theta} \mathcal{L}_{\text{pre}}(\theta; D_{\text{source}})

Sau đó, bộ tham số θ0\theta_0 này sẽ được dùng làm điểm xuất phát để thích nghi trên tập dữ liệu đích DtargetD_{\text{target}}.

Pretraining không đồng nghĩa với “học không giám sát”

Đây là một ngộ nhận rất phổ biến. Pretraining chỉ nói về thời điểm huấn luyện (trước bài toán đích), không quy định loại tín hiệu nhãn:

Phương thức PretrainingBản chất tín hiệu giám sátVí dụ điển hình
Có giám sát (Supervised)Dùng nhãn lớp do con người gắnResNet học trên ImageNet với 1,000 nhãn vật thể.
Tự giám sát (Self-supervised)Nhãn sinh ra từ chính cấu trúc dữ liệuDự đoán từ tiếp theo (Next Token Prediction) trong GPT; đoán vùng ảnh bị che (Masked Autoencoders — MAE).
Đa phương thức (Multimodal)Ghép cặp giữa các dạng dữ liệu khác nhauCLIP học độ tương đồng giữa cặp ảnh và câu chú thích văn bản.
Tiếp tục học trước (Continued Pretraining)Giữ mục tiêu tự giám sát nhưng đổi sang kho văn bản miền mớiTiếp tục chạy Next Token Prediction trên kho tài liệu y khoa.

Pretraining LLM trên dữ liệu văn bản lớn tạo foundation model, sau đó fine-tuning trên dữ liệu nhỏ hơn cho tác vụ cụ thể.

Hình 2. Quy trình hai bước chuẩn mực: Pretraining trên kho dữ liệu khổng lồ để tạo Foundation Model, sau đó Fine-tuning trên tập dữ liệu nhỏ hơn cho bài toán đích. Nguồn: Sebastian Raschka.

Từ Backbone đến thời đại Foundation Model

Khái niệm Foundation Model (Mô hình nền tảng) chính là bước phát triển tột bậc của tư duy transfer learning: chi phí tính toán khổng lồ được trả một lần duy nhất ở giai đoạn pretraining, sau đó một checkpoint duy nhất có thể phân nhánh để giải quyết hàng trăm tác vụ khác nhau:

  • Một backbone ViT phục vụ đồng thời cho phân loại, phát hiện vật thể và phân vùng ảnh.
  • Một mô hình ngôn ngữ lớn (LLM) phục vụ dịch thuật, tóm tắt, viết code và trả lời câu hỏi nghiệp vụ.

Transfer learning: ba chiến lược thích nghi nền tảng

Khi chuyển giao một mô hình nền tảng sang bài toán mới, ta có ba chiến lược tiếp cận chính tùy thuộc vào lượng tài nguyên và mức độ lệch miền:

1. Trích đặc trưng (Feature Extraction / Frozen Backbone)

Ta đóng băng toàn bộ các tầng của backbone pretrained (θ0\theta_0 không đổi, param.requires_grad = False), chỉ thêm một lớp phân loại mới (Classification Head gϕg_\phi) và tối ưu tham số ϕ\phi:

z=fθ0(x),y^=gϕ(z)z = f_{\theta_0}(x), \qquad \hat{y} = g_\phi(z)
  • Ưu điểm: Huấn luyện cực nhanh, tốn rất ít bộ nhớ GPU, không bao giờ lo bị hỏng biểu diễn cũ, chống overfitting tuyệt đối khi dữ liệu đích nhỏ.
  • Nhược điểm: Nếu miền dữ liệu đích khác xa miền nguồn (ví dụ từ ảnh chụp đời thường sang ảnh chụp hiển vi tế bào), backbone cố định không thể tự điều chỉnh để trích xuất các đặc trưng mới phù hợp.

2. Tinh chỉnh một phần (Partial Fine-tuning)

Ta đóng băng các tầng đầu và chỉ mở khóa một số khối cuối cùng của backbone cùng với Head mới. Vì các tầng cuối đại diện cho các khái niệm đặc thù cấp cao, việc cho phép chúng thích nghi nhẹ giúp mô hình bám sát dữ liệu đích hơn mà vẫn tiết kiệm chi phí tính toán.

3. Tinh chỉnh toàn bộ (Full Fine-tuning)

Mọi tham số của mạng đều được cập nhật gradient. Chiến lược này cho trần hiệu năng cao nhất nhưng đòi hỏi tập dữ liệu đích phải đủ lớn và cần dùng tốc độ học rất nhỏ để tránh phá vỡ các đặc trưng hữu ích đã có.

Quy trình Freeze Backbone và Train Classification Head

Hình 3. Minh họa trực quan: Backbone được đóng băng để trích xuất vector đặc trưng, chỉ có Classification Head được cập nhật gradient.

Vì sao transfer learning lại hoạt động hiệu quả?

Tính phân cấp của biểu diễn (Feature Hierarchy)

Trong các mạng nơ-ron sâu (nhất là CNN và Vision Transformer), các tầng tính toán có sự phân hóa tự nhiên từ tổng quát đến chuyên biệt:

  • Tầng đầu: Học các đặc trưng thị giác phổ quát (cạnh biên Gabor, góc nhọn, mảng màu, tần số không gian). Bất kỳ bài toán thị giác nào — từ nhận diện khuôn mặt, chẩn đoán X-quang đến phân loại ô tô — đều cần các thành phần sơ cấp này.
  • Tầng giữa: Ghép các cạnh thành họa tiết (texture), hoa văn, hình tròn, mắt, mũi, bánh xe.
  • Tầng cuối: Ghép thành các bộ phận đặc thù của lớp (chó corgi, xe buýt trường học).

Nghiên cứu kinh điển của Yosinski và cộng sự (NeurIPS 2014) đã chứng minh rằng các tầng đầu có khả năng chuyển giao xuyên bài toán cực kỳ mạnh mẽ, trong khi các tầng cuối mang tính chuyên biệt cao hơn.

Khởi đầu thuận lợi trong không gian tối ưu

Một mạng khởi tạo ngẫu nhiên nằm ở một vị trí bất kỳ trên mặt phẳng hàm mất mát và phải vượt qua hàng nghìn yên ngựa (saddle points) gồ ghề. Trọng số pretrained đặt mô hình vào một vùng thung lũng đã có cấu trúc tốt, giúp thuật toán tối ưu hội tụ nhanh hơn nhiều lần và tìm được nghiệm tổng quát hóa tốt hơn.

Khi nào nên freeze, partial fine-tune hay full fine-tune?

Quyết định chọn chiến lược phụ thuộc chủ yếu vào hai trục: Kích thước dữ liệu đích và Độ tương đồng miền (Domain Similarity) giữa nguồn và đích:

Miền đích giống miền nguồnMiền đích khác xa miền nguồn
Dữ liệu đích rất nhỏ (vài chục đến vài trăm mẫu)Đóng băng Backbone (Frozen)
Chỉ học lớp Head mới. Hạn chế tối đa nguy cơ overfitting.
Thử thách lớn nhất
Khóa backbone nhưng tìm checkpoint gần miền hơn; thử dùng PEFT hoặc áp dụng regularization cực mạnh.
Dữ liệu đích lớn (hàng chục nghìn mẫu trở lên)Tinh chỉnh một phần →\rightarrow Toàn bộ
Mô hình có đủ dữ liệu để tinh chỉnh biểu diễn mà không sợ overfit.
Tinh chỉnh toàn bộ (Full Fine-tuning)
Dữ liệu đủ lớn để tái định hình toàn bộ backbone sang phân phối miền mới.

Nguyên tắc bất biến: Không bao giờ mở khóa toàn bộ backbone khi lớp Head mới vẫn còn mang trọng số ngẫu nhiên. Gradient khổng lồ và hỗn loạn từ một Head chưa hội tụ sẽ phá hỏng ngay lập tức các biểu diễn tinh vi của backbone. Quy trình đúng luôn là: Huấn luyện Head trước cho ổn định, sau đó mới unfreeze backbone với learning rate nhỏ.

Continued pretraining: khi miền nguồn chưa đủ gần miền đích

Điều gì xảy ra khi bạn có một mô hình ngôn ngữ lớn học từ Internet chung (Wikipedia, báo chí) nhưng bài toán của bạn là phân tích hồ sơ bệnh án hoặc hợp đồng bảo hiểm phức tạp?

Khoảng cách miền (domain gap) lúc này quá lớn: mô hình thiếu từ vựng chuyên ngành, cấu trúc câu lạ lẫm và kiến thức chuyên sâu. Khi đó, phương pháp Continued Pretraining (hoặc Domain-Adaptive Pretraining — DAPT) là chiếc cầu nối hoàn hảo (Gururangan et al., ACL 2020):

  1. Thu thập kho văn bản chuyên ngành không cần nhãn (hàng nghìn bài báo y sinh, hàng triệu trang luật).
  2. Tiếp tục chạy mục tiêu tự giám sát (đoán từ tiếp theo) trên kho dữ liệu này.
  3. Khi mô hình đã quen thuộc với văn phong và thuật ngữ miền, ta mới bắt đầu fine-tune có giám sát cho bài toán phân loại hoặc trích xuất thông tin.

Negative transfer và hiện tượng quên thảm khốc (Catastrophic Forgetting)

Transfer learning không phải là phép màu luôn luôn mang lại chiến thắng. Có hai rủi ro kỹ thuật lớn cần kiểm soát:

1. Chuyển giao tiêu cực (Negative Transfer)

Xảy ra khi việc kế thừa tri thức từ nguồn làm kết quả trên bài toán đích kém hơn cả việc huấn luyện từ đầu. Nguyên nhân thường do:

  • Hai miền dữ liệu có tương quan đối nghịch hoặc xung đột về mặt bản chất;
  • Tiền xử lý dữ liệu (chuẩn hóa ảnh, tokenization) bị làm lệch pha so với cấu hình gốc của checkpoint;
  • Pretraining objective học những đặc trưng gây nhiễu cho bài toán đích.

Để phát hiện negative transfer, kỹ sư bắt buộc phải luôn xây dựng một baseline huấn luyện từ đầu (from scratch) hoặc một mô hình tuyến tính đơn giản để đối chiếu.

2. Hiện tượng quên thảm khốc (Catastrophic Forgetting)

Khi ta fine-tune mô hình trên một tập dữ liệu hẹp, mạng neural có xu hướng ghi đè lên các trọng số cũ, dẫn đến việc mất đi toàn bộ những năng lực tổng quát mà nó từng có (ví dụ: một LLM sau khi fine-tune trả lời câu hỏi y tế thì quên mất cách làm thơ hoặc viết code Python).

Các giải pháp ngăn chặn:

  • Sử dụng tốc độ học (learning rate) cực nhỏ kết hợp với Early Stopping;
  • Trộn một tỉ lệ nhỏ dữ liệu tổng quát cũ vào tập fine-tune;
  • Áp dụng các kỹ thuật PEFT (như LoRA) để đóng băng hoàn toàn trọng số gốc.

PEFT: tinh chỉnh hiệu quả tham số khi mô hình quá lớn

Khi bước sang kỷ nguyên của các mô hình hàng tỷ tham số (như LLaMA 7B, 70B hay ViT khổng lồ), việc tinh chỉnh toàn bộ mô hình (Full Fine-tuning) trở thành cơn ác mộng phần cứng:

  • Để fine-tune một mô hình 7 tỷ tham số (14 GB trọng số ở dạng FP16), optimizer như Adam cần lưu thêm momentum và variance, cộng thêm gradient và activation, ngốn từ 60 đến 80 GB VRAM.
  • Mỗi tác vụ riêng biệt lại sinh ra một file checkpoint nặng hàng chục gigabyte, không thể lưu trữ hay triển khai trên quy mô lớn.

PEFT (Parameter-Efficient Fine-Tuning) ra đời để giải quyết bài toán này: đóng băng 99% tham số của mô hình nền và chỉ cập nhật một phần nhỏ (dưới 1%) tham số phụ.

Cơ chế hoạt động của LoRA và QLoRA

LoRA (Low-Rank Adaptation)

Được đề xuất bởi Edward Hu và cộng sự (ICLR 2022), LoRA dựa trên một giả thuyết hình học sâu sắc: sự thay đổi trọng số ΔW\Delta W trong quá trình thích nghi bài toán có thứ hạng nội tại (intrinsic rank) rất thấp.

Với một ma trận trọng số pretrained W∈Rd×kW \in \mathbb{R}^{d \times k}, thay vì cập nhật trực tiếp ΔW\Delta W, LoRA phân tích nó thành tích của hai ma trận hạng thấp:

W′=W+ΔW,ΔW=αrBAW' = W + \Delta W, \qquad \Delta W = \frac{\alpha}{r} B A

Trong đó:

  • A∈Rr×kA \in \mathbb{R}^{r \times k} được khởi tạo ngẫu nhiên theo phân phối Gauss;
  • B∈Rd×rB \in \mathbb{R}^{d \times r} được khởi tạo bằng 0;
  • Hạng r≪min⁡(d,k)r \ll \min(d, k) (thường chỉ chọn r=4,8,16r = 4, 8, 16).

Lợi ích vượt trội của LoRA:

  • Tiết kiệm VRAM tới 70%: Không cần lưu trạng thái optimizer cho ma trận khổng lồ WW.
  • File adapter siêu nhỏ: Một file LoRA chỉ nặng vài megabyte, dễ dàng lưu trữ và chia sẻ.
  • Không tăng độ trễ suy diễn: Khi triển khai, ta có thể cộng gộp trực tiếp ΔW\Delta W vào WW (Wdeploy=W+αrBAW_{\text{deploy}} = W + \frac{\alpha}{r}BA) nên tốc độ suy diễn không hề chậm đi một mili-giây nào!

QLoRA: Lượng tử hóa 4-bit kết hợp LoRA

Tim Dettmers và cộng sự (NeurIPS 2023) đẩy giới hạn đi xa hơn nữa:

  • Nén toàn bộ mô hình nền WW xuống định dạng 4-bit NormalFloat (NF4);
  • Áp dụng kỹ thuật Double Quantization và Paged Optimizers;
  • Chỉ tính toán gradient và lưu trạng thái optimizer trên các adapter LoRA ở dạng 16-bit.

Kết quả là: QLoRA cho phép fine-tune một mô hình 65 tỷ tham số trên một card đồ họa đơn lẻ 48GB VRAM mà vẫn bảo toàn hơn 99% hiệu năng so với full fine-tuning 16-bit.

Từ CNN sang Vision Transformer và LLM: nguyên tắc không đổi

Mặc dù kiến trúc đã tiến hóa từ các tầng tích chập ConvNet sang cơ chế Self-Attention của Transformer, các nguyên lý cốt lõi của transfer learning vẫn nguyên giá trị:

  1. Với CNN (ResNet, ConvNeXt): Đóng băng feature extractor, thay thế fully-connected head.
  2. Với Vision Transformer (ViT): Giữ nguyên patch embedding và các khối Transformer blocks, chỉ thay đổi classification token ([CLS]) head. Chèn LoRA vào các ma trận Query/Value projection.
  3. Với LLM (LLaMA, Mistral): Huấn luyện theo dạng Supervised Fine-Tuning (SFT) trên các cặp dữ liệu Instruction–Output, sử dụng LoRA/QLoRA để điều chỉnh phong cách và khả năng tuân thủ mệnh lệnh.

Mạch best practices trước khi bấm nút Train

Để tránh lãng phí thời gian và tài nguyên, hãy luôn tuân thủ quy trình 6 bước chuẩn mực:

  1. Xác định đúng bài toán: Mô hình của bạn đang thiếu gì? Nếu thiếu kiến thức cập nhật theo ngày, hãy dùng RAG; nếu thiếu phong cách hành vi hoặc nhãn tác vụ, hãy fine-tune.
  2. Chọn Checkpoint đúng miền: Ưu tiên mô hình được pretrain trên miền dữ liệu gần nhất với bài toán thay vì chỉ nhìn vào vị trí trên bảng xếp hạng leaderboard.
  3. Khóa quy trình chia dữ liệu (Data Split): Luôn chia train/val/test trước khi thực hiện bất kỳ phép biến đổi dữ liệu nào. Nếu dữ liệu có cấu trúc nhóm (nhiều ảnh của cùng một bệnh nhân), bắt buộc phải dùng Group Split để tránh rò rỉ dữ liệu (data leakage).
  4. Bắt đầu từ baseline rẻ nhất: Thử nghiệm Frozen Backbone trước →\rightarrow Tinh chỉnh một phần →\rightarrow Chỉ chuyển sang Full fine-tune hoặc PEFT khi thật sự cần thiết.
  5. Huấn luyện Head trước khi mở khóa Backbone: Giúp tránh các bước cập nhật gradient khổng lồ làm hỏng biểu diễn đã học.
  6. Xử lý đặc biệt với Batch Normalization: Khi đóng băng backbone trong PyTorch, hãy chú ý trạng thái eval() của các tầng BatchNorm để không làm sai lệch running mean và running variance.

Nếu chỉ nhớ 8 ý

  • Pretraining trả chi phí tính toán lớn một lần duy nhất; Transfer Learning tái sử dụng tri thức biểu diễn đó cho vô số bài toán con.
  • Không phải lúc nào cũng train from scratch; với dữ liệu nhỏ, transfer learning là cứu cánh duy nhất để tránh overfitting.
  • Các tầng mạng học biểu diễn có tính phân cấp: tầng đầu mang tính phổ quát, tầng sâu mang tính đặc thù.
  • Đóng băng backbone (Feature Extraction) là mốc cơ sở nhanh, rẻ và an toàn nhất trước khi nghĩ đến fine-tuning.
  • Luôn huấn luyện Head mới cho ổn định trước khi mở khóa (unfreeze) backbone với tốc độ học nhỏ.
  • Negative transfer xảy ra khi miền dữ liệu quá lệch pha; Catastrophic forgetting xảy ra khi mô hình bị ghi đè mất tri thức cũ.
  • Continued Pretraining là phương pháp thích nghi miền không nhãn khi khoảng cách giữa nguồn và đích quá lớn.
  • LoRA và QLoRA định hình nên tiêu chuẩn fine-tuning hiện đại bằng cách chỉ cập nhật các ma trận hạng thấp, tiết kiệm tới 70% VRAM.

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

  1. Tại sao một mô hình ResNet sử dụng trọng số ImageNet nhưng toàn bộ backbone bị đóng băng lại không được gọi là full fine-tuning?
  2. Nếu mở khóa toàn bộ backbone ngay từ epoch đầu tiên với learning rate lớn cùng một Head khởi tạo ngẫu nhiên, hiện tượng gì sẽ xảy ra?
  3. Khi tập dữ liệu đích vừa nhỏ lại vừa khác xa tập dữ liệu pretraining, kỹ sư nên ưu tiên hướng xử lý nào?
  4. Phân biệt sự khác nhau giữa Continued Pretraining và Supervised Fine-Tuning về mặt hàm mục tiêu và dữ liệu.
  5. Hiện tượng Negative Transfer là gì và làm thế nào để phát hiện ra nó trong thực nghiệm?
  6. Tại sao việc đặt requires_grad = False trong PyTorch vẫn chưa đủ để đóng băng hoàn toàn hành vi của các tầng BatchNorm2d?
  7. Cơ chế phân tích hạng thấp ΔW=αrBA\Delta W = \frac{\alpha}{r}BA của LoRA giúp tiết kiệm bộ nhớ GPU như thế nào?
  8. Nêu sự đánh đổi (trade-off) khi lựa chọn QLoRA 4-bit thay vì Full Fine-tuning 16-bit.

Mạch nối sang bài tiếp theo

Hiểu rõ lý thuyết về pretraining, transfer learning và LoRA là một chuyện; tự tay tổ chức một quy trình thí nghiệm hoàn chỉnh, viết code PyTorch an toàn và xử lý các bẫy ngầm trong thực tế lại là một chuyện hoàn toàn khác.

Làm thế nào để chia tập dữ liệu tránh rò rỉ khi một bệnh nhân có nhiều ảnh chụp? Code PyTorch đóng băng backbone và xử lý BatchNorm chính xác từng dòng ra sao? Làm sao đọc đồ thị learning curves để biết mô hình đang underfit hay overfit?

Tất cả sẽ được giải quyết từng bước trong bài học tiếp theo: Fine-tuning trong thực tế: từ baseline đến thí nghiệm đáng tin cậy.

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