Skip to content

About

[IEEE TCE] Meta-transfer learning-based cross-domain gesture recognition using WiFi channel state information

Resources

Stars

0 stars

Watchers

0 watching

Forks

 
 

Latest commit

 

History

4 Commits

Folders and files

Repository files navigation

MetaTrans_GestureRec

Code for Meta-Transfer Learning-Based Cross-Domain Gesture Recognition Using WiFi Channel State Information, Penglin Dai, Junfei Zhou, Jialong Ma, Hao Zhang, Xiao Wu. IEEE Transactions on Consumer Electronics, 71(2): 2530-2543, 2025.

WiFi CSI changes with location, orientation, user and environment, so a gesture classifier trained in one domain degrades in another. This code trains in two stages:

  1. Transfer learning (unsupervised domain adaptation). A ResNet feature extractor is trained adversarially against a domain discriminator, so that its features describe the gesture rather than the domain.
  2. Meta-learning (MAML). With the feature extractor frozen, the gesture classifier is meta-trained so that a few labelled samples from a new domain are enough to adapt it (6-way 1-shot / 5-shot).

Evaluation uses Widar3.0 (in-domain, cross-location, cross-orientation, cross-user, cross-environment, multi-domain) and a self-collected real-world set.

Method and code map

raw CSI ─► CSI ratio + Savitzky-Golay ─► heatmap .jpg                 (Sec. 3.1-3.2, done offline)

Stage 1   train_uda.py                                                 (Sec. 3.3-3.4, Algorithm 1)
  source (labelled)    ─┐                     ┌─► G_y gesture classifier ───────► L_y  (Eq. 13)
                        ├─► G_f ResNet-18+SE ─┤
  target (unlabelled)  ─┘                     └─► GRL R ─► G_d domain discr. ─► L_d  (Eq. 14)
                                                  L = L_y + L_d                       (Eq. 15)

Stage 2   train_meta.py, G_f frozen                                    (Sec. 3.5, Algorithm 2)
  meta-train on source tasks: inner loop on the support set (Eq. 16), outer loop on the query set (Eq. 17)
  meta-test on target tasks: adapt on the k-shot support set, classify the query set
Paper Code
Feature extractor G_f (Fig. 6, Eq. 7) metatrans/models/uda.py · FeatureExtractor
Gesture classifier G_y (Fig. 8, Eq. 9) metatrans/models/uda.py · GestureClassifier
Domain discriminator G_d (Fig. 9, Eq. 10) metatrans/models/uda.py · DomainDiscriminator
Gradient reversal layer (Eq. 11-12) metatrans/models/uda.py · GradientReversalFn
Stage-1 training (Eq. 13-15, Algorithm 1) train_uda.py
MAML classifier, inner loop (Eq. 16) metatrans/models/maml.py · MAML.adapt
Task sampling, outer loop (Eq. 17, Algorithm 2) metatrans/data/episodic.py, train_meta.py

Repository layout

train_uda.py              Stage 1: feature extractor with UDA (or without, `uda: false`)
train_meta.py             Stage 2: MAML gesture classifier + few-shot evaluation
metatrans/
  data/csi_dataset.py     heatmap dataset for Stage 1
  data/episodic.py        N-way K-shot episode sampling for Stage 2
  models/uda.py           G_f, G_y, G_d, gradient reversal
  models/maml.py          fast-weight layers, meta classifier, MAML inner loop
  utils.py                config loading, log folders, confusion-matrix I/O
configs/
  uda/                    Stage 1 with UDA, one file per experiment
  no_uda/                 Stage 1 ablation without UDA
  meta/                   Stage 2
  aril/                   ARIL dataset (cross-location), not in the paper
scripts/                  launchers grouped by experiment
tools/                    preprocessing, plots, model complexity / FPS
docs/                     result tables used for figures

Setup

pip install -r requirements.txt

Run every command from the repository root: the data and log paths in the configs are relative to it.

Data

The loaders read CSI heatmaps that are already rendered (CSI ratio between two antennas, Savitzky-Golay smoothing, colour-mapped to an image, paper Sec. 3.2). This rendering step for Widar3.0 is not part of this repository.

data/
  env/        Widar3.0 heatmaps:  {user}-{gesture}-{location}-{orientation}-{repetition}.jpg
  our_env/    self-collected set:  me-{gesture}-1-1-{repetition}.jpg, repetitions 1..230
  aril/amp/   ARIL heatmaps written by tools/preprocess_aril.py
  • Gestures 1-6: Push&Pull, Sweep, Clap, Slide, Draw-O (Horizontal), Draw-Zigzag (Horizontal).
  • Widar3.0 domains: locations 1-5, orientations 1-5, repetitions 1-5.
  • User groups used in the configs: env1_users = user5, 10-15, 17; env2_users = user1, 2, 3, 6; env3_users = user33, 7, 8, 9.

Training

Stage 1: feature extractor

python train_uda.py --hypes_yaml configs/uda/cross_env1_adam.yaml

A config lists three domain splits, each given as data_list + users / ges / pos / ori / rep: source_domain_data (labelled), target_domain_data (used without labels by the domain discriminator) and test_data. Outputs go to logs/<name>_<timestamp>/:

