[딥러닝]5. 딥러닝 활용 <3>RNN

3. 순환 신경망(RNN, Recurrent Neural Network)

  • 여러 개의 데이터 순서대로 입력되었을 때, 앞서 입력받은 데이터를 잠시 기억해둠 ➡️ 기억된 데이터의 중요도에 따라 가중치 부여
    • 인공지능이 문장을 듣고 '이해' ➡️ '이미 학습(train)'된 것을 기반으로 함
    • 문장 학습 : 과거 입력 데이터와 나중에 입력된 데이터와의 관계를 따질 필요가 있음

      ex) '오늘 주가가 몇이야?' : 순환부에서 앞선 단어를 기억하며 학습
    • 입력에 대한 결과가 뒤의 입력부에 영향을 줌

3-1) LSTM(Long Short Term Memory)

  • 반복되기 직전에 다음층으로 기억된 값을 넘길지 말지 결정하는 단계 추가 ➡️ 기억 값의 가중치를 관리하는 장치
    • RNN 문제점 : 한 층 내에서 반복이 되므로 일반 신경망보다 기울기 소실 문제가 더 많이 발생함.

3-2) RNN 장점

  • 입력값과 출력값의 설정에 따라 여러가지 상황에 적용 가능
    • 1️⃣ 다수 입력 / 단일 출력
      ex) 문장을 읽고 뜻 파악
    • 2️⃣ 단일 입력 / 다수 출력
      ex) 사진 캡션 만들 때 활용
    • 3️⃣ 다수 입력 / 다수 출력
      ex) 문장 번역

3-3) 로이터 뉴스 카테고리 분류 예제

1) 로이터 뉴스 데이터

  • 입력된 문장의 의미를 파악 = 모든 단어를 종합하여 하나의 카테고리로 분류하는 작업
  • 로이터 뉴스 데이터 : 총 11,258개의 뉴스 기사가 46개의 카테고리로 나누어진 대용량 텍스트 데이터
#로이터 뉴스 데이터셋 불러오기
from keras.datasets import reuters
# 불러온 데이터를 학습셋과 테스트셋으로 나누기
(X_train, Y_train), (X_test, Y_test) = reuters.load_data(num_words=1000, test_split=0.2)
  • reuter.load_data() : 데이터 불러오기
    • num_words : 빈도수에 따른 데이터 추출
      • 1000: 1~1000번의 빈도수를 갖는 단어만 선택
    • test_split : 테스트셋 데이터 비율
      • 학습데이터 : 8982 학습용 뉴스기사
      • 테스트데이터 : 2246 테스트용 뉴스기사
import numpy

category = numpy.max(Y_train) + 1 #0부터 세기 때문에 1 더해줌
print(category, '카테고리') # 46
print(len(X_train), '학습용 뉴스 기사')
print(len(X_test), '테스트용 뉴스 기사')
print(X_train[0]) # [1, 2, 2, 8, 43, 10, 447, 5, 25, 207…]
  • X_train[0] : 단어를 이미 숫자로 변환해두었음.
    • 숫자 = 단어의 빈도수 순위
      • 3인 경우 : 문장내에서 세번째로 빈도수가 높음

2) 데이터 전처리

from keras.preprocessing import sequence
#데이터 전처리
x_train = sequence.pad_sequences(X_train, maxlen=100)
x_test = sequence.pad_sequences(X_test, maxlen=100)

from keras.utils import np_utils
#원-핫 인코딩
y_train = np_utils.to_categorical(Y_train)
y_test = np_utils.to_categorical(Y_test)
  • 각 기사의 단어 수 통일
    • maxlen = 100 : 기사 단어수 100개 초과시 101개째 단어부터는 버림, 100개 미만 시 부족한 부분은 0으로 채움

3) 딥러닝 구조 생성

from keras.models import Sequential
from keras.layers import Dense, LSTM, Embedding

import tensorflow as tf
import matplotlib.pyplot as plt

