ASR bias для транскрипции: open-source код и примеры | AiManual
AiManual Logo Ai / Manual.
11 Июн 2026 Инструмент

Как добавить ASR bias для моделей транскрипции голоса: открытая реализация и пример кода

Практическое руководство по добавлению смещения (bias) в модели ASR для улучшения распознавания специфических слов. Код на Python для Whisper и других моделей.

Реклама
hor_partv1

Вот сидите вы и пишете голосового ассистента для врачей. Всё работает, пока пациент не ляпнет «Ацетилсалициловая кислота». И тут модель выдаёт что-то вроде «ацетил силиконовая кислота». Знакомо? Стандартные ASR-модели тренированы на общих данных — они тупят на редких терминах, именах и названиях компаний.

Можно дообучить модель. Но это дорого, нужно собирать размеченный корпус, гонять fine-tuning неделями. А если завтра сменился список препаратов или появился новый сленг — опять переобучать. Есть способ проще: ASR bias (смещение декодера). Смысл в том, чтобы подкрутить вероятности нужных слов прямо во время распознавания, без пересборки весов. О том, как это сделать своими руками на open-source стеке, и поговорим.

Если вы ещё не выбрали базовую модель — гляньте наше сравнение актуальных ASR-моделей для английского. Спойлер: Whisper по-прежнему хорош, но и Parakeet от NVIDIA дышит в спину.

Что такое bias в ASR и зачем он вам (спойлер: вы сэкономите недели)

Базовый принцип: на этапе декодирования мы вводим дополнительную информацию — список слов или фраз с весами. Чем выше вес, тем охотнее модель выбирает этот токен, даже если акустический сигнал неидеален. Это не магия, а обычное логарифмическое смещение логарифмов вероятностей.

Представьте, что у вас есть список названий лекарств, которые модель постоянно коверкает. Вы задаёте bias-файл вида:

[
  {"word": "ацетилсалициловая", "weight": 10},
  {"word": "метформина гидрохлорид", "weight": 8}
]

Декодер прибавляет логарифм веса к скорам соответствующих токенов. Если слово распадается на несколько токенов — веса суммируются по правилу среднегеометрического. Всё честно, без подтасовок.

Важный нюанс: bias не убирает все ошибки. Если акустика совсем плохая (шум, дикция с кашей во рту), bias может лишь слегка подтолкнуть. Но для чистых диктофонных записей или звонков — это спасение.

Открытая реализация: как это работает на практике

Мы взяли за основу Whisper large-v3 (последняя стабильная версия на июнь 2026) и встроили bias через модификацию лог-пробы декодера. Код полностью открытый, лежит на GitHub. Поддерживаются все модели семейства Whisper, а также любые модели на базе CTC (wav2vec 2.0, Branchformer) — нужно лишь адаптировать интерфейс логарифмов.

Основная идея: после получения финальных лог-пробы для каждого токена мы прибавляем bias-вектор, сгенерированный из вашего списка. Если слово из bias-листа состоит из нескольких токенов (BPE), мы маппим его на соответствующие позиции и добавляем вес к каждому входящему в слово токену.

Вот упрощённый сниппет той части, где происходит добавление bias:

def apply_bias(logits, bias_dict, tokenizer):
    # bias_dict: {token_id: log_bias_weight}
    for token_id, weight in bias_dict.items():
        logits[:, :, token_id] += weight
    return logits

Но на деле bias-слова нужно предварительно токенизировать и разобрать по токенам. Полный рабочий пример смотрите в коде ниже.

1Подготовка bias-словаря

Сначала собираем список слов, которые модель должна узнавать точнее. Для медицинского случая это:

bias_phrases = ["ацетилсалициловая кислота", "метформина гидрохлорид", "клопидогрел"]
weights = [10.0, 8.0, 9.0]

Токенизируем каждую фразу, получаем последовательности ID токенов. Если фраза разбивается на части, мы делим вес на количество токенов (лог-сложение), чтобы итоговый вес был равномерный. Собираем словарь token_id → weight.

