Files
radiacode/train/vega_ml/agents.md
Jacquin Antoine 745a64b342 Pipeline complet Radiacode 103 - identification automatique d'isotopes
- VegaModel CNN-FCNN 34.5M params, 82 isotopes, val acc 99.89%
- Generation 50k spectres synthetiques 1D (12-24h durees)
- Entrainement 100 epochs sur RTX 5060 Ti (CUDA 12.8, Blackwell)
- Detection continue avec soustraction du background
- Capture background 24h avec gestion deconnexion
- Docker Compose : conteneur train (GPU) + detect (CPU/USB)
- Modele entraite inclus (vega_best.pt, 395 Mo)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-19 12:29:56 +02:00

413 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Agents.md - AI Agent Context for ML Isotope Identification
This document provides comprehensive context for AI agents working on this project. It describes the system architecture, purpose, configuration options, and implementation details of the synthetic gamma spectra generation and ML training systems.
## Project Purpose
This project generates **synthetic gamma-ray spectra** for training machine learning models to perform **isotope identification**. The goal is to create a neural network that can identify radioactive isotopes from gamma spectra captured by consumer-grade scintillation detectors (Radiacode devices).
### Why Synthetic Data?
1. **Real gamma spectra are expensive/dangerous to collect** - requires radioactive sources, permits, and safety protocols
2. **Need massive datasets** - ML models require 10,000-100,000+ training samples
3. **Controlled variation** - can systematically vary activities, durations, isotope combinations
4. **Ground truth labels** - perfect annotations impossible with real-world data
5. **Reproducibility** - can regenerate datasets with different parameters
## System Architecture
```
ml-for-isotope-identification/
├── synthetic_spectra/ # Spectrum generation package
│ ├── __init__.py # Package initialization
│ ├── config.py # Detector configurations (Radiacode 101-110)
│ ├── generator.py # Main SpectrumGenerator class
│ ├── generate_spectra.py # CLI batch generation script
│ ├── ground_truth/
│ │ ├── __init__.py
│ │ ├── isotope_data.py # 82 isotopes with gamma emission lines
│ │ └── decay_chains.py # U-238, Th-232, U-235, Cs-137 chains
│ └── physics/
│ ├── __init__.py
│ └── spectrum_physics.py # Physics calculations for peak generation
├── training/ # ML training infrastructure
│ ├── __init__.py
│ └── vega/ # Vega model package
│ ├── __init__.py
│ ├── isotope_index.py # Bidirectional isotope ↔ index mapping
│ ├── model.py # VegaModel CNN-FCNN architecture
│ ├── dataset.py # PyTorch Dataset and DataLoader
│ ├── train.py # VegaTrainer and training loop
│ └── run_training.py # CLI training entry point
├── inference/ # Inference engine
│ ├── vega_inference.py # VegaInference class for predictions
│ └── run_inference.py # CLI inference script
├── models/ # Saved model checkpoints
│ ├── vega_best.pt # Best validation loss checkpoint
│ ├── vega_final.pt # Final epoch checkpoint
│ ├── vega_history.json # Training metrics history
│ └── vega_isotope_index.txt # Isotope index mapping
└── data/synthetic/spectra/ # Generated training data
```
## Core Concepts
### 1. Spectrum Representation
Each spectrum is a **2D numpy array**:
- **X-axis (columns):** 1023 energy channels mapping to 20 keV - 3000 keV
- **Y-axis (rows):** Time intervals (1-second bins)
- **Values:** Normalized counts [0, 1]
This creates an "image-like" representation suitable for CNN-based models.
### 2. Physics Model
The generation follows realistic gamma spectroscopy physics:
#### Peak Generation (Gaussian)
```
G(E) = (λ / (σ√(2π))) × exp(-(E - E₀)² / (2σ²))
```
Where:
- `E₀` = gamma line energy (keV)
- `σ = FWHM / 2.355` (standard deviation)
- `λ = A × t × I × ε × T` (expected counts)
- `A` = activity (Bq)
- `t` = counting time (s)
- `I` = branching ratio (emission probability)
- `ε` = detector efficiency
- `T` = geometric factor
#### FWHM Scaling
```
FWHM(E) = FWHM_662 × √(E / 662)
```
Resolution degrades at higher energies following square-root scaling.
#### Background Model
- **Exponential continuum:** `B(E) = B₀ × exp(-E / E_char)`
- **Environmental isotopes:** K-40, Pb-214, Bi-214, Pb-212, Tl-208, Ac-228
- **Compton continuum:** Simplified model for scattered photons
#### Statistical Noise
**Poisson counting statistics** applied to all counts:
```
observed = Poisson(expected)
```
### 3. Detector Configurations
| Model | Crystal | FWHM @ 662 keV | Energy Range |
|-------|---------|----------------|--------------|
| radiacode_101 | CsI(Tl) | 9.0% | 20-3000 keV |
| radiacode_102 | CsI(Tl) | 9.5% | 20-3000 keV |
| radiacode_103 | CsI(Tl) | 8.4% | 20-3000 keV |
| radiacode_103g | GAGG(Ce) | 7.4% | 20-3000 keV |
| radiacode_110 | CsI(Tl) | 8.4% | 20-3000 keV |
### 4. Isotope Database
**82 isotopes** across categories:
- `NATURAL_BACKGROUND`: K-40, Ra-226, Rn-222
- `PRIMORDIAL`: U-238, U-235, Th-232
- `COSMOGENIC`: Be-7, Na-22, C-14
- `U238_CHAIN`: Pa-234m, Th-234, Ra-226, Pb-214, Bi-214, Pb-210, Po-210
- `TH232_CHAIN`: Ac-228, Ra-224, Pb-212, Bi-212, Tl-208
- `U235_CHAIN`: Pa-231, Th-227, Ra-223, Rn-219, Pb-211, Bi-211
- `CALIBRATION`: Am-241, Ba-133, Cs-137, Co-57, Co-60, Eu-152, Na-22, Mn-54
- `INDUSTRIAL`: Ir-192, Se-75, Cd-109, I-131, Y-90
- `MEDICAL`: Tc-99m, F-18, Ga-67, Ga-68, In-111, I-123, I-125, Tl-201, Lu-177
- `REACTOR_FALLOUT`: Cs-134, Cs-137, I-131, Sr-90, Zr-95, Nb-95, Ru-103, Ru-106, Ce-141, Ce-144
- `ACTIVATION`: Fe-59, Cr-51, Zn-65, Ag-110m, Sb-124, Sb-125
---
## Vega Model Architecture
**Vega** is the primary ML model for isotope identification, using a CNN-FCNN hybrid architecture based on research showing 99%+ accuracy on gamma spectroscopy tasks.
### Model Design
```python
VegaModel (34.5M parameters)
├── CNN Backbone
├── ConvBlock1: Conv1d(164, k=7) BN LeakyReLU MaxPool
├── ConvBlock2: Conv1d(64128, k=7) BN LeakyReLU MaxPool
└── ConvBlock3: Conv1d(128256, k=7) BN LeakyReLU MaxPool
├── Flatten
├── FC Layers
├── Linear BN LeakyReLU Dropout(0.3)
└── Linear BN LeakyReLU Dropout(0.3)
└── Dual Output Heads
├── Classifier: Linear(25682) [logits for BCEWithLogitsLoss]
└── Regressor: Linear(25682) ReLU [activity in Bq]
```
### Key Configuration (VegaConfig)
```python
@dataclass
class VegaConfig:
num_channels: int = 1023 # Input spectrum channels
num_isotopes: int = 82 # Output classes
cnn_channels: List[int] = [64, 128, 256]
kernel_size: int = 7 # Captures spectral features
fc_hidden_dims: List[int] = [512, 256]
dropout_rate: float = 0.3
leaky_relu_slope: float = 0.01
max_activity_bq: float = 1000.0 # Activity normalization
```
### Loss Function
Multi-task loss combining classification and regression:
```python
total_loss = BCE_weight * BCEWithLogitsLoss(logits, presence)
+ Huber_weight * HuberLoss(pred_activity, true_activity)
```
- **BCEWithLogitsLoss:** AMP-safe, applies sigmoid internally
- **HuberLoss:** Robust to activity outliers
- Default weights: classification=1.0, regression=0.1
### Training Configuration
```python
@dataclass
class TrainingConfig:
data_dir: str = "data/synthetic"
model_dir: str = "models"
epochs: int = 100
batch_size: int = 32
learning_rate: float = 1e-3
weight_decay: float = 1e-5
use_amp: bool = True # Mixed precision on GPU
early_stopping_patience: int = 15
lr_scheduler_patience: int = 5
lr_scheduler_factor: float = 0.5
```
### GPU Support
**RTX 5090 (Blackwell sm_120) requires PyTorch nightly with CUDA 12.8:**
```bash
pip install --pre torch --index-url https://download.pytorch.org/whl/nightly/cu128
```
The training and inference scripts automatically test CUDA compatibility and fall back to CPU if needed.
---
## Configuration & Variation
### SpectrumConfig Parameters
```python
@dataclass
class SpectrumConfig:
detector_type: str = "radiacode_103" # Which detector to simulate
duration_seconds: int = 300 # Total measurement time
interval_seconds: int = 1 # Time bin size (always 1s)
include_background: bool = True # Add environmental background
background_scale: float = 1.0 # Background intensity multiplier
noise_enabled: bool = True # Apply Poisson statistics
normalize: bool = True # Normalize to [0, 1]
```
### Variation in Generated Data
The `generate_training_batch()` function creates varied samples:
| Category | Proportion | Description |
|----------|------------|-------------|
| Single isotope | 40% | One source isotope + background |
| Dual isotope | 30% | Two source isotopes blended |
| Multi isotope | 20% | 3-5 isotopes combined |
| Background only | 10% | Environmental background only |
#### Activity Ranges
- **Activity:** 10-500 Bq (randomized per isotope)
- **Duration:** 60-600 seconds (randomized)
- **Background scale:** 0.5-2.0× (randomized)
#### Isotope Pool
Common isotopes used for generation:
```python
ISOTOPE_POOL = [
"Am-241", "Ba-133", "Cs-137", "Co-57", "Co-60",
"Eu-152", "Na-22", "Mn-54", "K-40", "Ra-226",
"Th-232", "U-238", "I-131", "Tc-99m", "Ir-192"
]
```
## Output Format
### Directory Structure
```
data/synthetic/spectra/
├── {uuid}_spectrum.npy # Numpy array (time × channels)
├── {uuid}_spectrum.png # Visualization image
└── labels.json # Metadata for all samples
```
### Labels JSON Schema
```json
{
"sample_id": {
"isotopes": [
{
"name": "Cs-137",
"activity_bq": 123.45,
"category": "CALIBRATION"
}
],
"background_isotopes": ["K-40", "Pb-214", ...],
"detector": "radiacode_103",
"duration_seconds": 300,
"num_intervals": 300,
"background_scale": 1.2,
"generation_timestamp": "2025-01-24T..."
}
}
```
### Numpy Array Details
- **Shape:** `(num_intervals, 1023)`
- **Dtype:** `float64`
- **Range:** `[0.0, 1.0]` (normalized)
- **Channel mapping:** `channel_i → 20 + i × (3000-20)/1023 keV`
## Usage
### Generate Test Batch (10 samples)
```bash
python -m synthetic_spectra.generate_spectra
```
### Generate Large Training Set
Edit `generate_spectra.py`:
```python
generate_training_batch(
n_samples=100000,
output_dir=Path("data/synthetic/spectra"),
detector_type="radiacode_103"
)
```
### Programmatic Generation
```python
from synthetic_spectra.generator import SpectrumGenerator, SpectrumConfig, IsotopeSource
from synthetic_spectra.config import RADIACODE_CONFIGS
generator = SpectrumGenerator(RADIACODE_CONFIGS["radiacode_103"])
config = SpectrumConfig(
duration_seconds=300,
include_background=True,
background_scale=1.0
)
sources = [
IsotopeSource(isotope_name="Cs-137", activity_bq=100.0),
IsotopeSource(isotope_name="Co-60", activity_bq=50.0)
]
spectrum = generator.generate_spectrum(sources, config)
# spectrum.data is the 2D numpy array
# spectrum.metadata contains all generation parameters
```
## Future Enhancements
### Planned Improvements
1. **Compton edge modeling** - More realistic continuum shapes
2. **Pile-up effects** - High count rate distortions
3. **Gain drift simulation** - Energy calibration shifts over time
4. **Source geometry** - Distance/shielding effects
5. **Decay during measurement** - Short-lived isotope activity changes
6. **Data augmentation** - Channel shifts, noise injection
7. **Confusion matrix analysis** - Per-isotope performance metrics
## Key Files for Modification
| File | Purpose | When to Modify |
|------|---------|----------------|
| `synthetic_spectra/config.py` | Detector specs | Add new detector types |
| `synthetic_spectra/ground_truth/isotope_data.py` | Isotope database | Add isotopes, update gamma lines |
| `synthetic_spectra/ground_truth/decay_chains.py` | Chain relationships | Add decay chain logic |
| `synthetic_spectra/physics/spectrum_physics.py` | Physics model | Improve realism |
| `synthetic_spectra/generator.py` | Generation logic | Add features, change output format |
| `synthetic_spectra/generate_spectra.py` | Batch generation | Adjust sample distribution |
| `training/vega/model.py` | Vega architecture | Modify CNN/FC layers, heads |
| `training/vega/train.py` | Training loop | Change optimization, callbacks |
| `training/vega/dataset.py` | Data loading | Add augmentation, preprocessing |
| `inference/vega_inference.py` | Inference engine | Modify prediction pipeline |
## Usage
### Generate Synthetic Data
```bash
python -m synthetic_spectra.generate_spectra
```
### Train Model
```bash
# Quick test (5 epochs)
python training/vega/run_training.py --test
# Full training
python training/vega/run_training.py --epochs 100 --batch-size 32
# Without AMP (if GPU issues)
python training/vega/run_training.py --no-amp
```
### Run Inference
```bash
python inference/run_inference.py --model models/vega_best.pt --data data/synthetic
```
### Programmatic Usage
```python
# Training
from training.vega.train import train_vega, TrainingConfig
from training.vega.model import VegaConfig
config = TrainingConfig(epochs=100, batch_size=32)
model_config = VegaConfig()
model, results = train_vega(config, model_config)
# Inference
from inference.vega_inference import VegaInference
inference = VegaInference("models/vega_best.pt")
prediction = inference.predict_from_file("spectrum.npy", threshold=0.5)
print(prediction.summary())
```
## Dependencies
```
numpy>=1.24.0 # Array operations
scipy>=1.10.0 # Statistical functions
pillow>=9.0.0 # PNG image generation
torch>=2.11.0 # PyTorch (nightly for RTX 5090)
```
## References
- Radiacode device specifications: https://radiacode.com/
- Gamma spectroscopy physics: Knoll, "Radiation Detection and Measurement"
- Isotope data: IAEA Nuclear Data Services, NNDC at Brookhaven
- CNN-FCNN architecture: Wang et al. research on gamma spectroscopy ML
---
*This document should be updated whenever significant changes are made to the generation or training systems.*