model = Sequential()
model.add(Embedding(1000, 100))
model.add(LSTM(100, activation='tanh'))
model.add(Dense(46, activation='softmax'))

# 모델의 컴파일
model.compile(loss='categorical_crossentropy', optimizer='adam' ,metrics=['accuracy'])
# 모델의 실행
history = model.fit(x_train, y_train, batch_size=100, epochs=20, validation_data=(x_test, y_test))
# 테스트 정확도 출력
model.evaluate(x_test, y_test)[1]
  • Embedding('불러온 단어의 총 개수', '기사당 단어 수') : 데이터 전처리 과정을 통해 입력된 값을 받아 다음 층이 알아들을 수 있는 형태로 변환하는 역할
  • LSTM(기사당 단어 수, 기타 옵션) : RNN에서 기억 값에 대한 가중치를 제어

4) 시각화

#테스트셋 오차
y_vloss = history.history['val_loss']
#학습셋 오차
y_loss = history.history['loss']

# 그래프로 시각화
x_len = numpy.arange(len(y_loss))
plt.plot(x_len, y_vloss, marker='.', c='red', label='Testset_loss')
plt.plot(x_len, y_loss, marker='.', c='blue', label='Trainset_loss')

plt.legend(loc='upper right')
plt.grid()
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

3-4) LSTM와 CNN 조합을 이용한 영화 리뷰 분석

1) 데이터

  • IMDB(인터넷 영화 데이터베이스, Internet Movie Database) : 영화와 관련된 정보와 출연진 정보, 개봉 정보, 영화 후기, 평점에 이르기까지 매우 폭넓은 데이터가 저장된 자료
    • 영화에 관해 남긴 2만 5000여 개의 영화 리뷰
    • 해당 영화를 긍정적으로 평가했는지 혹은 부정적으로 평가
    • 데이터셋에서 나타나는 빈도에 따라 번호가 정해지므로 빈도가 높은 데이터를 불러와 학습시킬 수 있음.
    • 클래스가 긍정, 부정뿐이라서 원핫인코딩할 필요없음.
from keras.preprocessing import sequence
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from keras.layers import Embedding
from keras.layers import LSTM
from keras.layers import Conv1D, MaxPooling1D
from keras.datasets import imdb

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

seed=0
np.random.seed(seed)
tf.random.set_seed(seed)

(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=5000)

x_train = sequence.pad_sequences(x_train, maxlen=100)
x_test = sequence.pad_sequences(x_test, maxlen=100)
model = Sequential()
model.add(Embedding(5000, 100))
model.add(Dropout(0.5))
model.add(Conv1D(64, 5, padding='valid', activation='relu', strides=1))
model.add(MaxPooling1D(pool_size=4))
model.add(LSTM(55))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.summary()

  • Conv1D : Conv2D의 개념을 1차원으로 옮김
    • 현재 데이터는 배열 형태로 이루어진 1차원 배열이기 때문
    • 컨볼루션 층 : 1차원
    • 이동하는 배열 : 1차원
    • 원래 1차원 배열에 가중치를 각각 곱하여 새로운 층인 컨볼루션 층 만듦
  • MaxPooling1D : 2차원 배열이 1차원으로 바뀌어 정해진 구역 안에서 가장 큰 값을 다음 층으로 넘기고 나머지는 버림.
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

history = model.fit(x_train, y_train, batch_size=100, epochs=5, validation_data=(x_test, y_test))
model.evaluate(x_test, y_test)[1]

y_vloss = history.history['val_loss']
y_loss = history.history['loss']

# 그래프로 표현
x_len = numpy.arange(len(y_loss))
plt.plot(x_len, y_vloss, marker='.', c="red", label='Testset_loss')
plt.plot(x_len, y_loss, marker='.', c="blue", label='Trainset_loss')
  
# 그래프에 그리드를 주고 레이블을 표시
plt.legend(loc='upper right')
plt.grid()
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()

좋은 웹페이지 즐겨찾기