Open Set Anime Character Classification aims to identify anime characters while detecting unseen classes that are absent from the training set. The model must correctly classify known characters and reject unknown ones, improving robustness in real-world scenarios.
1
stars
26
commits
Jupyter Notebook
primary language
Jul 28, 2026
updated
Dự án này nhằm giải quyết bài toán nhận diện nhân vật anime bằng cách sử dụng các mô hình học máy hiện đại.
flowchart TD
A([🖼️ Ảnh đầu vào]) --> B
subgraph S1["📦 Giai đoạn 1 — Thu thập & Tiền xử lý"]
B[Thu thập dữ liệu\nGrabber Booru] --> C
C[Lọc ảnh thủ công\nLoại ảnh không thỏa điều kiện] --> D
D[Face detection & localization\nLoại background noise] --> E
E[Resize & Normalize\n448×448 · normalize -1 to 1]
end
E --> F
subgraph S2["🧠 Giai đoạn 2 — Huấn luyện mô hình"]
F[ViT-Base model\nwd-vit-tagger-v3] --> G
G[Transfer learning\nFine-tune · 45 nhân vật · 7k ảnh] --> H
H[Lưu checkpoint\nbest_vit_model.pth] --> I & J
I[Mô hình phân loại\nAccuracy / F1-Score]
J[Trích xuất đặc trưng\nTạo embedding gallery]
end
I & J --> K
subgraph S3["⚡ Giai đoạn 3 — Suy luận thời gian thực"]
K([Ảnh query]) --> L
L[Tiền xử lý\nMTCNN detect · crop · expand 20–30%] --> M
M[ViT backbone frozen\nTrích xuất + L2-normalize CLS token] --> N & O
N[Cosine similarity\nmax sim query vs gallery]
O[Đầu phân loại\nXác suất softmax]
N & O --> P{max_sim ≥ τ = 0.657?}
P -->|Không| Q([❌ UNKNOWN])
P -->|Có| R[Weighted fusion\nα · gallery + 1-α · cls_prob]
R --> S([✅ Kết quả nhận diện\nchar_id + điểm tin cậy])
end
style S1 fill:#0d3b2e,stroke:#2fa882,color:#c8ede5
style S2 fill:#1e1040,stroke:#6b5fbe,color:#d4cfee
style S3 fill:#161624,stroke:#555570,color:#d0d0d8
style Q fill:#7a2c18,stroke:#b04428,color:#f5c4b0
style S fill:#1d7a5f,stroke:#2fa882,color:#c8ede5
Bộ dữ liệu sử dụng trong dự án này có thể được tải xuống từ:
Dưới đây là cấu trúc hiện tại của repo và cách mình nên hiểu từng phần:
ML_code/
├── README.md
├── requirements.txt
├── config.yaml
├── main.py
├── data/
│ └── class_names.txt
├── notebooks/
│ └── main.ipynb
├── src/
│ ├── dataset.py
│ ├── eval.py
│ ├── inference.py
│ ├── model.py
│ ├── train.py
│ └── utils.py
├── assets/
│ └── model_link.txt
├── checkpoints/
│ └── best_vit_model.pth
├── embeddings/
├── outputs/
├── logs/
└── scripts/
main.py là entry point chính để chạy toàn bộ pipeline bằng CLI.src/ chỉ nên chứa code xử lý, train, eval, inference và các hàm dùng lại.notebooks/ dùng cho thử nghiệm, phân tích và trình bày kết quả.data/ dành cho dữ liệu đầu vào hoặc file metadata như danh sách class.assets/ chứa tài nguyên tĩnh như ghi chú, hình minh họa hoặc file tham khảo.checkpoints/ chỉ nên dùng cho checkpoint mô hình.embeddings/ lưu gallery, centroid và các file trung gian phục vụ open-set.outputs/ lưu ảnh, biểu đồ và kết quả đánh giá.logs/ dành cho log khi train hoặc chạy pipeline.scripts/ là nơi để đặt các script tiện ích nếu sau này tách nhỏ luồng chạy.Nếu sau này repo lớn hơn, có thể tách thêm data/raw, data/processed, data/external để quản lý dữ liệu rõ hơn. Hiện tại, cấu trúc ở trên là đủ gọn và phù hợp với cách repo này đang chạy.
Thiết lập nhanh (venv):
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
Các thư viện chính:
Toàn bộ pipeline được điều phối qua main.py kết hợp file cấu hình config.yaml. Bạn có thể ghi đè bất kỳ tham số nào trong config.yaml bằng cách truyền trực tiếp qua CLI.
Lưu ý: Trước khi chạy, hãy kiểm tra lại các đường dẫn trong
config.yamlcho khớp với máy của bạn, đặc biệt làdata.input_dir,data.output_dir, vàmodel.model_path.
Crop khuôn mặt anime từ ảnh gốc và lưu thành cấu trúc split train/val/test.
python main.py preprocess --config config.yaml
Tham số có thể ghi đè:
| Argument | Mặc định (từ config) | Mô tả |
|---|---|---|
--input_dir | ./data_split | Thư mục dataset gốc theo dạng split |
--output_dir | ./faces_split | Thư mục xuất ảnh đã crop mặt |
--cascade | ./lbpcascade_animeface.xml | File cascade XML (tự tải nếu chưa có) |
--splits | train val test | Các split cần xử lý |
Ví dụ ghi đè:
python main.py preprocess --config config.yaml --input_dir ./my_data --splits train val
Fine-tune classification head của ViT backbone trên tập dữ liệu đã crop mặt.
python main.py train --config config.yaml
Tham số có thể ghi đè:
| Argument | Mặc định (từ config) | Mô tả |
|---|---|---|
--train_dir | ./faces_split/train | Thư mục ảnh train |
--val_dir | ./faces_split/val | Thư mục ảnh validation |
--model_name | SmilingWolf/wd-vit-tagger-v3 | Tên pretrained backbone trên HuggingFace |
--epochs | 30 | Số epoch tối đa |
--batch_size | 256 | Kích thước batch |
--lr | 1e-5 | Learning rate |
--patience | 5 | Số epoch chịu đựng khi val loss không cải thiện (early stopping) |
--model_save_path | ./checkpoints/best_vit_model.pth | Đường dẫn lưu checkpoint tốt nhất |
--metrics_save_path | ./outputs/training_metrics.txt | File lưu kết quả metric |
--plot_save_path | ./outputs/training_plots.png | File lưu biểu đồ loss/accuracy |
--num_workers | -1 (auto) | Số worker cho DataLoader (-1 = tự phát hiện) |
Ví dụ chạy nhanh với batch nhỏ hơn:
python main.py train --config config.yaml --batch_size 64 --epochs 10
Trích xuất embedding từ tập train và biên soạn gallery centroid dùng cho open-set inference.
python main.py build_index --config config.yaml
Tham số có thể ghi đè:
| Argument | Mặc định (từ config) | Mô tả |
|---|---|---|
--train_dir | ./faces_split/train | Thư mục ảnh train để trích xuất |
--model_name | SmilingWolf/wd-vit-tagger-v3 | Tên pretrained backbone |
--model_path | ./checkpoints/best_vit_model.pth | Checkpoint đã train |
--gallery_dir | ./embeddings | Thư mục lưu các file gallery |
--num_classes | 45 | Số lớp của model đã train |
--batch_size | 64 | Batch size khi trích xuất embedding |
Các file được sinh ra trong ./embeddings/:
gallery_embeddings.npy — toàn bộ embedding theo ảnhgallery_index.pkl — index ánh xạ embedding → classclass_centroids.npy — vector centroid trung bình mỗi lớpclass_names.pkl — danh sách tên các lớpĐánh giá độ chính xác phân loại, open-set recognition và trực quan hóa embedding (t-SNE).
python main.py eval --config config.yaml
Tham số có thể ghi đè:
| Argument | Mặc định (từ config) | Mô tả |
|---|---|---|
--eval_mode | all | Chế độ đánh giá: accuracy / open_set / tsne / all |
--test_dir | ./faces_split/test | Thư mục ảnh test |
--model_name | SmilingWolf/wd-vit-tagger-v3 | Tên pretrained backbone |
--model_path | ./checkpoints/best_vit_model.pth | Checkpoint đã train |
--gallery_dir | ./embeddings | Thư mục chứa gallery index |
--output_dir | ./outputs | Thư mục lưu biểu đồ và confusion matrix |
--cascade | ./lbpcascade_animeface.xml | File cascade XML |
--num_known | 36 | Số lớp "known" dùng cho open-set split |
Ví dụ chỉ đánh giá accuracy:
python main.py eval --config config.yaml --eval_mode accuracy
Ví dụ chỉ vẽ t-SNE:
python main.py eval --config config.yaml --eval_mode tsne
Lưu ý:
run_evalluôn đọcclass_names.pkltừgallery_dirtrước tiên ở tất cả các mode. Do đó bạn phải chạybuild_indextrước khi chạyeval, dù chỉ dùng--eval_mode accuracy.
Nhận diện nhân vật từ một hoặc nhiều ảnh đầu vào qua dual-branch pipeline (cosine similarity + softmax fusion).
python main.py predict --config config.yaml --image_paths path/to/image1.jpg path/to/image2.jpg
Tham số có thể ghi đè:
| Argument | Mặc định (từ config) | Mô tả |
|---|---|---|
--image_paths | (bắt buộc) | Một hoặc nhiều đường dẫn ảnh cần nhận diện |
--model_name | SmilingWolf/wd-vit-tagger-v3 | Tên pretrained backbone |
--model_path | ./checkpoints/best_vit_model.pth | Checkpoint đã train |
--gallery_dir | ./embeddings | Thư mục chứa class_centroids.npy và class_names.pkl |
--cascade | ./lbpcascade_animeface.xml | File cascade XML |
--threshold | 0.657 | Ngưỡng cosine similarity tối thiểu để chấp nhận kết quả (dưới ngưỡng → UNKNOWN) |
--alpha | 0.7 | Trọng số kết hợp giữa gallery score và softmax probability |
Ví dụ với nhiều ảnh và ghi đè ngưỡng (PowerShell):
python main.py predict --config config.yaml `
--image_paths ./test1.jpg ./test2.jpg ./test3.jpg `
--threshold 0.70
Ví dụ tương đương trên một dòng:
python main.py predict --config config.yaml --image_paths ./test1.jpg ./test2.jpg ./test3.jpg --threshold 0.70
Lưu ý: Cần chạy
build_indextrước để tạo file gallery trong./embeddings/trước khi dùng lệnhpredict.
python main.py preprocess --config config.yaml
python main.py train --config config.yaml
python main.py build_index --config config.yaml
python main.py eval --config config.yaml
Chúng tôi sử dụng SmilingWolf/wd-vit-tagger-v3 làm pretrained backbone thay vì baseline để so sánh, do sự khác biệt về domain và objective giữa hai task:
Việc so sánh accuracy trực tiếp sẽ không phản ánh đúng bản chất của hai bài toán. Thay vào đó, chúng tôi đánh giá hiệu quả của transfer learning từ backbone pretrained sang task cụ thể.








