English | 中文
Code for SpectrumFM v2 (Memory Transformer + LoRA). Paper code for v1 is on main.
@ARTICLE{11301740,
author={Zhou, Fuhui and Liu, Chunyu and Zhang, Hao and Wu, Wei and Wu, Qihui and Quek, Tony Q. S. and Chae, Chan-Byoung},
journal={IEEE Journal on Selected Areas in Communications},
title={SpectrumFM: A Foundation Model for Intelligent Spectrum Management},
year={2025},
doi={10.1109/JSAC.2025.3644783}}git clone -b v2 https://github.com/ChunyuLiu188/SpectrumFM.git
cd SpectrumFM
pip install -r requirements.txtPretrained checkpoint: ckpts/best.pt. LoRA adapters: runs/finetune/<task>/seed{42,123,456}/best.pt (load together with ckpts/best.pt).
Memory Transformer (model.py): I/Q projected separately, RMT memory tokens at both ends, bidirectional attention.
| v1 | v2 | |
|---|---|---|
|
|
256, 4, 512, 16 | 512, 8, 2048, 16 |
| Memory tokens | — | 16 |
| Sequence | 128 | 128 (ManyTx: 256, split into two 128 windows) |
| Pretrain | mask + next-slot | masked I/Q reconstruction only |
| Fine-tune | full | LoRA qkv,out_proj,ff
|
| Parameters | — |
|
Layout: [mem (16) | IQ (128) | mem (16)]. Masked I/Q are replaced by learnable mask tokens (not dropped). Fine-tune pooling: mean over IQ tokens.
Default (pretrain, LoRA, and baselines): sample-level IQ RMS-power, applied on the GPU batch, not written to disk.
Statistics are per burst (I and Q share one scale), not batch- or dataset-level. Input to the model is raw (B, L, 2) float32. For ManyTx (long_mode=split).
Pretrain 1 epoch on RML2018.01A; LoRA on RML2016.10a, a stratified 10k WTC subset, and WiSig ManySig (RFFI). Same architecture; three seeds; mean$\pm$std (%). Not the full-run protocol below.
| Scope | Input | AMC | WTC | RFFI |
|---|---|---|---|---|
| None | Raw IQ | |||
| None | Raw AP | |||
| Sample | IQ min–max | |||
| Sample | IQ |
|||
| Sample | IQ RMS-power | |||
| Sample | IQ max-abs | |||
| Sample | AP min–max | |||
| Sample | AP |
|||
| Dataset | IQ min–max | |||
| Dataset | IQ |
|||
| Dataset | IQ RMS-power |
Released runs use sample-level IQ RMS-power.
Masked reconstruction. Each of model.masked_mse).
python prepare_data.py --config config.yaml # shards under ./cache/pretrain; no RMS
bash run_pretrain.sh| Data | mixed radio IQ under data.root (config.yaml) |
| Precision / ZeRO | bf16, DeepSpeed ZeRO-2 |
| Optimizer | AdamW, peak |
| Batch (example) | micro 512 |
| Epochs / val | 10 / 1% hold-out; ckpts/best.pt = lowest val MSE |
| Dropout | 0 (set to 0.1 in fine-tune) |
CKPT=./ckpts/best.pt bash run_finetune.sh
python eval_finetune.py ./runs/finetune/rml2016a/seed42LoRA qkv,out_proj,ff. Head: LayerNorm
Split. --split 6:2:2, --split-seed 0 (independent of --seed). Stratify on class and SNR when available. 80/20 then 75/25 of the train pool --seed
| Task | Data | Notes |
|---|---|---|
rml2016a |
data/RML2016.10a_dict.pkl |
11-way, |
rml2016b |
data/RML2016.10b.dat |
10-way, |
wtc |
data/TecRec/finetune.mat |
WiFi/LTE/ZigBee; per_cell=9200 |
manytx |
data/ManyTx.pkl |
150 TX, 2021_03_01, equalized=0; extra test days 2–4 |
Paths: RADIO_ROOT, EMLM_CACHE, WTC_MAT, MANYTX_PKL (defaults ./data, ./cache).
Baselines (AWN, MCCFN, IQGCA, AvgNet, STF-GCN): same split and sample RMS.
TASK=rml2016a bash run_baselines.shCNN/GNN ManyTx numbers use a 128-crop; LoRA ManyTx uses 256 + split.
6:2:2, seeds
| Task | SpectrumFM v2 LoRA | Best baseline |
|---|---|---|
| RML2016.10a | STFGCN 62.62 | |
| RML2016.10b | STFGCN 65.25 | |
| WTC | STFGCN 70.55 | |
| ManyTx day 1 | AWN 87.31 | |
| ManyTx day 2/3/4 |
|
MCCFN 34.9 / 32.5 / 29.0 |