TensorFlow

TensorFlow 기초 38 - 문자열(corpus - 자연어 데이터 집합) 토큰화 + LSTM으로 감성 분류

코딩탕탕 2022. 12. 13. 17:30

 

padding : 서로 다른 길이의 데이터를 가장 긴 데이터의 길이와 같게 만듦

Embedding에 입력될 단어의 수를 지정하는데 가능한 토큰 갯수는 단어 인덱스 최대값 + 1을 부여한다.

# 문자열(corpus - 자연어 데이터 집합) 토큰화 + LSTM으로 감성 분류
# 토큰(Token): text를 단어, 문장, 형태소 별로 나눌 수 있는데 이렇게 나뉜 조각들을 token이라고 한다.
import numpy as np
from keras.preprocessing.text import Tokenizer 
from keras.utils import pad_sequences

docs = ['너무 재밌네요', '최고에요', '참 잘 만든 작품입니다', '추천하고 싶어요', '한 번 더 보고 싶군요', '글쎄요', '별로네요', '생각보다 너무 지루해요', '연기가 어색하더군요', '재미없어요']
labels = np.array([1,1,1,1,1,0,0,0,0,0])

token = Tokenizer()
token.fit_on_texts(docs) # 정수 인코딩
print(token.word_index) # 각 단어에 대한 인덱싱 확인

x = token.texts_to_sequences(docs) # 텍스트를 정수 인덱싱하여 list로 반환
print(x)

# padding : 서로 다른 길이의 데이터를 가장 긴 데이터의 길이와 같게 만듦
padded_x = pad_sequences(x, 5)
print('padded_x :\n', padded_x)

# model
from keras.models import Sequential
from keras.layers import Dense, Flatten, Embedding, LSTM

word_size = len(token.word_index) + 1 # Embedding에 입력될 단어의 수를 지정. 가능한 토큰 갯수는 단어 인덱스 최대값 + 1
model = Sequential()

model.add(Embedding(word_size, 8, input_length=5)) # (가능 토큰 수, 임베딩 차원, 입력 수)
model.add(LSTM(32, activation='tanh')) # 자연어 처리

model.add(Flatten())

model.add(Dense(units=32, activation='relu'))
model.add(Dense(units=1, activation='sigmoid'))
print(model.summary())

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
model.fit(padded_x, labels, epochs=20, verbose=2)
print('evaluate :', model.evaluate(padded_x, labels))

print('predict :', np.where(model.predict(padded_x) > 0.5, 1, 0).ravel())
print('labels :', labels)


<console>
{'너무': 1, '재밌네요': 2, '최고에요': 3, '참': 4, '잘': 5, '만든': 6, '작품입니다': 7, '추천하고': 8, '싶어요': 9, '한': 10, '번': 11, '더': 12, '보고': 13, '싶군요': 14, '글쎄요': 15, '별로네요': 16, '생각보다': 17, '지루해요': 18, '연기가': 19, '어색하더군요': 20, '재미없어요': 21}
[[1, 2], [3], [4, 5, 6, 7], [8, 9], [10, 11, 12, 13, 14], [15], [16], [17, 1, 18], [19, 20], [21]]
padded_x :
 [[ 0  0  0  1  2]
 [ 0  0  0  0  3]
 [ 0  4  5  6  7]
 [ 0  0  0  8  9]
 [10 11 12 13 14]
 [ 0  0  0  0 15]
 [ 0  0  0  0 16]
 [ 0  0 17  1 18]
 [ 0  0  0 19 20]
 [ 0  0  0  0 21]]

Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 embedding (Embedding)       (None, 5, 8)              176       
                                                                 
 lstm (LSTM)                 (None, 32)                5248      
                                                                 
 flatten (Flatten)           (None, 32)                0         
                                                                 
 dense (Dense)               (None, 32)                1056      
                                                                 
 dense_1 (Dense)             (None, 1)                 33        
                                                                 
