본문 바로가기
카테고리 없음

[AI] 간단한 RNN 모델로 노래 가사 예측하기

by Foxy현 2022. 12. 18.
728x90
반응형

안녕하세요!
오늘은 노래 가사를 데이터로 사용하여, 특정 단어가 주어졌을 때 다음 단어로 어떤 게 나올지 예측해보는
프로그램을 실습하겠습니다!

먼저, 필요한 라이브러리를 불러옵니다.

import numpy as np
from tensorflow.keras.layers import Embedding, Flatten, Dense, LSTM, SimpleRNN
from tensorflow.keras.models import Sequential
from tensorflow.keras.preprocessing.text import one_hot
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.utils import to_categorical


text_data로는 Jason Mraz의 'I'm Yours' 의 일부를 사용하겠습니다.

text_data = """Well, you done done me in, you bet I felt it\n
I tried to be chill, but you're so hot that I melted\n
I fell right through the cracks\n
Now I'm trying to get back\n
Before the cool done run out\n
I'll be giving it my bestest\n
And nothing's gonna stop me but divine intervention\n
I reckon it's again my turn\n
To win some or learn some\n
But I won't hesitate no more, no more\n
It cannot wait, I'm yours\n
Well, open up your mind and see like me\n
Open up your plans and, damn, you're free\n
Look into your heart and you'll find love, love, love, love\n
Listen to the music of the moment, people dance and sing\n
We're just one big family\n
And it's our God-forsaken right to be loved, loved, loved, loved, loved\n
So I won't hesitate no more, no more\n
It cannot wait, I'm sure\n
There's no need to complicate\n
Our time is short\n
This is our fate, I'm yours\n
"""


문장으로부터 단어를 토큰화하고 숫자에 대응하는 딕셔너리를 생성하는 Tokenizer 객체를 생성하겠습니다.
fit_on_texts는 문자 데이터를 입력 받아 리스트 형태로 변환합니다.
texts_to_sequences는 단어들을 시퀀스 데이터 형태로 변환합니다.

tokenizer = Tokenizer() # 문장으로부터 단어를 토큰화하고 숫자에 대응하는 딕셔너리 생성
tokenizer.fit_on_texts([text_data]) # 문자 데이터를 입력 받아 리스트 형태로 변환
encoded = tokenizer.texts_to_sequences([text_data])[0] # 단어들을 시퀀스 데이터 형태로 변환
print(encoded)

결과를 확인해보면 텍스트 데이터가 숫자 형태의 리스트로 저장된 것을 확인할 수 있습니다.

다음으로, 단어와 숫자의 키-값을 포함하는 딕셔너리로 변환하는 word_index를 합니다.
Vocab_size는 RNN 학습 데이터 형태로 만들기 위해 인덱스에 + 1한 값을 저장합니다.

print(tokenizer.word_index) # 각 단어들의 인덱스 표현
vocab_size = len(tokenizer.word_index)+1 # 재귀 신경망의 학습 데이터 형태로 만들어주기 위해 index + 1
print('vocab_size', vocab_size)


한 단어를 입력으로, 한 단어를 출력으로 하는 단어 Sequence를 생성합니다.

sequences = list()
for i in range(1, len(encoded)):
    sequence = encoded[i-1:i+1]  # i-1은 입력, i+1은 출력
    sequences.append(seqence)
print(sequences)
print('length', len(sequences))

encoded 배열의 i-1 항목은 이전 내용에 대한, i 항목은 다음 혹은 현재 상태에 대한 내용이 저장됩니다.

생성한 Sequence 데이터를 이용해 훈련 데이터의 입력, 결과를 생성합니다.

seqences = np.array(seqences) # 모델에 넣기 위해 데이터를 행렬로 표현
X,y = seqences[:,0], seqences[:,1]
print("X: ", X) 
print("y: ", y)

X,y를 비교해보면 y가 X보다 1씩 큰 것을 확인할 수 있습니다.

이제 본격적으로 신경망에 데이터를 넣어 학습해볼까요?

간단한 모델을 생성해봅시다.

  • Embedding -> 번호가 붙여진 단어를 입력 받아 실수로 된 단어 벡터를 출력
  • LSTM
  • 출력 Dense
model = Sequential([
	Embedding(vocab_size, 10, input_length=1),
    LSTM(50),
    Dense(vocab_size, activation='softmax')
])

model.summary()

Sparse_categorical_crossentropy를 사용해 원핫인코딩 되지 않은 데이터들을 분류합니다.

model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
# 정수형 분류를 위한 loss 방법


모델을 학습합니다.
y 에는 X+1의 인덱스가 들어있습니다.

model.fit(X, y, epochs=400, verbose=2)


정확도는 약 70% 정도 나왔네요
모델이 간략한지라 성능이 좋지않지만, 테스트를 해볼까요?

Jason Mraz의 노래에서는 I'm + Yours 의 형태의 가사가 종종 나옵니다.
과연 I'm 다음에는 어떤 단어가 나올까요?

테스트 데이터도 위와 마찬가지로 Sequence 데이터로 변환해주고, 모델에 넣기 위해 배열로 변환해줍니다.

test_text = "i'm" # i'm 다음에는 yours, trying등 다양한 단어가 옴
encoded = tokenizer.texts_to_sequences([test_text])[0] # i'm의 인덱스 표현
encoded = np.array([encoded])
print('encoded', encoded)


이제 예측해보겠습니다!

onehot_output = model.predict(encoded) # 모델 예측
print('onehot_output=', onehot_output)
output = np.argmax(onehot_output) # i'm 다음으로 가장 많이(max) 나오는 단어 지정
print('output=', output)

for word, index in tokenizer.word_index.items():
    # 인덱스와 yours(29)가 같으면 조건문
    if index == output:
        print(test_text, "=>", word)

잘 나오네요!


요약하자면,

  • 텍스트 데이터들을 토큰화하여 각 단어별로 인덱스를 지정한다.
  • Sequence 데이터로 변환한다.
  • RNN
  • 이전 값(I'm) 을 입력으로 넣으면 다음 상태(Yours)의 값이 출력된다.


Hola

728x90
반응형