File Content
epoch_<e>_featureExtractor.pth, epoch_<e>_model.pth saved whenever test accuracy improves
loss1.txt, loss2.txt L_y and L_d per iteration (loss2.txt only with UDA)
acc.txt test accuracy per epoch
best_confusion_matrix.txt row-normalised confusion matrix of the best epoch

Stage 2: meta-learning

Point feature_extractor_pth in the config at a Stage-1 checkpoint, or pass it on the command line:

python train_meta.py --hypes_yaml configs/meta/cross_env1.yaml \
    --feature_extractor_pth logs/<stage1_run>/epoch_<e>_featureExtractor.pth

meta_learning sets shot (1 or 5), the inner loop (inner_steps, inner_lr), the outer loop (meta_lr, tasks_per_update) and the number of training / testing episodes. Each class in an episode draws n_fea domain cells (user × location × orientation) × 5 samples; the first shot samples form the support set and the rest the query set. Outputs: acc_training.txt and acc_testing.txt (running accuracy per episode), best_confusion_matrix_testing.txt, meta_classifier.pth.

Ablations:

python train_meta.py --hypes_yaml configs/meta/cross_env1.yaml --reinit_before_test                      # w/o meta-training
python train_meta.py --hypes_yaml configs/meta/cross_env1.yaml --test_noise_mean 0.4 --test_noise_std 0.1 # noisy target inputs
python train_uda.py  --hypes_yaml configs/no_uda/cross_env1.yaml                                          # w/o UDA

Experiments

Paper section Config Setting
4.2.5 Cross-environment configs/uda/cross_env1_adam.yaml, cross_env2.yaml, cross_env3.yaml target = env1 / env2 / env3, source = the other two
configs/uda/cross_env1.yaml target env1, source = all 16 users (env1 users included)
4.2.7 Multiple domains configs/uda/multicross_lo.yaml, multicross_lop.yaml, multicross_lope.yaml train on locations/orientations {1,2,4,5}, test on location 3 + orientation 3; LOP adds unseen env1 users, LOPE unseen users from all three environments
4.2.11 Real-world test configs/uda/cross_our_env.yaml source = env1 users, target = data/our_env
Stage 2 configs/meta/cross_env1.yaml 6-way 5-shot, target env1
Ablation w/o UDA configs/no_uda/cross_env1.yaml, cross_our_env.yaml
ARIL (extra) configs/aril/cross_loc_uda.yaml, cross_loc_meta.yaml cross-location

The in-domain, cross-location, cross-orientation and cross-user settings (Sec. 4.2.1-4.2.4) use the same configs with different pos / ori / users lists, e.g. cross-location trains on pos: [1, 2, 3, 4] and adapts to / tests on pos: [5].

scripts/ holds launchers for these groups (cross_environment.sh, multi_domain.sh, real_world.sh, ablation.sh); set CUDA_VISIBLE_DEVICES to pick a GPU.

Tools

Run as modules from the repository root, e.g. python -m tools.plot_curves uda logs/<run>.

Script Purpose
tools/preprocess_aril.py render the ARIL .mat files into heatmaps named like Widar3.0
tools/plot_csi.py plot the raw CSI time series of .mat files
tools/csi_kurtosis.py mean kurtosis of the CSI series per gesture
tools/plot_curves.py Stage-1 loss/accuracy curves; Stage-2 accuracy with vs. without meta-training
tools/plot_confusion_matrix.py camera-ready confusion matrix from a *confusion_matrix*.txt
tools/complexity.py parameter count and GFLOPs
tools/benchmark_fps.py inference throughput
tools/clean_logs.py delete log folders without checkpoints (--dry_run to preview)

docs/realworld_confusion_matrix.txt is the confusion matrix of the real-world test (Fig. 14b).

Implementation notes

Details of the code that the paper does not spell out:

  • G_f is the ImageNet-pretrained ResNet-18 trunk followed by a squeeze-and-excitation block on the 512-channel output.
  • Stage-1 G_y is Linear(512, 128) - BatchNorm - ReLU - Linear(128, 6), trained with cross-entropy on logits. G_d is a 512-512-512-1 MLP trained with binary cross-entropy on a single source/target logit.
  • The GRL coefficient ramps from 0 to 1 as 2 / (1 + exp(-10 p)) - 1 over training (Ganin et al., JMLR 2016). Each config chooses SGD or Adam.
  • MAML is first-order: the inner-loop gradients are detached. The meta classifier's BatchNorm always normalises with the current batch statistics.
  • The learning-rate scheduler is stepped with scheduler.step(epoch) as in the original runs, so each decay takes effect one epoch after its milestone.
  • Checkpoints from the first release contain unused lstm.* / w parameters; load_feature_extractor drops them, so those checkpoints still load.

Citation

@article{dai2025meta,
  title={Meta-transfer learning-based cross-domain gesture recognition using WiFi channel state information},
  author={Dai, Penglin and Zhou, Junfei and Ma, Jialong and Zhang, Hao and Wu, Xiao},
  journal={IEEE Transactions on Consumer Electronics},
  volume={71},
  number={2},
  pages={2530--2543},
  year={2025},
  publisher={IEEE}
}

About

[IEEE TCE] Meta-transfer learning-based cross-domain gesture recognition using WiFi channel state information

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages