본문 바로가기
논문으로 현업 씹어먹기

[VALL-E] Neural Codec Language Models are Zero-Shot Text to Speech Synthesizers 리뷰 - (5~7/12 Page.)

by Yoo Sung Hyun 2023. 1. 23.
728x90

2023.01.16 - [논문으로 현업 씹어먹기] - [VALL-E] Neural Codec Language Models are Zero-Shot Text to Speech Synthesizers 리뷰 - (1~4/12 Page.)

 

[VALL-E] Neural Codec Language Models are Zero-Shot Text to Speech Synthesizers 리뷰 - (1~4/12 Page.)

3초만을 가지고 TTS를 할 수 있고, 심지어 잘된다. GPT3의 Incontext-Learning에서 영감을 받았다고 한다. Language Modeling이다. 다만 TTS FrameWork를 사용했을뿐. 일단 읽으면서 되는데로 정리를 할 예정이라

shyu0522.tistory.com

여기서 이어집니다.

 

이전 Section 3. 까지는, TTS를 위한 음향 딥러닝의 기술적 동향과 VALL-E의 기본 컨셉정도만 알아봤다.

이번에는 Section 4.만 집중해서 정리를 할 까 하는데, 이후부터는 experiment라서 좀 내용이 가벼워지지 싶다.

뭔가 음향 딥러닝을 해봤다면, 충분히 들어봤을법한 단어들로 구성되어있고, 수식도 어려운걸 떠나 거의 없다시피하는데도, 뭔가 구조나 방식에 대해 Why가 없는 설명이라서, 전반적인 구조를 상상하며 읽을 수 밖에 없다. (뭔가 논문이 친절한듯 불친절하게 써놨다...;;)

 

결론적으로, 100% 이해하고 쓰는 것 같지는 않고, 실제로 MS git에 코드 구현이 뜨던지 하면, 코드 대조 및 논문도 앞으로 두어번 더 훑어봐야 할 것 같아서, 일단 1번 정독해본 내용을 토대로 작성하고, 이후에 수정해나가도록 하겠다.

 

그리고 혹시 읽어보신 분들 중, 밑에 몇가지 질문에 대해 아시는 분 있으면 댓글 달아주시면 감사하겠다. (봐서 커피 기프티콘이라도 사드림)

1. share layer를 왜 자꾸 이야기하는지 모르겠다. (4.2.1과 4.2.2에서)

    임베딩 -> transformer -> proj(pred) layer 의 순으로 갈텐데, 마지막을 임베딩이랑 share weight해서 얻을 수 있는

    기대효과가 잘 상상되지 않았다. 임베딩은 freeze시켜놓을 것이고 share된 proj 혹은 pred layer만 조금씩 미세조정

    될테니, 학습 데이터 상황에 따라 변화될 수 있는 임베딩 표현을 좀 더 빨리 찾기 위함정도로 이해할 수 있지 않을까 싶기

    도 하고... (기본적인 학습법이었다면, 굳이 이렇게까지 연속적 언급을 하진 않을 것 같은데, 그렇다고 이유를 명확히

    써놓지도 않았다.)

2. enrolled 라는 표현을 왜 자꾸 쓰는지 모르겠다. 뒤에 experiment보면, unseen에 대한 실험결과도 있긴 하던데, 해당 실험결과를 보기 전까지, unseen으로 잘되는거 맞아? 그냥 seen중에 갑자기 바뀔 수 있는 악센트나 (미국인이 갑자기 영어발음을 하려고 한다던가) 감정표현같은, 화자는 있지만 상황을 처음보는것만 잘되는거 아닌가? 하는 의구심을 가지고있었다. (enrolled가 4.2.1에서 나오는 AR Quantizer의 output을 의미하는 것인지?)

3. Multilingualism (vs YourTTS)

YourTTS는 다중언어가 지원된다는게 매우 색달랐다. VALL-E는 그에 대한 실험결과는 없다. 과연 YourTTS보다 유용할까?

(YourTTS는 개발중이니, VALL-E와 대조 실험이 필요할지도 모르겠음)

4. VALL-E