=================================================================
Total params: 6,513
Trainable params: 6,513
Non-trainable params: 0
_________________________________________________________________
None
Epoch 1/20
1/1 - 1s - loss: 0.6936 - accuracy: 0.3000 - 1s/epoch - 1s/step
Epoch 2/20
1/1 - 0s - loss: 0.6929 - accuracy: 0.6000 - 2ms/epoch - 2ms/step
Epoch 3/20
1/1 - 0s - loss: 0.6924 - accuracy: 0.8000 - 2ms/epoch - 2ms/step
Epoch 4/20
1/1 - 0s - loss: 0.6919 - accuracy: 0.8000 - 2ms/epoch - 2ms/step
Epoch 5/20
1/1 - 0s - loss: 0.6915 - accuracy: 0.8000 - 1ms/epoch - 1ms/step
Epoch 6/20
1/1 - 0s - loss: 0.6911 - accuracy: 0.9000 - 2ms/epoch - 2ms/step
Epoch 7/20
1/1 - 0s - loss: 0.6906 - accuracy: 0.9000 - 3ms/epoch - 3ms/step
Epoch 8/20
1/1 - 0s - loss: 0.6902 - accuracy: 0.9000 - 2ms/epoch - 2ms/step
Epoch 9/20
1/1 - 0s - loss: 0.6897 - accuracy: 0.9000 - 2ms/epoch - 2ms/step
Epoch 10/20
1/1 - 0s - loss: 0.6891 - accuracy: 0.9000 - 997us/epoch - 997us/step
Epoch 11/20
1/1 - 0s - loss: 0.6886 - accuracy: 0.9000 - 996us/epoch - 996us/step
Epoch 12/20
1/1 - 0s - loss: 0.6879 - accuracy: 0.9000 - 997us/epoch - 997us/step
Epoch 13/20
1/1 - 0s - loss: 0.6873 - accuracy: 0.9000 - 997us/epoch - 997us/step
Epoch 14/20
1/1 - 0s - loss: 0.6865 - accuracy: 0.9000 - 3ms/epoch - 3ms/step
Epoch 15/20
1/1 - 0s - loss: 0.6856 - accuracy: 0.9000 - 2ms/epoch - 2ms/step
Epoch 16/20
1/1 - 0s - loss: 0.6847 - accuracy: 0.9000 - 996us/epoch - 996us/step
Epoch 17/20
1/1 - 0s - loss: 0.6837 - accuracy: 0.9000 - 996us/epoch - 996us/step
Epoch 18/20
1/1 - 0s - loss: 0.6826 - accuracy: 0.9000 - 2ms/epoch - 2ms/step
Epoch 19/20
1/1 - 0s - loss: 0.6814 - accuracy: 0.9000 - 2ms/epoch - 2ms/step
Epoch 20/20
1/1 - 0s - loss: 0.6802 - accuracy: 0.9000 - 996us/epoch - 996us/step

1/1 [==============================] - ETA: 0s - loss: 0.6788 - accuracy: 0.9000
1/1 [==============================] - 0s 271ms/step - loss: 0.6788 - accuracy: 0.9000
evaluate : [0.6788328289985657, 0.8999999761581421]

1/1 [==============================] - ETA: 0s
1/1 [==============================] - 0s 301ms/step
predict : [1 0 1 1 1 0 0 0 0 0]
labels : [1 1 1 1 1 0 0 0 0 0]

텍스트를 정수 인덱싱하여 list로 반환하여 출력하였다.

 

 

 

Embedding 클래스 : 문장 토큰화와 단어 토큰화를 위한 개념 이해용 소스

참고 : 케라스의 Embedding 레이어는 처음에 무작위로 초기화된 상태에서 정수로 오는 word를 정해진 크기의 벡터로 바꿔서 다음 레이어로 넘기고, 학습단계에서는 역전파되는 기울기를 바탕으로 해당 word의 임베딩 값을 조정한다. 즉 주변 문맥을 반영하지 않는다. 그럼 Dense레이어랑  같은거 아닌가 싶지만  차이점은 원핫벡터로 값을 안넣어줘도 되서 덕분에 메모리 절약할 수 있고, 케라스에서 지원하는 masking 기능을 사용할 수 있고, 꼭 문장뿐만아니라 추천 시스템 등에서 User 등을 벡터로 나타낼 때도 사용할 수 있다. 하지만 웬만하면 weights 지정 기능을 이용해서 pre-trained 된 word2vec 등을 지정해야 할 것이다.

 

출처 : https://cafe.daum.net/flowlife/S2Ul/19