Ghi chú: các biểu đồ loss/accuracy, confusion matrix, và phân bố cosine similarity được vẽ trong notebooks/main.ipynb.
Nhận xét:
Nguyễn Tấn Phúc Thịnh - 24521696
random_seed cố định để đảm bảo tính tái hiện (reproducibility)Makefile hoặc run.sh để chạy toàn bộ pipeline bằng một lệnh duy nhấtThis project is licensed under the MIT License — see the LICENSE file for details.
26 commits
Jupyter Notebook
99.3%
Open Set Anime Character Classification aims to identify anime characters while detecting unseen classes that are absent from the training set. The model must correctly classify known characters and reject unknown ones, improving robustness in real-world scenarios.
1
stars
26
commits
Jupyter Notebook
primary language
Jul 28, 2026
updated
Dự án này nhằm giải quyết bài toán nhận diện nhân vật anime bằng cách sử dụng các mô hình học máy hiện đại.
flowchart TD
A([🖼️ Ảnh đầu vào]) --> B
subgraph S1["📦 Giai đoạn 1 — Thu thập & Tiền xử lý"]
B[Thu thập dữ liệu\nGrabber Booru] --> C
C[Lọc ảnh thủ công\nLoại ảnh không thỏa điều kiện] --> D
D[Face detection & localization\nLoại background noise] --> E
E[Resize & Normalize\n448×448 · normalize -1 to 1]
end
E --> F
subgraph S2["🧠 Giai đoạn 2 — Huấn luyện mô hình"]
F[ViT-Base model\nwd-vit-tagger-v3] --> G
G[Transfer learning\nFine-tune · 45 nhân vật · 7k ảnh] --> H
H[Lưu checkpoint\nbest_vit_model.pth] --> I & J
I[Mô hình phân loại\nAccuracy / F1-Score]
J[Trích xuất đặc trưng\nTạo embedding gallery]
end
I & J --> K
subgraph S3["⚡ Giai đoạn 3 — Suy luận thời gian thực"]
K([Ảnh query]) --> L
L[Tiền xử lý\nMTCNN detect · crop · expand 20–30%] --> M
M[ViT backbone frozen\nTrích xuất + L2-normalize CLS token] --> N & O
N[Cosine similarity\nmax sim query vs gallery]
O[Đầu phân loại\nXác suất softmax]
N & O --> P{max_sim ≥ τ = 0.657?}
P -->|Không| Q([❌ UNKNOWN])
P -->|Có| R[Weighted fusion\nα · gallery + 1-α · cls_prob]
R --> S([✅ Kết quả nhận diện\nchar_id + điểm tin cậy])
end
style S1 fill:#0d3b2e,stroke:#2fa882,color:#c8ede5
style S2 fill:#1e1040,stroke:#6b5fbe,color:#d4cfee
style S3 fill:#161624,stroke:#555570,color:#d0d0d8
style Q fill:#7a2c18,stroke:#b04428,color:#f5c4b0
style S fill:#1d7a5f,stroke:#2fa882,color:#c8ede5
Bộ dữ liệu sử dụng trong dự án này có thể được tải xuống từ:
Dưới đây là cấu trúc hiện tại của repo và cách mình nên hiểu từng phần:
ML_code/
├── README.md
├── requirements.txt
├── config.yaml
├── main.py
├── data/
│ └── class_names.txt
├── notebooks/
│ └── main.ipynb
├── src/
│ ├── dataset.py
│ ├── eval.py
│ ├── inference.py
│ ├── model.py
│ ├── train.py
│ └── utils.py
├── assets/
│ └── model_link.txt
├── checkpoints/
│ └── best_vit_model.pth
├── embeddings/
├── outputs/
├── logs/
└── scripts/
main.py là entry point chính để chạy toàn bộ pipeline bằng CLI.src/ chỉ nên chứa code xử lý, train, eval, inference và các hàm dùng lại.notebooks/ dùng cho thử nghiệm, phân tích và trình bày kết quả.data/ dành cho dữ liệu đầu vào hoặc file metadata như danh sách class.assets/ chứa tài nguyên tĩnh như ghi chú, hình minh họa hoặc file tham khảo.checkpoints/ chỉ nên dùng cho checkpoint mô hình.embeddings/ lưu gallery, centroid và các file trung gian phục vụ open-set.outputs/ lưu ảnh, biểu đồ và kết quả đánh giá.logs/ dành cho log khi train hoặc chạy pipeline.scripts/ là nơi để đặt các script tiện ích nếu sau này tách nhỏ luồng chạy.Nếu sau này repo lớn hơn, có thể tách thêm data/raw, data/processed, data/external để quản lý dữ liệu rõ hơn. Hiện tại, cấu trúc ở trên là đủ gọn và phù hợp với cách repo này đang chạy.
Thiết lập nhanh (venv):
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
Các thư viện chính:
Toàn bộ pipeline được điều phối qua main.py kết hợp file cấu hình config.yaml. Bạn có thể ghi đè bất kỳ tham số nào trong config.yaml bằng cách truyền trực tiếp qua CLI.
Lưu ý: Trước khi chạy, hãy kiểm tra lại các đường dẫn trong
config.yamlcho khớp với máy của bạn, đặc biệt làdata.input_dir,data.output_dir, vàmodel.model_path.
Crop khuôn mặt anime từ ảnh gốc và lưu thành cấu trúc split train/val/test.
python main.py preprocess --config config.yaml
Tham số có thể ghi đè:
| Argument | Mặc định (từ config) | Mô tả |
|---|---|---|
--input_dir | ./data_split | Thư mục dataset gốc theo dạng split |
--output_dir | ./faces_split | Thư mục xuất ảnh đã crop mặt |
--cascade | ./lbpcascade_animeface.xml | File cascade XML (tự tải nếu chưa có) |
--splits | train val test | Các split cần xử lý |
Ví dụ ghi đè:
python main.py preprocess --config config.yaml --input_dir ./my_data --splits train val
Fine-tune classification head của ViT backbone trên tập dữ liệu đã crop mặt.
python main.py train --config config.yaml
Tham số có thể ghi đè:
| Argument | Mặc định (từ config) | Mô tả |
|---|---|---|
--train_dir | ./faces_split/train | Thư mục ảnh train |
--val_dir | ./faces_split/val | Thư mục ảnh validation |
--model_name | SmilingWolf/wd-vit-tagger-v3 | Tên pretrained backbone trên HuggingFace |
--epochs | 30 | Số epoch tối đa |
--batch_size | 256 | Kích thước batch |
--lr | 1e-5 | Learning rate |
--patience | 5 | Số epoch chịu đựng khi val loss không cải thiện (early stopping) |
--model_save_path | ./checkpoints/best_vit_model.pth | Đường dẫn lưu checkpoint tốt nhất |
--metrics_save_path | ./outputs/training_metrics.txt | File lưu kết quả metric |
--plot_save_path | ./outputs/training_plots.png | File lưu biểu đồ loss/accuracy |
--num_workers | -1 (auto) | Số worker cho DataLoader (-1 = tự phát hiện) |
Ví dụ chạy nhanh với batch nhỏ hơn:
python main.py train --config config.yaml --batch_size 64 --epochs 10
Trích xuất embedding từ tập train và biên soạn gallery centroid dùng cho open-set inference.
python main.py build_index --config config.yaml
Tham số có thể ghi đè:
| Argument | Mặc định (từ config) | Mô tả |
|---|---|---|
--train_dir | ./faces_split/train | Thư mục ảnh train để trích xuất |
--model_name | SmilingWolf/wd-vit-tagger-v3 | Tên pretrained backbone |
--model_path | ./checkpoints/best_vit_model.pth | Checkpoint đã train |
--gallery_dir | ./embeddings | Thư mục lưu các file gallery |
--num_classes | 45 | Số lớp của model đã train |
--batch_size | 64 | Batch size khi trích xuất embedding |
Các file được sinh ra trong ./embeddings/:
gallery_embeddings.npy — toàn bộ embedding theo ảnhgallery_index.pkl — index ánh xạ embedding → classclass_centroids.npy — vector centroid trung bình mỗi lớpclass_names.pkl — danh sách tên các lớpĐánh giá độ chính xác phân loại, open-set recognition và trực quan hóa embedding (t-SNE).
python main.py eval --config config.yaml
Tham số có thể ghi đè:
| Argument | Mặc định (từ config) | Mô tả |
|---|---|---|
--eval_mode | all | Chế độ đánh giá: accuracy / open_set / tsne / all |
--test_dir | ./faces_split/test | Thư mục ảnh test |
--model_name | SmilingWolf/wd-vit-tagger-v3 | Tên pretrained backbone |
--model_path | ./checkpoints/best_vit_model.pth | Checkpoint đã train |
--gallery_dir | ./embeddings | Thư mục chứa gallery index |
--output_dir | ./outputs | Thư mục lưu biểu đồ và confusion matrix |
--cascade | ./lbpcascade_animeface.xml | File cascade XML |
--num_known | 36 | Số lớp "known" dùng cho open-set split |
Ví dụ chỉ đánh giá accuracy:
python main.py eval --config config.yaml --eval_mode accuracy
Ví dụ chỉ vẽ t-SNE:
python main.py eval --config config.yaml --eval_mode tsne
Lưu ý:
run_evalluôn đọcclass_names.pkltừgallery_dirtrước tiên ở tất cả các mode. Do đó bạn phải chạybuild_indextrước khi chạyeval, dù chỉ dùng--eval_mode accuracy.
Nhận diện nhân vật từ một hoặc nhiều ảnh đầu vào qua dual-branch pipeline (cosine similarity + softmax fusion).
python main.py predict --config config.yaml --image_paths path/to/image1.jpg path/to/image2.jpg
Tham số có thể ghi đè:
| Argument | Mặc định (từ config) | Mô tả |
|---|---|---|
--image_paths | (bắt buộc) | Một hoặc nhiều đường dẫn ảnh cần nhận diện |
--model_name | SmilingWolf/wd-vit-tagger-v3 | Tên pretrained backbone |
--model_path | ./checkpoints/best_vit_model.pth | Checkpoint đã train |
--gallery_dir | ./embeddings | Thư mục chứa class_centroids.npy và class_names.pkl |
--cascade | ./lbpcascade_animeface.xml | File cascade XML |
--threshold | 0.657 | Ngưỡng cosine similarity tối thiểu để chấp nhận kết quả (dưới ngưỡng → UNKNOWN) |
--alpha | 0.7 | Trọng số kết hợp giữa gallery score và softmax probability |
Ví dụ với nhiều ảnh và ghi đè ngưỡng (PowerShell):
python main.py predict --config config.yaml `
--image_paths ./test1.jpg ./test2.jpg ./test3.jpg `
--threshold 0.70
Ví dụ tương đương trên một dòng:
python main.py predict --config config.yaml --image_paths ./test1.jpg ./test2.jpg ./test3.jpg --threshold 0.70
Lưu ý: Cần chạy
build_indextrước để tạo file gallery trong./embeddings/trước khi dùng lệnhpredict.
python main.py preprocess --config config.yaml
python main.py train --config config.yaml
python main.py build_index --config config.yaml
python main.py eval --config config.yaml
Chúng tôi sử dụng SmilingWolf/wd-vit-tagger-v3 làm pretrained backbone thay vì baseline để so sánh, do sự khác biệt về domain và objective giữa hai task:
Việc so sánh accuracy trực tiếp sẽ không phản ánh đúng bản chất của hai bài toán. Thay vào đó, chúng tôi đánh giá hiệu quả của transfer learning từ backbone pretrained sang task cụ thể.








Ghi chú: các biểu đồ loss/accuracy, confusion matrix, và phân bố cosine similarity được vẽ trong notebooks/main.ipynb.
Nhận xét:
Nguyễn Tấn Phúc Thịnh - 24521696
random_seed cố định để đảm bảo tính tái hiện (reproducibility)Makefile hoặc run.sh để chạy toàn bộ pipeline bằng một lệnh duy nhấtThis project is licensed under the MIT License — see the LICENSE file for details.
26 commits
Jupyter Notebook
99.3%