황규진 2024. 7. 18. 09:44
  • 자연어 처리(NLP, Natural Language Processing) : 음성이나 텍스트를 컴퓨터가 인식하고 처리하는 것
  • AI 스피커 애플 시리, 구글 어시스턴트, 아마존 알렉사, SK Nugu, 네이버 클로바 
  • 딥러닝이 등장하면서 자연어처리 연구가 활발해짐 (대용량 데이터를 학습할 수 있는 딥러닝의 속성 때문) 
  • 컴퓨터는 수치 데이터만 이해할 수 있기 때문에, 자연어처리는 텍스트 전처리 과정이 필수임

덱스트의 토큰화

먼저 해야 할 일은 텍스트(문장)를 잘게 나누는 것
  • 토큰(token) : 텍스트(문장)를 단어별, 문장별, 형태소별로 나눌 수 있는데, 이렇게 나누어진 단위
  • 토큰화(tokenization) : 입력된 텍스트를 잘게 나누는 과정
#텍스트 정의
text = '해보지 않으면 해낼 수 없다.'
  • 케라스 text 모듈의 text_to_word_sequence() 함수를 사용하면 문장의 단어 단위 토큰화가 가능
# 토큰화
result %3D text_to_word_sequence(text)
print('원문 %3A'%2C text)
print('토큰화된 결과 %3A'%2C result)

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

from tensorflow.keras.preprocessing.text import text_to_word_dequence

#텍스트 정의
text = '해보지 않으면 해낼 수 없다.'

# 토큰화
result %3D text_to_word_sequence(text)
print('원문 %3A'%2C text)
print('토큰화된 결과 %3A'%2C result)

 

문장을 토큰화하면 이를 이용해 여러 가지를 할 수 있음

  •  단어 빈도 확인
  •  중요 단어 파악
# 단어 빈도수 세기
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)

 

원-핫 인코딩

단어가 문장의 다른 요소와 어떤 관계를 가지고 있는지를 알아보는 방법 = 원-핫 인코딩

 

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 tensorflow.keras.utils import to_categorical

word_size = len(token.word_index) %2B 1
x = to_categorical(x, num_classes = word_size)
print('문장의 원-핫 인코딩:\n', x)

 

워드 임베딩( word embedding)

  • 원-핫 인코딩을 그대로 사용하면 벡터의 길이가 너무 길어진다는 단점이 있음
  • 공간적 낭비를 해결하기 위해 등장한 것이 단어 임베딩(word embedding)이라는 방법 
  • 단어 임베딩은 주어진 배열을 정해진 길이로 압축시킴

 

  • 단어 임베딩으로 얻은 결과가 밀집된 정보를 가지고 있고 공간의 낭비가 적다는 것을 알 수 있음 
  • 이런 결과가 가능한 이유는 각 단어 간의 유사도를 계산했기 때문

 

  • 단어 간 유사도 계산은 오차 역전파를 이용
  • 적절한 크기로 배열을 바꾸어 주기 위해 최적의 유사도를 계산하는 학습 과정을 거치게 된다.

 

  • Embedding( ) 함수를 사용하면 간단히 해낼 수 있음
  • Embedding( ) 함수는 최소 2개의 매개변수를 필요로 하는데, 바로 ‘입력’과 ‘출력’의 크기 
  • Embedding(16, 4) : 입력될 총 단어 수는 16, 임베딩 후 출력되는 벡터 크기는 4 
    • 단어를 매번 몇 개씩 입력할지 지정 가능
  • Embedding(16, 4, input_length=2) : 총 입력되는 단어 수는 16개, 매번 2개씩 넣겠다는 뜻

 

텍스트를 읽고 긍정, 부정 예측하기

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)
print(x)

 

패딩(padding)

  • 패딩(padding) : 길이를 똑같이 맞춰 주는 작업 
  • 패딩은 자연어 처리뿐 아니라 GAN에서도 중요한 역할을 함 
  • pad_sequnce( ) 함수 : 원하는 길이보다 짧은 부분은 숫자 0을 넣어서 채워주고, 긴 데이터는 잘라줌
padded_x = pad_sequences(x, 4)
print(padded_x)

  • 임베딩 함수에 필요한 세 가지 파라미터는 ‘입력, 출력, 단어 수’임
  • 이때 전체 단어의 맨 앞에 0이 먼저 나와야 하므로 총 단어 수 에 1을 더하는 것을 잊지 마시기 바람
word_size = len(token.word_index) + 1

 

Embedding(word_size, 8, input_length=4)

 

모델 생성

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, labels, epochs=20)
print("\n Accuracy: %.4f" % (model.evaluate(padded_x, labels)[1]))

 

최종 코드

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

from tensorflow.keras.preprocessing.text import text_to_word_dequence

#텍스트 정의
text = '해보지 않으면 해낼 수 없다.'

# 토큰화
result %3D text_to_word_sequence(text)
print('원문 =', text)
print('토큰화된 결과 =', result)

# 단어 빈도수 세기
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)

docs = ['너무 재밌네요', '최고예요', '참 잘 만든 영화예요', '추천하고 싶은 영화에요','한 번 더 보고 싶네요',
        '글세요', '별로예요', '생각보다 지루하네요', '연기가 어색해요', '재미없어요']
        
lebels = 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)
print('리뷰 텍스트, 토큰화 결과: \n'x)

# 패딩
padded_x = pad_sequences(x, 4)
print(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, labels, epochs=20)
print("\n Accuracy: %.4f" % (model.evaluate(padded_x, labels)[1]))