데이터분석/예시코드

RNN을 이용한 텍스트 생성

이규승 2022. 5. 27. 16:23
728x90

RNN을 이용한 텍스트 생성 : 문맥을 반영해서 다음 단어를 예측하고 텍스트를 생성하기

데이터

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

text = """경마장에 있는 말이 뛰고 있다
그의 말이 법이다
가는 말이 고와야 온는 말이 곱다"""

 

인덱싱

# word indexing
tok = Tokenizer()
tok.fit_on_texts([text]) #list type
encoded = tok.texts_to_sequences([text])[0] #list type

vocab_size = len(tok.word_index) + 1 # 원핫 처리, embedding에 사용

 

훈련 데이터 만들기

sequences = list()
for line in text.split('\n'): #문장 토큰화
    enco = tok.texts_to_sequences([line])[0]
    print(enco)
    # 바로 다음 단어를 label로 사용하기 위해
    for i in range(1, len(enco)):
        sequ = enco[:i+1]
        print(sequ) # [2, 3]...
        sequences.append(sequ)
        
print('학습에 참여할 샘플 수 :%d'%len(sequences)) #11
print(sequences) #[[2, 3], [2, 3, 1], [2, 3, 1, 4], ..

print(max(len(i) for i in sequences)) # 모든 벡터 중에서 가장 길이가 긴 값 출력

# 전체 각가의 벡터의 길이를 통일
max_len = max(len(i) for i in sequences)

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
학습에 참여할 샘플 수 :11
[[2, 3], [2, 3, 1], [2, 3, 1, 4], [2, 3, 1, 4, 5], [6, 1], [6, 1, 7], [8, 1], [8, 1, 9], [8, 1, 9, 10], [8, 1, 9, 10, 1], [8, 1, 9, 10, 1, 11]]
6

 

패딩 채우기

# 패딩채우기
psequences = pad_sequences(sequences, maxlen=max_len, padding='pre')
print(psequences)

# 각 벡터의 마지막 요소(단어)를 레이블로 사용하기 위해 분리
x = psequences[:,:-1] #feature
y = psequences[:, -1] #label
print(x)
print(y)

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
[[ 0  0  0  0  2  3]
 [ 0  0  0  2  3  1]
 [ 0  0  2  3  1  4]
 [ 0  2  3  1  4  5]
 [ 0  0  0  0  6  1]
 [ 0  0  0  6  1  7]
 [ 0  0  0  0  8  1]
 [ 0  0  0  8  1  9]
 [ 0  0  8  1  9 10]
 [ 0  8  1  9 10  1]
 [ 8  1  9 10  1 11]]
[[ 0  0  0  0  2]
 [ 0  0  0  2  3]
 [ 0  0  2  3  1]
 [ 0  2  3  1  4]
 [ 0  0  0  0  6]
 [ 0  0  0  6  1]
 [ 0  0  0  0  8]
 [ 0  0  0  8  1]
 [ 0  0  8  1  9]
 [ 0  8  1  9 10]
 [ 8  1  9 10  1]]
[ 3  1  4  5  1  7  1  9 10  1 11]

 

원핫 처리

# 레이블을 원핫 처리
y = to_categorical(y, num_classes=vocab_size)
print(y[:2])

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
[[0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]

 

모델

# model
model = Sequential()
model.add(Embedding(vocab_size, 32, input_length=max_len-1))
model.add(LSTM(32, activation ='tanh'))
model.add(Flatten()) # FClayer
model.add(Dense(32, activation='relu'))
model.add(Dense(32, activation='relu'))
model.add(Dense(vocab_size, activation='softmax'))

print(model.summary())

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 embedding (Embedding)       (None, 5, 32)             384       
                                                                 
 lstm (LSTM)                 (None, 32)                8320      
                                                                 
 flatten (Flatten)           (None, 32)                0         
                                                                 
 dense (Dense)               (None, 32)                1056      
                                                                 
 dense_1 (Dense)             (None, 32)                1056      
                                                                 
 dense_2 (Dense)             (None, 12)                396       
                                                                 
=================================================================
Total params: 11,212
Trainable params: 11,212
Non-trainable params: 0
_________________________________________________________________
None

 

컴파일

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(x, y, epochs=200, verbose=2)
print('model.evaluate', model.evaluate(x, y))


ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

Epoch 200/200
1/1 - 0s - loss: 0.0091 - accuracy: 1.0000 - 2ms/epoch - 2ms/step

1/1 [==============================] - ETA: 0s - loss: 0.0090 - accuracy: 1.0000
1/1 [==============================] - 0s 333ms/step - loss: 0.0090 - accuracy: 1.0000
model.evaluate [0.008973545394837856, 1.0]

 

문자열 생성 함수 만들기

# 문자열 생성 함수
def sequence_gen_text(model, t, current_word, n):
    init_word = current_word
    sentence = ''
    for _ in range(n):
        encoded = t.texts_to_sequences([current_word])[0]
        encoded = pad_sequences([encoded], maxlen=max_len-1, padding='pre') # 패딩
        result = np.argmax(model.predict(encoded, verbose=0),axis=-1)
        
        # 예측단어 찾기
        for word, index in t.word_index.items():
            #print(word, index)
            if index == result:
                break
            
        current_word = current_word +' '+word
        sentence = sentence+' '+ word
            
    sentence = init_word + sentence
    return sentence

print(sequence_gen_text(model, tok, '경마', 1))
print(sequence_gen_text(model, tok, '그의', 2))
print(sequence_gen_text(model, tok, '가는', 3))
print(sequence_gen_text(model, tok, '경마장에', 4))

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
경마 말이
그의 말이 법이다
가는 말이 고와야 온는
경마장에 있는 말이 뛰고 있다
728x90

'데이터분석 > 예시코드' 카테고리의 다른 글

웹 스크래핑 : 네이버 영화 평점  (0) 2022.06.01
웹 스크래핑 : 기초  (0) 2022.05.29
CountVectorizer, TfidfVectorizer  (0) 2022.05.26
word2vec  (0) 2022.05.26
회귀 분석  (0) 2022.05.04