프로젝트 개요
지능시스템 캡스톤 디자인 프로젝트에서는 RelGAN이라는 생성모델과 KoBERT라는 자연어 처리 모델, TTS 기술을 사용하여, 문장에 감정을 담아 실감나게 읽어주는 TTS 서비스를 제작하고자 진행하고 있습니다. 조금 더 자세히 설명드리자면 KoBERT 모델을 사용하여 텍스트 문장에서 감정을 추출하고, TTS를 통해 해당 텍스트를 Speech로 변환합니다. 마지막으로 변환한 Speech에 RelGAN을 사용하여 KoBERT에서 추출한 감정을 입혀 실감나는 TTS 서비스를 제작하고자 합니다. 이 중 저는 RelGAN을 통해 음성에 감정을 입히는 부분을 도맡아 하고 있습니다.
프로젝트 이슈
이제 프로젝트 마감이 일주일 남았다... 완전하게 학습이 끝난 것은 아니지만 어느정도 쓸만한 weight 파일이 나왔기 때문에, KoBERT와 RelGAN과 SCE-TTS를 연동하는 파이프라인을 구축하고 있다. 학습시킬 때 batch_size를 고려하지 않고, 그냥 기본 모델에 배치가 5로 되어 있길래 나도 5로 놓고 학습을 시켰는데 후에 test할 때도 5묶음씩 사용해야한다는 것을 깨달았다... 일단 학습시키던 것을 중단하고 다시 batch_size를 1로 두고 학습을 진행하고, 혹시 몰라 batch_size가 5여도 파이프라인으로 연결될 수 있도록 코드를 작성하려고 한다. 우선 간단하게 그림을 그려보자면 우리 모델의 구조는 다음과 같다.
batch size가 1인 모델 가중치가 생각보다 일찍 나와서 한 개씩 출력하는 코드를 먼저 작성해보기로 하자.
코드는 다음과 같다.
import argparse
import os
import time
import yaml
import numpy as np
import torch
import torch.nn as nn
import torch.utils.data as data
import torchvision.datasets as datasets
import torchvision.transforms as transforms
from torchvision.utils import make_grid, save_image
from RelGAN.helpers import run_from_ipython
from RelGAN.voice_nn import GAN
from RelGAN.ops import inv_normalize
import matplotlib.pyplot as plt
#GAN에 필요한 parameters
args = argparse.Namespace(
attr = 'C:/.../RelGAN/attributes.yaml',
data = 'C:/.../voiceDatsaetv6',
dataset = 'voiceDataset',
load = '/C:/.../model/middletosad.19999.499.pth',
save = 'model/test.pth',
steps = 4000,
start_step = 0,
name = 'voice Conversion',
gpu = False,
multi_gpu= False,
image_size=256,
lr = 5e-5,
b1 = 0.5,
b2 = 0.999,
iterG = 50,
iterD = 50,
repeat_G = 6,
batch_size = 5,
sample_size = 2,
epochs = 5,
l1 = 10.0,
l2 = 10.0,
l3 = 1.0,
l4 = 0.000001,
gamma = 0.1,
zero_consistency = True,
cycle_consistency = True,
interpolation_regularize = True,
orthogonal_regularize = True,
log_interval = 100,
sample_interval = 100,
save_interval = 100,
selected_attributes = ['sad']
)
args.selected_attributes = yaml.full_load(open(args.attr, 'r', encoding='utf-8'))
selected_attributes = args.selected_attributes
assert type(selected_attributes) is list
#========================변경할 감정 입력하기========================
#middle -> sad로 변경
interpolating_attributes = ['middle']
test_attributes = [
('angry', 0), ('embarrassed', 0), ('middle', 0),
('pleasure', 0), ('sad', 1)
]
#====================================================================
inter_annos = np.zeros(
(10 * len(interpolating_attributes), len(selected_attributes)),
dtype=np.float32
)
for i, attr in enumerate(interpolating_attributes):
index = selected_attributes.index(attr)
inter_annos[np.arange(10*i, 10*i+10), index] = np.linspace(0.1, 1, 10)
test_annos = np.zeros(
(len(test_attributes), len(selected_attributes)),
dtype=np.float32
)
for i, (attr, value) in enumerate(test_attributes):
index = selected_attributes.index(attr)
test_annos[i, index] = value
#========================변경할 데이터들 입력하기========================
img = np.load('C:.../100.npy').tolist()
img = torch.tensor(img, dtype=torch.float).to('cuda')
attr = [0, 0, 1, 0, 0]
attr = torch.tensor(attr, dtype=torch.float).to('cuda')
#kobert에서 받아올 감정 리스트
kobert_attr = [1, 0, 0, 0, 0]
kobert_attr = torch.tensor(kobert_attr, dtype=torch.float).to('cuda')
#=============================모델 가져오기=============================
gan = GAN(args)
gan.to('cuda')
g, d, d_critic = gan.summary()
load_file = 'C:.../RelGAN/model/batch_1_weight.19999.pth'
if load_file is not None:
gan.load(load_file)
gan.eval()
#=============================test 시작하기=============================
attribute = kobert_attr - attr #relative attribute 만들기
#Generate하기
with torch.no_grad():
conversion = gan.G(img, attribute).detach()
conversion_test = inv_normalize(conversion)
np.save('C:/.../test', conversion_test)
길어보이지만 설명이 많아서 그렇지 사실은 간단하다. 우선은 KoBERT를 연결했다는 가정 하에 RelGAN에서 음성 하나만 변환하는 코드를 작성하였다. 그런데 이상한 문제가 생겼다.
분명히 학습할 때는 잘 되었던 모델이 테스트 코드를 작성하니까 Dimension out of range 오류가 생겼다. 달라진 것은 데이터 입력 방식밖에 없기 때문에 변형한 RelGAN에서 데이터의 입력 사이즈가 어떻게 되는지 확인하기 위해 print로 사이즈를 직접 찍어보았다.
위에부터 순서대로 attr과 img의 사이즈이다. 나는 당연히 img가 [1, 256, 256]으로 입력될 것이라고 생각했는데 4차원으로 출력되었다. 그러면 data를 받아오는 코드에서 뭔가 전처리가 들어갔다는 의미이다.
그래서 데이터 입력받는 곳에서 unsqueeze()함수를 사용하여 맨 처음에 1차원을 추가해주었다.
img = np.load('.../100.npy').tolist()
img = torch.tensor(img, dtype=torch.float).to('cuda')
img = img.unsqueeze(0) #입력 데이터에 맞게 numpy resize 진행하기
일단 데이터 사이즈는 이렇게 맞춰 음성은 출력이 되었다. 근데 억지로 차원을 늘려서 그런건지 아님 후처리 코드에 문제가 있는건지 아예 음성에서 노이즈만 출력이 되었다.....
전체 코드는 깃헙에서 확인할 수 있습니다.
'지능시스템 졸업 프로젝트' 카테고리의 다른 글
[지능시스템 캡스톤 디자인] 음성 합성 프로젝트 일지 ⑨ (0) | 2023.06.04 |
---|---|
[지능시스템 캡스톤 디자인] 음성 합성 프로젝트 일지 ⑧ (0) | 2023.05.30 |
[지능시스템 졸업 프로젝트] 음성 합성 프로젝트 일지 ⑥ (0) | 2023.05.22 |
[지능시스템 졸업 프로젝트] 음성 합성 프로젝트 개요 ⑤ (0) | 2023.05.22 |
[지능시스템 캡스톤 디자인] 음성 합성 프로젝트 일지 ④ (0) | 2023.05.22 |