[딥러닝]5. 딥러닝 활용 <2>NLP

2. NLP(Natural Language Processing)

* 딥러닝을 이용한 자연어 처리

1) 텍스트 토큰화

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

text = '해보지 않으면 해낼 수 없다'
result = text_to_word_sequence(text)
print(result)
  • text_to_word_sequence() : 문장을 단어 단위로 나눠주는 함수
  • Bag of words(단어의 가방) : 같은 단어끼리 따로따로 가방에 담은 뒤 각 가방에 몇 개의 단어가 들어있는지를 세는 기법
    • 단어의 빈도수 = 중요 단어
  • Tokenizer() : 단어의 빈도수 확인 가능
from tensorflow.keras.preprocessing.text import Tokenizer

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

token = Tokenizer()
token.fit_on_texts(docs)
print(token.word_counts)
# OrderedDict([('먼저', 1), ('텍스트의', 2), ('각', 1), ('단어를', 1), ('나누어', 1), ('토큰화합니다', 1), ('단어로', 1), ('토큰화해야', 1), ('딥러닝에서', 2), ('인식됩니다', 1), ('토큰화한', 1), ('결과는', 1), ('사용할', 1), ('수', 1), ('있습니다', 1)])
print(token.document_count) # 3
print(token.word_docs)
# defaultdict(<class 'int'>, {'토큰화합니다': 1, '먼저': 1, '텍스트의': 2, '각': 1, '단어를': 1, '나누어': 1, '토큰화해야': 1, '딥러닝에서': 2, '단어로': 1, '인식됩니다': 1, '수': 1, '토큰화한': 1, '있습니다': 1, '사용할': 1, '결과는': 1})
print(token.word_index)
#{'딥러닝에서': 3, '단어를': 6, '결과는': 13, '수': 16, '한': 12, '인식됩니다': 11, '합니다': 8, '텍스트의': 2, '토큰화': 1, '할': 15, '각': 5, '있습니다': 17, '먼저': 4, '나누어': 7, '해야': 10, '사용': 14, '단어로': 9}
  • word_counts : 단어의 빈도 수를 계산
  • document_count : 총 문장의 개수 계산
  • word_docs : 각 단어 당 문장에 출현하는 빈도수(랜덤하게 나옴)
  • word_index : 각 단어의 인덱스값 출력

2) 단어의 원-핫 인코딩(one-hot encoding)

  • 단어가 문장의 다른 요소와 어떤 관계를 가지고 있는지를 알아보는 방법
    ➡️ 각 단어를 모두 0으로 바꿔주고 원하는 단어만 1로 바꿈
    1️⃣ 단어 수만큼 0으로 채워진 벡터 공간 만들기
    2️⃣ 각 단어가 배열 내에서 해당하는 위치를 1로 표시

    ex) (0인덱스) 오랫동안 꿈꾸는 이는 그 꿈을 닮아간다
    [ 0 0 0 0 0 0 0 ]

from tensorflow.keras.preprocessing.text import Tokenizer

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

token = Tokenizer()
token.fit_on_texts([text])
print(token.word_index)

x = token.texts_to_sequences([text])
print(x)

from keras.utils import to_categorical

# 인덱스 수에 하나를 추가해서 원-핫 인코딩 배열 만들기
word_size = len(token.word_index) + 1
x = to_categorical(x, num_classes=word_size)
print(x)
  • texts_to_sequences() : 토큰의 인덱스로만 채워진 새로운 배열 생성
  • to_categorical() : 정수 인덱스를 0과 1로만 이루어진 배열로 변경
    • 배열 맨 앞에 0 추가됨 : 단어 수 + 1 = 인덱스값

3) 단어 임베딩

  • 원-핫 인코딩의 단점 : 벡터의 길이가 너무 길어짐
    ex) 1만개의 단어 토큰으로 이루어진 말뭉치 ➡️ 9999개의 0, 1개의 1로 구성된 단어 벡터 1만개 생성
    • 단어 임베딩(word embedding) : 원-핫 인코딩으로 인한 공간적 낭비 해결
      • 단어의 유사도 계산 : 밀집된 정보 + 공간 낭비 적음
        ex) happy는 bad보다 good에 가까움. ➡️ 이러한 유사도를 고려해 각 배열을 새로운 수치로 바꿔줌

✔️ 유사도 계산 : 오차 역전파 이용

  • 최적의 유사도를 계산하는 학습 과정을 거침
  • Embedding(입력, 출력)
from keras.layers import Embedding
from keras.models import Sequential

model = Sequential()
model.add(Embedding(16,4))
  • Embedding(16,4)
    • 입력될 총 단어 수 : 16
    • 임베딩 후 출력되는 벡터 크기 : 4
    • Embedding(16,4, input_length=2) : 입력되는 단어는 16개지만 매번 2개씩만 입력함

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)
#{'너무': 1, '재밌네요': 2, '최고예요': 3, '참': 4, '잘': 5, '만든': 6, '영화예요': 7, '추천하고': 8, '싶은': 9, '영화입니다': 10, '한번': 11, '더': 12, '보고싶네요': 13, '글쎄요': 14, '별로예요': 15, '생각보다': 16, '지루하네요': 17, '연기가': 18, '어색해요': 19, '재미없어요': 20}
print(token.texts_to_sequences(docs))
#[[1, 2], [3], [4, 5, 6, 7], [8, 9, 10], [11, 12, 13], [14], [15], [16, 17], [18, 19], [20]]
  • 입력 데이터의 토큰 수가 다 다름
    • '너무 재밌네요' = 2개의 토큰 ➡️ [[1,2]]
    • '최고예요' = 1개의 토큰 ➡️ [[3]]
      ➡️ 딥러닝 학습을 위해서는 입력데이터 길이가 동일해야함
  • 패딩(padding)
    • 길이를 똑같이 맞춰 주는 작업
    • pad_sequence() : 원하는 길이보다 짧은 부분은 숫자 0을 넣어서 채워주고, 긴 데이터는 잘라서 같은 길이로 맞춰줌
# 패딩, 서로 다른 길이의 데이터를 4로 맞춤
padded_x = pad_sequences(x, 4)  
"\n패딩 결과\n", print(padded_x)

# 임베딩에 입력될 단어 수 지정
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=10)
 
print("\n Accuracy: %.4f" % (model.evaluate(padded_x, classes)[1]))
  • 임베딩(Embedding)
    • 입력 : 총 몇 개의 단어 집합
      • token.word_index 길이 + 1
    • 출력 : 몇 개의 임베딩 결과를 사용
      • 8개의 임베딩 결과 출력 : 내부 레이어로 딥러닝의 레이어로 활용됨
    • 단어 수 : 매번 입력될 단어 수는 몇 개로 할지
      - 패딩 과정을 거쳐 4개 길이로 맞췄기 때문에 4개 단어로 나눔

좋은 웹페이지 즐겨찾기