4.1 Problem Formulation: Regarding TTS as Conditional Codec Language Modeling

 y는 audio sample, x는 전사 Text(g2p생략이라고 가정) 이라고 하자. 각각의 audio sample을 discrete acoustic code로 학습시키는데, Encodec(y)는 \( C^{T\times 8} \) 로 2차원의 code matrix가 된다.(T는 downsample된 발화 길이이다.)

 행 벡터는 각각의 acoustic code가 된다. (특정 타임 t에 대한 8개짜리의 음성벡터 표현이 되므로.)

 열 벡터는 전체 시간에 대한 특정 acoustic code가 된다. (전체 시간에 대한 8개중 각각 어느 것의 code 표현이므로. (여기서 8개는 코드북의 개수이다.)

codebook은 어디서부터 유례되었는지는 나는 명확하진 않지만, 처음 접한 것은 wav2vec 2.0에서였다. Embedding Table과 비슷하면서도 약간 다르다. codebook은 연속된 값을 Embedding처럼 표현하기 위해, discrete하게 표현하고, 연속값 특징의 다양한 표현력을 얻기위해(discrete하면 어느정도 소실되니,) 여러개의 codebook을 유지한다는게 좀 차이다. (코드북 x embedding size) 이걸 이제 sum해서 쓰던, avg해서 쓰던, 쓰는거로, '아!' 라는 음성이 들어갔을때, 음성 feature보다는 단순한 벡터가 될 수 있도록 변환해서 나오게 된다.

 여튼 codebook을 neural codec decoder로 다시 waveform으로 변환하면, 그 변환된 값은 원본 y에 근사해야한다. (Wav2Vec 2.0은 오히려 원상복구에 초점을 맞추기 보단, 최대한 압축해서 발화의 중요표현만 집중해서 뽑아오는 것에 초점을 맞춘다. (그렇기 때문에, 노이즈나, 억양이나 이런거에서 좀 더 robust하게 된다는 장점이 있음.))

 Zero-shot TTS는 unseen speakers에 잘 합성되는 것을 목표로 한다. 이번 실험에서, 자기들은 zero-shot TTS가 conditional codec language modeling task인 것을 확인했다고 한다. (작년 5월 Meta의 GSLM에서도 wave quantize codec code만 써서 LM을 학습시키는데 성공하는 것으로, 동일한 이야기를 한다.)

 phoneme sequence x와 acoustic prompt codebook  \( \tilde{C} \) 에 조건부인 acoustic code matirx C를 생성하는 neural language model을 학습하는 것으로 이룰 수 있다고 하며, 때문에, x와  \( \tilde{C} \) 를 넣었을때 원본 C를 maximize optimize하는 것이 학습의 목표이다. (모델이 내용과 화자의 정보를 얻어내기를 기대하는 것이다.)

 Inference 시점에는, phoneme sequence와 3초의 unseen speaker의 enrolled recording로 내용과 화자의 목소리가 학습된 language model에서 나오고, 그 다음에 neural codec decoder로 높은 품질의 음성합성을 해낸다.

4.2 Training: Conditional Codec Language Modeling

들어가기 전에, 내가 이해한 것을 기준으로 한가지만 정의하겠다.
위에서 보면 x는 Phoneme Sequence로, 아마 G2P (철자를 읽은 발음기호로 변환해주는 알고리즘 오픈소스 툴이다.)를 진행한 text라고 정의한다. 즉 간단히 얘기하면 그냥 text다!)
C: 어느 시점 값일지는 몰라도, Quantizer Layer에서 나온 output (Sequence Predict에서 이전 output -> 현재 input정도로 이해하는 그 값)
\( \tilde{C} \): 음성 Prompt (3초 넣는다는 그 음성이다.)
참고로, C는 대문자면 전체를, 소문자면 특정 구간을 의미.

 Discrete audio representations를 동작시키는 모델이라는 설명으로부터 시작.

 Residual quantization이 적용되어있다고 한다. (residual은 깊어지는 신경망에서 이전 값을 넘겨주는 것으로, 뭐 기억력을 좀 더 유지시켜주는 효과? 정도로 볼 수 있을텐데, quantize layer가 8개나 되다보니 깊어져서 쓰나보다.)

 이전 Quantizer에서의 토큰이 화자 특성같은 음향 속성을 회복시켜주고, 연속 Quantizer가 음향의 detail을 배워나가는 것으로 설명한다. 각각의 Quantizer들은 이전의 Quantizer들로부터 residual하게 학습된다고 한다.

 이것에서 영감을 받아서, 2개의 조건부 language model을 구성했다고 한다.

 첫 quantizer인 \( c_{:, 1} \) 에서의 discrete token은 autoregressive decoder-only language model (이하 AR)로 학습했다.

 이것의 조건부는 x와 \( \tilde{c}_{:, 1} \)로 표현된다.

