ãã®èšäºã¯ NTTã³ãã¥ãã±ãŒã·ã§ã³ãº Advent Calendar 2021 ã®20æ¥ç®ã®èšäºã§ãã ã¯ããã« ããã«ã¡ã¯ããã©ãããã©ãŒã ãµãŒãã¹æ¬éšã¢ããªã±ãŒã·ã§ã³ãµãŒãã¹éšã®æ¯æŸã§ãã NTTã³ãã¥ãã±ãŒã·ã§ã³ãºã§ã¯èªç¶èšèªåŠçãæ©æ¢°ç¿»èš³ãé³å£°èªèã»åæãèŠçŽãæ åè§£æãªã©ã®AIé¢é£æè¡ã掻çšããæ³äººåããµãŒãã¹ãæäŸããŠããŸããïŒ COTOHA ã·ãªãŒãº ïŒ NTTã³ãã¥ãã±ãŒã·ã§ã³ãºããã®ãããªAIé¢é£æè¡ã掻çšãããµãŒãã¹ãå±éãã匷ã¿ãšããŠã NTTç ç©¶æã®ç ç©¶ææãå©çšå¯èœã§ããããš èªç€Ÿã®ä»ãµãŒãã¹ãå©çšããŠããã客æ§ã«å¯ŸããŠã·ããžãŒã®ãããµãŒãã¹ãææ¡ã§ããããš ãã®2ç¹ãæãããããšæããŸãã å®éã«ãç§ãæ
åœããŠãã COTOHA Voice Insight 㯠é話é³å£°ããã¹ãåã«ãã£ãŠã³ã³ã¿ã¯ãã»ã³ã¿ãŒã®æ¥åå¹çåã»é«åºŠåãå®çŸãããµãŒãã¹ãªã®ã§ããã NTTç ç©¶æã®é³å£°èªèæè¡ã掻çšããŠãããèªç€ŸãµãŒãã¹ãšã®é£æºãç©æ¥µçã«è¡ã£ãŠããŸãã ã¿ãŒã²ãããšããŠããã³ã³ã¿ã¯ãã»ã³ã¿ãŒã®DXåžå Žã¯å€åãæ¿ããæ¥çã§ãããªããã ç§ãã¡ã®ãµãŒãã¹ã¯ãã®å€åã«ã€ããŠããäœå¶ãæŽã£ãŠããªãããšã課é¡ã ãšæããŠããŸãã æ§ã
ãªäºæ
ãããå®éã«ãµãŒãã¹ã§äœ¿çšããŠããé³å£°èªèã¢ãã«ãæ°è»œã«è©Šãããšã¯é£ããã®ã§ããããªãŒãã³ãœãŒã¹ã®é³å£°èªèæè¡ã掻çšããããšã§ãµãŒãã¹ã®å質åäžã«ã€ãªããç¥èŠãéããããšãå¯èœã ãšèããæè¡èª¿æ»ãããŠããŸããã æ¬èšäºã§ã¯ããã®ãããªåãçµã¿ã®1ã€ãšããŠãwav2vec 2.0 ãšãããªãŒãã³ãœãŒã¹ãçšããŠãäºååŠç¿ãããé³å£°èªèã¢ãã«ãå°éã®ããŒã¿ã»ããã§ãã¥ãŒãã³ã°ããæ¹æ³ãã玹ä»ããŸãã æå
ã§ç°¡åã«é³å£°èªèã詊ãããšãã§ããããã«ãªãã°ãPoC(Proof of Concept)ãªã©ãéããŠç¥èŠãéããããšãã§ãã ãªããªãå°åããå¹ããªããµãŒãã¹éçºã®å¹çåäžãæåŸ
ã§ãããšèããŠããŸãã wav2vec 2.0 ãšã¯ 2020.6 ã« wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations ãšããè«æã§ææ¡ãããé³å£°èªèãã¬ãŒã ã¯ãŒã¯ã§ãã wav2vec 2.0 ã§ã¯ãã©ãã«ä»ãïŒæžãèµ·ããæãããïŒã®é³å£°ããŒã¿ã ãã§ãªãã©ãã«ãªãé³å£°ããŒã¿ãåŠç¿ã«æŽ»çšãããèªå·±æåž«ããåŠç¿ã®ææ³ãæ¡çšããŠããŸãã å°éã®ã©ãã«ä»ãããŒã¿ + ããããã®ã©ãã«ãªãããŒã¿ã§ãããããŸã§ã®ææ³ã«å¹æµããé³å£°èªè粟床ãéæãã ã©ãã«ä»ãããŒã¿ã®éãå¢ãããŠããããšã§é³å£°èªè粟床ãããã«åäžããŠããããšã瀺ããŸããã çŸåšã§ã wav2vec 2.0 ãåºã«ããææ³ãè€æ°ã®é³å£°èªèã¿ã¹ã¯ã§æé«æ§èœãèšé²ããŠããŸãã https://paperswithcode.com/task/speech-recognition wav2vec 2.0 ã®è©³çްã¯åè«æãã解説èšäºïŒ ãã¡ã ãåãããããã£ãã§ãïŒãåç
§ãã ããã wav2vec 2.0 ã®çŽ æŽãããç¹ãšããŠãå€§èŠæš¡é³å£°ããŒã¿ãçšããŠäºååŠç¿ãããã¢ãã«ã«å¯ŸããŠãå°éã®ããŒã¿ã»ãããçšããŠãã©ã¡ãŒã¿ãå調æŽïŒFine TuningïŒããããšã«ãã£ãŠãåŸãã远å ããé³å£°ããŒã¿ã«ããŸãé©åããã¢ãã«ãäœããããšãæããããŸãã ããããwav2vec 2.0 ã¯ããœãŒã¹ã³ãŒããšäºååŠç¿ãããã¢ãã«ãå
¬éãããŠãããã( ãã¡ã )ã誰ã§ãç°¡åã«ã¢ãã«ããã¥ãŒãã³ã°ã§ããŸãã æ¥æ¬èªããŒã¿ã»ããã䜿ã£ãŠé³å£°èªèã¢ãã«ããã¥ãŒãã³ã°ãã wav2vec 2.0 ã®å¹æçãªäœ¿ãæ¹ãšããŠãäºååŠç¿ãããèšèªéäŸåã®ã¢ãã«ãå°éã®ç¹å®èšèªããŒã¿ã»ããã§ Fine Tuning ããææ³ããããŸãã ãã®ææ³ã¯ã話è
ãå°ãªããªã©ã®çç±ã§ããŒã¿ã»ãããååååšããªãèšèªã®é³å£°èªèã¢ãã«ãäœæããéã«å¹æçã§ãã ä»ã«ããæ¹èšãç¹å®ã®è©±è
ã«ç¹åããã¢ãã«ãé»è©±é³å£°ãªã©ç¹å®ã®ãã¡ã€ã³ã®ã¿ã§äœ¿çšããã¢ãã«ãªã©ããããŸã§ã¯ååãªããŒã¿ãçšæã§ããŠããªãã£ãåéã§ã®æŽ»çšãæåŸ
ãããŸãã ä»åã¯ãèšèªéäŸåã®äºååŠç¿ã¢ãã«ã«å¯ŸããŠãå°éã®æ¥æ¬èªé³å£°ããŒã¿ã䜿ã£ãŠ Fine Tuning ãè¡ããŸãã 倧ãŸããªæµãã¯ãè±èªããŒã¿ã»ããã䜿çšããŠãã¥ãŒãã³ã°ãè¡ãªã£ãŠãã ãã¡ã ã®èšäºãåèã«ããŠããŸãã解説ãããããããã®ã§èå³ã®ããæ¹ã¯å
ã®èšäºããåç
§ãã ããã ç°å¢ Google Colaboraoty Pro ã䜿çšããŸããã ç¡æçã§ããå Žåã¯ãããããåŠç¿æã«GPUã®ã¡ã¢ãªãè¶³ããªããªãã®ã§ãããããµã€ãºãå°ãããããªã©ããŠå¯Ÿå¿ããŠãã ããã äºåã«å¿
èŠãªã©ã€ãã©ãªãã€ã³ã¹ããŒã«ããŸãã %%capture # æ¥æ¬èªããŒã¿ã»ããã®ããŠã³ããŒã !pip install datasets==1.13.3 # æ©æ¢°åŠç¿ã©ã€ãã©ãª !pip install transformers==4.11.3 !pip install torchaudio # é³å£°ããŒã¿åŠççšã©ã€ãã©ãª !pip install librosa # 圢æ
çŽ è§£æ !pip install mecab-python3 !pip install unidic # ããªããŒãå倿 !pip install romkan ææ°ã®æ¥æ¬èªèŸæžãããŠã³ããŒãããŠãããŸãã !python -m unidic download åŠç¿ããŒã¿ã®æºå ãŸãã¯ãFine Tuning ã«äœ¿çšããæ¥æ¬èªããŒã¿ã»ãããçšæããŸãããã common voice ãšãããªãŒãã³ãœãŒã¹ã®é³å£°ããŒã¿ã»ãããæ§ç¯ãããããžã§ã¯ãããããããã§ã¯æ§ã
ãªèšèªã®é³å£°ããŒã¿ãåé²ã»å
¬éãããŠããŸãã äžèšã®ã©ã€ãã©ãªã䜿ãããšã§ãcommon voice ããŒã¿ã»ãããç°¡åã«äœ¿ãããšãã§ããŸãã https://pypi.org/project/datasets/ äœè«ã§ãããcommon voice ã®webãµã€ãã§ã¯ã衚瀺ãããããã¹ããèªã¿äžããŠé²é³ããããé²é³ãããé³å£°ã®å質ãè©äŸ¡ãããããããšã§ãããžã§ã¯ãã«è²¢ç®ã§ããŸããèå³ãããæ¹ã¯ãã²è©ŠããŠã¿ãŠãã ããã datasets.load_dataset() ã䜿ã£ãŠæ§ã
ãªèšèªã®ããŒã¿ã»ãããããŠã³ããŒãå¯èœã§ãã æ¥æ¬èªã®å Žåã¯ç¬¬2åŒæ°ã« "ja" ãšå
¥åããŸãã ããŒã¿ã»ããã¯ãtrain, validation, test ã®3çš®é¡ã«åãããŠãããä»å㯠train ããŒã¿ãš test ããŒã¿ã®2ã€ã«åããã°ååãªã®ã§ãtest ãš validation ã train ããŒã¿ãšããŸãã from datasets import load_dataset, load_metric, Audio common_voice_train = load_dataset("common_voice", "ja", split="train+validation") common_voice_test = load_dataset("common_voice", "ja", split="test") ããŒã¿ã»ããã¯ãtrain, validation, test ã®3çš®é¡ã«åãããŠããŸãããä»å㯠train ãš test ããŒã¿ã®2ã€ã«åããŠäœ¿çšããŸãã ä»åã¯ãtrainããŒã¿ã1308çµãtestããŒã¿ã632çµã§ããã len(common_voice_train), len(common_voice_test) (1308, 632) ããŒã¿ã»ããã®äžèº«ãèŠãŠã¿ãŸãããã common_voice_train[0] {'accent': '', 'age': 'twenties', 'audio': {'array': array([ 0. , 0. , 0. , ..., 0.00085527, -0.00014246, -0.00077921], dtype=float32), 'path': '/root/.cache/huggingface/datasets/downloads/extracted/07b0a73f2103df267f566548f7597fe8d75f8d4bdd37b7f556478ae85378bd6a/cv-corpus-6.1-2020-12-11/ja/clips/common_voice_ja_19817895.mp3', 'sampling_rate': 48000}, 'client_id': 'b067e4a64d0c78c7c24b8eb93f9efc165121f9281fa6c31386d872529c2951a5a1f144ee8e5679c1bd41003695583b1c341de7d67fea995d584b5724b91ce984', 'down_votes': 1, 'gender': 'male', 'locale': 'ja', 'path': '/root/.cache/huggingface/datasets/downloads/extracted/07b0a73f2103df267f566548f7597fe8d75f8d4bdd37b7f556478ae85378bd6a/cv-corpus-6.1-2020-12-11/ja/clips/common_voice_ja_19817895.mp3', 'segment': "''", 'sentence': 'äºæ³å€ã®äºæ
ã«ãé»åäŒç€Ÿããã¡ãã£ãŽãå°ææ°å³ã ã', 'up_votes': 2} æ§ã
ãªæ
å ±ãå«ãŸããŠããŸãããä»åã¯é³å£°ããŒã¿ãšããã¹ãæ
å ±ã ããããã°ããã®ã§ã äžèŠãªæ
å ±ãé€ããŸãã common_voice_train = common_voice_train.remove_columns(["accent", "age", "client_id", "down_votes", "gender", "locale", "segment", "up_votes"]) common_voice_test = common_voice_test.remove_columns(["accent", "age", "client_id", "down_votes", "gender", "locale", "segment", "up_votes"]) é³å£°ããŒã¿ã®ç¢ºèª 次ã«é³å£°ããŒã¿ã確èªããŠã¿ãŸãããã "path" ã«å®éã®é³å£°ããŒã¿ãæ ŒçŽãããŠãããã¡ã€ã«ã®å ŽæãèšèŒãããŠããŸãã ããããæ¢ã«"audio" ã«é³å£°ãã¡ã€ã«ã®äžèº«ã®ãã€ããªããŒã¿ãæ ŒçŽãããŠããã®ã§ã äžèšã®éã "audio" ã®äžèº«ãé©åã«åŠçããããšã§é³å£°ããŒã¿ãåçã§ããŸãã import IPython.display as ipd import numpy as np import random rand_int = random.randint(0, len(common_voice_train)-1) ipd.Audio(data=common_voice_train[rand_int]["audio"]["array"], autoplay=True, rate=16000) ããã¹ãããŒã¿ã®ç¢ºèª é³å£°ããŒã¿ãã©ããªå
容ã話ããŠãããã¯ã"sentence" ã®äžã«èšèŒãããŠããŸãã ä»åã¯å¥èªç¹ãé€ããç¶æ
ã§ãã¥ãŒãã³ã°ãè¡ãã®ã§ãå¥èªç¹ãªã©ã®äžèŠãªèšå·ãé€å»ãã颿°ãäœæããããã¹ããæŽåœ¢ããŸãã import re chars_to_ignore_regex = '[ã,ã]' def remove_special_characters(batch): batch["sentence"] = re.sub(chars_to_ignore_regex, '', batch["sentence"]).lower() + " " return batch common_voice_train = common_voice_train.map(remove_special_characters) common_voice_test = common_voice_test.map(remove_special_characters) ããã§ãããŒã¿ã»ããã®äžèº«ãã©ã³ãã ã«10æåºåãã颿°ãäœæããŠã衚瀺ããŠã¿ãŸãã 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())) show_random_elements(common_voice_test.remove_columns(["path","audio"])) sentence 0 ãã®ã«ã¬ãŒã¯ãšãŠãèŸãã§ã 1 ããŒãã³ã¯ã€ãŒã¹ããã³ãã®ã£ã³ã°ã®ã¹ããŒã¯ã€ãŒãžãŒã®äžããããè³è³ãåã£ãŠãããšãåããã 2 æ¯ã¯ãã€ããããã«è²·ãç©ãé Œã¿ãŸã 3 å±ãªãã®ã§ãã¡ããžè¡ããªãã§ãã ãã 4 ããã¯ãããŠãäžæéã«ãåã¶ 5 äžæºãããã ã¡ã¯ãã£ã±ãåéšã身ã®ãŸããã«åããããŠãã 6 æ¥æã®åãåœãžåž°ããŸã 7 ãã®ç®±ã¯ãšãŠãéãã§ã 8 åšã®ãã£ã¢ã³ã»ã§ããã€ã ãã«ã¯ã©ãããŠãè² ããããªã 9 ãã¡ã®äžåŠã¯åŒåœå¶ã§æã£ãŠè¡ããªãå Žåã¯äºååã®åŠæ ¡è²©å£²ã®ãã³ãè²·ã å¥èªç¹ãé€å»ãããŠããããšã確èªã§ããŸããã ããã§ãå¿
èŠãªé³å£°ããŒã¿ãšããã¹ãæ
å ±ã®ã»ããã®æºåãã§ããŸããã åŠç¿ããŒã¿ã®å€æïŒããªæŒ¢åã»ã«ãã»ããŒãåïŒ æ¬¡ã«ã3ãã¿ãŒã³ã®ããŒã¿ã»ãããçšæããããšæããŸãã 1ã€ç®ã¯åç¯ã§çšæããããŒã¿ã»ããïŒããªæŒ¢åæïŒããã®ãŸãŸäœ¿çšãããã®ã 2ã€ç®ã¯ããªæŒ¢åæãã«ãæã«å€æãããã®ã 3ã€ç®ã¯ã«ãæãããŒãåã«å€æãããã®ã§ãã ããªæŒ¢åæãã«ãæã«å€æããããã«ã圢æ
çŽ è§£æåšã䜿çšããŸãã ä»å㯠MeCab ãšããæåãªåœ¢æ
çŽ è§£æã©ã€ãã©ãªã䜿çšããŸãã ãŸãã¯MeCabã䜿çšããŠã¿ãŸãããã import MeCab import unidic import romkan mecab = MeCab.Tagger() sentence = common_voice_train[0]['sentence'] print(sentence) print(mecab.parse(sentence)) äºæ³å€ã®äºæ
ã«é»åäŒç€Ÿãã¡ãã£ãŽãå°ææ°å³ã äºæ³ åè©,æ®éåè©,ãµå€å¯èœ,,,,ãšãœãŠ,äºæ³,äºæ³,ãšãœãŒ,äºæ³,ãšãœãŒ,挢,"","","","","","",äœ,ãšãœãŠ,ãšãœãŠ,ãšãœãŠ,ãšãœãŠ,"0","C2","",10819203040944640,39360 å€ æ¥å°ŸèŸ,åè©ç,äžè¬,,,,ã¬ã€,å€,å€,ã¬ã€,å€,ã¬ã€,挢,"","","","","","",æ¥å°Ÿäœ,ã¬ã€,ã¬ã€,ã¬ã€,ã¬ã€,"","C3","",2169894821044736,7894 ã® å©è©,æ Œå©è©,,,,,ã,ã®,ã®,ã,ã®,ã,å,"","","","","","",æ Œå©,ã,ã,ã,ã,"","åè©%F1","",7968444268028416,28989 äºæ
åè©,æ®éåè©,äžè¬,,,,ãžã¿ã€,äºæ
,äºæ
,ãžã¿ã€,äºæ
,ãžã¿ã€,挢,"","","","","","",äœ,ãžã¿ã€,ãžã¿ã€,ãžã¿ã€,ãžã¿ã€,"1","C1","",4922247303275008,17907 ã« å©è©,æ Œå©è©,,,,,ã,ã«,ã«,ã,ã«,ã,å,"","","","","","",æ Œå©,ã,ã,ã,ã,"","åè©%F1","",7745518285496832,28178 é»å åè©,æ®éåè©,äžè¬,,,,ãã³ãªã§ã¯,é»å,é»å,ãã³ãªã§ã¯,é»å,ãã³ãªã§ã¯,挢,"","","","","","",äœ,ãã³ãªã§ã¯,ãã³ãªã§ã¯,ãã³ãªã§ã¯,ãã³ãªã§ã¯,"0,1","C2","",7095706913481216,25814 äŒç€Ÿ åè©,æ®éåè©,äžè¬,,,,ã«ã€ã·ã£,äŒç€Ÿ,äŒç€Ÿ,ã«ã€ã·ã£,äŒç€Ÿ,ã«ã€ã·ã£,挢,"ã«æ¿","åºæ¬åœ¢","","","","",äœ,ã«ã€ã·ã£,ã«ã€ã·ã£,ã«ã€ã·ã£,ã«ã€ã·ã£,"0","C2","",1577258053673472,5738 ã å©è©,ä¿å©è©,,,,,ã¢,ã,ã,ã¢,ã,ã¢,å,"","","","","","",ä¿å©,ã¢,ã¢,ã¢,ã¢,"","åè©%F2@-1,圢容è©%F4@-2,åè©%F1","",10324972564259328,37562 ã¡ãã£ãŽã å¯è©,,,,,,ãã§ãããª,ã¡ãã£ãŽã,ã¡ãã£ãŽã,ãã§ãããª,ã¡ãã£ãŽã,ãã§ãããª,å,"","","","","","",çž,ãã§ãããª,ãã§ãããª,ãã§ãããª,ãã§ãããª,"3","","",6652053971673600,24200 å°æ åè©,æ®éåè©,ãµå€å¯èœ,,,,ã³ã³ã¯ã¯,å°æ,å°æ,ã³ã³ã¯ã¯,å°æ,ã³ã³ã¯ã¯,挢,"","","","","","",äœ,ã³ã³ã¯ã¯,ã³ã³ã¯ã¯,ã³ã³ã¯ã¯,ã³ã³ã¯ã¯,"0","C2","",3654785274356224,13296 æ°å³ åè©,æ®éåè©,äžè¬,,,,ãã,æ°å³,æ°å³,ã®ã,æ°å³,ã®ã,挢,"ãæ¿","æ¿é³åœ¢","","","","",äœ,ã®ã,ã®ã,ã®ã,ãã,"2","C3","",2424706640790016,8821 ã å©åè©,,,,å©åè©-ã,çµæ¢åœ¢-äžè¬,ã,ã ,ã ,ã,ã ,ã,å,"","","","","","",å©å,ã,ã,ã,ã,"","åè©%F1","",6299110739157675,22916 EOS ããªæŒ¢åæããã«ãæãžã®å€æ äžèšããåŸãããåºåã®ãã¡ãã«ãã®æ
å ±ã ããéããŠ1ã€ã®æã«ç¹ãçŽãããã®é¢æ°ãäœæããŸãã def convert_sentence_to_kana(batch): s = mecab.parse(batch["sentence"]) kana = "" for line in s.split("\n"): if line.find("\t")<=0: continue columns = line.split(',') if len(columns) < 10: kana += line.split('\t')[0] else: kana += columns[9] batch["kana"] = kana return batch äžæ Œå¥œãªé¢æ°ã§ãããããã§ä»å䜿çšããæ¥æ¬èªããŒã¿ã®ããã¹ããå
šãŠã«ãæã«å€æã§ããŸãã æ³šæããç¹ãšããŠãããšããšã«ã¿ã«ãã ã£ãåèªãªã©ã¯èªã¿ã®æ
å ±ãåºåãããªãã®ã§ã å ŽååããããŠå
ã®è¡šèšããã®ãŸãŸäœ¿çšããããã«ããŠããŸãã ã§ã¯ãæ£ããåŠçãã§ãããã©ãã確èªããŠã¿ãŸãããã show_random_elements(common_voice_test.remove_columns(["path","audio"])) sentence kana 0 人ã
ã¯è±ã®èãçš®ãçŒåŽãçã®è±ãå
šéšæããšã£ãŠããŸã ããããã¯ãããããšã€ã¿ããªã·ã§ãŒãã£ã¯ã·ãã¿ã±ããããªãŒã³ããããããã·ã㊠1 æ¯æ¥å¿ããã®ã§ããŸãäŒãããšãã§ããŸãã ãã€ããã€ãœã¬ã·ãŒããã¢ããªã€ã¹ã ã³ãã¬ãããã»ã³ 2 女æ§ãšã¯éã§äœãšãåžžèãç Žã£ãŠãã ã£ãŠããããšææ°èŸŒã人ãã»ãšãã©ã ãžã§ã»ãŒãã¯ã®ã£ã¯ããã³ãã«ãžã§ãŒã·ããªã€ãããã¡ãããã€ããŒãã€ããŽã ããã¬ããã³ãã 3 现é·ãæå
ã§æ¿ããéµãå©ã ããœãã¬ã€ãŠããµãããã²ã·ã¯ã«ã®ãªã¿ã¿ã¯ 4 ã¯ã£ãŒã³ãºã¢ããã¥ãŒã¢ã«ãã¡ã«æå±ããŠãã ã¯ã£ãŒã³ãºã¢ããã¥ãŒã¢ã«ãã¡ãã·ã§ãŸã¯ã·ãã€ã« 5 å±±ç°ããã¯æ¥ææ±äº¬ãžè¡ãããã§ã ã€ãããµã³ã¯ã©ã€ã²ãããŒãã§ãŒãšã€ã¯ãœãŒãã¹ 6 éçã®åŸã®ããŒã«ãããããŸããã®ã¯ãªã ã€ãã¥ãŒãã¢ããããŒã«ã°ã©ã€ãŠãã€ã¢ãã¯ã〠7 å±±ç°ããã¯ããããã人ã§ã ã€ãããµã³ã¯ãªã¢ã·ãã€ãããã¹ 8 ãããã¯æããžãã§ã ã¯ã¿ã·ã¯ãŠã¿ã¬ãã¿ãã¹ 9 ç±ããè¶ã飲ã¿ããã§ã ã¢ãã€ãªãã£ã¬ããã¿ã€ãã¹ ã«ãæããããŒãåæãžã®å€æ ã«ãæãžã®å€æãã§ããããããŒãåæãžã®å€æã¯ç°¡åã§ãã ã«ããšããŒãåã倿ããŠããã romkan ã©ã€ãã©ãªã䜿ããŸãã def convert_sentence_to_roman(batch): s = mecab.parse(batch["sentence"]) kana = "" for line in s.split("\n"): if line.find("\t")<=0: continue columns = line.split(',') if len(columns) < 10: kana += line.split('\t')[0] else: kana += columns[9] roman = romkan.to_roma(kana) batch["roman"] = kana return batch ãã¡ããæ£ãã倿ãã§ããã確èªããŠã¿ãŸãããã # "kana" ã¯éªéãªã®ã§é€ããŠãã show_random_elements(common_voice_test.remove_columns(["path","audio", "kana"])) sentence roman 0 ã€ããã¯ãããã²ããŠããã®ã§å
æ°ãããããŸãã isanwakazeohi-teirunodegenkijaarimasen 1 ãã¥ã¬ã³ãã«ãé ã¯ãŽã¥ã«ãã³ãã«ã¯é ã«ç·šå
¥ããã tsuxyurenharutoryo-wabyurutenberukuryo-nihen'nyu-sareta 2 èªç©ºäºæ
ãéããªããŒãã«è¿ã¥ããã«ã¯ããã»ã©ãªãæ¯ãããŸãã¬åªåããã ko-ku-jikookagirinakuzeronichikazukeruniwasorehodonarifurikamawanudoryokugairu 3 ãåæ¹ããããããšç»å Žãæçž®ãã oerakatagazokuzokutoto-jo-shikyo-shukusuru 4 å°æããã¯éãåãæã£ãŠããŸã kobayashisanwaaoikasaomotteimasu 5 å·èµåº«ã«åµãéèãæç©ãªã©ããããŸã re-zo-konitamagoyayasaiyakudamononadogaarimasu 6 ãã®çµµã¯è²ããããã§ã konoewairogakire-desu 7 ãã³ã·ã«ããã¢å·ãã£ã©ãã«ãã£ã¢ã®éå€ãŠã£ã³ãŠããã®ã©ã³ã±ããŠç
é¢ã§çãŸãã penshirubeniashu-firaderufianoko-gaiwin'uddonorankenaubyo-indeumareta 8 å±ãªãã®ã§ãããã®çªãéããŠã¯ãããŸãã abunainodeasokonomadooaketewaikemasen 9 å
æãããã¯äŒç€ŸããããŸãã sengetsuwatashiwakaishaoyamemashita Tokenizerã®äœæ ããããã¯çšæããæ¥æ¬èªããŒã¿ã»ããã䜿ã£ãŠãFine Tuning ããããã®æºåãé²ããŠãããŸãã äºååŠç¿ããã wav2vec 2.0 ã®ã¢ãã«ã¯ãèšèªéäŸåã®ã¢ãã«ãªã®ã§åºåãæ¥æ¬èªã«å¯Ÿå¿ããŠããŸããã åºåãæ¥æ¬èªããŒã¿ã»ããã®åœ¢åŒã«åãããããã«ãå°çšã® Tokenizer ãšãããã®ãäœæããå¿
èŠããããŸãã ãã®æºåã®ããã«ãããã¹ãããŒã¿ã1æåãã€ã«åå²ããŠãéè€ãé€å»ãããã®ã vocab_dict_{sentence|kana|roman} ã«èŸæžåœ¢åŒã§æ ŒçŽããŸãã 3ãã¿ãŒã³ã®èŸæžïŒvocab_dictïŒãäœæããŠããã³ãŒãïŒã¯ãªãã¯ãããšéããŸãïŒ def extract_all_chars_sentence(batch): all_text = " ".join(batch["sentence"]) vocab = list(set(all_text)) return {"vocab": [vocab], "all_text": [all_text]} def extract_all_chars_kana(batch): all_text = " ".join(batch["kana"]) vocab = list(set(all_text)) return {"vocab": [vocab], "all_text": [all_text]} def extract_all_chars_kana(batch): all_text = " ".join(batch["roman"]) vocab = list(set(all_text)) return {"vocab": [vocab], "all_text": [all_text]} vocab_train_sentence = common_voice_train.map(extract_all_chars_sentence, batched=True, batch_size=-1, keep_in_memory=True, remove_columns=common_voice_train.column_names) vocab_test_sentence = common_voice_test.map(extract_all_chars_sentence, batched=True, batch_size=-1, keep_in_memory=True, remove_columns=common_voice_test.column_names) vocab_list_sentence = list(set(vocab_train_sentence["vocab"][0]) | set(vocab_test_sentence["vocab"][0])) vocab_dict_sentence = {v: k for k, v in enumerate(vocab_list_sentence)} vocab_train_kana = common_voice_train.map(extract_all_chars_kana, batched=True, batch_size=-1, keep_in_memory=True, remove_columns=common_voice_train.column_names) vocab_test_kana = common_voice_test.map(extract_all_chars_kana, batched=True, batch_size=-1, keep_in_memory=True, remove_columns=common_voice_test.column_names) vocab_list_kana = list(set(vocab_train_kana["vocab"][0]) | set(vocab_test_kana["vocab"][0])) vocab_dict_kana = {v: k for k, v in enumerate(vocab_list_kana)} vocab_train_roman = common_voice_train.map(extract_all_chars_roman, batched=True, batch_size=-1, keep_in_memory=True, remove_columns=common_voice_train.column_names) vocab_test_roman = common_voice_test.map(extract_all_chars_roman, batched=True, batch_size=-1, keep_in_memory=True, remove_columns=common_voice_test.column_names) vocab_list_roman = list(set(vocab_train_roman["vocab"][0]) | set(vocab_test_roman["vocab"][0])) vocab_dict_roman = {v: k for k, v in enumerate(vocab_list_roman)} ããããã®èŸæžã®æ°ãèŠãŠã¿ãŸãããã len(vocab_dict_sentence), len(vocab_dict_kana), len(vocab_dict_roman) (1432, 82, 30) ããªæŒ¢åæã®å Žåã¯ã挢åãããããå«ãŸããŠããã®ã§ãããªãã®æ°ã«ãªããŸãã ã«ãæãããŒãåã®å Žåã¯æŒ¢åãèªã¿ã«å€æããŠããã®ã§ã æ
å ±éãèœã¡ãŠãã代ããã« vocab_dict ã®æ°ãæããããŠããŸãã ããããã¯ã3çš®é¡ã®ããŒã¿ã»ããã§è¡ãåŠçãå
šãåããªã®ã§ãvocab_dict_{sentence|kana|roman} ã vocab_dict ã«çµ±äžããŠèšèŒããŸããå®éã«åããå Žåã¯ãããããèªã¿æ¿ããŠãã ããã vocab_dict ã«ãã®ããšã®åŠçã§å¿
èŠãªãæªç¥èªãæå³ãã"[UNK]"ãšã空çœãæå³ãã"[PAD]"ã远å ããŠãjsonãã¡ã€ã«ã«åºåããŸãã CTC(Connectionist Temporal Classification)ãšããã¢ã«ãŽãªãºã ã§ãé³å£°ã®æç³»åãšããã¹ãã®å¯Ÿå¿ãèšç®ããéã«å¿
èŠãªåŠçã§ããïŒ https://distill.pub/2017/ctc/ ïŒ vocab_dict["[UNK]"] = len(vocab_dict) vocab_dict["[PAD]"] = len(vocab_dict) import json with open('vocab.json', 'w') as vocab_file: json.dump(vocab_dict, vocab_file) åºåããjsonãã¡ã€ã«ã䜿çšããŠãTokenizer ãäœæããŸãã from transformers import Wav2Vec2CTCTokenizer tokenizer = Wav2Vec2CTCTokenizer("./vocab.json", unk_token="[UNK]", pad_token="[PAD]", word_delimiter_token="|") Feature Extractor ã®äœæ 次ã«ãé³å£°ããŒã¿ãäºååŠç¿ã¢ãã«ã«å
¥åã§ãã圢ã«å€æããããã® Feature ExtractorãäœæããŸãã from transformers import Wav2Vec2FeatureExtractor feature_extractor = Wav2Vec2FeatureExtractor(feature_size=1, sampling_rate=16000, padding_value=0.0, do_normalize=True, return_attention_mask=True) ãããã䜿ãäºååŠç¿ã¢ãã«ã¯ãµã³ããªã³ã°ã¬ãŒã16000Hzã§åŠç¿ãããŠããã®ã§ãsampling_rate 㯠16000 ã«èšå®ããå¿
èŠããããŸãã ãã®åŸã®åŠçãç°¡åã«ããããã«ãFeature Extractor ãš Tokenizer ããŸãšãã Processor ãäœæããŸãã from transformers import Wav2Vec2Processor processor = Wav2Vec2Processor(feature_extractor=feature_extractor, tokenizer=tokenizer) ããŒã¿ã®ååŠç common_voice ããŒã¿ã»ããã®é³å£°ããŒã¿ã¯16000Hzã§ã¯ãªããããããªãã®ã§ãå
šéš16000Hzã«ãªãµã³ããªã³ã°ããŸãã common_voice_train = common_voice_train.cast_column("audio", Audio(sampling_rate=16_000)) common_voice_test = common_voice_test.cast_column("audio", Audio(sampling_rate=16_000)) ããã§å
ã»ã© tokenizer ãš feature Extractor ããŸãšãã processor ã䜿ã£ãŠãé³å£°ããŒã¿ãšæžãèµ·ããæããã®åŸåŠçãããã圢ã«å€æããŸãã def prepare_dataset(batch): audio = batch["audio"] # batched output is "un-batched" batch["input_values"] = processor(audio["array"], sampling_rate=audio["sampling_rate"]).input_values[0] with processor.as_target_processor(): batch["labels"] = processor(batch["sentence"]).input_ids return batch common_voice_train = common_voice_train.map(prepare_dataset, remove_columns=common_voice_train.column_names, num_proc=4) common_voice_test = common_voice_test.map(prepare_dataset, remove_columns=common_voice_test.column_names, num_proc=4) åŠç¿ãšæšè« data collector ãå®çŸ©ããŸãããã以éã®åŠç¿åŠçã¯åºæ¬çã«åèã«ããèšäºãšåãã«ããŠããŸãã data collector ã®è©³çް import torch from dataclasses import dataclass, field from typing import Any, Dict, List, Optional, Union @dataclass class DataCollatorCTCWithPadding: """ Data collator that will dynamically pad the inputs received. Args: processor (:class:`~transformers.Wav2Vec2Processor`) The processor used for proccessing the data. padding (:obj:`bool`, :obj:`str` or :class:`~transformers.tokenization_utils_base.PaddingStrategy`, `optional`, defaults to :obj:`True`): Select a strategy to pad the returned sequences (according to the model's padding side and padding index) among: * :obj:`True` or :obj:`'longest'`: Pad to the longest sequence in the batch (or no padding if only a single sequence if provided). * :obj:`'max_length'`: Pad to a maximum length specified with the argument :obj:`max_length` or to the maximum acceptable input length for the model if that argument is not provided. * :obj:`False` or :obj:`'do_not_pad'` (default): No padding (i.e., can output a batch with sequences of different lengths). max_length (:obj:`int`, `optional`): Maximum length of the ``input_values`` of the returned list and optionally padding length (see above). max_length_labels (:obj:`int`, `optional`): Maximum length of the ``labels`` returned list and optionally padding length (see above). pad_to_multiple_of (:obj:`int`, `optional`): If set will pad the sequence to a multiple of the provided value. This is especially useful to enable the use of Tensor Cores on NVIDIA hardware with compute capability >= 7.5 (Volta). """ processor: Wav2Vec2Processor padding: Union[bool, str] = True max_length: Optional[int] = None max_length_labels: Optional[int] = None pad_to_multiple_of: Optional[int] = None pad_to_multiple_of_labels: Optional[int] = None 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 lenghts and need # different padding methods input_features = [{"input_values": feature["input_values"]} for feature in features] label_features = [{"input_ids": feature["labels"]} for feature in features] batch = self.processor.pad( input_features, padding=self.padding, max_length=self.max_length, pad_to_multiple_of=self.pad_to_multiple_of, return_tensors="pt", ) with self.processor.as_target_processor(): labels_batch = self.processor.pad( label_features, padding=self.padding, max_length=self.max_length_labels, pad_to_multiple_of=self.pad_to_multiple_of_labels, 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) batch["labels"] = labels return batch data_collator = DataCollatorCTCWithPadding(processor=processor, padding=True) äºååŠç¿ãããã¢ãã«ãçšæããŸãã ä»åã¯ãwav2vec2-large-xlsr-53 ãšãã53èšèªã®ããŒã¿ãçšããŠäºååŠç¿ãããå€§èŠæš¡ã¢ãã«ã䜿çšããŠããŸãã ã¢ãã«ã®è©³çް from transformers import Wav2Vec2ForCTC model = Wav2Vec2ForCTC.from_pretrained( "facebook/wav2vec2-large-xlsr-53", attention_dropout=0.1, hidden_dropout=0.1, feat_proj_dropout=0.0, mask_time_prob=0.05, layerdrop=0.1, ctc_loss_reduction="mean", pad_token_id=processor.tokenizer.pad_token_id, vocab_size=len(processor.tokenizer) ) # Fine Tuning ã§ Feature Extractor ãå€åããªãããã«èšå®ãå
¥ãã model.freeze_feature_extractor() åŠç¿æã®èšå®å€ã決ããŸãã from transformers import TrainingArguments training_args = TrainingArguments( output_dir="./wav2vec2-large-xlsr-japanese-demo", group_by_length=True, per_device_train_batch_size=16, gradient_accumulation_steps=2, evaluation_strategy="steps", num_train_epochs=30, fp16=True, save_steps=100, eval_steps=100, logging_steps=10, learning_rate=3e-4, warmup_steps=500, save_total_limit=2, ) ä»ãŸã§äœæããŠãããã®ã䜿ã£ãŠãTrainer ãäœæããŸãã from transformers import Trainer trainer = Trainer( model=model, data_collator=data_collator, args=training_args, train_dataset=common_voice_train, eval_dataset=common_voice_test, tokenizer=processor.feature_extractor, ) ãããŸã§ãç²ãæ§ã§ããã åŸã¯å®éã«åŠç¿ãå®è¡ããŠãæ³å®ãããã®ãæ£ããã§ããŠãããã確èªããã ãã§ãã ç§ã®ç°å¢ã§ã¯åŠç¿ã«2æéã»ã©ããããŸããã trainer.train() åŠç¿æã®åºåäŸïŒã«ãæã®å ŽåïŒ Step Training Loss Validation Loss 100 11.832900 9.277085 200 4.031800 4.175367 300 3.988200 4.157576 400 3.896900 4.027470 500 3.612100 3.709400 600 1.262500 1.241253 700 0.588300 0.966568 800 0.411600 0.989113 900 0.343900 0.975543 1000 0.280400 1.019831 1100 0.268400 0.964782 1200 0.282000 0.991331 ããã§ã¯ãåŠç¿ãã3çš®é¡ã®ã¢ãã«ã«ã€ããŠããããããã¹ãããŒã¿ãå
¥åããŠã©ã®ãããªæååãåºåããããã確èªããŠã¿ãŸãããã ã«ãæŒ¢åæ pred_str text å
ãã®ã¯ããã¯ããŸãããŠã§ãã å
çã®è©±ã¯æå³ãåãããŸããã§ãã å
æ¥ã®ã«ãæ¥ãšãããããŸã å
çã®æºã®äžã«èŸæžãäºåãšéèªãäžåãããŸã ããªã§ãŸã©ãããŸã å°ãæãã®ã§çªãéããŸã ããã®ã«ãšããããŸã ãã°ãã®äžã«ããŒãããããŸã ãåãšãŠãããŸãã äºå¹Žå劻ãšçµå©ããŸãã ã¹ã¯ãããããã©ãšãããã ãããããããããããšãããããããã å
ãã®ãæ¬ãããŸãã å
é±å§ã®çµå©ããŒãã£ãŒããããŸãã ããããã®ããã¯ã®åŠãã«ããããããŸã åæ
æãããååã®å¿ã¯å°æ¥ã®ç€ŸäŒç掻ã«åŒ·ã圱é¿ãåãŒããŸã èªè粟床ã¯ãäžèŸã«ãè¯ããšã¯èšããŸããã ãã®çç±ãšããŠã¯ãvocab_dict ã®æ°ãå€ããåãæŒ¢åãåºçŸããããšãå°ãªãããã«åŠç¿ãããŸããããªãã£ãããšãæãããããã§ãã ãŸãåŠç¿ããŒã¿ã®äžã«åºçŸããªãã£ã挢åãããã¹ãããŒã¿ã®äžã«åºçŸããŠãããã§ããã ã«ãæ pred_str text ã»ã³ã»ãŒããã·ã¯ã€ãŒãã«ã¯ã«ããã»ã³ãã·ã¿ ã»ã³ã»ãŒãããã·ã¯ã€ãã¬ã¯ã«ãªãã»ã³ãã·ã¿ ã»ã³ã»ãŒããã¯ãšããŠãšããã·ã§ã¬ããµããããã·ã¬ã€ããµãã¢ãªãã¹ ã»ã³ã»ãŒããã¯ãšããŠãšããžã·ã§ã¬ããµããã¶ãã·ã¬ã€ããµãã¢ãªãã¹ ã¹ã³ã·ã¢ãã€ãããããªã¬ã¢ããã¹ ã¹ã³ã·ã¢ãã€ãããããªã¢ã±ãã¹ ã³ãã³ããã«ãããŒãã¬ã¢ãªãã¹ ã«ãã³ããã«ãããŒãã¬ã¢ãªãã¹ ãŽãã³ããšãããã±ãã³ã³ã·ãã·ã¿ ãŽãã³ãŒã³ãµã€ãã±ãã³ã³ã·ãã·ã¿ ããã¬ã¢ã«ã«ã©ãªã£ããŒããµã³ã¶ã³ãªã¯ã¬ã¿ ããã¬ã¢ã«ã«ã©ã€ã¡ãããµã³ã¶ã³ã€ã¯ã¬ã¿ ã»ã³ãã¥ãŒã¢ããã±ãã³ã³ããŒãã€ã¬ã¢ãªãã·ã¿ ã»ã³ã·ã¥ãŒã¢ããã±ãã³ã³ããŒãã£ãŒã¬ã¢ãªãã·ã¿ ãŠãŒãžã§ãŒãªã¢ã¢ãªãã§ãŒã«ã¯ãã³ã³ãã¯ã·ã§ãŒã©ã€ãã·ã£ã«ã€ã»ãŒã«ãããºãšã€ãšãŒãã§ãŒãªãªãŒãã·ãã¹ ãŠãŒãžã§ãŒãªã¢ã€ã€ãªãã§ãŒãªã§ã¯ãã³ã³ãã¯ã·ã§ãŒã©ã€ãã·ã£ã«ã€ã»ãŒã«ããããšã€ãšãŒãã§ãŒãªãªãšãã·ãã¹ ã«ã¬ããœãããã³ã«ãªãããã±ãã±ãããµã©ããã¬ãªãµã¡ã¿ ã«ã¬ã¢ã·ã§ãã¥ãŒãªãã³ã«ã€ãã·ãã²ãããããµãšãã©ã¬ããªãªãµã¡ã¿ ãããã³ãã¯ã¿ãã¿ãŒã¬ããšã€ãã¹ ãããã³ãã¯ã·ã¥ã³ããŒã¬ããšã€ãã¹ äžèŠãããã«ããã§ãããã«ã挢åæãšæ¯èŒããŠé³ã綺éºã«æšæž¬ã§ããŠãããšèšãããã§ãã äžæ¹ã§ãããŸããããªãã£ãã±ãŒã¹ããããŸããã äŸãã°æåŸã®æã¯ãããªæŒ¢åæã ãšãæ¥æ¬ã§ã¯æ¥é¢šã匷ãã§ããã§ããã é³å£°ã¯ãã·ã¥ã³ããŒãã§ã¯ãªãããã«ã«ãŒããšèªãã§ãããšæãããŸãã 圢æ
çŽ è§£æã®ãã¹ã«ãã£ãŠããŒã¿ã«ãã€ãºãå«ãŸããŠããããšã瀺åãããŸãã ãããã³ãã¯ã¿ãã¿ãŒã¬ããšã€ãã¹ ãããã³ãã¯ã·ã¥ã³ããŒã¬ããšã€ãã¹ ããŒãå pred_str text sensu-noharashiwai-mikawakaremasenteshita sensu-nohekuta-runazuhiwaimigawakarimasendeshita sense-notsukuenoueniiichishogan'isatsutoyasshigaissatsuarimasu sensu-nottosukuenouenijizuhogan'izuattosutozasshigaissatsuarimasu sok-shiwatsunademadogaakemasu sukoshiatsuinodemadooakemasu gabannonakanio-togaarimasu kabannonakanino-togaarimasu gonenmaeimatokekonshimashita go-nenzensaitokekkonshimashita terogaaa-rukararyajho-tosanzaniwareta terogaarukarayamerotosanzaniwareta senkyu-anenokekkonpa-teigaarimashita senshu-anenokekkonpa-ti-gaarimashita yu-jo-omoiarikyo-rukunokokorowasho-rainoshakaise-katshunizuyoie-kyo-oooboshimasu yu-jo-omoiyarikyo-ryokunokokorowasho-rainoshakaise-katsunitsuyoie-kyo-ooyoboshimasu tarnoosokyrohponru-ridat-tsute-kekikekunasarananakakuo-sameta karemoshokyu-ohon'a-ruyu-aidi-azuhittoegekittoekinasayonaragachioosameta nippondewatabikazegatsugyoidesu nippondewashunpu-gatsuyoidesu ã«ãæããããã«èªã¿ã¥ããã¯ãããŸãããæ¯èŒçããŸããã£ãŠãããã§ãã ããŒãåã®äžã«ã·ã³ã°ã«ã¯ãªãŒãã'ããå«ãŸããŠããŸãããããã¯äŸãã°ãããããšãã«ããåºå¥ããããã®èšå·ã§ãã ãããã« ãã®èšäºã§ã¯ãæè»œã«èªåã ãã®é³å£°èªèã¢ãã«ãæ§ç¯ããæ¹æ³ã«ã€ããŠã玹ä»ããŸããã æ¥æ¬èªããŒã¿ã»ãããæŽåããŠãããªæŒ¢åã»ã«ãã»ããŒãåã®ããããã§ã©ã®ãããªã¢ãã«ãçæã§ããã®ãã確èªããŸããã ã«ã挢åæããã®ãŸãŸäœ¿ãå Žåã¯ä»åã®ãããªã·ã³ãã«ãªããæ¹ã ãšããŸããããŸããã§ããã ã«ãæãšããŒãåæã®å Žåã¯ãèªèç²ŸåºŠãæ¯èŒçé«ãã¢ãã«ãã§ããŸããã ãã ããåºåãããæãã«ãã»ããŒãåã®ãŸãŸã«ãªã£ãŠããŸãã®ã§ã å®çšã«ããã£ãŠã¯ãåŸåŠçã§ã«ã挢åæã«å€æãããªã©ã®å¯Ÿå¿ãå¿
èŠã§ãã ãŸããä»åã¯èšèªã¢ãã«ã䜿çšããã«ã·ã³ãã«ã«é³å£°ããŒã¿ãšããã¹ãæ
å ±ã®å¯Ÿå¿ããšããŸããã äºååŠç¿æžã¿ã®èšèªã¢ãã«ã䜿çšããããšã§åèªã®ååŸé¢ä¿ãæèãèæ
®ããããé«ãæ§èœã®é³å£°èªèã¢ãã«ãæ§ç¯ã§ãããšèããããŸãã å€§èŠæš¡ããŒã¿ã»ããã§åŠç¿ãããé³å£°èªèã¢ãã«ãç¡åã§èª°ã§ã䜿ãããªããŠãçŽ æŽãããæä»£ã«çãŸãããšæããŸãã èªåã§é³å£°èªèã¢ãã«ããã¥ãŒãã³ã°ã§ããããšã§ãé³å£°èªèãµãŒãã¹ã®ãã©ã€ã¢ã³ããšã©ãŒãã©ãã©ãåãããšãå¯èœã«ãªããšæåŸ
ããŠããŸãã ä»åã玹ä»ããææ³ã¯ãŸã ãŸã æ¹åã®äœå°ãããã®ã§ãåŒãç¶ãæè¡æ€èšãé²ããããšæããŸãã ããã§ã¯ãææ¥ã®èšäºããæ¥œãã¿ã«ïŒ åèã«ãããã® https://maelfabien.github.io/machinelearning/wav2vec/ https://huggingface.co/blog/fine-tune-wav2vec2-english/ https://tech.fusic.co.jp/posts/2021-03-30-wav2vec-fune-tune/