# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview This is the **BEATs** (Audio Pre-Training with Acoustic Tokenizers) project, part of Microsoft's UniLM family. It implements a self-supervised audio pre-training framework based on iterative acoustic tokenization and masked audio modeling. Paper: [arXiv:2212.09058](https://arxiv.org/abs/2212.09058). The repo also contains an active extension, **Spatial-BEATs**, which adds spatial audio understanding (direction-of-arrival, distance estimation) on top of the frozen BEATs encoder for First Order Ambisonics (FOA) data. ## Key Dependencies - PyTorch, torchaudio (for fbank feature extraction via `torchaudio.compliance.kaldi`) - `einops` (used by quantizer for codebook k-means init) - Training uses `torchrun` for distributed data parallel ## Training Commands ### Spatial-BEATs (three-stage mono-AST on ov1 FOA data) ```bash # All knobs overridable via env vars: GPUS, BATCH_SIZE, NUM_WORKERS, etc. ./run_ov1_ast_three_stage.sh ``` Stages: (1) class warmup with frozen BEATs, (2) spatial-first, (3) balanced classification + spatial. ### Pre-trunk AST experiment (two-stage) ```bash ./run_ov1_pretrunk_ast_experiment.sh ``` Stages: (1) class-only warmup with task tokens inside BEATs trunk, (2) spatial CE finetune. ### Single training run ```bash torchrun --nproc_per_node=4 train_spatial_beats.py \ --preset \ --output-dir \ --batch-size 8 --num-workers 4 --num-epochs 12 ``` Available presets are defined via `make_*_config()` factories in `train_spatial_beats.py` and listed in `spatial_beats_ov123_stage1_config.py`. ## Architecture ### Original BEATs (inference-only weights) ``` Raw waveform (16kHz) → fbank (128 mel bins, frame_length=25ms, frame_shift=10ms) → normalize with fixed mean/std → Conv2d patch embedding → LayerNorm → optional Linear projection → TransformerEncoder (N layers with relative position bias + GRU gating) → extract_features() returns [B, T, D] representations → (finetuned models) → Linear predictor → sigmoid → class probabilities ``` Two model classes share this backbone: - **`BEATs`** (`BEATs.py`): audio encoder. `extract_features()` returns representations or class probs (if finetuned). - **`Tokenizers`** (`Tokenizers.py`): same encoder + `NormEMAVectorQuantizer` head. `extract_labels()` returns discrete codebook indices. ### Spatial-BEATs extension Builds on top of BEATs to add spatial audio capabilities: - **`SpatialBEATs`** (`spatial_beats.py`): wraps a frozen BEATs `TransformerEncoder` with multi-channel FOA preprocessing (`SpatialBEATsPreprocessor`), a `SpatialPatchEmbedding` for the extra channels, and task-specific prediction heads. - **`spatial_modules.py`**: contains all building blocks — `SpatialPatchEmbedding`, `SpatialDeltaPatchAdapter`, `FixedSlotReadout`, `MonoTaskTokenReadout`, `FrequencyPool`, `TemporalResampler`, and prediction heads (`SpatialPredictionHeads`, `MonoTaskPredictionHeads`, `PreTrunkASTPredictionHeads`). - **`spatial_dataset.py`**: `SpatialDataset` loads FOA audio from JSONL manifests with per-frame source annotations (azimuth, elevation, distance, class). Uses a Qwen-2.5-Omni-aligned mel frontend (16kHz, 128 bins, hop=160). - **`spatial_loss.py`**: multi-task loss with Hungarian-style slot matching — activity BCE, azimuth/elevation CE over binned angles, distance regression, and auxiliary source classification. ### Module dependency graph ``` modules.py — primitives: GradMultiply, SamePad, GLU_Linear, quant_noise, activation fns quantizer.py — NormEMAVectorQuantizer, EmbeddingEMA (VQ-VAE codebook with EMA updates) backbone.py — TransformerEncoder, TransformerSentenceEncoderLayer, MultiheadAttention BEATs.py — BEATs model (uses backbone) Tokenizers.py — Tokenizers model (uses backbone + quantizer) spatial_modules.py — spatial building blocks (patch embeddings, readout heads, prediction heads) spatial_beats.py — SpatialBEATs model (uses backbone + spatial_modules) spatial_dataset.py — SpatialDataset + collation spatial_loss.py — loss computation + slot matching (uses spatial_modules output types) train_spatial_beats.py — training loop, presets, CLI (uses spatial_beats, spatial_dataset, spatial_loss) ``` ## Loading Pre-trained Checkpoints Checkpoints are `dict` with keys `'cfg'` (config dict) and `'model'` (state dict): ```python checkpoint = torch.load('model.pt') cfg = BEATsConfig(checkpoint['cfg']) model = BEATs(cfg) model.load_state_dict(checkpoint['model']) ``` Same pattern for `Tokenizers` with `TokenizersConfig`. ## Audio Input Contract - All models expect **16kHz mono** waveforms - `preprocess()` converts to 128-bin fbank features normalized with fixed mean=15.41663, std=6.55582 - Padding masks are `bool` tensors where `True` = padded position - Spatial-BEATs uses 4-channel FOA input instead of mono 我希望在原始BEATs的基础上更改模型的框架,让模型有FOA音频的理解能力,能够在声源分类之外拥有识别位置的能力,这样的encoder作为我未来输入给LLM的例子。我之前自己尝试了一些做法,不过class分类不是很收敛,空间指标比如dis,ele,azimuth的loss几乎不收敛,我感觉我的方法太过于ML了,没有充分的利用DL的能力,或许应该一定程度上相信attention的能力来学习。我认为应该像BAT一样,你看这个目录下面的Spatial-AST的训练是从AudioMAE的训练开始的,我觉得确实应该学习他的设计来类似的训练我的Spatial-BEATs,我设计了实验run_ov1_pretrunk_ast_experiment.sh来验证,现在有了初步的结果,但是看的出来,还不是很收敛,预期结果和我想的完全不一样,我到底应该怎么办呢?还有疑问是BEATS是用audioset训练的,我现在的ov1数据干声来源于FSD50K,这是不是首先会影响分类任务,我是不是应该先在分类任务上finetune到一定的程度之后再考虑空间呢