ML/모두의 딥러닝

17장) 딥러닝을 이용한 자연어 처리

busy맨 2023. 7. 18. 14:41
  • 자연어란 우리가 평소에 말하는 음성이나 텍스트를 의미
  • 자연어 처리는 이러한 음성이나 텍스트를 컴퓨터가 인식하고 처리하는 것

 

1. 텍스트의 토큰화

  • 토큰(token)
    • 텍스트를 단어 별이나 문장 별, 형태소별로 나눈 하나의 단위
  • 토큰화(tokenization)
    • 입력된 텍스트를 잘게 나누는 과정
  • 케라스의 text 모듈의 text_to_word_sequence()를 사용해 토큰화
from tensorflow.keras.preprocessing.text import text_to_word_sequence

# 전처리할 텍스트를 정합니다.
text = '해보지 않으면 해낼 수 없다'

# 해당 텍스트를 토큰화합니다.
result = text_to_word_sequence(text)
print("\n원문:\n", text)
print("\n토큰화:\n", result)

  • Tokenizer()
    • 단어의 빈도 수 계산
  • document_count()
    • 문장의 수 계산
  • word_docs()
    • 각 단어들이 몇 개의 문장에서 사용되는지 계산
  • word_index()
    • 각 단어에 매겨진 인덱스 값을 계산
from tensorflow.keras.preprocessing.text import Tokenizer

docs = ['먼저 텍스트의 각 단어를 나누어 토큰화합니다.',
        '텍스트의 단어로 토큰화해야 딥러닝에서 인식됩니다.',
        '토큰화한 결과는 딥러닝에서 사용할 수 있습니다.',
       ]

token = Tokenizer()      # 토큰화 함수 지정
token.fit_on_texts(docs) # 토큰화 함수에 문장 적용
print("\n단어 카운트:\n", token.word_counts) # 단어의 빈도수를 계산한 결과 출력

print("\n문장 카운트: ", token.document_count)

print("\n각 단어가 몇 개의 문장에 포함되어 있는가:\n", token.word_docs)

print("\n각 단어에 매겨진 인덱스 값:\n", token.word_index)

 

 

2. 단어의 원-핫 인코딩

  • 각 단어를 모두 0으로 바꾸어 주고 원하는 단어만 1로 바꿔 주는 것
    1. 단어 수만큼 0으로 채워진 벡터 공간으로 바꿔줌
    2. 각 단어가 배열 내에서 해당하는 위치를 1로 바꿔서 벡터화
from keras.utils import to_categorical
from tensorflow.keras.preprocessing.text import Tokenizer

text='오랫동안 꿈꾸는 이는 그 꿈을 닮아간다'

token=Tokenizer()
token.fit_on_texts([text])
x = token.texts_to_sequences([text])
word_size=len(token.word_index)+1  			# +1을 하는 이유는 배열 맨 앞에 0이 추가되므로
x=to_categorical(x,num_classes=word_size)
print(x)

3. 단어 임베딩(word embedding)

  • 원-핫 인코딩을 그대로 사용하면 벡터의 길이가 너무 길어진다는 단점이 존재
  • 단어 임베딩을 통해 이런 공간적 낭비를 해결
    • 단어 임베딩은 주어진 배열을 정해진 길이로 압축

원-핫 인코딩
단어 임베딩

  • 단어 간의 유사도를 계산하였기 때문에 결과가 밀집된 정보를 가지고 있고, 공간의 낭비가 적음

단어 간 유사도

4. 영화 리뷰의 긍정/부정 예측하기

import numpy
import tensorflow as tf
from numpy import array
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Flatten,Embedding

# 텍스트 리뷰 자료를 지정합니다.
docs = ["너무 재밌네요","최고예요","참 잘 만든 영화예요","추천하고 싶은 영화입니다","한번 더 보고싶네요","글쎄요","별로예요","생각보다 지루하네요","연기가 어색해요","재미없어요"]

# 긍정 리뷰는 1, 부정 리뷰는 0으로 클래스를 지정합니다.
classes = 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)
print("\n리뷰 텍스트, 토큰화 결과:\n",  x)

# 패딩, 서로 다른 길이의 데이터를 4로 맞추어 줍니다.
padded_x = pad_sequences(x, 4)  
print("\n패딩 결과:\n", padded_x)
 