Formula 1

\( c_{:, 1} \)과 X가 AR의 Input으로 들어가는 모양.

AR 구조

 그리고 그렇게 나온 \( c_{<t, 1} \) 가 causal하게 들어가는 형태. (뭔가 결국에는 3놈이 AR의 input으로 사용된다.)

 \( \tilde{c}_{:, 1} \) 와 \( c_{:, 1} \) 가 concatenation되어서 들어가야된다고 한다. 그리고, 학습시에는 그 두개를 구별하기위한 특정한 토큰은 사용하지 않는다고 한다. (<sep>같은거 안쓴다는 말인듯.)

 오직 \( c_{:, 1} \)만 예측시점에 주어진  \( \tilde{c}_{:, 1} \)로 예측된다.

 

 두번째부터 마지막(8번째) 까지의 quantizer는, \( c_{:, j\in [2,8]} \) 이 되겠고, non-autoregressive (이하 NAR) language model로 학습했다고 한다. NAR스럽게 각 서로 토큰은 서로 access할 수 없다. 이는, 화자의 특성을 제약하기 위함이며, acuostic prompt matrix  \( \tilde{C} \)는 acoustic prompt로 사용된다. 그러므로, 모델은 acoustic prompt와 phoneme sequence x, 이전 codebook \( C_{:, <t} \) 으로 예측된 acoustic tokens에 조건부로 표현된다.

Formula 2

 AR model과 NAR model을 섞어쓰는 것은, 음성 품질과 예측 속도에 좋은 trade-off로 작용한다.

 한편으로는, 생성된 음성의 품질은 enrolled recording에 한결같아야 한다. 그리고 그것은 다른 화자들에 대한 서로 다른 발화 속도로 다양해지는 length predictor를 학습하기 어렵게 만든다. AR model은 이 문제를 더 자연스러운 음성으로, acoustic sequence length prediction을 유연하게 한다. (아마, left-to-right 방식이라, 음성의 전체 라기보단, 직전의 일부만 보니까, 이전 발화가 빠르거나? 느리거나? 하는 것에 영향을 크게 받아서 빠르면 빠르게, 느리면 느리게 하면 그만이니까 이지 않을까....?)

 다른 한 편으로는, 연속적인 구간(NAR model을 의미하는 것 같다)에서, sequence length가 AR model에서 output shape으로 고정되니, 시간 복잡도가 O(T)에서 O(1)로 줄어든다는 것이다. (이 부분도 조금 의문인게, 확실히 줄긴 할텐데 어짜피 decoder도 self-attention이 있어서 T가 아니고, 최소 AR model output shape 정도 일 것 같은데... 심지어 이놈은 full attend이다.)

NAR 구조

 각설하고, 그럼 전체 C를 예측하기 위한 모델링은,

Formula 3

으로 표현할 수 있다. (첫번째 quantizer의 AR과, 두번째 이후 quantizer의 NAR의 조합)