💡
Обратите внимание: bias-вес добавляется ко всем токенам, которые встречаются в вашем списке. Если слово "клопидогрел" разбивается на ['кл', 'опи', 'дог', 'рел'], то каждый из этих токенов получит прибавку. Это может случайно усиливать появление "кл" в других словах ("клубника" → "клуб..."). Советую не ставить вес выше 15, чтобы не сломать общую лексику.

2Интеграция bias в пайплайн транскрипции

import whisper
import numpy as np

def transcribe_with_bias(audio_path, bias_dict):
    model = whisper.load_model("large-v3")
    audio = whisper.load_audio(audio_path)
    audio = whisper.pad_or_trim(audio)
    mel = whisper.log_mel_spectrogram(audio).to(model.device)

    # Декодируем с помощью модифицированного семплирования
    options = whisper.DecodingOptions(language="ru", without_timestamps=True, fp16=False)
    result = model.decode(mel, options, bias_dict=bias_dict)
    return result.text

Мы расширили DecodingOptions, добавив параметр bias_dict. Внутри decode() перед выбором следующего токена вызывается apply_bias(). Всё делается за один проход, без пересборки графа.

Честное предупреждение: в официальном репозитории Whisper нет такой опции. Мы форкнули и добавили сами. Код доступен на GitHub (ссылка будет в конце). Но вы можете легко повторить — правка в файле decoding.py занимает 15 строк.

Сравнение с альтернативами: почему bias, а не дообучение

МетодВремя настройкиГибкостьРиск деградации
Fine-tuningот 48 часовТребует датасетМожет забыть общую лексику
N-gram LM rescoring (Kaldi, Flashlight)2–4 часаНужна внешняя LMНе меняет акустику
Bias (наш метод)10 минутСписок слов — и готовоМинимальный при разумных весах

Fine-tuning — это тяжёлая артиллерия. Его стоит применять, если нужно сменить язык или домен полностью (например, адаптировать модель для русской речи с архитектурой SALM). Но когда задача — просто добавить десяток терминов, bias выигрывает по скорости в 300 раз.

N-gram rescoring, как в подходах с глубиной LM, тоже работает. Но он добавляет второй проход, усложняет конвейер. Bias же встраивается прямо в декодер, не требуется никаких внешних библиотек.

Из коммерческих решений: Cohere Transcribe и AssemblyAI поддерживают Hotwords через API. Но это закрытый код, вы платите за каждый час и привязаны к облаку. Наш подход — локальный, бесплатный, подходит для конфиденциальных данных (про сборку локального ASR мы писали вот здесь).

Пример из жизни: как bias спас транскрипцию IT-конференции

Недавно мы настраивали распознавание для записи русскоязычного митапа по MLOps. Спикеры то и дело сыпали терминами: «DVC» (Data Version Control), «CML» (Continuous Machine Learning), «Airflow». Стандартный Whisper large-v3 превращал «DVC» в «ди-ви-си» или «диВиСи». Добавили bias с весом 12 для каждого из этих сокращений — и результат стал близок к идеалу. Единичные пропуски остались только при явном шуме.

Ранее мы описывали фиксы для гибридного русского и английского — bias хорошо ложится поверх тех решений. Комбинация кастомного постпроцессинга и смещения даёт синергию.

Кому это реально упростит жизнь

  • Разработчикам медицинских систем — чтобы диктовать лекарства без искажений.
  • Создателям голосовых ассистентов для юристов — там каждое слово в договоре на вес золота.
  • Интеграторам call-центров — чтобы «передайте трубочку» не превращалось в «передайте трубку».
  • Любому, кто мучается с распознаванием на узком домене (геймдев, финансы, мода).

Инструмент лёгкий, встраивается за вечер. Единственное, о чём стоит помнить: не используйте слишком высокие веса (больше 20), иначе модель начнёт галлюцинировать bias-слова там, где их нет. А так — берите и делайте.

PS: Полный код пакета с примерами и тестами выложен в репозиторий. Инструкция по установке и API описаны в README. Если уткнётесь в баги — пишите issue, контрибьюторы welcome.

Подписаться на канал