Skip to content
This repository was archived by the owner on Jun 11, 2026. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 106 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,53 +103,120 @@ An experimental project exploring:

📓 **[RESEARCH_LOG.md](RESEARCH_LOG.md)** - Detailed experiment notes, results, and analysis

## Project Structure
## Project Structure (v0.2 - Configuration-Driven)

```
python/phantomx/
model.py # ProgressiveVQVAE (MLP-based)
models_extended.py # CausalTransformerVQVAE, GumbelVQVAE (best performers)
trainer.py # ProgressiveTrainer (3-phase training)
tta.py # Test-Time Adaptation (TTAWrapper, OnlineTTA)
tokenizer/ # Spike tokenization
data/ # MC_Maze data loading
python/
exp10_beat_lstm.py # Latest: CausalTransformer + Gumbel experiments
compare_models.py # Model comparisons
models/
exp9_progressive_vqvae.pt # Progressive VQ-VAE (R²=0.71)
comparison_results.json # All experiment results
PhantomX/
├── configs/ # 🆕 Hydra YAML configurations
│ ├── config.yaml # Main config
│ ├── model/ # Model configs (vqvae, mamba, lstm, transformer)
│ ├── dataset/ # Dataset configs (mc_maze, mc_rtt)
│ ├── trainer/ # Training configs (default, progressive)
│ ├── augmentation/ # Augmentation configs (none, standard, strong)
│ └── experiment/ # Experiment presets (exp25_mamba, etc.)
├── src/ # 🆕 Unified source code
│ ├── models/ # Model implementations
│ ├── datamodules/ # Dataset loading
│ ├── trainer.py # Unified trainer
│ └── utils/ # Logging, seeding, metrics
├── train.py # 🆕 SINGLE entry point for all experiments
├── python/ # Legacy experiment scripts (deprecated)
├── data/ # NWB data files
└── logs/ # Experiment outputs (auto-generated)
```

## Quick Start
## Quick Start (v0.2)

```python
from phantomx.model import ProgressiveVQVAE
from phantomx.trainer import ProgressiveTrainer
from phantomx.data import MCMazeDataset

# Load data
dataset = MCMazeDataset("path/to/mc_maze.nwb")
train_loader, val_loader, test_loader = create_dataloaders(dataset)

# Create and train model
model = ProgressiveVQVAE(n_channels=142, window_size=10)
trainer = ProgressiveTrainer(model, train_loader, val_loader)
result = trainer.train()
print(f"Best R²: {result['best_r2']:.4f}")

# Test-Time Adaptation for new sessions
from phantomx.tta import OnlineTTA
tta = OnlineTTA(model)
predictions = tta.predict(new_data)
```

## Setup
### Installation

```bash
# Create environment
python -m venv venv
venv\Scripts\activate # Windows
pip install -r requirements.txt
# source venv/bin/activate # Linux/Mac

# Install with new dependencies
pip install -e ".[all]"

# Or just core dependencies
pip install -e .
```

### Basic Training

```bash
# Default: VQ-VAE on MC_Maze
python train.py

# Mamba on MC_RTT (Exp 25)
python train.py experiment=exp25_mamba

# LSTM baseline
python train.py model=lstm dataset=mc_maze

# Override hyperparameters
python train.py model=mamba model.n_layers=6 trainer.learning_rate=1e-4

# Disable WandB for quick tests
python train.py trainer.max_epochs=5 logging.use_wandb=false
```

### Multi-Seed Validation (Exp 23 style)

```bash
# Run with multiple seeds
python train.py experiment=exp23_validation --multirun seed=42,123,456,789,1337
```

### Hyperparameter Sweeps

```bash
# Model comparison
python train.py --multirun model=vqvae,lstm,mamba dataset=mc_maze

# Full grid search
python train.py --multirun \
model=mamba \
model.d_model=64,128,256 \
model.n_layers=2,4,6
```

### Python API

```python
import hydra
from omegaconf import OmegaConf

from src.models import build_model
from src.datamodules import build_datamodule
from src.trainer import Trainer
from src.utils import seed_everything

# Load config
cfg = OmegaConf.load("configs/config.yaml")
cfg = OmegaConf.merge(cfg, OmegaConf.load("configs/model/mamba.yaml"))
cfg = OmegaConf.merge(cfg, OmegaConf.load("configs/dataset/mc_rtt.yaml"))

seed_everything(42)

# Build components
datamodule = build_datamodule(cfg)
datamodule.setup()

model = build_model(cfg, n_channels=datamodule.n_channels)
trainer = Trainer(model, datamodule.train_dataloader(), datamodule.val_dataloader(), cfg)

# Train
results = trainer.train()
print(f"Best R²: {results['best_r2']:.4f}")
```

## Legacy Quick Start (v0.1)

```python
# Still works for backward compatibility
from python.phantomx.model import ProgressiveVQVAE
from python.phantomx.trainer import ProgressiveTrainer
```

## Current Status
Expand Down Expand Up @@ -192,6 +259,7 @@ This project was developed with assistance from AI coding assistants and workflo
- Claude Sonnet 4.5 (Anthropic)
- Gemini 3.0 Pro (Google)
- GPT 5.2 (OpenAI)
- Grok Code Fast 1 (xAi)

All code was tested, and validated by the author.

Expand Down
19 changes: 19 additions & 0 deletions RESEARCH_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2443,3 +2443,22 @@ split = 70% train / 15% val / 15% test (sequential)

