오디오 분류

오디오 분류 (Audio classification)

오디오 분류는 텍스트 분류와 마찬가지로 입력 데이터로부터 클래스 라벨을 출력으로 할당하는 작업입니다. 유일한 차이는 텍스트 입력 대신 원시 오디오 파형을 사용한다는 점입니다. 오디오 분류의 실제 활용 사례로는 화자의 의도 식별, 언어 분류, 심지어 동물 소리로 종(種)을 식별하는 것까지 있습니다.

출처: 문서

본문

이 가이드에서 다룰 내용은 다음과 같습니다.

  1. MInDS-14 데이터셋에서 Wav2Vec2를 파인튜닝해 화자 의도를 분류합니다.
  2. 파인튜닝된 모델을 추론(inference)에 사용합니다.

이 작업과 호환되는 모든 아키텍처와 체크포인트를 보려면 task-page를 확인하는 것을 권장합니다.

시작하기 전에 필요한 라이브러리를 모두 설치했는지 확인해 주세요.

pip install transformers datasets evaluate soundfile librosa torchcodec

Hugging Face 계정에 로그인해 모델을 커뮤니티에 업로드하고 공유하는 것을 권장합니다. 프롬프트가 나타나면 토큰을 입력해 로그인하세요.

>>> from huggingface_hub import notebook_login

>>> notebook_login()

MInDS-14 데이터셋 로드하기

🤗 Datasets 라이브러리에서 MInDS-14 데이터셋을 로드하는 것부터 시작하겠습니다.

>>> from datasets import load_dataset, Audio

>>> minds = load_dataset("PolyAI/minds14", name="en-US", split="train")

train_test_split 메서드로 데이터셋의 train 스플릿을 더 작은 train과 test 세트로 나눕니다. 이렇게 하면 전체 데이터셋에 더 많은 시간을 투자하기 전에 실험해 보고 모든 것이 잘 작동하는지 확인할 수 있습니다.

>>> minds = minds.train_test_split(test_size=0.2)

그런 다음 데이터셋을 살펴봅니다.

>>> minds
DatasetDict({
    train: Dataset({
        features: ['path', 'audio', 'transcription', 'english_transcription', 'intent_class', 'lang_id'],
        num_rows: 450
    })
    test: Dataset({
        features: ['path', 'audio', 'transcription', 'english_transcription', 'intent_class', 'lang_id'],
        num_rows: 113
    })
})

데이터셋에는 lang_id나 english_transcription 같은 유용한 정보가 많이 포함되어 있지만, 이 가이드에서는 audio와 intent_class에 초점을 맞출 것입니다. remove_columns 메서드로 다른 컬럼을 제거합니다.

>>> minds = minds.remove_columns(["path", "transcription", "english_transcription", "lang_id"])

다음은 예시입니다.

>>> minds["train"][0]
{'audio': {'array': array([ 0.        ,  0.        ,  0.        , ..., -0.00048828,
         -0.00024414, -0.00024414], dtype=float32),
  'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~APP_ERROR/602b9a5fbb1e6d0fbce91f52.wav',
  'sampling_rate': 8000},
 'intent_class': 2}

여기에는 두 개의 필드가 있습니다.

  • audio: 오디오 파일을 로드하고 리샘플링하기 위해 호출해야 하는 1차원 array 형태의 음성 신호입니다.
  • intent_class: 화자 의도의 클래스 id를 나타냅니다.

모델이 라벨 id로부터 라벨 이름을 쉽게 얻을 수 있도록, 라벨 이름과 정수를 서로 매핑하는 딕셔너리를 만듭니다.

>>> labels = minds["train"].features["intent_class"].names
>>> label2id, id2label = dict(), dict()
>>> for i, label in enumerate(labels):
...     label2id[label] = str(i)
...     id2label[str(i)] = label

이제 라벨 id를 라벨 이름으로 변환할 수 있습니다.

>>> id2label[str(2)]
'app_error'

전처리 (Preprocess)

다음 단계는 오디오 신호를 처리할 Wav2Vec2 피처 추출기(feature extractor)를 로드하는 것입니다.

>>> from transformers import AutoFeatureExtractor

