import os, re
import numpy as np
import tensorflow as tf
import glob
import os
from sklearn.model_selection import train_test_split
txt_file_path = os.getenv('HOME')+'/aiffel/lyricist/data/lyrics/*'
txt_list = glob.glob(txt_file_path)
raw_corpus = []
# 여러개의 txt 파일을 모두 읽어서 raw_corpus 에 담습니다.
for txt_file in txt_list:
with open(txt_file, "r") as f:
raw = f.read().splitlines()
raw_corpus.extend(raw)
print("데이터 크기:", len(raw_corpus))
print("Examples:\n", raw_corpus[:-1])
데이터 크기: 187088
Examples:
["Now I've heard there was a secret chord", 'That David played, and it pleased the Lord', "But you don't really care for music, do you?", 'It goes like this', 'The fourth, the fifth', 'The minor fall, the major lift', 'The baffled king composing Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah Your faith was strong but you needed proof', 'You saw her bathing on the roof', 'Her beauty and the moonlight overthrew her', 'She tied you', 'To a kitchen chair', 'She broke your throne, and she cut your hair', 'And from your lips she drew the Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah You say I took the name in vain', "I don't even know the name", "But if I did, well really, what's it to you?", "There's a blaze of light", 'In every word', "It doesn't matter which you heard", 'The holy or the broken Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', "Hallelujah I did my best, it wasn't much", "I couldn't feel, so I tried to touch", "I've told the truth, I didn't come to fool you", 'And even though', 'It all went wrong', "I'll stand before the Lord of Song", 'With nothing on my tongue but Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah Suzanne takes you down to her place near the river', 'You can hear the boats go by, you can spend the night forever', "And you know that she's half-crazy but that's why you want to be there", 'And she feeds you tea and oranges that come all the way from China', 'And just when you mean to tell her that you have no love to give her', 'Then he gets you on her wavelength', "And she lets the river answer that you've always been her lover And you want to travel with her, and you want to travel blind", 'And you know that she will trust you', "For you've touched her perfect body with your mind And Jesus was a sailor when he walked upon the water", 'And he spent a long time watching from his lonely wooden tower', 'And when he knew for certain only drowning men could see him', 'He said all men will be sailors then until the sea shall free them', 'But he himself was broken, long before the sky would open', 'Forsaken, almost human, he sank beneath your wisdom like a stone And you want to travel with him, and you want to travel blind', "And you think you maybe you'll trust him", "For he's touched your perfect body with her mind Now, Suzanne takes your hand and she leads you to the river", "She's wearing rags and feathers from Salvation Army counters", 'And the sun pours down like honey on our lady of the harbor', 'And she shows you where to look among the garbage and the flowers', 'There are heroes in the seaweed, there are children in the morning', 'They are leaning out for love and they wil lean that way forever', 'While Suzanne holds her mirror And you want to travel with her, and you want to travel blind', 'And you know that you can trust her', "For she's touched your perfect body with her mind Everybody knows that the dice are loaded", 'Everybody rolls with their fingers crossed', 'Everybody knows the war is over', 'Everybody knows the good guys lost', 'Everybody knows the fight was fixed', 'The poor stay poor, the rich get rich', "That's how it goes", 'Everybody knows Everybody knows that the boat is leaking', 'Everybody knows that the captain lied', 'Everybody got this broken feeling', 'Like their father or their dog just died', 'Everybody talking to their pockets', 'Everybody wants a box of chocolates', 'And a long-stem rose', 'Everybody knows Everybody knows that you love me baby', 'Everybody knows that you really do', "Everybody knows that you've been faithful", 'Ah, give or take a night or two', "Everybody knows you've been discreet", 'But there were so many people you just had to meet', 'Without your clothes', 'And everybody knows Everybody knows, everybody knows', "That's how it goes", 'Everybody knows Everybody knows, everybody knows', "That's how it goes", "Everybody knows And everybody knows that it's now or never", "Everybody knows that it's me or you", 'And everybody knows that you live forever', "Ah, when you've done a line or two", 'Everybody knows the deal is rotten', "Old Black Joe's still pickin' cotton", 'For your ribbons and bows', 'And everybody knows And everybody knows that the Plague is coming', "Everybody knows that it's moving fast", 'Everybody knows that the naked man and woman', 'Are just a shining artifact of the past', 'Everybody knows the scene is dead', "But there's gonna be a meter on your bed", 'That will disclose', "What everybody knows And everybody knows that you're in trouble", "Everybody knows what you've been through", 'From the bloody cross on top of Calvary', 'To the beach of Malibu', "Everybody knows it's coming apart", 'Take one last look at this Sacred Heart', 'Before it blows', 'And everybody knows Everybody knows, everybody knows', "That's how it goes", 'Everybody knows Everybody knows, everybody knows', "That's how it goes", 'Everybody knows Everybody knows, everybody knows', "That's how it goes", 'Everybody knows Everybody knows Dance me to your beauty with a burning violin', "Dance me through the panic till I'm gathered safely in", 'Lift me like an olive branch and be my homeward dove', 'Dance me to the end of love', 'Dance me to the end of love Oh, let me see your beauty when the witnesses are gone', 'Let me feel you moving like they do in Babylon', 'Show me slowly what I only know the limits of', 'Dance me to the end of love', 'Dance me to the end of love Dance me to the wedding now, dance me on and on', 'Dance me very tenderly and dance me very long', "We're both of us beneath our love, we're both of us above", 'Dance me to the end of love', 'Dance me to the end of love Dance me to the children who are asking to be born', 'Dance me through the curtains that our kisses have outworn', 'Raise a tent of shelter now, though every thread is torn', 'Dance me to the end of love Dance me to your beauty with a burning violin', "Dance me through the panic till I'm gathered safely in", 'Touch me with your naked hand or touch me with your glove', 'Dance me to the end of love', 'Dance me to the end of love', "Dance me to the end of love Now I've heard there was a secret chord", 'That David played, and it pleased the Lord', "But you don't really care for music, do you?", 'It goes like this', 'The fourth, the fifth', 'The minor fall, the major lift', 'The baffled king composing Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah Your faith was strong but you needed proof', 'You saw her bathing on the roof', 'Her beauty and the moonlight overthrew her', 'She tied you', 'To a kitchen chair', 'She broke your throne, and she cut your hair', 'And from your lips she drew the Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah You say I took the name in vain', "I don't even know the name", "But if I did, well really, what's it to you?", "There's a blaze of light", 'In every word', "It doesn't matter which you heard", 'The holy or the broken Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', "Hallelujah I did my best, it wasn't much", "I couldn't feel, so I tried to touch", "I've told the truth, I didn't come to fool you", 'And even though', 'It all went wrong', "I'll stand before the Lord of Song", 'With nothing on my tongue but Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah', 'Hallelujah Suzanne takes you down to her place near the river', 'You can hear the boats go by, you can spend the night forever', "And you know that she's half-crazy but that's why you want to be there", 'And she feeds you tea and oranges that come all the way from China', 'And just when you mean to tell her that you have no love to give her', 'Then he gets you on her wavelength', "And she lets the river answer that you've always been her lover And you want to travel with her, and you want to travel blind", 'And you know that she will trust you', "For you've touched her perfect body with your mind And Jesus was a sailor when he walked upon the water", 'And he spent a long time watching from his lonely wooden tower', 'And when he knew for certain only drowning men could see him', 'He said all men will be sailors then until the sea shall free them', 'But he himself was broken, long before the sky would open', 'Forsaken, almost human, he sank beneath your wisdom like a stone And you want to travel with him, and you want to travel blind', "And you think you maybe you'll trust him", "For he's touched your perfect body with her mind Now, Suzanne takes your hand and she leads you to the river", "She's wearing rags and feathers from Salvation Army counters", 'And the sun pours down like honey on our lady of the harbor', 'And she shows you where to look among the garbage and the flowers', 'There are heroes in the seaweed, there are children in the morning', 'They are leaning out for love and they wil lean that way forever', 'While Suzanne holds her mirror And you want to travel with her, and you want to travel blind', 'And you know that you can trust her', "For she's touched your perfect body with her mind Everybody knows that the dice are loaded", 'Everybody rolls with their fingers crossed', 'Everybody knows the war is over', 'Everybody knows the good guys lost', 'Everybody knows the fight was fixed', 'The poor stay poor, the rich get rich', "That's how it goes", 'Everybody knows Everybody knows that the boat is leaking', 'Everybody knows that the captain lied', 'Everybody got this broken feeling', 'Like their father or their dog just died', 'Everybody talking to their poeven believe in breathin' I'm leavin' air in your lungs", "Just to hear you keep screamin' for me to seep it", "Okay, I'm ready to go play", 'I go the machete from O.J.', "I'm ready to make everyone's throat ache", "You faggots keep eggin' me on", 'Til I have you at knife point, then you beg me to stop?', 'Shut up! Give me your hands and feet', "I said shut up when I'm talkin' to you", "You hear me? Answer me! Bitch I'm a kill you! You don't want to fuck with me", "Girls leave, you ain't nothin' but a slut to me", "Bitch I'm a kill you! You ain't got the balls to beef", "We ain't goin' never stop beefin' I don't squash the beef Ha ha ha, I'm just playin' ladies"]
Step 2. 데이터 정제¶
문장 전처리 방식¶
- 소문자로 바꾸고, 양쪽 공백을 지웁니다
- 특수문자 양쪽에 공백을 넣고
- 여러개의 공백은 하나의 공백으로 바꿉니다
- a-zA-Z?.!,¿가 아닌 모든 문자를 하나의 공백으로 바꿉니다
- 다시 양쪽 공백을 지웁니다
- 문장 시작에는 start, 끝에는 end를 추가합니다
- 괄호 제거 - 코러스 싫다(추가)
- 토큰 갯수 15개 이하로 조정(추가)
#정제함수 만들기
def preprocess_sentence(sentence):
sentence = sentence.lower().strip() # 1
sentence = re.sub(r"([?.!,¿])", r" \1 ", sentence) # 2
sentence = re.sub(r'[" "]+', " ", sentence) # 3
sentence = re.sub(r"[^a-zA-Z?.!,¿]+", " ", sentence) # 4
sentence = sentence.strip() # 5
sentence = re.sub(r"\(.\)", " ", sentence) # 7
sentence = '<start> ' + sentence + ' <end>' # 6
return sentence
# 이 문장이 어떻게 필터링되는지 확인해 보세요.
print(preprocess_sentence("This @_is ;;;sample (sentences) sentence ."))
<start> this is sample sentences sentence . <end>
정제 데이터 구축하기¶
소스문장은 start + sentence + end, 타겟문장은 sentence + end
# 여기에 정제된 문장을 모을겁니다
corpus = []
for sentence in raw_corpus:
# 우리가 원하지 않는 문장은 건너뜁니다
if len(sentence) == 0: continue
if sentence[-1] == ":": continue
if len(sentence) > 105 : continue
# 정제를 하고 corpus list에 담기
preprocessed_sentence = preprocess_sentence(sentence) # 들어온 한 문장에 위의 함수처리한걸 받는 인자
corpus.append(preprocessed_sentence) #함수처리한 str값을 corpus 리스트에 집어넣기
# 정제된 결과를 10개만 확인
print(corpus[:10])
len(corpus) #문장 갯수
['<start> now i ve heard there was a secret chord <end>', '<start> that david played , and it pleased the lord <end>', '<start> but you don t really care for music , do you ? <end>', '<start> it goes like this <end>', '<start> the fourth , the fifth <end>', '<start> the minor fall , the major lift <end>', '<start> the baffled king composing hallelujah hallelujah <end>', '<start> hallelujah <end>', '<start> hallelujah <end>', '<start> hallelujah your faith was strong but you needed proof <end>']
174461
한 단어 평균 길이 6, 15어절이면 15단어 + 공백 15개 = 15x6 + 15 = 105 정도로 산정하여 코퍼스 길이를 조절했다. 이렇게 하면 긴 가사 데이터때문에 발생하는 과도한 패딩을 막을 수 있다.
데이터 벡터화(텐서화) - str 에서 숫자로¶
데이터를 숫자로 변환하기. 이 과정을 벡터화(vectorize) 라 하며, 숫자로 변환된 데이터를 텐서(tensor) 라고 칭한다. 우리가 사용하는 텐서플로우로 만든 모델의 입출력 데이터는 실제로는 모두 이런 텐서로 변환되어 처리되는 것.
# 토큰화 할 때 텐서플로우의 Tokenizer와 pad_sequences를 사용합니다
def tokenize(corpus): #corpus : 정제된 문장str 들의 리스트
# 12000단어를 기억할 수 있는 tokenizer를 만들겁니다
# 우리는 이미 문장을 정제했으니 filters가 필요없어요
# 12000단어에 포함되지 못한 단어는 '<unk>'로 바꿀거에요
tokenizer = tf.keras.preprocessing.text.Tokenizer(
num_words=12000, #인덱스 최대치
filters=' ', #필터 필요 없어서 비워둠
oov_token="<unk>" # 최대치
)
# corpus를 이용해 tokenizer 내부의 단어장을 완성합니다
tokenizer.fit_on_texts(corpus)
# 준비한 tokenizer를 이용해 corpus를 Tensor로 변환합니다
tensor = tokenizer.texts_to_sequences(corpus)
# 입력 데이터의 시퀀스 길이를 일정하게 맞춰줍니다
# 만약 시퀀스가 짧다면 문장 뒤에 패딩을 붙여 길이를 맞춰줍니다.
# 문장 앞에 패딩을 붙여 길이를 맞추고 싶다면 padding='pre'를 사용합니다
tensor = tf.keras.preprocessing.sequence.pad_sequences(tensor, padding='post') #post는 뒤에다가 패딩 붙이기
print("토크나이저 : ",tokenizer,"\n" ,tensor)
return tensor, tokenizer
tensor, tokenizer = tokenize(corpus)
tensor.shape
토크나이저 : <keras_preprocessing.text.Tokenizer object at 0x7ff33ca1ab80>
[[ 2 50 5 ... 0 0 0]
[ 2 17 2589 ... 0 0 0]
[ 2 35 7 ... 0 0 0]
...
[ 2 131 5 ... 0 0 0]
[ 2 23 89 ... 0 0 0]
[ 2 7 33 ... 0 0 0]]
(174461, 35)
기존에 학습을 진행하려 헀을떄, 텐서의 크기가 12001x256x347로 매우 길었다. 아무래도 가사 중 한 줄이 매우 길어, 나머지 가사 데이터에도 과도한 패딩이 삽입된것으로 판단되었다. 하여 정제 데이터를 만들 때 15어절 이상 되는 문장들을 모두 절삭했다,
corpus tensor 모든 로우의 시작값이 2, 문장 종료값이 3, 나머지는 0인 이유?¶
인덱스 2,3이 start와 end라서 모든 코퍼스 내 원소의 시작은 2, 끝지점은 3, 7000단어까지 인덱싱을 하고도 남은 단어는 1(unk), 남은 길이는 패딩인 0이 된다.
#토크나이저 내부 인덱스별 할당된 단어 모음 1~10까지만 보기
for idx in tokenizer.index_word:
print(idx, ":", tokenizer.index_word[idx])
if idx >= 10: break
1 : <unk>
2 : <start>
3 : <end>
4 : ,
5 : i
6 : the
7 : you
8 : and
9 : a
10 : to
훈련데이터와 평가데이터 분리¶
tensor에서 마지막 토큰을 잘라내어 소스문장을 만들고(end보단 pad가 지워질 가능성 多), 첫번째 start를 잘래내서 타겟 문장을 만든다. 이렇게 함으로서 scr_input과 trg_input의 크기를 맞춘다.
사이킷 런 split함수를 이용해서 훈련용 데이터와 검증용 데이터를 나눈다
# 소스문장과 타겟문장으로 1차 분리
src_input = tensor[:, :-1]
# tensor에서 <start>를 잘라내서 타겟 문장을 생성합니다.
tgt_input = tensor[:, 1:]
print("텐서 길이: ",tensor.shape)
print("소스문장 길이: ",len(src_input[0])) #346 start + sentence + end + padding n개
print("타겟문장 길이: ",len(tgt_input[0])) #346 sentence + end + 패딩 n+1개
# 각각의 데이터에서 훈련셋, 평가셋 나누기
enc_train, enc_val, dec_train, dec_val = train_test_split(src_input,
tgt_input,
test_size=0.2,
random_state=7)
print("Source Train 길이:", enc_train.shape)
print("Target Train 길이:", dec_train.shape)
print("Source Test 길이:", enc_val.shape)
print("Target Test 길이:", dec_val.shape)
텐서 길이: (174461, 35)
소스문장 길이: 34
타겟문장 길이: 34
Source Train 길이: (139568, 34)
Target Train 길이: (139568, 34)
Source Test 길이: (34893, 34)
Target Test 길이: (34893, 34)
tf.data.Dataset객체를 생성¶
tf.data.Dataset.from_tensor_slices() 메소드를 이용해 tf.data.Dataset객체를 생성
# 하이퍼파라미터 설정
BUFFER_SIZE = len(src_input)
BATCH_SIZE = 256
steps_per_epoch = len(src_input) // BATCH_SIZE
VOCAB_SIZE = tokenizer.num_words + 1
# tokenizer가 구축한 단어사전 내 12000개 + 0:<pad> = 12001개
# 1. 학습데이터셋 객체 만들기
dataset_train = tf.data.Dataset.from_tensor_slices((enc_train, dec_train)) #각 원소별로 자르기
dataset_train = dataset_train.shuffle(BUFFER_SIZE) # 해당 길이에서 랜덤으로 원소 나열
dataset_train = dataset_train.batch(BATCH_SIZE, drop_remainder=True) # 해당 값만큼의 연속된 원소들 묶음
#2. 검증데이터셋 객체 만들기
dataset_val = tf.data.Dataset.from_tensor_slices((enc_val, dec_val)) #각 원소별로 자르기
dataset_val = dataset_val.shuffle(BUFFER_SIZE) # 해당 길이에서 랜덤으로 원소 나열
dataset_val = dataset_val.batch(BATCH_SIZE, drop_remainder=True) # 해당 값만큼의 연속된 원소들 묶음
print(dataset_train)
print(dataset_val)
<BatchDataset shapes: ((256, 34), (256, 34)), types: (tf.int32, tf.int32)>
<BatchDataset shapes: ((256, 34), (256, 34)), types: (tf.int32, tf.int32)>
만약 데이터가 같은 크기(차원)을 가졌다면, drop-remainder를 True(나머지 원소 버림)
배치 사이즈로 데이터를 나누다 보면, 마지막에 배치 사이즈보다 작아서 안나눠지는 원소들이 있다. 이걸 안없애면마지막 배치는 다른 배치들과 크기가 안맞아서 오류가 날수도. 배치사이즈가 데이터 길이와 정확히 나누어 떨어지지 않을떈 True로 바꿔주자.
LSTM 모델설명¶
우리 입력 텐서에는 단어 사전의 인덱스가 들어 있다. Embedding 레이어는 이 인덱스 값을 해당 인덱스 번째의 워드 벡터로 바꿔 준다. 이 워드 벡터는 의미 벡터 공간에서 단어의 추상적 표현(representation)으로 사용된다.
class TextGenerator(tf.keras.Model):
def __init__(self, vocab_size, embedding_size, hidden_size):
super().__init__() #얘는 무슨 초기화값을 상속받는것인가
self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_size)
self.rnn_1 = tf.keras.layers.LSTM(hidden_size, return_sequences=True)
self.rnn_2 = tf.keras.layers.LSTM(hidden_size, return_sequences=True)
self.linear = tf.keras.layers.Dense(vocab_size) #단어책 사이즈로 줄여줘야 다음에 무슨 단어를 낼지에 대한 각 클래스별 수치 나옴
def call(self, x):
out = self.embedding(x)
out = self.rnn_1(out)
out = self.rnn_2(out)
out = self.linear(out)
return out
embedding_size = 256 #워드 벡터의 차원수, 즉 단어가 추상적으로 표현되는 크기
hidden_size = 1024 #hidden state의 차원 수 : 판단 횟수? or 판단 다양성? 판단하는 두뇌 수?
model = TextGenerator(tokenizer.num_words + 1, embedding_size , hidden_size) #모델 정의
model
<__main__.TextGenerator at 0x7ff32f763a30>
# 데이터셋에서 데이터 한 배치만 불러오는 방법입니다.
for src_sample, tgt_sample in dataset_train.take(1): break
# 한 배치만 불러온 데이터를 모델에 넣어봅니다
model(src_sample)
<tf.Tensor: shape=(256, 34, 12001), dtype=float32, numpy=
array([[[ 6.9890462e-05, 1.2302386e-04, -2.3614240e-04, ...,
-1.7891931e-05, 8.8219800e-05, -1.7181928e-04],
[ 6.2084873e-05, 1.8533210e-04, -6.6537847e-05, ...,
4.3826429e-05, -1.2303291e-04, -5.1719649e-04],
[ 6.5600601e-05, 3.2257460e-04, -2.2192957e-04, ...,
1.8803528e-04, -3.3346534e-04, -5.6645385e-04],
...,
[ 1.6001218e-03, -1.7209121e-03, 1.6671011e-03, ...,
1.7798361e-03, 1.5855556e-03, -2.1146890e-03],
[ 1.6336303e-03, -1.7272026e-03, 1.7200509e-03, ...,
1.7958258e-03, 1.5988543e-03, -2.1144727e-03],
[ 1.6626426e-03, -1.7330914e-03, 1.7654380e-03, ...,
1.8053156e-03, 1.6068969e-03, -2.1113551e-03]],
[[ 6.9890462e-05, 1.2302386e-04, -2.3614240e-04, ...,
-1.7891931e-05, 8.8219800e-05, -1.7181928e-04],
[ 2.5214516e-05, 2.2094949e-04, -1.7311501e-04, ...,
-1.1887746e-04, -3.3147906e-05, -3.7780695e-04],
[-1.6571439e-04, 3.0812109e-04, -1.3039616e-05, ...,
-2.0551367e-04, -2.3654602e-04, -3.2653118e-04],
...,
[ 1.7223302e-03, -1.7733467e-03, 1.8954466e-03, ...,
1.7736976e-03, 1.6577835e-03, -2.1311496e-03],
[ 1.7400858e-03, -1.7783067e-03, 1.9175935e-03, ...,
1.7785274e-03, 1.6509631e-03, -2.1172722e-03],
[ 1.7559454e-03, -1.7828743e-03, 1.9352873e-03, ...,
1.7808949e-03, 1.6433178e-03, -2.1041979e-03]],
[[ 6.9890462e-05, 1.2302386e-04, -2.3614240e-04, ...,
-1.7891931e-05, 8.8219800e-05, -1.7181928e-04],
[ 2.1778757e-04, 4.6852816e-05, -3.6291368e-04, ...,
6.1500526e-05, 7.0178539e-05, -3.5610961e-04],
[ 4.4207377e-04, 1.0229261e-05, -4.3715839e-04, ...,
1.6286712e-04, -1.1932215e-04, -2.0887644e-04],
...,
[ 1.3166339e-03, -1.6129328e-03, 1.5469586e-03, ...,
1.6118240e-03, 1.3783925e-03, -1.9305162e-03],
[ 1.3858657e-03, -1.6353991e-03, 1.6013976e-03, ...,
1.6699085e-03, 1.4363576e-03, -1.9767755e-03],
[ 1.4471270e-03, -1.6535829e-03, 1.6523016e-03, ...,
1.7145452e-03, 1.4813526e-03, -2.0107469e-03]],
...,
[[ 6.9890462e-05, 1.2302386e-04, -2.3614240e-04, ...,
-1.7891931e-05, 8.8219800e-05, -1.7181928e-04],
[ 2.5235114e-04, 1.0280946e-04, -5.2404427e-04, ...,
5.3720560e-05, -3.1236963e-05, -5.6305726e-04],
[ 3.6411770e-04, 3.2023119e-04, -5.2974711e-04, ...,
3.9026840e-05, -1.5800849e-04, -4.2459651e-04],
...,
[ 1.6234976e-03, -1.6960505e-03, 1.8624075e-03, ...,
1.7997758e-03, 1.6839014e-03, -2.1134496e-03],
[ 1.6533016e-03, -1.7068246e-03, 1.8846986e-03, ...,
1.8033733e-03, 1.6746887e-03, -2.1047590e-03],
[ 1.6796637e-03, -1.7173303e-03, 1.9036020e-03, ...,
1.8040800e-03, 1.6644868e-03, -2.0955335e-03]],
[[ 6.9890462e-05, 1.2302386e-04, -2.3614240e-04, ...,
-1.7891931e-05, 8.8219800e-05, -1.7181928e-04],
[ 1.3426633e-04, 4.3778584e-04, -6.3207600e-04, ...,
1.8907829e-04, 3.3499586e-04, 4.0491766e-05],
[ 2.2303511e-04, 5.5509532e-04, -6.7670282e-04, ...,
-2.0520329e-05, 6.4877770e-04, 1.7103092e-04],
...,
[ 1.7589974e-03, -1.7559971e-03, 1.8873872e-03, ...,
1.7884470e-03, 1.5982640e-03, -2.0932755e-03],
[ 1.7752702e-03, -1.7636589e-03, 1.9068717e-03, ...,
1.7897842e-03, 1.5968939e-03, -2.0836729e-03],
[ 1.7893732e-03, -1.7704326e-03, 1.9225434e-03, ...,
1.7894646e-03, 1.5948535e-03, -2.0746663e-03]],
[[ 6.9890462e-05, 1.2302386e-04, -2.3614240e-04, ...,
-1.7891931e-05, 8.8219800e-05, -1.7181928e-04],
[-7.6767119e-06, 2.0043371e-04, -3.9125624e-04, ...,
-1.5301259e-04, 1.7711469e-04, -3.5978085e-04],
[-2.3362853e-04, 4.0939733e-04, -1.6460339e-04, ...,
-3.4285858e-04, 3.0592838e-04, -4.4570011e-04],
...,
[ 1.5849182e-03, -1.6908842e-03, 1.8239557e-03, ...,
1.8449147e-03, 1.6467485e-03, -2.1344591e-03],
[ 1.6228110e-03, -1.7097075e-03, 1.8538389e-03, ...,
1.8456778e-03, 1.6455570e-03, -2.1278446e-03],
[ 1.6558898e-03, -1.7255087e-03, 1.8791597e-03, ...,
1.8433908e-03, 1.6421666e-03, -2.1198641e-03]]], dtype=float32)>
shape=(256, 34, 12001) 12001 - dense layer 출력 차원수 : 다음에 무슨 단어가 올 확률이 높은가?
256 - 배치사이즈, 256개의 문장 가져옴 take(1) 이므로 배치 1번
34 - tf.keras.layers.LSTM(hidden_size, return_sequences=True)에서 return_sequences=True와 연관있다. 자신에게 입력된 시퀀스의 길이만큼 동일한 길이의 시퀀스 출력하라는 의미 return_sequences=False 면 1로 출력됨
모델 구조 확인¶
model.summary()
tf.test.is_gpu_available() #gpu 사용하고 있는지?
Model: "text_generator"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding (Embedding) multiple 3072256
_________________________________________________________________
lstm (LSTM) multiple 5246976
_________________________________________________________________
lstm_1 (LSTM) multiple 8392704
_________________________________________________________________
dense (Dense) multiple 12301025
=================================================================
Total params: 29,012,961
Trainable params: 29,012,961
Non-trainable params: 0
_________________________________________________________________
WARNING:tensorflow:From /tmp/ipykernel_295/3050079633.py:2: is_gpu_available (from tensorflow.python.framework.test_util) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.config.list_physical_devices('GPU')` instead.
True
모델 학습시키기¶
optimizer = tf.keras.optimizers.Adam()
loss = tf.keras.losses.SparseCategoricalCrossentropy(
from_logits=True,
reduction='none'
)
model.compile(loss=loss, optimizer=optimizer)
model.fit(dataset_train, epochs=10)
Epoch 1/10
545/545 [==============================] - 258s 469ms/step - loss: 1.6943
Epoch 2/10
545/545 [==============================] - 257s 471ms/step - loss: 1.4004
Epoch 3/10
545/545 [==============================] - 257s 470ms/step - loss: 1.3234
Epoch 4/10
545/545 [==============================] - 257s 470ms/step - loss: 1.2666
Epoch 5/10
545/545 [==============================] - 256s 470ms/step - loss: 1.2180
Epoch 6/10
545/545 [==============================] - 256s 470ms/step - loss: 1.1739
Epoch 7/10
545/545 [==============================] - 257s 471ms/step - loss: 1.1329
Epoch 8/10
545/545 [==============================] - 257s 471ms/step - loss: 1.0944
Epoch 9/10
545/545 [==============================] - 257s 471ms/step - loss: 1.0579
Epoch 10/10
545/545 [==============================] - 257s 471ms/step - loss: 1.0232
<keras.callbacks.History at 0x7ff32f4388b0>
모델 사용해 보기¶
#단어
#생성기
def generate_text(model, tokenizer, init_sentence="<start>", max_len=30):
# 테스트를 위해서 입력받은 init_sentence도 텐서로 변환합니다
test_input = tokenizer.texts_to_sequences([init_sentence])
test_tensor = tf.convert_to_tensor(test_input, dtype=tf.int64)
end_token = tokenizer.word_index["<end>"]
# 단어 하나씩 예측해 문장을 만듭니다
# 1. 입력받은 문장의 텐서를 입력합니다
# 2. 예측된 값 중 가장 높은 확률인 word index를 뽑아냅니다
# 3. 2에서 예측된 word index를 문장 뒤에 붙입니다
# 4. 모델이 <end>를 예측했거나, max_len에 도달했다면 문장 생성을 마칩니다
while True:
# 1
predict = model(test_tensor)
# 2
predict_word = tf.argmax(tf.nn.softmax(predict, axis=-1), axis=-1)[:, -1]
# 3
test_tensor = tf.concat([test_tensor, tf.expand_dims(predict_word, axis=0)], axis=-1)
# 4
if predict_word.numpy()[0] == end_token: break
if test_tensor.shape[1] >= max_len: break
generated = ""
# tokenizer를 이용해 word index를 단어로 하나씩 변환합니다
for word_index in test_tensor[0].numpy():
generated += tokenizer.index_word[word_index] + " "
return generated
While문의 역할¶
해당 모델을 평가하기 위한 평가지표인 테스트 셋이 존재하지 않는다. 또한, 소스문장도 따로 존재하지 않는다. 그럼 평가척도는?
while문은 RNN의 구조상 필요한 형식이다. 루프를 한번 돌면 start 뒤에 가장 높은 확률의 단어 인덱스를 삽입한다.
아래의 for문은 해당 인덱스에 할당된 단어 str을 generated str값 안에다가 집어넣어 문장을 완성한다.
단어 생성!¶
generate_text(model, tokenizer, init_sentence="<start> i love", max_len=20)
'<start> i love you , i love you , i love you <end> '
회고¶
힘들었던 부분¶
가장 힘들었던 부분은 데이터 정제와 인코딩을 통해 텐서화가 되며, 현재 데이터의 차원을 계속 인지하는 부분이였다. 데이터의 크기와 모양이 맞지 않아 그걸 맞추느라 고생했고, 두번째는 과연 어떻게 15 어절에서 토큰을 끊어낼 수 있는가 였다. 처음에는 텐서화시키는 부분에서 절삭을 하려했다. 다시말해, 패딩이 들어가는 부분에서 처리를 하려 했는데, 그렇게 하니 긴 문장에서 end값이 삭제되어 버린다는 것을 깨달았다. 결국 데이터 전처리 부분, 즉 정규표현식을 이용한 str값 처리 + 예외조항에서 처리해 줘야하는 거였다. start값과 end값을 삽입하기 이전 데이터에서 말이다. 단어 어절 별로 끊는 방법을 물색해 봤으나, 결국 찾지 못해 아쉬운대로 코퍼스의 길이값을 이용해 끊어내기로 했다. 한 단어의 평균 길이를 6정도로 산정하고, (기준은 played, danced, killed 등 동사 + ed 등의 단어가 자주 나오는 듯 하여 그렇게 구성함. 훨씬 긴 단어도 많았지만, i나 he 등과 같이 짧은 길이 단어도 존재하니, 어느정도 참작이 될 거라 판단했다.), 15어절이니 띄어쓰기 15칸을 포함해 길이 105를 산정했다. 105보다 긴 길이의 코퍼스는 생각보다 많지 않았고, 이를 통해 이상치들을 삭제할 수 있었다. 더 정확한 방법을 찾지 못해 사용한 임시방편이였으나, 결괏값이 좋았으므로 나쁘지 않은 접근방식으로 생각된다.
느낀점¶
저번 프로젝트와는 다르게 코드가 나오면 파라미터는 무엇이 있는지 하나하나 차근차근 확인해 보며 진행했다. 시간은 수십배 더 걸렸으나, 자잘한 오류나 변수 오판 등의 실수를 상당히 감소시켰다. 마지막으로, 문제 해결을 위해 코딩만 잘하면 되는 게 아니라 어떤식으로 접근할지 생각하는지도 굉장히 중요하다는 걸 깨달았다. 접근 방식을 달리하니, 어렵게 구현할 문제도 굉장히 쉬워지곤 했다. 궁금한 점은 시키는대로 트레이닝 셋과 테스트 셋을 나눴는데, 테스트셋이 어디에 들어가는지를 인지하지 못했다. 아직 모델 학습에 관한 이해도가 부족한 것으로 보여 모델 학습과 관련한 코드를 더 뜯어보고자 다짐한다.
'Computer Technology 기록부 > 코딩기록부 : Python' 카테고리의 다른 글
머신러닝을 위한 sklearn 라이브러리 기능 이용 (0) | 2022.07.05 |
---|---|
DecisionTreeClassifier 이용한 Data classification (0) | 2022.07.05 |
MNIST Dataset 이용한 CNN 모델 구축 (0) | 2022.07.05 |
[최종] 카메라 스티커 만들기 - 예외처리 포함 (0) | 2022.01.13 |
카메라 스티커 만들기 (0) | 2022.01.11 |
댓글