Indian AMD: YAMNet-GRU (person vs machine on Indian phone calls)
This is a small, fast answering-machine / voicemail detector for Indian outbound calls (Hindi and Indian English). It listens to the first seconds of a call and tells a live person from a machine: carrier announcements ("the number you are calling is switched off"), voicemail greetings, IVR menus, call-progress tones, and robocalls.
- 3.5M parameters, 14 MB, and about 7β70 ms per check on one CPU thread.
- It needs no transcript and no speech-to-text; it works on the audio directly.
- It was built because no public AMD model handles Hindi. Every public model we tested flagged 44β90% of Hindi speakers as machines; this one flags 0.7β9.3% (details below).
Current version: v2 (2026-10-13). v1 is still available at revision tag v1.
Results (v2)
Test sets: all held out from training (no shared speakers, scripts or files). Every clip went through a real 8 kHz G.711 Β΅-law round trip, so it sounds like a phone line.
Decision rule: the machine-only rule described below. "Caught" means the share of machines it detected; "wrongly flagged" means the share of real people it called a machine.
| Group (clips) | v2 | v1 | Median audio heard (v2) |
|---|---|---|---|
| Real US robocalls (150) | 98.7% caught | 99.3% | 1.1 s |
| Indian English machine voices (45) | 100% caught | 100% | 1.3 s |
| Hindi machine voices (24) | 100% caught | 100% | 1.3 s |
| Hindi-then-English machine voices (7) | 100% caught | 100% | 1.3 s |
| Indian English people (150) | 1.3% wrongly flagged | 2.7% | β |
| Hindi people, microphone recordings (150) | 9.3% wrongly flagged | 13.3% | β |
| Hindi people on a phone line, 8 kHz (150) | 0.7% wrongly flagged | 22.7% | β |
Share called "machine" by seconds of audio heard (v2, one-shot, threshold 0.5):
| Group | 1 s | 2 s | 3 s | 4 s | 6 s | 10 s |
|---|---|---|---|---|---|---|
| Robocall | 76.7% | 84.0% | 90.0% | 93.3% | 98.0% | 97.3% |
| Indian machine voices | 96.1% | 100% | 100% | 100% | 100% | 100% |
| Indian English people | 2.7% | 1.3% | 0.7% | 0.7% | 0.7% | 0.7% |
| Hindi people (microphone) | 12.7% | 10.0% | 7.3% | 8.0% | 9.3% | 8.7% |
v2 is more cautious than v1 in the first second: one-shot robocall recall at 1 s is 77%, against 93% for v1. With the streaming rule it still catches 98.7%; the slowest 10% of robocalls are flagged by about 4.5 s.
Compared with public models on the same test set and rule
| Model | Hindi people wrongly flagged | Indian English people wrongly flagged | CPU per check |
|---|---|---|---|
| AbijahKaj/whisper-telephony-amd (as published) | 61.3% | 5.3% | ~750 ms |
| ozonetg/amd-telephony-yamnet-gru (as published, CC BY-NC) | 44.0% | 4.0% | ~10β70 ms |
| EfficientAT mn04 / CED-tiny (AudioSet, zero-shot) | ~90% | 96β98% | 15β75 ms |
| This model, v1 | 13.3% | 2.7% | 11β70 ms |
| This model, v2 | 9.3% | 1.3% | 7β70 ms |
Speed (CPU, 1 thread, PyTorch fp32, Intel Core Ultra 7 155H)
| Audio heard | 1 s | 2 s | 4 s | 8 s |
|---|---|---|---|---|
| ms per check | 7β11 | 12β18 | 23β34 | 48β70 |
The ranges come from repeated runs under different machine load.
How to use
import numpy as np, soundfile as sf
from huggingface_hub import snapshot_download
import sys
folder = snapshot_download("Aakash22134/indian-amd-yamnet-gru") # add revision="v1" for v1
sys.path.insert(0, folder)
from amd_yamnet import AMDYamnet, MachineOnlyRule
model = AMDYamnet.from_pretrained(folder)
audio, sr = sf.read("call_start.wav", dtype="float32") # mono, 16 kHz (resample 8 kHz phone audio up)
print("p_machine:", model.p_machine(audio)) # one-shot, uses the last 8 s
t = MachineOnlyRule(model).run(audio) # the rule used for the results above
print("machine at %.2f s" % t if t is not None else "person")
Requirements: torch, torchaudio, numpy, safetensors (and soundfile for the example).
The decision rule (MachineOnlyRule)
- Start checking 0.8 s after speech starts, then every 0.5 s, up to 8 s.
- Say "machine" if p β₯ 0.9 once, or p β₯ 0.75 on two checks in a row. Otherwise stay "person".
- It is asymmetric on purpose. Hanging up on a real person is the costly mistake, so "person" is never decided early. A voice bot can start talking normally and stop only if "machine" fires.
- Run inference on a worker thread (for example
asyncio.to_thread), not on the audio event loop.
Training (v2)
Backbone: Google YAMNet (AudioSet), loaded from the MIT PyTorch port w-hc/torch_audioset. Head: linear 1024β128 + tanh, then a bidirectional GRU (hidden 96), then linear β 1 logit. The whole network was fine-tuned.
Frontend: YAMNet's: 16 kHz, 25 ms / 10 ms STFT, 64 mel bands (125β7500 Hz), log(mel + 0.001), 0.96 s patches with a 0.48 s hop, last 8 s of audio.
Data: about 12,450 clips, ~24 h. Batch sampling: 60% people and 40% machines.
Group Class Clips Source Telephony people person 1,500 AbijahKaj/telephony-amd-dataset (train split) Real callers on phone lines (v2) person 1,500 PolyAI MINDS14, 14 languages Indian English people person 1,374 (458 speakers) Mozilla Common Voice, "India and South Asia" accent Hindi people person 1,600 Google FLEURS hi_in(train split)Hindi people (v2) person 1,150 (403 speakers) Mozilla Common Voice 17 Hindi Hindi people, 8 kHz (v2) person 1,500 (13 speakers) MUCS 2021 Hindi (OpenSLR 103) Telephony machines machine 2,000 AbijahKaj/telephony-amd-dataset (train split) Robocalls machine 1,223 wspr-ncsu/robocall-audio-dataset Indian English and Hindi machine voices machine 360 ~80 scripts written for this model (carrier announcements, bank and telecom IVR, voicemail, Hinglish), spoken by Microsoft edge-tts en-IN / hi-IN voices Call-progress tones (v2) machine 240 generated Indian ringback, busy, congestion and SIT tones Augmentation: each sample is the first 1β8 s of a clip, after 0β0.8 s of leading silence, with random loudness, light noise (SNR 25β45 dB), and a real G.711 Β΅-law 8 kHz round trip.
Optimisation: 8 epochs Γ 250 steps Γ batch 32, AdamW (backbone lr 1e-4, head 1e-3), cosine decay, bf16 on one RTX 2000 Ada (~9 min). Best epoch chosen on a held-out validation split.
Test sets
| Group | Clips | Source |
|---|---|---|
| Real US robocalls | 150 | robocall-audio-dataset, files not used in training |
| Indian machine voices | 76 | 34 scripts different from training, edge-tts en-IN / hi-IN voices |
| Indian English people | 150 | Common Voice, speakers not in training |
| Hindi people, microphone | 150 | FLEURS hi_in validation split (separate speakers from train) |
| Hindi people, 8 kHz phone | 150 | MUCS 2021 Hindi, 6 speakers not in training (same corpus and sentences as the training speakers) |
All test clips were loudness-normalised and sent through G.711 Β΅-law at 8 kHz.
License and attribution
Model weights and code: Apache-2.0.
YAMNet (Google, tensorflow/models, Apache-2.0). PyTorch port and the vendored network code in
amd_yamnet.pyare from w-hc/torch_audioset: MIT, Β© 2021 Haochen (seeLICENSE-torch_audioset-MIT).Training data:
- Google FLEURS (CC BY 4.0, attribution: Conneau et al., 2022)
- PolyAI MINDS14 (CC BY 4.0, attribution: Gerz et al., 2021)
- Mozilla Common Voice and Common Voice 17 Hindi (CC0)
- wspr-ncsu robocall-audio-dataset (public domain)
- MUCS 2021 Hindi, OpenSLR 103 (Microsoft Research data license)
- AbijahKaj/telephony-amd-dataset (no license stated on its card)
- audio generated with Microsoft edge-tts (subject to Microsoft's service terms)
If you plan commercial use, review the last three items yourself.
No CC BY-NC model weights were used to train this model.
- Downloads last month
- 68