業界・業務から探す
導入目的・課題から探す
データ・AIについて学ぶ
News
Hakkyについて
ウェビナーコラム
◆トップ【AI・機械学習】
プロセスの全体像前処理・特徴量生成Fine Tuning手法まとめ機械学習モデルの選び方モデル評価手法プロトタイピング探索的分析(EDA)
AI

執筆者:Handbook編集部

CommonVoiceデータセットでWhisperをFine Tuning 

概要

本記事ではWhisperを複数言語ASRデータセットでHindi語向けにFine Tuningする方法について紹介します。 また、この記事はHugging Faceの公式ブログを参照にしています。

環境設定

本コードではffmpegのversion4が必要になるためバージョンをアップデートします。

!add-apt-repository -y ppa:jonathonf/ffmpeg-4
!apt update
!apt install -y ffmpeg

以下で必要なPythonパッケージをインストールします。

!pip install datasets>=2.6.1
!pip install git+https://github.com/huggingface/transformers
!pip install librosa
!pip install evaluate>=0.30
!pip install jiwer
!pip install gradio

Hugging Face Hubへのログインを行います。

from huggingface_hub import notebook_login

notebook_login()

前処理など

データセットの準備

最初にデータセットのロードを行います。今回はHugging Face Hubで公開されているmozilla-foundation/common_voice_11_0を利用します. 利用にあたり、利用規約に事前に同意する必要があります。

Hindi語はデータセット内に含まれているリソースが少ないため、trainvalidationを結合して学習用データとし、testを評価用データとして使います。また、不要なMetadataも削除してしまいます。

from datasets import load_dataset, DatasetDict

common_voice = DatasetDict()

common_voice["train"] = load_dataset("mozilla-foundation/common_voice_11_0", "hi", split="train+validation", use_auth_token=True)
common_voice["test"] = load_dataset("mozilla-foundation/common_voice_11_0", "hi", split="test", use_auth_token=True)

# Removing meta data.
common_voice = common_voice.remove_columns(["accent", "age", "client_id", "down_votes", "gender", "locale", "path", "segment", "up_votes"])

print(common_voice)

以下でWhisperの学習ずみ特徴量抽出器とTokenizerをロードします。

from transformers import WhisperFeatureExtractor
from transformers import WhisperTokenizer

feature_extractor = WhisperFeatureExtractor.from_pretrained("openai/whisper-small")
tokenizer = WhisperTokenizer.from_pretrained("openai/whisper-small", language="Hindi", task="transcribe")

特徴量抽出器とTokenizerを1つのクラスで利用できるようWhisperProcessorも用意します。

from transformers import WhisperProcessor

processor = WhisperProcessor.from_pretrained("openai/whisper-small", language="Hindi", task="transcribe")

データ前処理

CommonVoiceをWhisperで利用可能にするためにサンプリングレートを16Kにします。

from datasets import Audio

common_voice = common_voice.cast_column("audio", Audio(sampling_rate=16000))

以下の関数を利用することでWhisperの学習に必要な前処理を行うことができます。map関数を使って実際にデータセットに関数を適応します。

def prepare_dataset(batch):
    # load and resample audio data from 48 to 16kHz
    audio = batch["audio"]

    # compute log-Mel input features from input audio array
    batch["input_features"] = feature_extractor(audio["array"], sampling_rate=audio["sampling_rate"]).input_features[0]

    # encode target text to label ids
    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)

学習と評価

Whisper用のDataCollatorを準備します。

import torch

from dataclasses import dataclass
from typing import Any, Dict, List, Union

@dataclass
class DataCollatorSpeechSeq2SeqWithPadding:
    processor: Any

    def __call__(self, features: List[Dict[str, Union[List[int], torch.Tensor]]]) -> Dict[str, torch.Tensor]:
        # split inputs and labels since they have to be of different lengths and need different padding methods
        # first treat the audio inputs by simply returning torch tensors
        input_features = [{"input_features": feature["input_features"]} for feature in features]
        batch = self.processor.feature_extractor.pad(input_features, return_tensors="pt")

        # get the tokenized label sequences
        label_features = [{"input_ids": feature["labels"]} for feature in features]
        # pad the labels to max length
        labels_batch = self.processor.tokenizer.pad(label_features, return_tensors="pt")

        # replace padding with -100 to ignore loss correctly
        labels = labels_batch["input_ids"].masked_fill(labels_batch.attention_mask.ne(1), -100)

        # if bos token is appended in previous tokenization step,
        # cut bos token here as it's append later anyways
        if (labels[:, 0] == self.processor.tokenizer.bos_token_id).all().cpu().item():
            labels = labels[:, 1:]

        batch["labels"] = labels

        return batch


data_collator = DataCollatorSpeechSeq2SeqWithPadding(processor=processor)

Evaluation Metrics

今回、評価にはWord Error Rate (WER)を用いることとします。

import evaluate

metric = evaluate.load("wer")

今回のWhisper学習用のcompute_metricsを定義します。

def compute_metrics(pred):
    pred_ids = pred.predictions
    label_ids = pred.label_ids

    # replace -100 with the pad_token_id
    label_ids[label_ids == -100] = tokenizer.pad_token_id

    # we do not want to group tokens when computing the metrics
    pred_str = tokenizer.batch_decode(pred_ids, skip_special_tokens=True)
    label_str = tokenizer.batch_decode(label_ids, skip_special_tokens=True)

    wer = 100 * metric.compute(predictions=pred_str, references=label_str)

    return {"wer": wer}

Load a Pre-Trained Checkpoint

Whisperの事前学習済みモデルを読み込みます。

from transformers import WhisperForConditionalGeneration

model = WhisperForConditionalGeneration.from_pretrained("openai/whisper-small")

# Override generation arguments
model.config.forced_decoder_ids = None # no tokens are forced as decoder outputs
model.config.suppress_tokens = [] # no tokens are suppressed during generation

以下に学習用のハイパーパラメータを定義します。 パラメータの詳細はSeq2SeqTrainingArguments Docsを参照してください.

from transformers import Seq2SeqTrainingArguments
from transformers import Seq2SeqTrainer

# Define arguments
training_args = Seq2SeqTrainingArguments(
    output_dir="./whisper-small-hi",  # change to a repo name of your choice
    per_device_train_batch_size=16,
    gradient_accumulation_steps=1,  # increase by 2x for every 2x decrease in batch size
    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,
)


# Define trainer
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)

Training

以下のコードで実際に学習を行います。学習にはGPUによりますが5~10時間程度がかかります。

trainer.train()

弊社環境下では Best WERが約32%となりました。

終わりに

本記事ではWhisperをCommon VoiceでFine Tuningしました。弊社別の記事ではPyTorch Lightningを使ったFine Tuningの記事もありますが、本記事ではHuggingFaceエコシステム内で完結させてFine Tuningを行うことができました。

2025年06月15日に最終更新
読み込み中...