>>> feature_extractor = AutoFeatureExtractor.from_pretrained("facebook/wav2vec2-base")

MInDS-14 데이터셋의 샘플링 레이트는 8kHz입니다(이 정보는 dataset card에서 찾을 수 있습니다). 즉, 사전훈련된 Wav2Vec2 모델을 사용하려면 데이터셋을 16kHz로 리샘플링해야 합니다.

>>> minds = minds.cast_column("audio", Audio(sampling_rate=16_000))
>>> minds["train"][0]
{'audio': {'array': array([ 2.2098757e-05,  4.6582241e-05, -2.2803260e-05, ...,
         -2.8419291e-04, -2.3305941e-04, -1.1425107e-04], dtype=float32),
  'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~APP_ERROR/602b9a5fbb1e6d0fbce91f52.wav',
  'sampling_rate': 16000},
 'intent_class': 2}

이제 다음을 수행하는 전처리 함수를 만듭니다.

  1. audio 컬럼을 호출해 오디오 파일을 로드하고, 필요하면 리샘플링합니다.
  2. 오디오 파일의 샘플링 레이트가 모델이 사전훈련될 때 사용된 오디오 데이터의 샘플링 레이트와 일치하는지 확인합니다. 이 정보는 Wav2Vec2 model card에서 찾을 수 있습니다.
  3. 더 긴 입력을 잘라내지 않고 배칭할 수 있도록 최대 입력 길이를 설정합니다.
>>> def preprocess_function(examples):
...     audio_arrays = [x["array"] for x in examples["audio"]]
...     inputs = feature_extractor(
...         audio_arrays, sampling_rate=feature_extractor.sampling_rate, max_length=16000, truncation=True
...     )
...     return inputs

전체 데이터셋에 전처리 함수를 적용하려면 🤗 Datasets map 함수를 사용하세요. batched=True로 설정하면 데이터셋의 여러 요소를 한 번에 처리해 map을 더 빠르게 할 수 있습니다. 모델이 요구하는 대로 불필요한 컬럼을 제거하고 intent_class를 label로 이름을 바꿉니다.

>>> encoded_minds = minds.map(preprocess_function, remove_columns="audio", batched=True)
>>> encoded_minds = encoded_minds.rename_column("intent_class", "label")

평가 (Evaluate)

훈련 중에 메트릭을 포함하는 것은 모델 성능을 평가하는 데 자주 도움이 됩니다. 🤗 Evaluate 라이브러리로 평가 방법을 빠르게 로드할 수 있습니다. 이 작업에서는 accuracy 메트릭을 로드합니다(메트릭 로드·계산 방법에 대해 더 알아보려면 🤗 Evaluate quick tour를 참고하세요).

>>> import evaluate

>>> accuracy = evaluate.load("accuracy")

그런 다음 compute에 예측값과 라벨을 전달해 정확도를 계산하는 함수를 만듭니다.

>>> import numpy as np

>>> def compute_metrics(eval_pred):
...     predictions = np.argmax(eval_pred.predictions, axis=1)
...     return accuracy.compute(predictions=predictions, references=eval_pred.label_ids)

compute_metrics 함수가 준비되었습니다. 훈련을 설정할 때 다시 사용하게 됩니다.

훈련 (Train)

Trainer로 모델을 파인튜닝하는 방법이 익숙하지 않다면 기본 튜토리얼 여기를 확인해 보세요!

이제 모델 훈련을 시작할 준비가 되었습니다. 기대되는 라벨 수와 라벨 매핑과 함께 AutoModelForAudioClassification으로 Wav2Vec2를 로드합니다.

>>> from transformers import AutoModelForAudioClassification, TrainingArguments, Trainer

>>> num_labels = len(id2label)
>>> model = AutoModelForAudioClassification.from_pretrained(
...     "facebook/wav2vec2-base", num_labels=num_labels, label2id=label2id, id2label=id2label
... )