4.2.1 Autoregressive Codec Language Modeling

 autoregressive language model은 첫번째 quantizer에서 토큰을 생성한다. 그것은 phoneme embedding \( W_{x} \) 와 acoustic embedding \( W_{a} \), transformer decoder 그리고 prediction layer로 구성되어있다.

 특정 내용의 음성을 생성하기 위해서, 우리는 phoneme sequence를 language model의 phoneme prompt로 사용한다. 그러므로 model의 input은 x와 \( c_{:, 1} \)의 concatenation으로 구성된다. 그리고 각각 둘다 마지막에 <EOS> 토큰을 붙힌다. 또한 각각의 position embedding은 사인파 position embedding을 사용한다. causal transformer model로, 각 토큰 \( c_{t, 1} \) 는 (x, \( c_{\leq t, 1} \))와 attend될 수 있다. (AR 구조 이미지 참고)

 모델은 첫번째 코드북에서 다음 토큰을 maximize하는 것으로 학습된다. 우리는 output projection layer와 acoustic embedding \( W_{a} \) 의 parameter를 share한다.

 AR model에서, 학습때 명확한 음성의 clip을 추출해내지는 않는다. 학습 과정은 순수하게 casual language model training이다. 이 방법으로, 어떤 이전 sequence \( c_{<t, 1} \) 라도, 이후 sequence \( c_{\geq t, 1} \)에 영향을 끼치게 된다.  Inference 동안에, enrolled recording이 주어지면, phoneme sequence와 enrolled recording을 concatenation 해야한다. 그러는 중에, enrolled recording의 acoustic token sequence는 AR 디코딩의 사전 값으로 사용된다. Formula 1 에서처럼. 이 세팅을 뒤에서 검증한다고 한다.

(뭔가 당연한 이야기를 계속 반복하는거 같은데 (그림을 말로 풀어서 설명한 느낌), 잊지 않게 하기 위함인 것도 같은데, 뭔가 헷깔리게 만드는 여지도 있는듯...;;)

4.2.2 Non-Autoregressive Codec Language Modeling

첫번째 quantizer code를 AR model에서 얻는다면, non-autoregressive (NAR) model에서 나머지 7개의 quantizer의 코드를 생성한다. NAR model은 각각 8개의 acoustic embedding layers를 가진다는 것을 제외하면 AR model과 흡사하다. 각 training step에 랜덤하게 training stage i를 2~8중에 샘플링한다. 모델은 i 번째 quantizer codebook에서 acoustic token을 maximize하는 것으로 학습한다. stage 1부터 i-1까지의 acoustic token은 model input에서 임베딩되고 summed up 된다.

특정 c_t,j의 acoustic embedding weight를 찾아서 stage i-1만큼 j 어치를 더한다.

----- 논문 내용 아닌 개인적 해석 -----

 뭔가 뉘앙스가, 복수개의 codebook을 embedding에 맞춰넣으려는 시도로 보인다. codebook은 quantizer 개수만큼 나올 수 있다. (j개만큼 있을 수 있음) '아!'라고 발음해도, quantizer의 layer 구성을 어떻게 하느냐에 따라 layer를 타면서 학습되는 각 층의 quantizer의 output vector는 다 조금씩 달라질 수 있기 때문이다. ('아!'에 대한 7개의 vector표현이 나온다.) (이것으로 하나의 연속음성 값의 다양한 표현을 최대한 학습하도록 유도한다) 그러면 사실 raw audio보다야 vector가 단순화될 수 있어도, 임베딩 관점에서는 아직 차원이 많다. 그렇다고 여기서 또 차원을 줄이자니, 정보량은 날라갈 거라고 판단했을 수도 있고...

 그래서 임베딩 layer도 8개로 (대충 넉넉하게 둔거 아닐까?) quantizer layer 7개에서 나올 수 있는 각각의 code vector를 임베딩 layer를 랜덤으로 선택해가면서 code vector의 합으로, 음성에 대한 최대한 다양한 code vector 시나리오를 임베딩에 투영시키고자 한 것 정도로 이해하기로 했다. (7개의 code vector가 있으니, 1~3 더해서 임베딩해보고, 1~5 더해서 임베딩해보고, 1~7 더해서 임베딩해보고, 이런식으로 계속 반복하다보면 code vector에 근사하는 임베딩 테이블을 얻을 수 있지 않을까?) -> 이게 따지고보면 embedding layer만 학습하는게 낫지 않을까 싶을 순 있는데, 막상 그렇게하자니 raw waveform을 embedding layer에 어떻게 우겨넣을지 막상 표족한 수가 잘 떠오르지 않는다.

--------------------------------------------------

