ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Coqui TTS (XTTS-v2) 한국어 Fine-Tuning
    논문 후기와 구현 2024. 9. 3. 10:45

    Coqui TTS (쿠키 TTS)

    일단 Coqui TTS로는 다음을 할 수 있다:

    - 음성 생성

    - 음성 클로닝 (커스텀 TTS)

    - 음성 Conversion (커스텀 TTS)

     

    그런데 황망한 소식부터 전하자면, Coqui TTS24년 1월 운영중단되었다. GitHub에서 clone해와서 쓸 수는 있지만, 모델이 더 이상 업데이트되지는 않을 것이다. 이제 쓸만한 오픈소스 TTS는 OpenVoice 밖에 남지 않았다. 사실 굳이 AI 공부를 하려는 것이 아니고, 그저 고성능 Voice Cloning TTS(특히, 한국어)가 필요할 뿐이라면 Elevenlabs에서 유료로 사용하는 것을 추천한다. 한국어 성능도 이미 굉장히 좋아서, 한국어 Fine-tuning이고 나발이고 그냥 서비스를 갖다 쓰기만 하면 되니 이보다 더 편할 수가 없다.

     

    그래도 한번 Fine-tuning을 해보고 싶다면

    모델 Fine-tuning은 굉장히 좋은 경험이다. 일반인이 가지고 있을만한 고성능 노트북에서 이제 모델 training은 먼나라 이야기가 되었고, 그나마 해볼 수 있는 게 fine-tuning일 뿐이니까. 솔직히 요즘 논문 읽어보면 연구들도 fine-tuning이 대부분이다.... 슬픈현실

     

    Coqui XTTS-v2는 한국어가 가능하다고 주장하지만, 무슨 북한어나 중국 조선어를 말하듯이 생성된다 (비하 아님). 널린 게 K-drama 데이터셋일 텐데, 왜 그렇게 학습이 되었는지 잘 모르겠다.

     

    어쨌든, 이 포스트를 읽는다면, AI Hub에서 아나운서 발화 데이터셋을 받아 XTTS-v2를 Fine-tuning하여 남한어처럼 말할 수 있도록 fine-tuning을 해볼 수 있을 것이다. 과정이 좀 복잡하니 잘 따라오자. 당연히 CUDA, PyTorch 등 기본환경은 구성되어 있어야 한다.

     

    생각보다 fine-tuning된 모델의 한국어 성능이 괜찮으니, 시도해봄직하다. 단, GPU나 컴퓨터 용량은 충분해야 한다. 나의 경우에는 Nvidia GeForce RTX 4090 Laptop GPU, 32GB RAM을 갖춘 Windows 11 노트북에서 구동하였다. 또한 기기에 200GB 이상의 충분한 여유공간이 있어야 한다.


    0. 데이터셋 다운로드

    여기에서 우선 데이터셋을 받아보자. 아나운서의 음성(.wav) - 대응 텍스트(.json) 형식이므로, 어떤 텍스트에 대한 정확한 발음과 어조, 말투를 fine-tuning할 수 있을 것이다. fine-tuning만을 할 뿐이므로, 전체 데이터셋이 아닌 Validation 데이터만 받아도 충분하다.

     

    아래에서 라벨링데이터는 .json 데이터이고, 원천데이터는 .wav 데이터이다. 


    1. 음성(.wav) 데이터를 하나의 경로에 모은다.

    우리가 다운받은 데이터셋은 경로가 다소 복잡하게 되어있지만, 그래도 친절하게도 대응 데이터끼리 같은 제목을 공유하고 확장자만 다르다. 예를 들어, 1234.wav의 목소리와 1234.json은 같은 데이터이다. 하지만 음성(.wav), 대응 텍스트(.json) 파일들이 여러 경로에 혼재되어있다. 이를 하나의 음성은 음성끼리, 텍스트는 텍스트끼리 모아야 하는데, 일단 음성부터 모아보자. 텍스트는 어차피 추후 메타데이터에 모으면 된다.

     

    예를 들어, 아래의 코드를 이용할 수 있다.

    import os
    import shutil
    
    # 경로 설정
    source_base_dir = r"C:\...\VS"
    destination_dir = r"C:\...\all_wav_files"
    
    # 대상 폴더가 없다면 생성
    os.makedirs(destination_dir, exist_ok=True)
    
    # 모든 폴더를 재귀적으로 탐색하여 wav 파일을 찾는 함수
    def move_wav_files(source_dir, dest_dir):
        for root, dirs, files in os.walk(source_dir):
            for file in files:
                if file.endswith('.wav'):
                    # 원본 파일의 전체 경로
                    source_path = os.path.join(root, file)
                    # 대상 폴더의 경로로 파일을 이동
                    dest_path = os.path.join(dest_dir, file)
                    
                    # 이름 충돌을 피하기 위해 같은 이름의 파일이 있을 경우 파일명을 수정
                    if os.path.exists(dest_path):
                        base, ext = os.path.splitext(file)
                        count = 1
                        new_file_name = f"{base}_{count}{ext}"
                        new_dest_path = os.path.join(dest_dir, new_file_name)
                        while os.path.exists(new_dest_path):
                            count += 1
                            new_file_name = f"{base}_{count}{ext}"
                            new_dest_path = os.path.join(dest_dir, new_file_name)
                        dest_path = new_dest_path
                    
                    shutil.move(source_path, dest_path)  # 파일 이동
                    # shutil.copy2(source_path, dest_path)  # 파일 복사 시 사용
    
    # 실행
    move_wav_files(source_base_dir, destination_dir)
    
    print("모든 wav 파일이 이동되었습니다!")

     

    2. 음성파일을 22,050Hz로 변형한다. (매우중요!!!)

    이거 해야 하는 줄 모르고 "왜 안 되지 왜 안 되지"하고 며칠 날린 것 같다...

    XTTS-v2의 학습을 위한 .wav파일은 22,050Hz여야 한다. (근데 공식문서에는 22,050Hz여야 한다는 말 없던데 이거 안 하고 했다가 한동안 고생하다 어느 유튜브를 보고 겨우 알게 되었다...) 어쨌든 이를 위해 아래와 같은 코드를 사용한다.

    #22050Hz로 리샘플하는 코드
    
    import librosa
    import soundfile as sf
    from glob import glob
    import os
    
    def resample_wav_file(input_file, output_dir, target_sampling_rate=22050):
        try:
            audio, sampling_rate = librosa.load(input_file, sr=None)
            audio_resampled = librosa.resample(audio, orig_sr=sampling_rate, target_sr=target_sampling_rate)
            os.makedirs(output_dir, exist_ok=True)
            output_file = os.path.join(output_dir, os.path.basename(os.path.splitext(input_file)[0]) + "_{target_sampling_rate}.wav")
            sf.write(output_file, audio_resampled, target_sampling_rate)
            print(f"Resampled {input_file} to {output_file} at {target_sampling_rate}Hz")
        
        except Exception as e:
            print(f"Error processing {input_file}: {e}")
    
    # 이곳을 수정하고 실행할 것
    dataset_path = <wav 파일이 저장된 경로>
    output_dir = <22,050Hz 파일을 저장할 경로>
    
    for wav_file in glob(dataset_path + "*.wav"):
        resample_wav_file(wav_file, output_dir)

    3. 메타데이터를 만든다.

    메타데이터란 학습 데이터를 설명하는 데이터를 말한다. 보통은 .csv 형식이다. 이번에는 아래와 같은 형식을 사용한다.

    SPK089YTNSO922M005_22050|지난달 김포 집에서 알고 지내던 탈북민 여성을 성폭행한 혐의로 경찰 조사를 받았던 것으로 파악됐습니다|지난달 김포 집에서 알고 지내던 탈북민 여성을 성폭행한 혐의로 경찰 조사를 받았던 것으로 파악됐습니다
    SPK089YTNSO922M006_22050|북한이 군사분계선을 넘어 월북했다고 표현한 것에 대해서는 육상 철책이 뚫렸을 가능성보다 한강 하구를 헤엄쳐 북으로 넘어갔을 가능성에 무게가 실리고 있습니다|북한이 군사분계선을 넘어 월북했다고 표현한 것에 대해서는 육상 철책이 뚫렸을 가능성보다 한강 하구를 헤엄쳐 북으로 넘어갔을 가능성에 무게가 실리고 있습니다
    SPK089YTNSO922M007_22050|군 당국이 월북 사건 발생 가능성을 밝힌 것은 조선중앙통신 보도가 나온 지 여덟 시간이 지나서였습니다|군 당국이 월북 사건 발생 가능성을 밝힌 것은 조선중앙통신 보도가 나온 지 여덟 시간이 지나서였습니다
    SPK089YTNSO922M008_22050|해당 보도를 보고 나서야 탈북민의 월북 정황을 알게 된 셈이라 조사 결과가 나오면 군의 경계 실패에 대한 야당의 파상 공세와 문책성 인사 등 파장이 클 것으로 예상됩니다|해당 보도를 보고 나서야 탈북민의 월북 정황을 알게 된 셈이라 조사 결과가 나오면 군의 경계 실패에 대한 야당의 파상 공세와 문책성 인사 등 파장이 클 것으로 예상됩니다
    SPK089YTNSO923M001_22050|맹견의 일종인 로트와일러가 산책 나온 다른 개를 물어 죽이는 일이 발생했습니다|맹견의 일종인 로트와일러가 산책 나온 다른 개를 물어 죽이는 일이 발생했습니다

     

    보면 알게지만, 1열은 오디오 파일명(확장자제외), 2열은 텍스트 파일, 3열도 완전히 동일한 텍스트 파일이다. 원래는 3열에는 "소리나는 대로" 쓰여진 텍스트가 들어가야 하는데, XTTS-v2에서는 어차피 지원되지 않는 기능이라고 알고 있다.

     

    또한 중요한 것은, 아래와 같은 텍스트에 대한 전처리이다.

    "과밀학급은 경기도가 만 (7,481)/(칠천 사백 팔십 일) 학급 으로 가장 많았고 서울시가 (4,700)/(사천 칠백) 학급 으로 뒤를 이었습니다.",
    "최종문 외교부 이 차관이 (14 ∼ 17)/(십 사 에서 십 칠) 일 아이슬란드 레이캬비크에서 열리는 `이천 이십 일 북극서클 총회`에 참석합니다.",
    "동해 쪽은 파고가 (1.6m)/(일 점 육 미터) 이상으로 높게 일겠습니다.",
    "오늘 서울 낮 기온 (1.5)/(일 점 오) 도까지 올라 바깥 활동하기 한결 수월했습니다.",
    "내일 아침, 서울 (-6)/(마이너스 육) 도, 대구 (-3)/(마이너스 삼) 도, 광주 (-1)/(마이너스 일) 도로 오늘과 비슷하거나 조금 낮겠습니다.",
    "상, 벌점제 폐지도 반대한다는 응답이 (71.8%)/(칠십 일 점 팔 퍼센트) 로 찬성한다는 응답 (22.3%)/(이십 이 점 삼 퍼센트) 보다 압도적으로 많았습니다.",
    "삼 팔 노스는 지난 오 월 (~7)/(에서 칠) 월 상업 위성사진을 분석한 결과 이 같이 나타났다고 밝혔습니다."

     

    아주 친절하게도 숫자, 영어, 기호 등에 대한 데이터가 한국어 발음으로 쓰여져있는 것을 알 수 있다.

    이것을 아래와 같은 정규식 함수를 통해 정제할 수 있다.

    def convert_text(text):
        # 한글을 제외한 모든 문자 제거
        text = re.sub(r'[^가-힣\s]', '', text)
        # 두 번 이상 연속된 공백을 하나의 공백으로 줄임
        text = re.sub(r'\s+', ' ', text)
        # 양쪽 끝의 공백 제거
        return text.strip()

     

    즉, 텍스트 데이터는 아까 음성파일과는 다르게 굳이 한 폴더에 모을 필요가 없었던 것이, json 파일들을 훑으며 대사만 모아오면 되기 때문이다.

     

    전체코드는 아래와 같다.

    import os
    import csv
    import json
    import re
    
    # 경로 설정
    text_base_dir = r"C:\...\VL"
    voice_base_dir = r"C:\...\VS"
    output_csv = r"C:\...\metadata.csv"
    
    # 정규식을 사용해 숫자/텍스트 조합을 텍스트만 남기도록 변환하는 함수
    def convert_text(text):
        # 한글을 제외한 모든 문자 제거
        text = re.sub(r'[^가-힣\s]', '', text)
        # 두 번 이상 연속된 공백을 하나의 공백으로 줄임
        text = re.sub(r'\s+', ' ', text)
        # 양쪽 끝의 공백 제거
        return text.strip()
    
    # 모든 폴더를 재귀적으로 탐색하여 json 파일을 찾는 함수
    def find_json_files(directory):
        json_files = []
        for root, dirs, files in os.walk(directory):
            for file in files:
                if file.endswith('.json'):
                    json_path = os.path.join(root, file)
                    json_files.append(json_path)
        return json_files
    
    # 메타데이터 파일 생성
    with open(output_csv, mode='w', newline='', encoding='utf-8') as csv_file:
        writer = csv.writer(csv_file, delimiter='|')
        
        json_files = find_json_files(text_base_dir)
        
        for json_path in json_files:
            # text 경로를 voice 경로로 변환
            relative_path = os.path.relpath(json_path, text_base_dir)
            wav_path = os.path.join(voice_base_dir, relative_path.replace('text', 'voice').replace('.json', '.wav'))
            
            if os.path.exists(wav_path):
                with open(json_path, 'r', encoding='utf-8') as jf:
                    data = json.load(jf)
                    text = data["script"]["text"]
                    
                    # 텍스트 변환
                    converted_text = convert_text(text)
                    
                    # wav 파일 이름 추출 및 '_22050' 추가
                    wav_id = os.path.splitext(os.path.basename(wav_path))[0] + '_22050'
                    
                    # 메타데이터 파일에 기록 (3열에 2열과 동일한 값 추가)
                    writer.writerow([wav_id, converted_text, converted_text])
    
    print("metadata.csv 파일 생성 완료!")

    4. 글자수 필터링 (중요)

    XTTS-v2는 한국어의 경우 최대 92자까지만을 지원한다. 92자를 어떻게 세는지는 좀 의문이지만(예를 들어 띄어쓰기 포함인지 아닌지), 어쨌든, 아래와 같이 필터링할 필요가 있다.

    import pandas as pd
    
    # CSV 파일 로드
    df = pd.read_csv('metadata.csv', sep='|', header=None, names=['id', 'text1', 'text2'])
    
    # 텍스트 길이가 15자를 초과하지 않는 데이터만 필터링
    filtered_df = df[df['text1'].apply(len) <= 15]
    
    # 필터링된 데이터를 새로운 CSV 파일로 저장
    filtered_df.to_csv('filtered_metadata_15.csv', sep='|', index=False, header=False)
    
    print("필터링이 완료되었습니다. 필터링된 데이터는 'filtered_metadata_15.csv' 파일에 저장되었습니다.")

     

    20자를 기준으로 자르면 700개 정도로, 내 노트북 기준으로 약 30시간 정도의 fine-tuning이 필요하고 성능은 나쁘지 않은 수준이고,

    15자를 기준으로 자르면 240개 정도로, 내 노트북 기준으로 약 20시간 정도의 fine-tuning이 필요하고 성능은 별로였다.

     

    그래도 그냥 공부 목적으로 해보는 fine-tuning이라면, 15자 기준으로 해보는 것도 나쁘지 않다.


    5. 코드 준비

     

    우리는 XTTS-v2를 준비할 것이므로 위 사진의 경로로 접속한다. 

    그리고 아래의 동영상을 참고하여 코드를 각자에 맞게 바꾼다.

    https://www.youtube.com/watch?v=dzvW4QZamm8

     

     

    나는 아래와 같이 작성했다.

    import os
    
    from trainer import Trainer, TrainerArgs
    
    from TTS.config.shared_configs import BaseDatasetConfig
    from TTS.tts.datasets import load_tts_samples
    from TTS.tts.layers.xtts.trainer.gpt_trainer import GPTArgs, GPTTrainer, GPTTrainerConfig, XttsAudioConfig
    from TTS.utils.manage import ModelManager
    
    
    # Logging parameters
    RUN_NAME = "GPT_XTTS_v2.0_LJSpeech_FT"
    PROJECT_NAME = "XTTS_trainer"
    DASHBOARD_LOGGER = "tensorboard"
    LOGGER_URI = None
    
    # Set here the path that the checkpoints will be saved. Default: ./run/training/
    OUT_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "run", "training")
    
    # Training Parameters
    OPTIMIZER_WD_ONLY_ON_WEIGHTS = True  # for multi-gpu training please make it False
    START_WITH_EVAL = False  # if True it will star with evaluation
    BATCH_SIZE = 2  # set here the batch size
    GRAD_ACUMM_STEPS = 126  # set here the grad accumulation sateps
    # Note: we recommend that BATCH_SIZE * GRAD_ACUMM_STEPS need to be at least 252 for more efficient training. You can increase/decrease BATCH_SIZE but then set GRAD_ACUMM_STEPS accordingly.
    
    # Define here the dataset that you want to use for the fine-tuning on.
    config_dataset = BaseDatasetConfig(
        formatter="ljspeech",
        dataset_name="my_project_dataset",  # 원하는 이름으로 지정
        path="C:/.../resampled_wav_files_20",  # 데이터셋 경로 지정
        meta_file_train="C:/.../filtered_metadata_20.csv",  # 메타데이터 파일 경로 지정
        language="ko",
    )
    
    # Add here the configs of the datasets
    DATASETS_CONFIG_LIST = [config_dataset]
    
    # Define the path where XTTS v2.0.1 files will be downloaded
    CHECKPOINTS_OUT_PATH = os.path.join(OUT_PATH, "XTTS_v2.0_original_model_files/")
    os.makedirs(CHECKPOINTS_OUT_PATH, exist_ok=True)
    
    
    # DVAE files
    DVAE_CHECKPOINT_LINK = "https://coqui.gateway.scarf.sh/hf-coqui/XTTS-v2/main/dvae.pth"
    MEL_NORM_LINK = "https://coqui.gateway.scarf.sh/hf-coqui/XTTS-v2/main/mel_stats.pth"
    
    # Set the path to the downloaded files
    DVAE_CHECKPOINT = os.path.join(CHECKPOINTS_OUT_PATH, os.path.basename(DVAE_CHECKPOINT_LINK))
    MEL_NORM_FILE = os.path.join(CHECKPOINTS_OUT_PATH, os.path.basename(MEL_NORM_LINK))
    
    # download DVAE files if needed
    if not os.path.isfile(DVAE_CHECKPOINT) or not os.path.isfile(MEL_NORM_FILE):
        print(" > Downloading DVAE files!")
        ModelManager._download_model_files([MEL_NORM_LINK, DVAE_CHECKPOINT_LINK], CHECKPOINTS_OUT_PATH, progress_bar=True)
    
    
    # Download XTTS v2.0 checkpoint if needed
    TOKENIZER_FILE_LINK = "https://coqui.gateway.scarf.sh/hf-coqui/XTTS-v2/main/vocab.json"
    XTTS_CHECKPOINT_LINK = "https://coqui.gateway.scarf.sh/hf-coqui/XTTS-v2/main/model.pth"
    
    # XTTS transfer learning parameters: You we need to provide the paths of XTTS model checkpoint that you want to do the fine tuning.
    TOKENIZER_FILE = os.path.join(CHECKPOINTS_OUT_PATH, os.path.basename(TOKENIZER_FILE_LINK))  # vocab.json file
    XTTS_CHECKPOINT = os.path.join(CHECKPOINTS_OUT_PATH, os.path.basename(XTTS_CHECKPOINT_LINK))  # model.pth file
    
    # download XTTS v2.0 files if needed
    if not os.path.isfile(TOKENIZER_FILE) or not os.path.isfile(XTTS_CHECKPOINT):
        print(" > Downloading XTTS v2.0 files!")
        ModelManager._download_model_files(
            [TOKENIZER_FILE_LINK, XTTS_CHECKPOINT_LINK], CHECKPOINTS_OUT_PATH, progress_bar=True
        )
    
    
    # Training sentences generations
    # SPEAKER_REFERENCE = [
    #     "C:/Users/SKT005/TTS/my_dataset/sjy.wav"  # speaker reference to be used in training test sentences
    # ]
    # LANGUAGE = config_dataset.language
    # Training sentences generations
    SPEAKER_REFERENCE = [
        "./tests/data/ljspeech/wavs/LJ001-0002.wav"  # speaker reference to be used in training test sentences
    ]
    LANGUAGE = config_dataset.language
    
    
    
    def main():
        # init args and config
        model_args = GPTArgs(
            max_conditioning_length=132300,  # 6 secs
            min_conditioning_length=66150,  # 3 secs
            debug_loading_failures=False,
            max_wav_length=255995,  # ~11.6 seconds
            max_text_length=200,
            mel_norm_file=MEL_NORM_FILE,
            dvae_checkpoint=DVAE_CHECKPOINT,
            xtts_checkpoint=XTTS_CHECKPOINT,  # checkpoint path of the model that you want to fine-tune
            tokenizer_file=TOKENIZER_FILE,
            gpt_num_audio_tokens=1026,
            gpt_start_audio_token=1024,
            gpt_stop_audio_token=1025,
            gpt_use_masking_gt_prompt_approach=True,
            gpt_use_perceiver_resampler=True,
        )
        # define audio config
        audio_config = XttsAudioConfig(sample_rate=22050, dvae_sample_rate=22050, output_sample_rate=24000)
        # training parameters config
        config = GPTTrainerConfig(
            output_path=OUT_PATH,
            model_args=model_args,
            run_name=RUN_NAME,
            project_name=PROJECT_NAME,
            run_description="""
                GPT XTTS training
                """,
            dashboard_logger=DASHBOARD_LOGGER,
            logger_uri=LOGGER_URI,
            audio=audio_config,
            batch_size=BATCH_SIZE,
            batch_group_size=48,
            eval_batch_size=BATCH_SIZE,
            num_loader_workers=8,
            eval_split_max_size=256,
            print_step=50,
            plot_step=100,
            log_model_step=1000,
            save_step=10000,
            save_n_checkpoints=1,
            save_checkpoints=True,
            # target_loss="loss",
            print_eval=False,
            # Optimizer values like tortoise, pytorch implementation with modifications to not apply WD to non-weight parameters.
            optimizer="AdamW",
            optimizer_wd_only_on_weights=OPTIMIZER_WD_ONLY_ON_WEIGHTS,
            optimizer_params={"betas": [0.9, 0.96], "eps": 1e-8, "weight_decay": 1e-2},
            lr=5e-06,  # learning rate
            lr_scheduler="MultiStepLR",
            # it was adjusted accordly for the new step scheme
            lr_scheduler_params={"milestones": [50000 * 18, 150000 * 18, 300000 * 18], "gamma": 0.5, "last_epoch": -1},
            test_sentences=[
                {
                    "text": "목소리를 찾는 데 오랜 시간이 걸렸습니다.",
                    "speaker_wav": SPEAKER_REFERENCE,
                    "language": LANGUAGE,
                },
                {
                    "text": "이 케이크는 훌륭해요.",
                    "speaker_wav": SPEAKER_REFERENCE,
                    "language": LANGUAGE,
                },
            ],
        )
    
        # init the model from config
        model = GPTTrainer.init_from_config(config)
    
        # load training samples
        train_samples, eval_samples = load_tts_samples(
            DATASETS_CONFIG_LIST,
            eval_split=True,
            eval_split_max_size=config.eval_split_max_size,
            eval_split_size=config.eval_split_size,
        )
    
        # init the trainer and 🚀
        trainer = Trainer(
            TrainerArgs(
                restore_path=None,  # xtts checkpoint is restored via xtts_checkpoint key so no need of restore it using Trainer restore_path parameter
                skip_train_epoch=False,
                start_with_eval=START_WITH_EVAL,
                grad_accum_steps=GRAD_ACUMM_STEPS,
            ),
            config,
            output_path=OUT_PATH,
            model=model,
            train_samples=train_samples,
            eval_samples=eval_samples,
        )
        trainer.fit()
    
    
    if __name__ == "__main__":
        main()

     

     

    자, 이제 모든 준비는 다 끝났다.

    아래와 같은 명령어를 이용하여 코드를 실행한다.

    CUDA_VISIBLE_DEVICES="0" python recipes/ljspeech/xtts_v2/train_gpt_xtts.py

     

    Fine-tuning된 모델 이용해보기

    보통 이를 "모델을 Inference한다"라고 표현한다. 대부분의 모델은, inference하는 과정은 생각보다 아주아주 복잡하다. 여기도 마찬가지이니 잘 따라오자. 나는 약 30시간에 걸쳐 fine-tuning을 끝냈는데, 그러면 아래와 같은 경로여 체크포인트 모델들이 많이 생성되어 있을 것이다.

     

    맨 밑에는 fine-tuning이 되지 않은 원본 모델이 보존되어있음을 알 수 있다. 그거 말고 가장 최근에 생성된 폴더에 있는 best_model.pth의 이름을 model.pth로 바꿔야 한다. 또한 원본 모델 폴더 내에 있는 vocab.json을 복사해서 이용하고자 하는 폴더에 붙여넣어준다

     

    그러고 다음의 코드를 실행하면 파인튜닝된 모델에서 생성된 "한국어스러운" 한국어 음성을 들어볼 수 있을 것이다!!

    import torch
    from TTS.api import TTS
    
    # Get device
    device = "cuda" if torch.cuda.is_available() else "cpu"
    
    # Define the directory path (without appending 'model.pth')
    model_dir = r"C:\...\TTS\recipes\ljspeech\xtts_v2\run\training\GPT_XTTS_v2.0_LJSpeech_FT-August-26-2024_01+43PM-dbf1a08a"
    
    # Load the fine-tuned model (passing only the directory)
    tts1 = TTS(model_path=model_dir, config_path=f"{model_dir}/config.json").to(device)
    
    speaker_wav="C:/Users/SKT005/TTS/my_finetuning/dataset/target_shu/repeated_UDHR-slow-shu.wav"
    output_file_path_ft = "C:/.../TTS/my_finetuning/dataset/second_output_finetuned_3.wav"
    
    # Perform inference
    wav = tts1.tts_to_file(
        text="안녕하세요?",
        speaker_wav=speaker_wav,
        language="ko",
        #speed = 1.5,
        #emotion="happy",
        file_path=output_file_path_ft
    )

     

Designed by Tistory.