이 시점에서 남은 단계는 세 가지뿐입니다.

  1. TrainingArguments에서 훈련 하이퍼파라미터를 정의합니다. 유일한 필수 매개변수는 모델을 저장할 위치를 지정하는 output_dir입니다. push_to_hub=True로 설정하면 이 모델을 Hub에 푸시합니다(모델을 업로드하려면 Hugging Face에 로그인해야 합니다). 각 에폭이 끝날 때마다 Trainer는 정확도를 평가하고 훈련 체크포인트를 저장합니다.
  2. Trainer에 모델, 데이터셋, 토크나이저, 데이터 콜레이터, compute_metrics 함수와 함께 훈련 인자를 전달합니다.
  3. train()을 호출해 모델을 파인튜닝합니다.
>>> training_args = TrainingArguments(
...     output_dir="my_awesome_mind_model",
...     eval_strategy="epoch",
...     save_strategy="epoch",
...     learning_rate=3e-5,
...     per_device_train_batch_size=32,
...     gradient_accumulation_steps=4,
...     per_device_eval_batch_size=32,
...     num_train_epochs=10,
...     warmup_steps=0.1,
...     logging_steps=10,
...     load_best_model_at_end=True,
...     metric_for_best_model="accuracy",
...     push_to_hub=True,
...     report_to="trackio",
... )

>>> trainer = Trainer(
...     model=model,
...     args=training_args,
...     train_dataset=encoded_minds["train"],
...     eval_dataset=encoded_minds["test"],
...     processing_class=feature_extractor,
...     compute_metrics=compute_metrics,
... )

>>> trainer.train()

훈련이 끝나면 push_to_hub() 메서드로 모델을 Hub에 공유해 모두가 사용할 수 있게 하세요.

>>> trainer.push_to_hub()

오디오 분류를 위해 모델을 파인튜닝하는 더 심층적인 예시는 해당 PyTorch notebook을 참고하세요.

추론 (Inference)

좋습니다. 이제 모델을 파인튜닝했으니 추론에 사용할 수 있습니다!

추론에 사용할 오디오 파일을 로드합니다. 필요한 경우 오디오 파일의 샘플링 레이트를 모델의 샘플링 레이트에 맞게 리샘플링하는 것을 잊지 마세요.

>>> from datasets import load_dataset, Audio

>>> dataset = load_dataset("PolyAI/minds14", name="en-US", split="train")
>>> dataset = dataset.cast_column("audio", Audio(sampling_rate=16000))
>>> sampling_rate = dataset.features["audio"].sampling_rate
>>> audio_file = dataset[0]["audio"]["path"]

파인튜닝된 모델을 추론에 사용해 보는 가장 간단한 방법은 pipeline()에서 사용하는 것입니다. 모델로 오디오 분류용 pipeline을 만들고 오디오 파일을 전달합니다.

>>> from transformers import pipeline

>>> classifier = pipeline("audio-classification", model="stevhliu/my_awesome_minds_model")
>>> classifier(audio_file)
[
    {'score': 0.09766869246959686, 'label': 'cash_deposit'},
    {'score': 0.07998877018690109, 'label': 'app_error'},
    {'score': 0.0781070664525032, 'label': 'joint_account'},
    {'score': 0.07667109370231628, 'label': 'pay_bill'},
    {'score': 0.0755252093076706, 'label': 'balance'}
]

원한다면 pipeline의 결과를 직접 재현할 수도 있습니다.

오디오 파일을 전처리하고 input을 PyTorch 텐서로 반환할 피처 추출기를 로드합니다.

>>> from transformers import AutoFeatureExtractor

>>> feature_extractor = AutoFeatureExtractor.from_pretrained("stevhliu/my_awesome_minds_model")
>>> inputs = feature_extractor(dataset[0]["audio"]["array"], sampling_rate=sampling_rate, return_tensors="pt")

입력을 모델로 전달하고 logits을 반환받습니다.

>>> from transformers import AutoModelForAudioClassification

>>> model = AutoModelForAudioClassification.from_pretrained("stevhliu/my_awesome_minds_model")
>>> with torch.no_grad():
...     logits = model(**inputs).logits

확률이 가장 높은 클래스를 구하고, 모델의 id2label 매핑을 사용해 라벨로 변환합니다.

>>> import torch

>>> predicted_class_ids = torch.argmax(logits).item()
>>> predicted_label = model.config.id2label[predicted_class_ids]
>>> predicted_label
'cash_deposit'

더 알아보기 (Learn more)