Vessel Detection Example
This example demonstrates how to use PyNAS for automated vessel detection in Synthetic Aperture Radar (SAR) imagery, a common application in maritime surveillance and remote sensing.
Overview
Vessel detection in SAR images presents unique challenges:
Speckle noise inherent in SAR imagery
Variable vessel sizes from small boats to large ships
Complex backgrounds including sea clutter and weather effects
Real-time requirements for operational systems
PyNAS can automatically discover architectures optimized for these specific challenges while maintaining efficiency for edge deployment.
Dataset Setup
First, set up the vessel detection dataset:
import os
import torch
import pytorch_lightning as pl
from datasets.RawVessels.loader import RawVesselsDataModule
# Set up reproducibility
pl.seed_everything(42, workers=True)
torch.set_float32_matmul_precision("medium")
# Configure dataset paths
root_dir = 'data/TASI/DataSAR_real_refined'
# Verify dataset exists
if not os.path.exists(root_dir):
raise FileNotFoundError(f"Dataset not found at {root_dir}")
# Initialize data module for vessel detection
dm = RawVesselsDataModule(
root_dir=root_dir,
batch_size=8, # Adjust based on GPU memory
num_workers=4, # Parallel data loading
test_size=0.15, # 15% for testing
val_size=0.15, # 15% for validation
seed=42, # Reproducibility
transform=None # Add augmentations if needed
)
# Setup the data module
dm.setup()
# Inspect dataset properties
print(f"Dataset information:")
print(f" Input shape: {dm.input_shape}")
print(f" Number of classes: {dm.num_classes}")
print(f" Training samples: {len(dm.train_dataset)}")
print(f" Validation samples: {len(dm.val_dataset)}")
print(f" Test samples: {len(dm.test_dataset)}")
Population Configuration
Configure the genetic algorithm for vessel detection:
from pynas.core.population import Population
# Create population optimized for vessel detection
pop = Population(
n_individuals=30, # Moderate population size
max_layers=6, # Allow deeper networks for complex features
dm=dm, # Vessel detection data module
max_parameters=300_000 # Balance accuracy and efficiency
)
print(f"Initialized population for vessel detection:")
print(f" Population size: {pop.n_individuals}")
print(f" Max layers: {pop.max_layers}")
print(f" Parameter budget: {pop.max_parameters:,}")
Architecture Search Process
Run the neural architecture search optimized for vessel detection:
import configparser
# Load vessel-specific configuration
config = configparser.ConfigParser()
config.read('pynas/core/config.ini')
# Extract vessel detection parameters
epochs = 12 # More epochs for complex SAR data
batch_size = 8 # Balance memory and gradient quality
max_generations = 15 # Sufficient exploration
# Initialize population
print("Generating initial population for vessel detection...")
pop.initial_poll()
# Evolution loop
best_fitness_history = []
for generation in range(max_generations):
print(f"\\n{'='*50}")
print(f"Generation {generation + 1}/{max_generations}")
print(f"{'='*50}")
# Train current generation
print("Training architectures on vessel detection task...")
pop.train_generation(
task='classification', # Binary: vessel/no-vessel
epochs=epochs,
lr=0.001, # Conservative learning rate
batch_size=batch_size
)
# Sort population by fitness
pop._sort_population()
# Record best fitness
if pop.population:
best_fitness = pop.population[0].fitness
best_fitness_history.append(best_fitness)
print(f"Best fitness: {best_fitness:.4f}")
print(f"Best IoU: {pop.population[0].iou:.4f}")
print(f"Best FPS: {pop.population[0].fps:.2f}")
print(f"Best model size: {pop.population[0].model_size:,} parameters")
# Evolve to next generation (except last)
if generation < max_generations - 1:
print("Evolving to next generation...")
pop.evolve(
mating_pool_cutoff=0.6, # Top 60% for mating
mutation_probability=0.25, # Higher mutation for exploration
k_best=3, # Keep top 3 performers
n_random=5 # Add diversity
)
# Checkpoint progress
pop.save_population()
print(f"Generation {generation + 1} completed and saved")
Results Analysis
Analyze the discovered architectures:
import matplotlib.pyplot as plt
import pandas as pd
# Get top performing models
top_models = pop.elite_models(k_best=5)
print("\\n" + "="*60)
print("VESSEL DETECTION RESULTS")
print("="*60)
for i, model in enumerate(top_models):
print(f"\\nRank {i+1}:")
print(f" Architecture: {model.architecture}")
print(f" Fitness: {model.fitness:.4f}")
print(f" Detection Accuracy (IoU): {model.iou:.4f}")
print(f" Inference Speed: {model.fps:.2f} FPS")
print(f" Model Complexity: {model.model_size:,} parameters")
# Calculate efficiency ratio
efficiency = model.iou / (model.model_size / 1000) # Accuracy per 1K params
print(f" Efficiency Ratio: {efficiency:.6f} IoU/1K params")
# Plot evolution progress
plt.figure(figsize=(12, 8))
plt.subplot(2, 2, 1)
plt.plot(range(1, len(best_fitness_history) + 1), best_fitness_history, 'b-o')
plt.title('Fitness Evolution - Vessel Detection')
plt.xlabel('Generation')
plt.ylabel('Best Fitness')
plt.grid(True)
# Fitness vs Model Size scatter plot
plt.subplot(2, 2, 2)
fitnesses = [m.fitness for m in top_models]
sizes = [m.model_size for m in top_models]
plt.scatter(sizes, fitnesses, c='red', alpha=0.7, s=100)
plt.title('Fitness vs Model Size')
plt.xlabel('Model Size (parameters)')
plt.ylabel('Fitness')
plt.grid(True)
# IoU vs FPS trade-off
plt.subplot(2, 2, 3)
ious = [m.iou for m in top_models]
fps = [m.fps for m in top_models]
plt.scatter(fps, ious, c='green', alpha=0.7, s=100)
plt.title('Accuracy vs Speed Trade-off')
plt.xlabel('Inference Speed (FPS)')
plt.ylabel('Detection Accuracy (IoU)')
plt.grid(True)
plt.tight_layout()
plt.show()
Model Validation
Validate the best model on test data:
# Get the best performing model
best_individual = pop.population[0]
# Build the final model
best_model, is_valid = pop.build_model(
best_individual.parsed_layers,
task='classification'
)
if is_valid:
print(f"\\nBest model validation:")
print(f" Architecture: {best_individual.architecture}")
print(f" Model built successfully: {is_valid}")
print(f" Total parameters: {pop.evaluate_parameters(best_model):,}")
# Additional validation metrics
print(f"\\nPerformance metrics:")
print(f" Final test accuracy: {best_individual.iou:.4f}")
print(f" Inference speed: {best_individual.fps:.2f} FPS")
print(f" Memory footprint: {best_individual.model_size:,} parameters")
# Calculate deployment metrics
model_size_mb = best_individual.model_size * 4 / (1024**2) # Assuming float32
print(f" Estimated model size: {model_size_mb:.2f} MB")
# Real-time capability assessment
if best_individual.fps >= 10:
print(" ✅ Suitable for real-time vessel detection")
else:
print(" ⚠️ May not meet real-time requirements")
Deployment Preparation
Prepare the model for edge deployment:
import torch.jit
# Export best model for deployment
best_model.eval()
# Create example input for tracing
example_input = torch.randn(1, *dm.input_shape)
# Trace the model for deployment
traced_model = torch.jit.trace(best_model, example_input)
# Save the traced model
model_path = f"vessel_detection_best_model.pt"
traced_model.save(model_path)
print(f"Model saved for deployment: {model_path}")
# Save architecture information
architecture_info = {
'architecture_code': best_individual.architecture,
'parsed_layers': best_individual.parsed_layers,
'fitness': best_individual.fitness,
'iou': best_individual.iou,
'fps': best_individual.fps,
'model_size': best_individual.model_size,
'input_shape': dm.input_shape,
'num_classes': dm.num_classes
}
import json
with open('vessel_detection_architecture.json', 'w') as f:
json.dump(architecture_info, f, indent=2)
print("Architecture information saved: vessel_detection_architecture.json")
Performance Comparison
Compare with baseline architectures:
# Define baseline architectures for comparison
baselines = {
'Simple CNN': 'c3g c3g c3g a C',
'ResNet-like': 'c3g R3g R3g a C',
'MobileNet-like': 'm4g m4g m4g a C'
}
print("\\nComparing with baseline architectures:")
print("-" * 60)
for name, arch_code in baselines.items():
# Create individual with baseline architecture
from pynas.core.individual import Individual
baseline_individual = Individual(max_layers=5)
baseline_individual.architecture = arch_code
# Parse and validate
from pynas.core import architecture_builder
baseline_individual.parsed_layers = architecture_builder.parse_architecture_code(arch_code)
if pop.check_individual(baseline_individual):
print(f"{name}:")
print(f" Architecture: {arch_code}")
print(f" Model size: {baseline_individual.model_size:,} parameters")
# Note: Would need to train for fair comparison
else:
print(f"{name}: Invalid architecture")
Key Findings
From this vessel detection example, typical findings include:
Architecture Patterns: Successful architectures often combine: - Multiple convolutional layers for feature extraction - Efficient blocks (MBConv) for parameter efficiency - Appropriate pooling for spatial reduction
Performance Trade-offs: - Higher accuracy often requires more parameters - Real-time performance favors efficient architectures - SAR-specific features benefit from deeper networks
Optimization Insights: - Genetic algorithms effectively explore architecture space - Population diversity is crucial for finding optimal solutions - Evolution converges to practical architectures
Next Steps
Experiment with data augmentation for improved robustness
Try multi-scale architectures for detecting vessels of different sizes
Implement ensemble methods combining top architectures
Explore transfer learning from pre-trained models