bổ sung chức năng load 64 tỉnh thành và 32 tỉnh thành/ bổ sung mô hình Swin-Unet

This commit is contained in:
Victor Phan
2026-01-03 22:35:33 +07:00
parent e86709df85
commit 03048d9503
10 changed files with 2722 additions and 62 deletions
+173 -21
View File
@@ -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)