Files

178 lines
5.9 KiB
Python

import os
import glob
import time
import json
import itertools
import numpy as np
import joblib
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import TensorDataset, DataLoader
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, accuracy_score
from train_module import SwinUNetClassifier
def load_data():
cache_files = glob.glob('dataset_cache/training_data_*.joblib')
if not cache_files:
raise FileNotFoundError("No cache files found in dataset_cache/")
# Get the latest cache file
cache_file = max(cache_files, key=os.path.getctime)
print(f"Loading data from {cache_file}...")
data = joblib.load(cache_file)
features = data['features']
labels = data['labels']
# Map labels to 0..N-1
unique_labels = sorted(list(np.unique(labels)))
label_map = {lbl: idx for idx, lbl in enumerate(unique_labels)}
mapped_labels = np.array([label_map[l] for l in labels])
return features, mapped_labels, unique_labels
def train_evaluate(features, labels, embed_dim, lr, weight_decay, epochs, patience, device):
X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.2, random_state=42)
n_features = X_train.shape[1]
n_classes = len(np.unique(labels))
model = SwinUNetClassifier(n_features, n_classes, embed_dim=embed_dim).to(device)
X_train_t = torch.FloatTensor(X_train)
y_train_t = torch.LongTensor(y_train)
X_test_t = torch.FloatTensor(X_test)
y_test_t = torch.LongTensor(y_test)
train_dataset = TensorDataset(X_train_t, y_train_t)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
# Class weights
class_counts = np.bincount(y_train)
class_weights = 1.0 / (class_counts + 1e-6)
class_weights = class_weights / class_weights.sum() * len(class_counts)
class_weights_t = torch.FloatTensor(class_weights).to(device)
criterion = nn.CrossEntropyLoss(weight=class_weights_t)
optimizer = optim.AdamW(model.parameters(), lr=lr, weight_decay=weight_decay)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=50)
best_acc = 0.0
patience_counter = 0
best_model_state = None
model.train()
for epoch in range(epochs):
model.train()
for batch_X, batch_y in train_loader:
batch_X, batch_y = batch_X.to(device), batch_y.to(device)
optimizer.zero_grad()
outputs = model(batch_X)
loss = criterion(outputs, batch_y)
loss.backward()
optimizer.step()
scheduler.step()
# Eval
model.eval()
with torch.no_grad():
outputs = model(X_test_t.to(device))
_, preds = torch.max(outputs, 1)
acc = accuracy_score(y_test, preds.cpu().numpy())
if acc > best_acc:
best_acc = acc
best_model_state = model.state_dict()
patience_counter = 0
else:
patience_counter += 1
if patience_counter >= patience:
break
# Restore best
if best_model_state:
model.load_state_dict(best_model_state)
return model, best_acc, X_test_t, y_test
def main():
print("🚀 BẮT ĐẦU TÌM KIẾM SIÊU THAM SỐ CHO SWIN-UNET")
features, labels, unique_labels = load_data()
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(f"Using device: {device}")
param_grid = {
'embed_dim': [64, 128, 256, 512],
'lr': [1e-3, 5e-4, 1e-4],
'weight_decay': [0.01, 0.001],
'epochs': [200, 500]
}
keys = param_grid.keys()
combinations = list(itertools.product(*(param_grid[k] for k in keys)))
best_global_acc = 0.0
best_params = None
best_model = None
# Ensure dir exists
os.makedirs('land_classification_model', exist_ok=True)
os.makedirs('model_train', exist_ok=True)
for i, values in enumerate(combinations):
params = dict(zip(keys, values))
print(f"\n[{i+1}/{len(combinations)}] Training with params: {params}")
model, acc, X_test_t, y_test = train_evaluate(
features, labels,
embed_dim=params['embed_dim'],
lr=params['lr'],
weight_decay=params['weight_decay'],
epochs=params['epochs'],
patience=30,
device=device
)
print(f"Test Accuracy: {acc:.4f}")
if acc > best_global_acc:
best_global_acc = acc
best_params = params
best_model = model
print(f"🌟 NEW BEST ACCURACY: {acc:.4f}")
if acc >= 0.95:
print("🎯 ĐẠT MỤC TIÊU >95%! DỪNG TÌM KIẾM.")
break
if best_model is not None:
model_path = 'land_classification_model/model_swin-unet_optimized_95.joblib'
best_model = best_model.cpu()
joblib.dump(best_model, model_path)
print(f"\n✅ Đã lưu mô hình tốt nhất (Acc: {best_global_acc:.4f}) vào {model_path}")
print(f"Cấu hình tốt nhất: {best_params}")
# generate report
best_model.eval()
with torch.no_grad():
outputs = best_model(X_test_t)
_, preds = torch.max(outputs, 1)
clf_rep = classification_report(y_test, preds.cpu().numpy(), output_dict=True)
info = {
"model_type": "swin-unet",
"test_accuracy": float(best_global_acc),
"params": {"n_estimators": best_params['epochs'], "max_depth": best_params['embed_dim']},
"classification_report": clf_rep
}
with open('model_train/model_swin-unet_auto_info.json', 'w') as f:
json.dump(info, f, indent=2)
if __name__ == "__main__":
main()