---

## 🎰 Architecture Roulette — Time to Build Intuition
**Date**: 2026-01-23

We've been spinning the wheel: LSTM → Transformer → Mamba → VQ-VAE → FSQ → distillation... Each architecture wins on one dataset, fails on another. We're pattern-matching configurations without understanding **why** they work.

**The problem**: We lack intuition for neural signal structure.

**The plan**: Step back from BCI decoding and build fundamental intuition on a simpler domain — **music**. Audio has:
- Clear temporal structure (rhythm, melody)
- Multi-scale patterns (beats → bars → phrases)
- Well-understood representations (spectrograms, MFCCs)
- Easy human evaluation (does it sound right?)

If we can develop intuition for temporal tokenization on music, we can transfer those insights back to neural data.

**New repo**: https://github.com/yelabb/PhantomMusic

---

6 changes: 6 additions & 0 deletions configs/augmentation/none.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# No Augmentation Configuration
# ==============================
# Baseline: no data augmentation

name: "none"
enabled: false
35 changes: 35 additions & 0 deletions configs/augmentation/standard.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Standard Augmentation Configuration
# ====================================
# Data augmentation techniques from successful experiments

name: "standard"
enabled: true

# Electrode dropout (key for robustness)
electrode_dropout:
enabled: true
p: 0.1 # Probability of dropping each electrode
structured: false # Random vs structured dropout

# Temporal jitter
temporal_jitter:
enabled: true
max_shift_bins: 2 # Max bins to shift (50ms at 25ms bins)
wrap: false # Wrap around or zero-pad

# Noise injection
noise:
enabled: true
type: "gaussian" # gaussian, poisson
scale: 0.05 # Noise scale

# Spike count scaling
spike_scaling:
enabled: true
min_scale: 0.9
max_scale: 1.1

# Mixup (disabled by default)
mixup:
enabled: false
alpha: 0.2
42 changes: 42 additions & 0 deletions configs/augmentation/strong.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Strong Augmentation Configuration
# ==================================
# Aggressive augmentation for maximum robustness

name: "strong"
enabled: true

# Electrode dropout (aggressive)
electrode_dropout:
enabled: true
p: 0.2 # 20% electrode dropout
structured: true # Structured (realistic) dropout patterns

# Temporal jitter (aggressive)
temporal_jitter:
enabled: true
max_shift_bins: 4 # 100ms jitter
wrap: false

# Noise injection (stronger)
noise:
enabled: true
type: "gaussian"
scale: 0.1

# Spike count scaling (wider range)
spike_scaling:
enabled: true
min_scale: 0.8
max_scale: 1.2

# Mixup (enabled)
mixup:
enabled: true
alpha: 0.3

# Cutout (neural version)
cutout:
enabled: true
n_holes: 2
hole_size_channels: 10
hole_size_time: 3
51 changes: 51 additions & 0 deletions configs/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# PhantomX Main Configuration
# ============================
# Default configuration for all experiments.
# Override via command line: python train.py model=mamba dataset=mc_rtt

defaults:
- _self_
- model: vqvae # Default model
- dataset: mc_maze # Default dataset
- trainer: default # Default trainer settings
- augmentation: none # No augmentation by default
- optional experiment: null # Override everything for specific experiments

# ===== General Settings =====
seed: 42
output_dir: ${hydra:run.dir}
project_name: "PhantomX"
experiment_name: "${model.name}_${dataset.name}"

# ===== Logging =====
logging:
use_wandb: true
wandb_project: "PhantomX"
wandb_entity: null # Your wandb username/team
log_every_n_steps: 10
save_checkpoints: true
checkpoint_every_n_epochs: 10

# ===== Reproducibility =====
reproducibility:
deterministic: true
benchmark: false # Set true for faster training if input sizes don't change
save_git_hash: true
save_config: true # Hydra does this automatically

# ===== Hardware =====
hardware:
device: "auto" # auto, cuda, cpu, mps
num_workers: 4
pin_memory: true
precision: 32 # 16, 32, or "bf16"

# ===== Hydra Settings =====
hydra:
run:
dir: logs/${experiment_name}/${now:%Y-%m-%d_%H-%M-%S}
sweep:
dir: logs/sweeps/${experiment_name}
subdir: ${hydra.job.num}
job:
chdir: false # Don't change working directory
36 changes: 36 additions & 0 deletions configs/dataset/mc_maze.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# MC_Maze Dataset Configuration
# ==============================
# Motor cortex recordings during maze reaching task
# From Neural Latents Benchmark (NLB 2021)

name: "mc_maze"

# Dataset class for Hydra instantiation
_target_: src.datamodules.mc_maze.MCMazeDataModule

# Data paths
data_dir: ${oc.env:PHANTOMX_DATA_DIR,data}
filename: "mc_maze.nwb"

# Preprocessing
bin_size_ms: 25.0 # 40 Hz sampling
normalize: true # Z-score normalization
normalize_per_channel: true

# Splits
train_ratio: 0.7
val_ratio: 0.1
test_ratio: 0.2
shuffle_before_split: true # Shuffle trials, not time bins

# DataLoader settings
batch_size: 64
shuffle: true # Shuffle batches during training

# Dataset specifics
n_channels: 137 # Neural units
task: "velocity_decoding"
target_type: "velocity" # velocity, position, acceleration

# Trial structure
trial_based: true # MC_Maze has discrete trials
Loading