Automatic Speech Recognition
Transformers
Safetensors
English
fela-asr-ctc
feature-extraction
fela
fourier-neural-operator
fno
cpu
on-device
streaming
ctc
constant-memory
custom_code
Instructions to use lowdown-labs/fela-streaming-asr with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use lowdown-labs/fela-streaming-asr with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("automatic-speech-recognition", model="lowdown-labs/fela-streaming-asr", trust_remote_code=True)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("lowdown-labs/fela-streaming-asr", trust_remote_code=True, dtype="auto") - Notebooks
- Google Colab
- Kaggle
| from __future__ import annotations | |
| import json | |
| import os | |
| from typing import Optional | |
| import torch | |
| TARGET_SR = 16000 | |
| def validate_audio(wav: torch.Tensor, sr: int): | |
| if sr != TARGET_SR: | |
| raise ValueError( | |
| f"sample rate must be {TARGET_SR} Hz after resampling; got {sr}" | |
| ) | |
| if wav.dim() != 2 or wav.size(0) != 1: | |
| raise ValueError( | |
| f"waveform must be mono with shape (1, num_samples); got {tuple(wav.shape)}" | |
| ) | |
| if wav.numel() == 0: | |
| raise ValueError("empty waveform") | |
| if wav.abs().max() > 1.5: | |
| raise ValueError( | |
| "waveform looks unnormalized (values outside [-1, 1]); " | |
| "scale int16 by 1/32768 before passing it in" | |
| ) | |
| def preprocess_audio(source, sr: Optional[int] = None) -> torch.Tensor: | |
| import torchaudio | |
| if isinstance(source, str): | |
| wav, in_sr = torchaudio.load(source) | |
| else: | |
| wav = torch.as_tensor(source, dtype=torch.float32) | |
| if wav.dim() == 1: | |
| wav = wav.unsqueeze(0) | |
| in_sr = sr if sr is not None else TARGET_SR | |
| if wav.abs().max() > 1.5: | |
| wav = wav / 32768.0 | |
| if wav.size(0) > 1: | |
| wav = wav.mean(0, keepdim=True) | |
| if in_sr != TARGET_SR: | |
| wav = torchaudio.functional.resample(wav, in_sr, TARGET_SR) | |
| validate_audio(wav, TARGET_SR) | |
| return wav | |
| def _read_config(config_path: Optional[str]) -> dict: | |
| if config_path and os.path.exists(config_path): | |
| with open(config_path) as f: | |
| return json.load(f) | |
| return {} | |
| def load_model( | |
| weights: str, bpe: str = "bpe256.model", config_path: Optional[str] = None | |
| ): | |
| here = os.path.dirname(os.path.abspath(__file__)) | |
| if config_path is None: | |
| cand = os.path.join(here, "config.json") | |
| config_path = cand if os.path.exists(cand) else None | |
| cfg_json = _read_config(config_path) | |
| from fela_ctc2 import FELACTC2, BPE, greedy_decode_bpe | |
| from model_cpu_gpt2 import CPUGPTConfig | |
| bpe_obj = BPE(model_file=bpe) | |
| cfg = CPUGPTConfig( | |
| vocab_size=cfg_json.get("vocab", 257), | |
| seq_len=cfg_json.get("seq_len", 2048), | |
| n_layer=cfg_json.get("n_layer", 16), | |
| n_embd=cfg_json.get("n_embd", 512), | |
| n_head=cfg_json.get("n_head", 8), | |
| fno_modes=cfg_json.get("fno_modes", 256), | |
| gla_chunk=cfg_json.get("gla_chunk", 64), | |
| ffn_hidden=cfg_json.get("ffn_hidden", 2048), | |
| layer_pattern=cfg_json.get("layer_pattern", "FNO"), | |
| dropout=0.0, | |
| ) | |
| if hasattr(cfg, "gla_delta"): | |
| cfg.gla_delta = bool(cfg_json.get("gla_delta", False)) | |
| model = FELACTC2(cfg, vocab=bpe_obj.vocab).eval() | |
| if weights.endswith(".safetensors"): | |
| from safetensors.torch import load_file | |
| state = load_file(weights) | |
| else: | |
| ck = torch.load(weights, map_location="cpu", weights_only=False) | |
| state = ck.get("state", ck.get("model", ck)) if isinstance(ck, dict) else ck | |
| model.load_state_dict(state, strict=False) | |
| return model, bpe_obj, greedy_decode_bpe | |
| def from_pretrained(repo_id: str = "lowdown-labs/asr-streaming"): | |
| from huggingface_hub import hf_hub_download | |
| cfg_path = hf_hub_download(repo_id, "config.json") | |
| bpe = hf_hub_download(repo_id, "bpe256.model") | |
| try: | |
| w = hf_hub_download(repo_id, "model.safetensors") | |
| except Exception: | |
| w = hf_hub_download(repo_id, "model.pt") | |
| return load_model(w, bpe=bpe, config_path=cfg_path) | |
| def stream_transcribe( | |
| model, | |
| bpe, | |
| decode_fn, | |
| wav: torch.Tensor, | |
| frame_chunk: int = 100, | |
| reset_frames: int = 1200, | |
| ) -> str: | |
| out = [] | |
| for logp in model.stream_logits( | |
| wav, frame_chunk=frame_chunk, reset_frames=reset_frames | |
| ): | |
| t = decode_fn(logp[0], bpe) | |
| if t: | |
| out.append(t) | |
| return " ".join(out) | |