Huggingface
Fairseq
- facebook 에서 처음에는 shell 을 통해 바로 훈련시키는 fairseq 라는 AI 툴킷을 공개함
- 따라서 이 fairseq 를 통해 pretrained 모델을 가져와 fine-tuning 가능했었음
Huggingface
- 그 이후 huggingface 에서 python 에서 pretrained 모델을 가져와 fine-tuning 할 수 있도록 만들어줌
- Huggingface 는 자연어처리 스타트업에서 개발한 다양한 트랜스포머 모델(transformer.models) 과 학습 스크립트(transformer.Trainer) 를 제공하는 모듈
- transformers.models : 트랜스포머 기반의 다양한 모델을 pytorch, tensorflow 로 각각 구현해놓은 모듈
- 각 모델에 맞는 tokenizer 도 구현되어 있음 - transformers.Trainer : 딥러닝 학습 / 평가에 필요한 optimizer, 가중치 업데이트 등을 수행하는 모듈
TIMIT dataset 실습
데이터셋 로드하기
!pip install datasets==1.13.3
!pip install transformers==4.11.3
!pip install soundfile
!pip install jiwer
!pip install torchaudio
!pip install librosa
- jiwer : 단어 오류율 구하기
- torchaudio & librosa : 음악 파일 로딩, 처리
from datasets import load_dataset, load_metric
timit = load_dataset("timit_asr")
- timit 데이터셋의 경우 아주 고맙게도 load_dataset 을 통해 쉽게 로딩 가능
- 하지만 개인 데이터셋이나 처음 나오는 데이터셋의 경우 pre-processing 과정이 중요하고 까다로움
ex) 한국어라면 영어, 숫자, 특수문자 다 지워주어야 함
영어 약자로 된 것, 숫자 읽는법 다 처리해주어야 함 - pre-processing 은 스스로 만들어야 하는데, list, dict, pandas 등을 이용해서 가능 + editor 이용해 shell 에서도 가능
개인적으로 데이터셋을 만든다면 어떤 식으로 만들어야 할까?
- 보편적인 데이터셋 살펴보기
- Train / Test split
- 아예 처음부터 폴더를 다르게 해서 train, test 로 나눌 수도 있고, 한번에 데이터 로딩한 후 나중에 경로 지정을 다르게 해서 나눌 수도 있음
- train과 test 안에 dataset features 들 존재
- 음성인식에서 중요한 것은 오디오 경로와 그 오디오가 나타내는 target transcription 이 중요함
- 현재 TIMIT 데이터셋의 경우에는 특이하게 오디오 파일을 통째로 넣어서 벡터가 그대로 들어가 있음
- 한마디로 path 뿐만 아니라, 그 경로를 librosa 로 로딩해서 오디오로 나오는 긴 숫자 덩어리들이 함께 로드되어있음
- TIMIT 은 큰 데이터셋이 아니라 작은 데이터셋이기 때문에 위와 같이 오디오 긴 숫자 덩어리 전체를 함께 로드할 수 있었지만, 1000시간 이상의 대규모 데이터셋을 오디오로 다 바꾼 후 처리하면 용량이 커져서 실제로는 너무 느려짐
- 그래서 많이 쓰는 방법은 numpy 를 이용해 미리 뽑아놓은 후 뽑아놓은 것을 로드하는 방법으로 많이 이용함
timit = timit.remove_columns(["phonetic_detail", "word_detail", "dialect_region", "id", "sentence_type", "speaker_id"])
- 즉 결론은, 오디오 경로와 target transcription 이 필요하기 때문에 file, audio, text 외의 뒤에 있는 다른 feature 들 제거
from datasets import ClassLabel
import random
import pandas as pd
from IPython.display import display, HTML
def show_random_elements(dataset, num_examples=10):
assert num_examples <= len(dataset), "Can't pick more elements than there are in the dataset."
picks = []
for _ in range(num_examples):
pick = random.randint(0, len(dataset)-1)
while pick in picks:
pick = random.randint(0, len(dataset)-1)
picks.append(pick)
df = pd.DataFrame(dataset[picks])
display(HTML(df.to_html()))
- random elements 를 pandas 를 통해 보여주기
- 그냥 random number 뽑아서 append 해서 보여주는 형태
- 랜덤하게 뽑힌 audio 와 text 쌍을 확인할 수 있음 - 'path', 'array', 'sampling rate', 'text'
- sampling rate 도 array 를 위해 필수임. - 핵심적으로는 'array' 와 'text' 가 필요
- 결국 array 와 text 를 mapping 시켜야 함. - 음성인식이 어려운 이유 중 하나는 다른 분야에 대해 mapping 이 매우 까다로움
- 숫자들 산더미인 array 와 여러 단어로 구성된 text 를 mapping 해주어야 함
- 기본적인 캐글, 통계데이터셋의 콤마로 구분되어 있는 csv 형태의 데이터셋의 경우,
ex) dimension 4, decision 3 : 4개의 영향을 끼치는 요소, 긍정/부정/중립의 3가지
4개의 차원에 있는 숫자와 머신러닝 / 회귀를 통해 어떻게든 mapping 가능 - 하지만, 오디오의 경우 array 도 숫자로 길고, text 도 문자로 길어서 항상 align 의 문제가 있음
ex) Birthday parties have cupcakes and ice cream.
- array [ 0.0, -9.1552734... ] 어디서부터 어디까지가 B 이고, 어디서부터 어디까지가 i 이고, r 이고 하는 것들을 처리하기 어려움 : align 의 문제
- 여기서는 거대한 mapping function 을 통해 mapping 하게 됨
간단한 전처리해주기
import re
chars_to_ignore_regex = '[\,\?\.\!\-\;\:\"]'
def remove_special_characters(batch):
batch["text"] = re.sub(chars_to_ignore_regex, '', batch["text"]).lower() + " "
return batch
- 정규표현식 활용해서 전처리해주기
- 먼저 batch 를 넣어주고, batch 에다가 text 를 새로 만들어줌
- 이 때 chars_to_ignore_regex 에 해당되는 index 를 다 제거해서 새로운 text 를 만들어주는 것임 - re.sub(chars_to_ignore_regex, '', batch["text"]).lower() + " "
- batch["text"] 의 데이터셋에서 chars_to_ignore_regex 의 인덱스들을 '' 로 바꿔주라는 명령 ('':빈칸)
- 그리고 알파벳을 다 소문자로 바꾼 후 빈칸 한 칸을 넣어줌
vocab dictionary 만들기
def extract_all_chars(batch):
all_text = " ".join(batch["text"])
vocab = list(set(all_text))
return {"vocab": [vocab], "all_text": [all_text]}
- 이제 문제는 text 의 문자들을 다 숫자로 만들어주어야 함.
- 총 단어를 모아서 독립적인 단어들을 숫자로 mapping 한 사전을 만들기 위해, 단어를 쭉 모아서 중복 제거하기
- all_text = " ".join(batch["text"]) : batch["text"] 에 있는 모든 dummy text 를 글자 통 all_text 에 다 집어넣기
- 그 다음 set() 을 이용해서 중복되는 것 제거
- 이제 vocab 완성됨
vocabs = timit.map(extract_all_chars, batched=True, batch_size=-1, keep_in_memory=True, remove_columns=timit.column_names["train"])
- 경우에 따라 test set 의 단어는 넣지 않고 vocab 만들자라는 사람도 있는데, 일단 여기서는 train, test 데이터셋의 vocab 모두 넣음
vocab_list = list(set(vocabs["train"]["vocab"][0]) | set(vocabs["test"]["vocab"][0]))
vocab_dict = {v: k for k, v in enumerate(vocab_list)}
- vocab_dict 를 통해 이제 드디어 문자를 숫자로 바꿀 수가 있어서, array 의 숫자와 text 의 변환된 숫자와의 mapping 이 가능하다.
- 이러한 vocab_dict 도 만드려는 유형에 따라 다양하다.
- 한국어의 경우에도 형태소 등등 개수 조정 가능
- 음절 단위 / 단어 단위 / 대어휘음성인식시스템 - 20~30만개 등등 dict 안의 개수 조정가능
- 이 예시에서는 30개 정도로 간단하게 만든 vocab_dict
vocab_dict["[UNK]"] = len(vocab_dict)
vocab_dict["[PAD]"] = len(vocab_dict)
len(vocab_dict) # 30
- 현재까지 vocab_dict 는 총 28개였음
- unknwon 토큰을 len(vocab_dict), 즉 dict 의 28의 값으로 넣어주고, padding 토큰을 그 이후 len(vocab_dict) 값인 29 의 값으로 넣어준다.
- 그래서 최종으로는 [UNK], [PAD] 를 추가한 0~29 의 30개의 vocab_dict 완성
import json
with open('vocab.json', 'w') as vocab_file:
json.dump(vocab_dict, vocab_file)
- 이제 vocab.json 이라는 이름의 파일을 작성
- 만들어 놓은 vocab_dict 를 위 파일인 vocab_file (=vocab.json) 에 넣어준다.
from transformers import Wav2Vec2CTCTokenizer
tokenizer = Wav2Vec2CTCTokenizer("./vocab.json", unk_token="[UNK]", pad_token="[PAD]", word_delimiter_token="|")
from transformers import Wav2Vec2FeatureExtractor
feature_extractor = Wav2Vec2FeatureExtractor(feature_size=1, sampling_rate=16000, padding_value=0.0, do_normalize=True, return_attention_mask=False)
- wav2vecCTCTokenizer = 언어학 파트
Reference
- https://wooono.tistory.com/413
- SpeechJJong 님의 <Timit Dataset을 이용한 huggingface wav2vec2.0 colab 실습 - part1> 강의
https://www.youtube.com/watch?v=pwX0IvO0YTU
'Spoken Language Processing' 카테고리의 다른 글
G2P(grapheme to phoneme)란? - 발음열 정보의 중요성 (0) | 2022.09.28 |
---|---|
Huggingface 튜토리얼 (1) 기초 개념 소개 (0) | 2022.09.15 |
wav2vec2.0 pretrained 모델로 디코딩하기 (0) | 2022.08.17 |
End-to-End ASR : Attention vs RNN-T (0) | 2022.08.04 |
Fairseq - Wav2vec 2.0 Pretraining (3) pretraining 시키기 (0) | 2022.06.14 |
댓글