{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Fun-ASR-Nano with native Transformers\n", "\n", "Chinese, English and Japanese transcription, without the FunASR toolkit or remote Python code. This notebook uses CPU float32, pinned Transformers 5.17.0 and the official native checkpoint. The first run downloads about 1.66 GB of weights. Colab runtimes change: verify dependency output before loading a model.\n", "\n", "[Model card](https://huggingface.co/FunAudioLLM/Fun-ASR-Nano-2512-hf) | [Guide](https://www.funasr.com/en/docs/native-transformers.html) | [Fun-ASR](https://github.com/QwenAudio/Fun-ASR)\n" ], "id": "native-01" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%pip install --index-url https://download.pytorch.org/whl/cpu 'torch==2.10.0+cpu' 'torchaudio==2.10.0+cpu'\n", "%pip install 'transformers==5.17.0' 'librosa==0.11.0' 'soundfile==0.13.1'\n", "%pip check\n" ], "id": "native-02" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Transcribe the official English sample\n", "Restart the notebook session after installation if it had already imported Torch or Transformers. Then run the following cell. This uses the original model repository only for its public audio sample; inference weights come from the separate native `-hf` checkpoint.\n" ], "id": "native-03" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import torch\n", "from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor\n", "\n", "torch.set_num_threads(4)\n", "model_id = \"FunAudioLLM/Fun-ASR-Nano-2512-hf\"\n", "revision = \"d93b302ee7fd505e1b3576120fc142fc6f7820e1\"\n", "audio = \"https://huggingface.co/FunAudioLLM/Fun-ASR-Nano-2512/resolve/272c57b82523ada6fd87095e955f8e29100979ab/example/en.mp3\"\n", "\n", "processor = AutoProcessor.from_pretrained(\n", " model_id, revision=revision, trust_remote_code=False, token=False\n", ")\n", "model = AutoModelForSpeechSeq2Seq.from_pretrained(\n", " model_id, revision=revision, trust_remote_code=False, token=False,\n", " dtype=torch.float32,\n", ").to(\"cpu\").eval()\n", "inputs = processor.apply_transcription_request(\n", " audio=audio, language=\"en\",\n", " processor_kwargs={\n", " \"return_tensors\": \"pt\",\n", " \"audio_kwargs\": {\"sampling_rate\": 16000},\n", " \"text_kwargs\": {\"padding\": True},\n", " },\n", ")\n", "with torch.inference_mode():\n", " generated = model.generate(**inputs, max_new_tokens=128, do_sample=False)\n", "new_tokens = generated[:, inputs.input_ids.shape[1]:]\n", "print(processor.batch_decode(new_tokens, skip_special_tokens=True)[0])\n" ], "id": "native-04" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Transcribe an uploaded recording\n", "Upload a short recording you are authorized to process to the notebook's Files panel. Set its path below. Audio is averaged to mono and explicitly resampled to 16 kHz; it is not renamed or trimmed. This short-file example rejects audio longer than 60 seconds. Use `zh`, `en` or `ja` to match the recording.\n" ], "id": "native-05" }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import librosa\nimport numpy as np\nimport soundfile as sf\n\npath = \"/content/audio.wav\"\ninfo = sf.info(path)\nif not 0 < info.duration <= 60:\n raise ValueError(\"Use a non-empty recording of at most 60 seconds\")\nwaveform, sample_rate = sf.read(path, dtype=\"float32\")\nif not np.isfinite(waveform).all():\n raise ValueError(\"Non-finite audio samples\")\nif waveform.ndim == 2:\n waveform = waveform.mean(axis=1)\nif sample_rate != 16000:\n waveform = librosa.resample(waveform, orig_sr=sample_rate, target_sr=16000)\ninputs = processor.apply_transcription_request(\n audio=waveform, language=\"zh\",\n processor_kwargs={\"return_tensors\": \"pt\", \"audio_kwargs\": {\"sampling_rate\": 16000}},\n)\nwith torch.inference_mode():\n generated = model.generate(**inputs, max_new_tokens=256, do_sample=False)\nnew_tokens = generated[:, inputs.input_ids.shape[1]:]\nprint(processor.batch_decode(new_tokens, skip_special_tokens=True)[0])\neos = model.generation_config.eos_token_id\neos_ids = eos if isinstance(eos, list) else [eos]\nif not any(token in eos_ids for token in new_tokens[0].tolist()):\n print(\"Warning: no EOS; generation may be truncated. Do not treat this as complete.\")\n" ], "id": "native-06" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Next steps\n", "For batches, keywords and a command-line script with input validation, see [the runnable example](https://github.com/QwenAudio/Fun-ASR/tree/main/examples/transformers). The native export returns text, not word timestamps, speaker identities, or a realtime protocol. The 31-language MLT checkpoint is separate. CPU success is not a GPU or throughput benchmark; model output still needs human evaluation.\n", "\n", "Choose [FunASR services, vLLM or llama.cpp](https://www.funasr.com/en/deploy/) when you need deployment rather than a notebook. Preserve the checkpoint/runtime versions and raw results when evaluating your application.\n" ], "id": "native-07" } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }