ML/모두의 딥러닝

18장) 시퀀스 배열로 다루는 순환 신경망(RNN)

busy맨 2023. 7. 19. 16:19
  • 인공지능이 문장을 듣고 이해한다는 것
    • 여러 데이터가 순서와 관계없이 입력되던 것과는 다르게 과거에 입력된 데이터와 나중에 입력된 데이터 사이의 관계를 고려해야 하는 문제가 발생
    • 순환 신경망을 통해 해결

1. RNN(Recurrent Neural Network)

1)RNN

  • 여러 개의 데이터가 순서대로 입력되었을 때 앞서 입력받은 데이터를 잠시 기억해 놓는 방법
  • 기억된 데이터의 중요도를 판별하여 별도의 가중치 부여한 후 다음 데이터로 이동
  • 이 작업을 반복하기 때문에 다음 층으로 넘어가기 전에 같은 층을 맴도는 것처럼 보여서 RNN이라 부름

일반 신경망과 순환 신경망

Ex) "오늘 주가가 몇이야?"

RNN 처리 과정

  • 앞에 나온 입력에 대한 결과가 뒤에 나오는 입력 값에 영향을 미침
  • 이를 통해 비슷한 두 문장이 입력되었을 때 그 차이를 구별하여 출력 값에 반영

  • RNN의 결과를 개선하기 위해 LSTM(Long Short Term memory) 방법을 함께 사용

 

2) LSTM

  • RNN의 특성상 일반 신경망보다 기울기 소실 문제가 더 많이 발생하고 이를 해결하기 어렵다는 단점을 보완
    • RNN은 한 층 안에서 반복을 많이 하기 때문
  • 반복되기 전, 다음 층으로 기억된 값을 넘길지 여부를 관리하는 단계를 추가하는 것
  • 기억된 값의 가중치를 관리하는 장치

 

3) RNN의 장점

1. 다수 입력 단일 출력

  • ex) 문장을 읽고 뜻을 파악할 때

2. 단일 입력 다수 출력

  • ex) 사진의 캡션을 만들 때

3. 다수 입력 단수 출력

  • ex) 문장을 번역할 때


2. LSTM을 이용한 로이터 뉴스 카테고리 분류하기

  • 긴 텍스트를 읽고 이 데이터가 어떤 의미를 지니는 지를 카테고리로 분류
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy
import os

# 로이터 뉴스 데이터셋 불러오기
from keras.datasets import reuters
from keras.models import Sequential
from keras.layers import Dense, LSTM, Embedding
from tensorflow.keras.preprocessing import sequence
from keras.utils import np_utils

# seed 값 설정
seed = 0
numpy.random.seed(seed)
tf.compat.v1.set_random_seed(3)

# 불러온 데이터를 학습셋, 테스트셋으로 나누기
(X_train, Y_train), (X_test, Y_test) = reuters.load_data(num_words=1000, test_split=0.2)

# 데이터 확인하기
category = numpy.max(Y_train) + 1
print(category, '카테고리')
print(len(X_train), '학습용 뉴스 기사')
print(len(X_test), '테스트용 뉴스 기사')
print(X_train[0])

# 데이터 전처리

#maxlen을 사용해 단어 수를 100개로 설정
x_train = sequence.pad_sequences(X_train, maxlen=100)  
x_test = sequence.pad_sequences(X_test, maxlen=100)
# y데이터에 원-핫 인코딩
y_train = np_utils.to_categorical(Y_train)  
y_test = np_utils.to_categorical(Y_test)

# 모델의 설정
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))

# 테스트 정확도 출력
print("\n Test Accuracy: %.4f" % (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()

  • 테스트셋에 대한 정확도는 71.33%
  • 테스트 오차가 상승하기 전까지의 학습이 과적합 직전의 최적 학습 시간
  • 모델 생성 시 Embedding 층과 LSTM 층을 생성
    • Embedding('불러온 단어의 총 개수', '기사당 단어 수')
      • 데이터 전처리 과정을 통해 입력된 값을 받아 다음 층이 알아들을 수 있는 형태로 변환
      • 모델 설정의 맨 처음에 있어야함
    • LSTM(기사당 단어 수, 기타 옵션)
      • RNN에서 기억 값에 대한 가중치 제어
      • 활성화 함수로는 tanh사용

3. LSTM과 CNN의 조합을 이용한 영화 리뷰 분류하기

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

from tensorflow.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

# seed 값 설정
seed = 0
numpy.random.seed(seed)
tf.compat.v1.set_random_seed(3)

# 학습셋, 테스트셋 지정하기
(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()

# 모델의 컴파일
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))

# 테스트 정확도 출력
print("\n Test Accuracy: %.4f" % (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()

  • 테스트셋의 정확도는 85.25%
  •  Conv1D
    • 1차원 배열 형태의 데이터를 다룸
    • 커널이 지나가면서 기존 1차원 배열에 가중치를 곱하여 새로운 컨볼루션 층을 생성

Conv1D 개념

  • MaxPooling1D
    • 2차원 배열을 1차원 배열로 바꾼 후, 정해진 구역 안에서 가장 큰 값을 다음 층으로 넘기고 나머지 버림