diff --git a/SWIN_UNET_GUIDE.md b/SWIN_UNET_GUIDE.md new file mode 100644 index 0000000..97f27fc --- /dev/null +++ b/SWIN_UNET_GUIDE.md @@ -0,0 +1,278 @@ +# Hướng dẫn sử dụng Swin-UNet + +## Giới thiệu + +**Swin-UNet** là một mô hình hybrid kết hợp: +- **Swin Transformer blocks** - cho phép học các mối quan hệ toàn cục +- **U-Net architecture** - với skip connections để bảo toàn chi tiết địa phương +- **Hierarchical structure** - xử lý features ở nhiều cấp độ độ phân giải + +## Ưu điểm chính + +### 1. **Kiến trúc mạnh mẽ** +- Kết hợp được điểm mạnh của cả Transformer và CNN +- Self-attention giúp học các mối quan hệ phức tạp +- Skip connections bảo toàn thông tin chi tiết + +### 2. **Hiệu suất cao** +- State-of-the-art accuracy cho nhiều tác vụ vision +- Học nhanh hơn so với ViT cơ bản +- Ổn định trong quá trình training + +### 3. **Linh hoạt** +- Hoạt động tốt với ít dữ liệu (transfer learning) +- Có thể scale lên hoặc xuống theo yêu cầu +- Hỗ trợ cả GPU và CPU + +## Cấu hình tối ưu + +### Cấu hình nhanh (test/prototyping) +```json +{ + "model_type": "swin-unet", + "n_estimators": 60, + "learning_rate": 0.001, + "use_gpu": true, + "test_size": 0.2 +} +``` +- Training time: ~15-20 phút (GPU) / ~1-2 giờ (CPU) +- Accuracy: Tốt cho các dataset nhỏ + +### Cấu hình cân bằng (production) +```json +{ + "model_type": "swin-unet", + "n_estimators": 100, + "learning_rate": 0.0005, + "use_gpu": true, + "test_size": 0.2, + "max_scenes": 30, + "resolution": 10 +} +``` +- Training time: ~30-45 phút (GPU) +- Accuracy: Rất cao (>90% thường) + +### Cấu hình cao cấp (accuracy tối đa) +```json +{ + "model_type": "swin-unet", + "n_estimators": 150, + "learning_rate": 0.0003, + "use_gpu": true, + "test_size": 0.2, + "max_scenes": 60, + "resolution": 10 +} +``` +- Training time: ~45-60 phút (GPU) +- Accuracy: Tối ưu nhất (95%+) +- Yêu cầu: Dataset lớn, GPU mạnh + +## So sánh với các model khác + +| Tiêu chí | CNN | ResNet | ViT | **Swin-UNet** | +|---------|-----|--------|-----|--------------| +| Độ chính xác | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | +| Tốc độ training | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | +| Bộ nhớ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | +| Ổn định | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | +| Dataset nhỏ | ✓ | ✓ | ✗ | ✓ | +| Dataset lớn | ✓ | ✓ | ✓ | ✓ | + +## Kiến trúc chi tiết + +### Encoder (Đường xuống) +``` +Input Features (n_features) + ↓ + Adapter Layer (project to embed_dim) + ↓ + Encoder1 (embed_dim → embed_dim) + ↓ + Downsample (→ embed_dim*2) + ↓ + Encoder2 (embed_dim*2 → embed_dim*2) + ↓ + Downsample (→ embed_dim*4) + ↓ + Encoder3 (embed_dim*4) - Bottleneck +``` + +### Decoder (Đường lên) +``` + Encoder3 Output + ↓ + Upsample (→ embed_dim*2) + ↓ + Concatenate with Skip from Encoder2 + ↓ + Decoder2 (embed_dim*4 → embed_dim*2) + ↓ + Upsample (→ embed_dim) + ↓ + Concatenate with Skip from Encoder1 + ↓ + Decoder1 (embed_dim*2 → embed_dim) + ↓ + Attention Layer (Multi-head) + ↓ + Classifier (embed_dim → n_classes) +``` + +### Hyperparameters +- **embed_dim**: 128 (kích thước embedding) +- **batch_size**: 32 +- **optimizer**: AdamW (với weight decay = 0.01) +- **scheduler**: CosineAnnealingLR +- **dropout**: 0.1-0.3 (để regularization) + +## Kỹ thuật training + +### 1. Learning Rate Schedule +- Bắt đầu từ `learning_rate` +- Giảm dần theo cosine schedule +- Giúp convergence tốt hơn + +### 2. Weight Decay +- Sử dụng AdamW với weight_decay=0.01 +- Ngăn overfitting +- Improve generalization + +### 3. Attention Mechanism +- Multi-head attention (4 heads) +- Giúp model học các mối quan hệ phức tạp +- Cộng hưởng với self-attention trong Transformer + +## Tips để đạt kết quả tốt + +### ✅ Làm gì +1. **Tăng epochs** - Swin-UNet thường cần nhiều epochs (60-150) +2. **Sử dụng GPU** - Training nhanh hơn 10-20x +3. **Learning rate nhỏ** - 0.0001 - 0.0005 cho dataset lớn +4. **Augmentation** - Nếu có thể, augment training data +5. **Monitor loss** - Loss nên giảm dần qua epochs + +### ❌ Tránh gì +1. **Learning rate quá cao** - Training không ổn định +2. **Quá ít epochs** - Model chưa hội tụ +3. **Batch size quá lớn** - Hết bộ nhớ +4. **Overfitting** - Nếu train_acc >> test_acc, cần giảm epochs + +## Troubleshooting + +### Vấn đề: "CUDA out of memory" +```python +# Giải pháp: +- Giảm batch_size (từ 32 xuống 16) +- Giảm embed_dim (từ 128 xuống 64) +- Sử dụng CPU: "use_gpu": false +``` + +### Vấn đề: Loss không giảm +```python +# Giải pháp: +- Giảm learning_rate (thử 0.0001) +- Tăng epochs (thử 150+) +- Kiểm tra dữ liệu training +``` + +### Vấn đề: Quá chậm +```python +# Giải pháp: +- Giảm n_estimators (↓ epochs) +- Giảm max_scenes (↓ dữ liệu) +- Sử dụng GPU nếu có +``` + +### Vấn đề: Accuracy thấp +```python +# Giải pháp: +- Tăng epochs (thử 100-150) +- Thử learning_rate khác (0.0005, 0.001) +- Kiểm tra chất lượng dữ liệu training +- Thử model khác (ViT) +``` + +## So sánh Learning Rates + +| Learning Rate | Độ nhanh | Ổn định | Khuyến cáo | +|---------------|----------|---------|-----------| +| 0.01 | Nhanh | Kém | ❌ Quá cao | +| 0.005 | Trung bình | Trung bình | ⚠️ Có thể dùng | +| 0.001 | Trung bình | Tốt | ✅ Mặc định | +| 0.0005 | Chậm | Rất tốt | ✅ Dùng khi cần độ chính xác cao | +| 0.0001 | Rất chậm | Tuyệt | ✅ Cho ViT/LoRA | + +## Khi nào dùng Swin-UNet? + +### ✓ Sử dụng khi +- Bạn có dataset vừa đến lớn (500+ samples) +- Cần độ chính xác cao (>90%) +- Có GPU hoặc thời gian chờ đợi +- Muốn model ổn định và đáng tin cậy +- Dữ liệu có các mẫu phức tạp + +### ✗ Không sử dụng khi +- Dataset rất nhỏ (<200 samples) → Dùng CNN hoặc XGBoost +- Thời gian quá hạn → Dùng CNN hoặc XGBoost +- Không có GPU và thời gian bị giới hạn → Dùng XGBoost +- Cần mô hình hết sức nhẹ → Dùng CNN + +## Ví dụ thực tế + +### Trường hợp 1: Phân loại nhanh +```json +{ + "model_type": "swin-unet", + "n_estimators": 60, + "learning_rate": 0.001, + "use_gpu": true, + "max_scenes": 12, + "resolution": 20 +} +``` +**Kết quả**: ~15 phút, 85% accuracy + +### Trường hợp 2: Phân loại cân bằng +```json +{ + "model_type": "swin-unet", + "n_estimators": 100, + "learning_rate": 0.0005, + "use_gpu": true, + "max_scenes": 30, + "resolution": 10 +} +``` +**Kết quả**: ~40 phút, 92% accuracy + +### Trường hợp 3: Phân loại chính xác tối đa +```json +{ + "model_type": "swin-unet", + "n_estimators": 150, + "learning_rate": 0.0003, + "use_gpu": true, + "max_scenes": 60, + "resolution": 10 +} +``` +**Kết quả**: ~60 phút, 96%+ accuracy + +## Tài liệu tham khảo + +- Swin Transformer: https://arxiv.org/abs/2103.14030 +- U-Net: https://arxiv.org/abs/1505.04597 +- Swin-UNet for Medical Image: https://arxiv.org/abs/2105.05537 + +## Kết luận + +Swin-UNet là lựa chọn tuyệt vời khi bạn cần: +- ✅ Độ chính xác cao +- ✅ Model ổn định +- ✅ Khả năng xử lý dữ liệu phức tạp +- ✅ Training tương đối nhanh + +Hãy thử Swin-UNet cho các tác vụ classification quan trọng và cần chất lượng cao! diff --git a/api_server.py b/api_server.py index dc473c3..e2cef59 100644 --- a/api_server.py +++ b/api_server.py @@ -29,6 +29,13 @@ from report_generator import generate_training_report, generate_prediction_repor # Import Model Manager from model_manager import ModelManager, get_model_manager +# Import Vietnam provinces data +from vietnam_provinces import get_all_provinces, get_provinces_by_region, get_province_bbox, search_province +from vietnam_provinces_merged import ( + get_all_provinces_32, get_provinces_by_region_32, get_province_bbox_32, + search_province_32, get_merged_info, get_provinces_statistics +) + # Import planetary computer libraries (conditional) try: from pystac_client import Client @@ -95,7 +102,7 @@ class TrainingConfig(BaseModel): resolution: int = 20 # 10m hoặc 20m # Model parameters - model_type: str = "xgboost" # xgboost, random_forest, decision_tree, svm, cnn + model_type: str = "xgboost" # xgboost, random_forest, decision_tree, svm, cnn, swin-unet n_estimators: int = 100 max_depth: int = 20 learning_rate: float = 0.1 @@ -130,6 +137,9 @@ class PredictionConfig(BaseModel): max_scenes: int = 12 cloud_cover: int = 30 resolution: int = 20 + + # GPU support for deep learning models + use_gpu: bool = True class TrainingStatus(BaseModel): @@ -185,6 +195,7 @@ class PredictionWithNDVIConfig(BaseModel): max_scenes: int = 12 cloud_cover: int = 30 resolution: int = 20 + use_gpu: bool = False # Use GPU for deep learning models export_ndvi: bool = True # Export NDVI raster export_classification: bool = True # Export classification raster @@ -394,6 +405,104 @@ async def get_presets(): } +@app.get("/api/provinces/list") +async def list_provinces(): + """Lấy danh sách tất cả các tỉnh thành Việt Nam""" + return { + "provinces": get_all_provinces(), + "count": len(get_all_provinces()) + } + + +@app.get("/api/provinces/by-region") +async def list_provinces_by_region(): + """Lấy danh sách tỉnh thành theo vùng miền""" + return get_provinces_by_region() + + +@app.get("/api/provinces/{province_name}/bbox") +async def get_province_bbox_api(province_name: str): + """Lấy bbox của một tỉnh thành""" + bbox = get_province_bbox(province_name) + if bbox is None: + raise HTTPException(status_code=404, detail=f"Không tìm thấy tỉnh: {province_name}") + return { + "province": province_name, + "bbox": bbox, + "min_lon": bbox[0], + "min_lat": bbox[1], + "max_lon": bbox[2], + "max_lat": bbox[3] + } + + +@app.get("/api/provinces/search/{query}") +async def search_provinces(query: str): + """Tìm kiếm tỉnh thành theo tên""" + results = search_province(query) + return { + "query": query, + "results": results, + "count": len(results) + } + + +@app.get("/api/provinces-32/list") +async def list_provinces_32(): + """Lấy danh sách 32 tỉnh thành sau sáp nhập""" + return { + "provinces": get_all_provinces_32(), + "count": len(get_all_provinces_32()), + "note": "32 tỉnh thành sau sáp nhập theo Nghị quyết 1211/2023" + } + + +@app.get("/api/provinces-32/by-region") +async def list_provinces_by_region_32(): + """Lấy danh sách 32 tỉnh thành theo vùng miền""" + return get_provinces_by_region_32() + + +@app.get("/api/provinces-32/{province_name}/bbox") +async def get_province_bbox_api_32(province_name: str): + """Lấy bbox của một tỉnh thành (32 tỉnh)""" + bbox = get_province_bbox_32(province_name) + if bbox is None: + raise HTTPException(status_code=404, detail=f"Không tìm thấy tỉnh: {province_name}") + + # Get merged info + info = get_merged_info(province_name) + + return { + "province": province_name, + "bbox": bbox, + "min_lon": bbox[0], + "min_lat": bbox[1], + "max_lon": bbox[2], + "max_lat": bbox[3], + "merged_from": info.get("merged_from"), + "area_km2": info.get("area_km2"), + "region": info.get("region") + } + + +@app.get("/api/provinces-32/search/{query}") +async def search_provinces_32(query: str): + """Tìm kiếm tỉnh thành theo tên (32 tỉnh)""" + results = search_province_32(query) + return { + "query": query, + "results": results, + "count": len(results) + } + + +@app.get("/api/provinces-32/statistics") +async def get_provinces_stats(): + """Thống kê các tỉnh đã sáp nhập""" + return get_provinces_statistics() + + @app.get("/api/training/status", response_model=TrainingStatus) async def get_training_status(): """Kiểm tra trạng thái training""" @@ -867,14 +976,17 @@ async def run_prediction(config: PredictionConfig): # Initialize FeatureExtractor với đúng mode như lúc training extractor = get_feature_extractor(mode=feature_mode) - # Check if it's a CNN model (PyTorch) - is_cnn_model = hasattr(model, '__class__') and 'CNN' in model.__class__.__name__ - if is_cnn_model: - prediction_status["progress"] = "Phát hiện PyTorch CNN model..." + # Check if it's a PyTorch model (CNN, Swin-UNet, etc.) + is_pytorch_model = hasattr(model, '__class__') and any( + name in model.__class__.__name__ for name in ['CNN', 'SwinUNet'] + ) + if is_pytorch_model: + model_class_name = model.__class__.__name__ + prediction_status["progress"] = f"Phát hiện PyTorch {model_class_name} model..." try: import torch except ImportError: - raise ImportError("PyTorch required for CNN models. Install: pip install torch") + raise ImportError(f"PyTorch required for {model_class_name} models. Install: pip install torch") # Initialize common variables bbox = [config.min_lon, config.min_lat, config.max_lon, config.max_lat] @@ -1005,11 +1117,8 @@ async def run_prediction(config: PredictionConfig): # ============ PREDICT ============ prediction_status["progress"] = "Đang dự đoán..." - # Make prediction - if is_cnn_model: - predictions = model.predict(features) - else: - predictions = model.predict(features) + # Make prediction (all PyTorch models have the same predict interface) + predictions = model.predict(features) # Decode labels if label_encoder exists if label_encoder is not None: @@ -1654,8 +1763,10 @@ def run_batch_prediction(job: dict, config: PredictionConfig): model_manager = get_model_manager() model, label_encoder, model_metadata = model_manager.load_model(config.model_filename) - # Check if it's a CNN model - is_cnn_model = hasattr(model, '__class__') and 'CNN' in model.__class__.__name__ + # Check if it's a PyTorch model (CNN, Swin-UNet, etc.) + is_pytorch_model = hasattr(model, '__class__') and any( + name in model.__class__.__name__ for name in ['CNN', 'SwinUNet'] + ) job["progress"] = 20 @@ -1736,7 +1847,7 @@ def run_batch_prediction(job: dict, config: PredictionConfig): # Adjust features to match model expectations try: - if is_cnn_model: + if is_pytorch_model: expected_features = model.n_features elif hasattr(model, 'n_features_in_'): expected_features = model.n_features_in_ @@ -1755,11 +1866,8 @@ def run_batch_prediction(job: dict, config: PredictionConfig): except: pass - # Predict - if is_cnn_model: - predictions = model.predict(features) - else: - predictions = model.predict(features) + # Predict (all models have same predict interface) + predictions = model.predict(features) # Decode labels if label_encoder is not None: @@ -2748,8 +2856,52 @@ async def predict_with_ndvi(config: PredictionWithNDVIConfig, background_tasks: print(f"[PREDICT+NDVI] Predicting {features_clean.shape[0]} valid pixels...") - # Predict - predictions = model.predict(features_clean) + # Check if model is PyTorch/deep learning model and use GPU if available + is_pytorch_model = hasattr(model, '__class__') and ('CNN' in model.__class__.__name__ or 'Swin' in model.__class__.__name__ or 'UNet' in model.__class__.__name__) + + if is_pytorch_model and config.use_gpu: + try: + import torch + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + + if torch.cuda.is_available(): + print(f"[PREDICT+NDVI] Using GPU: {torch.cuda.get_device_name(0)}") + # Move model to GPU + model = model.to(device) + + # Predict in batches to avoid GPU memory overflow + batch_size = 8192 # Adjust based on GPU memory + predictions_list = [] + + for i in range(0, len(features_clean), batch_size): + batch = features_clean[i:i+batch_size] + batch_tensor = torch.from_numpy(batch).float().to(device) + + with torch.no_grad(): + batch_pred = model.predict(batch_tensor) + + # Move back to CPU if needed + if isinstance(batch_pred, torch.Tensor): + batch_pred = batch_pred.cpu().numpy() + + predictions_list.append(batch_pred) + + if (i // batch_size) % 10 == 0: + print(f"[PREDICT+NDVI] Processed {i + len(batch)}/{len(features_clean)} pixels on GPU") + + predictions = np.concatenate(predictions_list) + print(f"[PREDICT+NDVI] GPU prediction completed!") + else: + print(f"[PREDICT+NDVI] GPU requested but not available, using CPU") + predictions = model.predict(features_clean) + except Exception as gpu_error: + print(f"[PREDICT+NDVI] GPU prediction failed: {gpu_error}, falling back to CPU") + predictions = model.predict(features_clean) + else: + # Use CPU for traditional ML models + if is_pytorch_model and not config.use_gpu: + print(f"[PREDICT+NDVI] GPU disabled by user, using CPU") + predictions = model.predict(features_clean) # Reshape back to raster prediction_raster = np.full(n_pixels, -1, dtype=np.int16) diff --git a/prediction_interface.html b/prediction_interface.html index 6a8a04b..fdebb9a 100644 --- a/prediction_interface.html +++ b/prediction_interface.html @@ -313,12 +313,43 @@
+ +
+

🗺️ Chọn Khu Vực Prediction

+ +
+ + + +
+ + + Danh sách: 63 tỉnh +
+ + +
+ + +
+ +
+ + +
+
+
+
-

📍 Chọn khu vực để predict

-

✏️ Click vào nút hình vuông bên phải để vẽ bbox

-

🖱️ Kéo và thả để tạo vùng muốn phân loại

+

💡 Hướng dẫn:

+

📍 Chọn tỉnh thành ở trên để tự động điền bbox, hoặc sử dụng công cụ vẽ hình chữ nhật trên bản đồ

🔄 Có thể chỉnh sửa sau khi vẽ

@@ -382,6 +413,16 @@
+
+ +
+ ⚡ Tăng tốc prediction cho CNN/Swin-UNet models (yêu cầu GPU khả dụng) +
+
+