(4)번 식의 동그라미 수식은 index selection이다. phoneme sequence(잊어먹었을까봐 참고로 x text이다.)는 또한 language model의 prompt로 사용된다. 주어진 화자의 유일한 음성을 복사하는 것 대비, acoustic prompt의 등록된 음성으로부터 acoustic token또한 사용한다. (뭔가 기 학습된 codebook에서의 유사한 화자 발화 특징을 추가하므로, 직으로 모사하는것 보다 잘됨을 어필하고 싶은 것인듯?) prompt로 들어온 음성을 먼저 neural codec model을 이용해서 \( \tilde{C}^{T X 8} \) 로 만든다. 8개의 codebook의 모두로부터 나오는 임베딩 표현은 acoustic prompt로부터 summed up되며, 1부터 8까지의 입력 음성 prompt의 특정 타임시점 t의 codebook의 합이 된다.

 i번째 codebook의 acoustic token을 예측하기 위해서, transformer input은 (text embedding, prompt codebook embedding, 예측된 직전 acoustic token codebook embedding)이 필요하다. Positional embedding은 각각의 입력에 적용되며, acoustic sequence에도 적용된다. 또한 Adaptive Layer Normalization으로 중간중간에 일반화 진행된다.

 AR과 다르게, NAR model은 각 토큰이 모든 input token과 self-attention 될 수 있도록 한다. 우리는 또한 acoustic embedding layer와 output prediction layer의 parameter를 share한다. 그 것의 의미는, j번째 prediction layer가 (j+1) acoustic embedding layer와 같음을 의미한다.

4.3 Inference: In-Context Learning via Prompting

 In-context learning은 text-based language model에서 놀라운 능력을 발휘했으며, unseen input에 대해 추가적인 parameter update 없이 가능하다는 것에 의미가 있다. TTS에서, 만약 모델이 unseen 화자에 대해 높은 품질의 합성을 fine-tuning없이 제공한다면, in-context learning으로 해결했을 것으로 볼 수 있다. 기존 TTS들의 in-context learning들은 추가 미세조정이 필요하거나, unseen 화자에 대해 약한 모습을 보였다.

 language model에서 prompting은 zero-shot scenario를 가능하게 하기위해 필요하다. 우리는 prompts와 inference를 이와 같이 하기위해 적용했다. phoneme sequence의 text와 acoustic matrix의 enrolled recording를 입력 prompt로 사용하기 위해 먼저 변환한다. 각각의 prompt는 AR과 NAR model에서 사용된다.

 AR model을 위해서 beam search는 무한루프에 빠질 경우가 있어서, sampling-based 조건부 decoding 을 prompt에 적용했다. 더군다나, sampling-based 방식은 output의 다양성을 증대시키는 효과도 가지고 있다.

 NAR model을 위해서, 우리는 greedy decoding 방식을 가장 높은 확률을 뽑기위해 사용했다.

 마지막으로 neural codec decoder를 이용해서 8개의 code sequence로부터 waveform을 생성하도록 하였다.

 acoustic prompt는 의미적으로 관련이 있을 수도, 없을 수도 있으며, 2가지 케이스에 대해 결과를 내도록 하였다.

  • VALL-E: unseen 화자에 대한 음성합성에 초점을 맞춘다. model은 text sentence, segment of enrolled speech, 그것들의 상응한 전사스크립트를 넣는다. 우리는 enrolled speech의 전사 phoneme을 입력된 sentence phoneme prompt에 이어붙힌다. (아마 일반 텍스트랑, g2p 텍스트를 이어붙힌다는 이야기일듯?) 그리고, acoustic token의 첫번째 layer(quantizer)의 값을 prefix한다. (input으로 넣기위한) phoneme prompt와 acoustic prefix로 VALL-E는 주어진 text에 대한 화자의 목소리를 생성한다.
  • VALL-E-continual: 이 설정에서, 우리는 전체 전사문과 3초의 acoustic prompt를 사용한다. 그리고 모델에게 이어지는 문장을 생성하도록 한다. 이 inference 처리는 의미적으로 연결되는 음성을 생성하는 것을 제외하면 VALL-E와 동일하게 처리한다.

 

 

Section 4에 대해, 논문 거의 직역+내 의견을 서술해봤다. 차근차근 전부 다 읽어보는걸 추천하고싶다. (그래서 본문의 강조표시를 최대한 자제했다.)

Model 구현체가 정말 궁금해지는 부분이 있고, 이 정도 지식으로 MS 관련인이 아니면, 완벽한 구현체를 개발할 수 있는 사람이 있을까 싶다..;;

728x90

댓글