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:

  1. Architecture Patterns: Successful architectures often combine: - Multiple convolutional layers for feature extraction - Efficient blocks (MBConv) for parameter efficiency - Appropriate pooling for spatial reduction

  2. Performance Trade-offs: - Higher accuracy often requires more parameters - Real-time performance favors efficient architectures - SAR-specific features benefit from deeper networks

  3. 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