Обучаем Whisper Small для распознавания казахской речи
1. Введение
Системы распознавания речи (Speech-to-Text) сегодня широко используются в голосовых помощниках, чат-ботах, сервисах автоматического перевода и других решениях, упрощающих взаимодействие человека с компьютерными системами. Поддержка локальных языков, таких как казахский, является особенно важной, поскольку готовых решений для этих языков часто не хватает.
В этой статье мы рассмотрим, как обучить (fine-tuning) модель Whisper Small от OpenAI на датасете Mozilla Common Voice для распознавания казахской речи. Мы также разберём, чем полезна такая модель и какие у неё могут быть сценарии применения.
2. О модели Whisper Small
Whisper — это семейство моделей для распознавания речи, разработанных компанией OpenAI. Они отличаются высокой точностью и способностью работать с разными языками. Однако у каждой модели есть свои ограничения. Whisper Small — более компактная версия, которая по умолчанию оптимизирована для английского языка.
Преимущества Whisper Small:
- Относительно небольшой размер (что упрощает процесс обучения и развёртывания).
- Достаточная точность для множества задач (особенно после дополнительного обучения).
- Возможность адаптации под новые языки и домены.
3. Применение и польза
Расширение поддержки казахского языка в сфере распознавания речи даёт целый ряд преимуществ:
- Инклюзивность: Удобство для носителей языка, в том числе людей с ограниченными возможностями.
- Автоматизация: Быстрая транскрибация встреч, лекций и телефонных разговоров на казахском языке.
- Образование: Создание интерактивных приложений для изучения языка или проведения тестирований.
- Медиаконтент: Автоматическая генерация субтитров на казахском языке.
- Развитие экосистемы: Стимулирование разработки локальных продуктов и решений.
4. Результаты обучения
Для обучения использовались:
- Google Colab с GPU T4 (около 5 часов обучения).
- Датасет Mozilla Common Voice (казахская часть).
В ходе эксперимента модель обучалась в течение 4000 шагов, и каждые 1000 шагов производилась промежуточная оценка. Ниже приведена сводка по ключевым метрикам — Training Loss, Validation Loss и WER (Word Error Rate, процент ошибок при распознавании речи):
Training Loss | Epoch | Step | Validation Loss | WER |
0.0059 | 6.0976 | 1000 | 0.0138 | 2.0531 |
0.0003 | 12.1951 | 2000 | 0.0006 | 1.8636 |
0.0001 | 18.2927 | 3000 | 0.0002 | 0.0 |
0.0001 | 24.3902 | 4000 | 0.0002 | 0.0 |
Как видно из таблицы, в конце обучения показатель WER на валидационной выборке достиг 0%. Это означает, что модель на тестовых сэмплах (из используемого набора) справляется без ошибок. Однако на реальных данных результат может отличаться, поэтому крайне важно дополнительно проверять качество на более разнообразных примерах.
5. Пошаговый разбор кода
Ниже приведён код, используемый для обучения модели Whisper Small на казахской выборке из Mozilla Common Voice. Код можно запускать в Google Colab или другой среде, поддерживающей Python.
# Обновляем pip до последней версии
!pip install --upgrade --quiet pip
# Устанавливаем библиотеки для работы со звуком, обучением, оценкой и веб-интерфейсом
!pip install --upgrade --quiet datasets[audio] transformers accelerate evaluate jiwer tensorboard
!pip install gradio==3.41.0
- datasets[audio] — позволяет загружать и обрабатывать аудиоданные из стандартных датасетов (например, Mozilla Common Voice).
- transformers — библиотека от Hugging Face для работы с моделями трансформеров (включая Whisper).
- accelerate — ускоряет обучение на нескольких GPU/TPU.
- evaluate, jiwer — инструменты для вычисления метрик, в том числе WER.
- tensorboard — для визуализации метрик обучения.
- gradio — для создания простого веб-приложения (демонстрации).
from huggingface_hub import notebook_login
notebook_login()
Чтобы иметь возможность загружать модель в свой репозиторий на Hugging Face, нужно авторизоваться через токен.
from datasets import load_dataset, DatasetDict
# Создаём объект DatasetDict
common_voice = DatasetDict()
# Загружаем обучающую (train+validation+validated) и тестовую выборки
common_voice["train"] = load_dataset("mozilla-foundation/common_voice_17_0", "kk", split="train+validation+validated")
common_voice["test"] = load_dataset("mozilla-foundation/common_voice_17_0", "kk", split="test")
# Удаляем ненужные колонки
common_voice = common_voice.remove_columns(["accent", "age", "client_id", "down_votes", "gender", "locale", "path", "segment", "up_votes"])
- load_dataset — загружает готовый датасет Mozilla Common Voice версии 17.0 для казахского языка (параметр "kk").
- Мы объединяем три подвыборки (train + validation + validated) в один тренировочный датасет.
- Удаляем неиспользуемые поля, чтобы сократить объём данных и упростить препроцессинг.
from transformers import WhisperFeatureExtractor, WhisperTokenizer, WhisperProcessor
feature_extractor = WhisperFeatureExtractor.from_pretrained("openai/whisper-small")
tokenizer = WhisperTokenizer.from_pretrained("openai/whisper-small", language="Kazakh", task="transcribe")
processor = WhisperProcessor.from_pretrained("openai/whisper-small", language="Kazakh", task="transcribe")
- WhisperFeatureExtractor — преобразует аудиосигнал в спектрограмму (лог-мел-спектр).
- WhisperTokenizer — превращает текстовые данные в токены.
- WhisperProcessor — обёртка, комбинирующая в себе и FeatureExtractor, и Tokenizer.
from datasets import Audio
# Приводим аудио к частоте 16кГц, которая ожидается моделью
common_voice = common_voice.cast_column("audio", Audio(sampling_rate=16000))
def prepare_dataset(batch):
audio = batch["audio"]
# Преобразуем звуковой сигнал в признаки лог-мел
batch["input_features"] = feature_extractor(
audio["array"],
sampling_rate=audio["sampling_rate"]
).input_features[0]
# Токенизируем текст
batch["labels"] = tokenizer(batch["sentence"]).input_ids
return batch
# Применяем функцию ко всему датасету
common_voice = common_voice.map(prepare_dataset, remove_columns=common_voice.column_names["train"], num_proc=2)
- cast_column — переводит аудио в формат, совместимый с библиотекой Audio.
- prepare_dataset — основной препроцессинг: вычисляем спектрограмму и токенизируем текст.
- map — применяем функцию ко всем элементам датасета. Параметр num_proc=2 включает параллелизм.
from transformers import WhisperForConditionalGeneration
model = WhisperForConditionalGeneration.from_pretrained("openai/whisper-small")
model.generation_config.language = "Kazakh"
model.generation_config.task = "transcribe"
model.generation_config.forced_decoder_ids = None
- WhisperForConditionalGeneration — модель для генерации текстовых выходов на основе аудио.
- Настраиваем язык и задачу в generation_config.
Создадим collator (специальный объект, который будет готовить батчи для тренировки):
import torch
from dataclasses import dataclass
from typing import Any, Dict, List, Union
@dataclass
class DataCollatorSpeechSeq2SeqWithPadding:
processor: Any
decoder_start_token_id: int
def __call__(self, features: List[Dict[str, Union[List[int], torch.Tensor]]]) -> Dict[str, torch.Tensor]:
# Извлекаем и паддируем аудиопризнаки
input_features = [{"input_features": f["input_features"]} for f in features]
batch = self.processor.feature_extractor.pad(input_features, return_tensors="pt")
# Извлекаем и паддируем метки (labels)
label_features = [{"input_ids": f["labels"]} for f in features]
labels_batch = self.processor.tokenizer.pad(label_features, return_tensors="pt")
# Заменяем паддинговые токены на -100
labels = labels_batch["input_ids"].masked_fill(labels_batch.attention_mask.ne(1), -100)
# Удаляем начальный токен (если он уже есть)
if (labels[:, 0] == self.decoder_start_token_id).all().cpu().item():
labels = labels[:, 1:]
batch["labels"] = labels
return batch
data_collator = DataCollatorSpeechSeq2SeqWithPadding(
processor=processor,
decoder_start_token_id=model.config.decoder_start_token_id,
)
import evaluate
metric = evaluate.load("wer")
def compute_metrics(pred):
pred_ids = pred.predictions
label_ids = pred.label_ids
# Заменяем -100 на pad_token_id
label_ids[label_ids == -100] = tokenizer.pad_token_id
# Раскодируем предсказания и настоящие метки в текст
pred_str = tokenizer.batch_decode(pred_ids, skip_special_tokens=True)
label_str = tokenizer.batch_decode(label_ids, skip_special_tokens=True)
# Считаем WER (Word Error Rate)
wer_value = 100 * metric.compute(predictions=pred_str, references=label_str)
return {"wer": wer_value}
from transformers import Seq2SeqTrainingArguments, Seq2SeqTrainer
training_args = Seq2SeqTrainingArguments(
output_dir="./whisper-small-kk",
per_device_train_batch_size=16,
gradient_accumulation_steps=1,
learning_rate=1e-5,
warmup_steps=500,
max_steps=4000,
gradient_checkpointing=True,
fp16=True,
evaluation_strategy="steps",
per_device_eval_batch_size=8,
predict_with_generate=True,
generation_max_length=225,
save_steps=1000,
eval_steps=1000,
logging_steps=25,
report_to=["tensorboard"],
load_best_model_at_end=True,
metric_for_best_model="wer",
greater_is_better=False,
push_to_hub=True,
)
trainer = Seq2SeqTrainer(
args=training_args,
model=model,
train_dataset=common_voice["train"],
eval_dataset=common_voice["test"],
data_collator=data_collator,
compute_metrics=compute_metrics,
tokenizer=processor.feature_extractor,
)
processor.save_pretrained(training_args.output_dir)
- max_steps=4000 — общее количество шагов обучения.
- evaluation_strategy="steps" — будем оценивать модель через определённый интервал шагов.
- save_steps=1000 и eval_steps=1000 — каждые 1000 шагов сохраним чекпойнт и оценим модель.
- logging_steps=25 — логируем метрики каждые 25 шагов.
- load_best_model_at_end=True — в конце загрузим лучший чекпойнт по метрике WER.
trainer.train()
На этом этапе начнётся процесс обучения. Важно контролировать метрики в TensorBoard или непосредственно в логах.
trainer.push_to_hub(
"armanibadboy/whisper-small-kazakh",
token="HF_TOKEN" # Ваш токен Hugging Face
)
Вы можете заменить "armanibadboy/whisper-small-kazakh" на любое другое название вашего репозитория на Hugging Face.
Чтобы проверить работу модели в реальном времени, можно создать простой веб-интерфейс на базе Gradio:
from transformers import pipeline
import gradio as gr
# Загружаем нашу обученную модель (замените на ваш путь/название репозитория)
pipe = pipeline(model="armanibadboy/whisper-small-kk")
def transcribe(audio):
text = pipe(audio)["text"]
return text
iface = gr.Interface(
fn=transcribe,
inputs=gr.Audio(source="microphone", type="filepath"),
outputs="text",
title="Whisper Small Kazakh",
description="Транскрибация аудио в текст для казахского языка (fine-tuning Whisper Small).",
)
iface.launch()
Теперь, запустив ячейку, вы получите веб-приложение с возможностью записи звука через микрофон. Модель автоматически распознает и выведет казахский текст.
Обучив модель Whisper Small на казахском датасете Mozilla Common Voice, мы получили систему, способную эффективно распознавать речь на казахском языке. Это открывает широкие перспективы для развития локальных приложений: от голосовых помощников и учебных платформ до сервисов автоматической транскрибации аудио/видеофайлов.
Подход с fine-tuning относительно небольшой модели (Whisper Small) оказался недорогим (около 10 кредитов в Google Colab Pro) и достаточно быстрым (5 часов на GPU T4). Итоговые результаты показывают хорошую точность распознавания (WER до 0% на тестовой выборке), однако в реальных условиях этот показатель может варьироваться.
Если вы хотите развивать этот проект дальше — добавляйте больше данных, улучшайте процесс препроцессинга, а также экспериментируйте с гиперпараметрами. Удачи в ваших исследованиях!
Пікірлер 4
Кіру пікір қалдыру үшін
Balzhan I · Қаң. 23, 2025 18:14
осындай модельдер жетпей жатыр қазақшаға
Арман Аубакиров · Қаң. 23, 2025 18:15
на этой неделе еще сделаю tts
Balzhan I · Қаң. 23, 2025 18:14
керемет!
САМАТ САГЫНДЫКОВ · Қаң. 23, 2025 17:38
Круто!