#딥러닝 모델
print("\n딥러닝 모델 시작:")

#임베딩에 입력될 단어의 수를 지정합니다.
word_size = len(token.word_index) +1
 
#단어 임베딩을 포함하여 딥러닝 모델을 만들고 결과를 출력합니다.
model = Sequential()
model.add(Embedding(word_size, 8, input_length=4))
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
model.fit(padded_x, classes, epochs=20)
print("\n Accuracy: %.4f" % (model.evaluate(padded_x, classes)[1]))
{'너무': 1, '재밌네요': 2, '최고예요': 3, '참': 4, '잘': 5, '만든': 6, '영화예요': 7, '추천하고': 8, '싶은': 9, '영화입니다': 10, '한번': 11, '더': 12, '보고싶네요': 13, '글쎄요': 14, '별로예요': 15, '생각보다': 16, '지루하네요': 17, '연기가': 18, '어색해요': 19, '재미없어요': 20}

리뷰 텍스트, 토큰화 결과:
 [[1, 2], [3], [4, 5, 6, 7], [8, 9, 10], [11, 12, 13], [14], [15], [16, 17], [18, 19], [20]]

패딩 결과:
 [[ 0  0  1  2]
 [ 0  0  0  3]
 [ 4  5  6  7]
 [ 0  8  9 10]
 [ 0 11 12 13]
 [ 0  0  0 14]
 [ 0  0  0 15]
 [ 0  0 16 17]
 [ 0  0 18 19]
 [ 0  0  0 20]]

딥러닝 모델 시작:
Epoch 1/20
1/1 [==============================] - 1s 855ms/step - loss: 0.6848 - accuracy: 0.7000
Epoch 2/20
1/1 [==============================] - 0s 11ms/step - loss: 0.6828 - accuracy: 0.7000
Epoch 3/20
1/1 [==============================] - 0s 10ms/step - loss: 0.6808 - accuracy: 0.7000
Epoch 4/20
1/1 [==============================] - 0s 10ms/step - loss: 0.6788 - accuracy: 0.7000
Epoch 5/20
1/1 [==============================] - 0s 11ms/step - loss: 0.6768 - accuracy: 0.7000
Epoch 6/20
1/1 [==============================] - 0s 13ms/step - loss: 0.6748 - accuracy: 0.8000
Epoch 7/20
1/1 [==============================] - 0s 14ms/step - loss: 0.6727 - accuracy: 0.8000
Epoch 8/20
1/1 [==============================] - 0s 12ms/step - loss: 0.6707 - accuracy: 0.8000
Epoch 9/20
1/1 [==============================] - 0s 11ms/step - loss: 0.6687 - accuracy: 0.8000
Epoch 10/20
1/1 [==============================] - 0s 10ms/step - loss: 0.6667 - accuracy: 0.8000
Epoch 11/20
1/1 [==============================] - 0s 9ms/step - loss: 0.6647 - accuracy: 0.8000
Epoch 12/20
1/1 [==============================] - 0s 10ms/step - loss: 0.6626 - accuracy: 0.8000
Epoch 13/20
1/1 [==============================] - 0s 10ms/step - loss: 0.6606 - accuracy: 0.8000
Epoch 14/20
1/1 [==============================] - 0s 9ms/step - loss: 0.6586 - accuracy: 0.8000
Epoch 15/20
1/1 [==============================] - 0s 10ms/step - loss: 0.6565 - accuracy: 0.8000
Epoch 16/20
1/1 [==============================] - 0s 13ms/step - loss: 0.6544 - accuracy: 0.8000
Epoch 17/20
1/1 [==============================] - 0s 10ms/step - loss: 0.6524 - accuracy: 0.8000
Epoch 18/20
1/1 [==============================] - 0s 10ms/step - loss: 0.6503 - accuracy: 0.8000
Epoch 19/20
1/1 [==============================] - 0s 13ms/step - loss: 0.6482 - accuracy: 0.9000
Epoch 20/20
1/1 [==============================] - 0s 10ms/step - loss: 0.6461 - accuracy: 0.9000
1/1 [==============================] - 0s 212ms/step - loss: 0.6439 - accuracy: 0.9000

 Accuracy: 0.9000