본문 바로가기
교재 리뷰/케라스 창시자에게 배우는 딥러닝

케라스 창시자에게 배우는 딥러닝 - 3. 신경망 시작하기

by 펄서까투리 2020. 8. 31.

# 세줄요약 #

  1. 신경망이 가장 많이 사용되는 문제로는 이진 분류, 다중 분류, 스칼라 회귀 등이 있으며 각각의 문제에 맞는 올바른 손실함수를 선택하는 것이 중요하다(이진 분류: Binary crossentropy, 다중 분류: Categorical crossentropy, 스칼라 회귀: Mean Squared Error).
  2. 전형적인 케라스 작업 흐름: 훈련 데이터(입력 텐서, 타깃 텐서) -> 네트워크(신경망 모델) 정의 -> 손실함수, 옵티마이저, 측정지표 선택 후 학습과정 설정 -> 모델의 fit() 메소드 반복 호출
  3. 훈련 데이터가 적으면 과대적합을 피하기 위해 은닉층의 수를 줄인 작은 모델을 쓰거나 k-겹 교차검증과 같은 방법으로 모델의 신뢰도를 올릴 수 있다(은닉층이 클수록 추출하는 특성이 많아지는데 데이터가 적을 경우 과하게 특성을 추출하여 해당 데이터에만 과대적함 됨).

 

# 상세 리뷰 #

1. 신경망의 구조

  • 네트워크(또는 모델)을 구성하는 층
    • 층(Layer): 층은 하나 이상의 텐서를 입력으로 받아 하나 이상의 텐서를 출력하는 데이터 처리 모듈, 층의 상태를 나타내는 파라미터인 가중치(weight)에 네트워크가 학습한 지식이 담겨있다.
    • 모델(Model or Neural Network): 딥러닝 모델은 층으로 만든 비순환 유향 그래프(Directed Acyclic Graph, DAG)로 입력과 출력의 갯수 또는 방식에 따라 다양한 네트워크 구조가 존재한다. 이러한 네트워크 구조는 가설공간(Hypothesis space)를 정의하며 학습을 통해 입력데이터를 출력데이터로 매핑하는 특정 텐서 연산으로 제한하므로서 정답을 찾아낸다.
  • 입력데이터와 그에 상응하는 타깃
  • 학습에 사용할 피드백 신호를 정의하는 손실함수
    • 손실함수(Loss function): 훈련하는 동안 최소화해야할 값이며 주어진 문제에 대한 성공 지표가 된다.
  • 학습 진행 방식을 결정하는 옵티마이저
    • 옵티마이저(Optimizer): 손실함수를 기반으로 네트워크가 어떻게 업데이트될지 결정.

그림 1. 네트워크, 층 손실함수, 옵티마이저 사이의 관계

2. 케라스(Keras)란?

 케라스는 딥러닝 모델을 만들기 위한 고수준의 구성요소를 제공하는 모델 수준의 라이브러리로 텐서조작이나 미분 같은 저수준의 연산은 백엔드 엔진으로 제공하는 텐서플로, CNTK, 씨아노 등의 텐서 라이브러리를 사용한다. 그러나 텐서플로 라이브러리가 2.0 버전을 출시하면서 keras를 메인 프레임워크 중 하나로 채택하였기에 이제 텐서플로 사용은 곧 케라스 사용을 의미한다.

 

* 케라스의 특징

  • 동일한 코드로 CPU와 GPU에서 실행할 수 있다.
  • 사용하기 쉬운 API를 가지고 있어서 딥러닝 모델의 프로토타입을 빠르게 만들 수 있다.
    • 실제로 딥러닝 입문자가 사용하기 가장 쉬운 라이브러리이다.
  • 합성곱 신경망(Computer vision 특화), 순환신경망(Sequence processing 특화), 적대적 생성 신경망(Generative Adversarial Network, GAN) 모두 지원하며 자유롭게 사용 가능하다.
  • 다중입력, 다중출력, 층의 공유, 모델 공유 등 어떤 네트워크 구조도 만들 수 있기에 대부분의 딥러닝 모델을 설계하고 만드는데 적합하다.
    • 다만 상대적으로 쉬운 문법을 가진 딥러닝 모델인만큼 응용적이고 복잡한 층을 새로 만들고 적용하는데는 다소 어려움이 따르는 라이브러리이다.

 

* 케라스의 작업흐름

  1. 입력 텐서와 타깃 텐서로 이루어진 훈련 데이터를 정의
  2. 입력과 타깃을 매핑하는 층으로 이루어진 네트워크(신경망 모델)을 정의
    • 이때 모델을 정의한는 방법은 두가지가 존재: 1. Sequential 클래스(층을 직렬로 순서대로 쌓아올린 네트워크), 2. 함수형 API(완전히 임의의 구조를 만들 수 있는 비순향 유향 그래프, DAG를 만듬)
  3. 손실함수, 옵티마이저, 모니터링을 위한 측정지표를 선택하여 학습 과정을 설정
  4. 훈련데이터에 대해 모델의 fit() 메소드를 반복적으로 호출

 

3. 주요 머신러닝 종류(이진분류, 다중분류, 스칼라 회귀)

3.1 이진 분류

 이진분류(binary classification)은 가장 기본적인 머신러닝 문제로 두종류의 정답으로 데이터를 분류하는 문제이다. 이진분류 문제에서는 마지막 출력층으로 하나의 유닛과 sigmoid 활성화 함수를 가진 Dense층을 사용하며, 손실함수는 'binary_crossentropy'를 사용한다. 

 아래의 예제코드는 영화리뷰를 긍정과 부정으로 분류하는 것이다.

##################
# Library Import #
##################
import keras
from keras.datasets import imdb
import numpy as np
from keras import models
from keras import layers
import matplotlib.pyplot as plt

################
# Data Loading #
################
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)

def vectorize_sequences(sequences, dimension=10000):
    # 크기가 (len(sequences), dimension))이고 모든 원소가 0인 행렬을 만듭니다
    results = np.zeros((len(sequences), dimension))
    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1.  # results[i]에서 특정 인덱스의 위치를 1로 만듭니다
    return results

# 훈련 데이터를 벡터로 변환합니다
x_train = vectorize_sequences(train_data)
# 테스트 데이터를 벡터로 변환합니다
x_test = vectorize_sequences(test_data)

# 레이블을 벡터로 바꿉니다
y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')

########################
# Neural Network Build #
########################
# 3개의 층으로 구성된 신경망 설계
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

# 모델 컴파일
model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['accuracy'])
              
# 검증 세트 만들기        
x_val = x_train[:10000]
partial_x_train = x_train[10000:]
y_val = y_train[:10000]
partial_y_train = y_train[10000:]

###############
# Train Model #
###############
history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=20,
                    batch_size=512,
                    validation_data=(x_val, y_val))
                    
################
# Train Result #
################
# 훈련정보 불러오기
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(1, len(acc) + 1)

# 훈련과 검증 손실 그리기
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()

# 훈련과 검증 정확도 그리기
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

 

3.2 다중 분류

 다중분류(Multiclass classification)은 정답의 클래스가 여러개인 데이터셋을 분류하는 문제로 마지막 출력층으로 유닛이 N개인 softmax 활성화함수를 가진 Dense층을 사용하며, 손실함수는 'categorical_crossentropy'를 사용한다.

 아래의 예제는 로이터 뉴스를 46개의 상호 배타적인 토픽(레이블이 중복되지 않는다)으로 분류하는 문제로 엄밀히는 단일레이블 다중분류 문제이다.

##################
# Library Import #
##################
import keras
from keras.datasets import reuters
import numpy as np
from keras import models
from keras import layers
import matplotlib.pyplot as plt

################
# Data Loading #
################
(train_data, train_labels), (test_data, test_labels) = reuters.load_data(num_words=10000)

def vectorize_sequences(sequences, dimension=10000):
    results = np.zeros((len(sequences), dimension))
    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1.
    return results

# 훈련 데이터 벡터 변환
x_train = vectorize_sequences(train_data)
# 테스트 데이터 벡터 변환
x_test = vectorize_sequences(test_data)

def to_one_hot(labels, dimension=46):
    results = np.zeros((len(labels), dimension))
    for i, label in enumerate(labels):
        results[i, label] = 1.
    return results

# 훈련 레이블 벡터 변환
one_hot_train_labels = to_one_hot(train_labels)
# 테스트 레이블 벡터 변환
one_hot_test_labels = to_one_hot(test_labels)

########################
# Neural Network Build #
########################
model = models.Sequential()
model.add(layers.Dense(64, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(46, activation='softmax'))

model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
              
###############
# Train Model #
###############
# 검증세트 만들기
x_val = x_train[:1000]
partial_x_train = x_train[1000:]
y_val = one_hot_train_labels[:1000]
partial_y_train = one_hot_train_labels[1000:]

# 모델 훈련
history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=20,
                    batch_size=512,
                    validation_data=(x_val, y_val))
                    
################
# Train Result #
################
loss = history.history['loss']
val_loss = history.history['val_loss']
acc = history.history['acc']
val_acc = history.history['val_acc']

epochs = range(1, len(loss) + 1)

# 손실 곡선 그리기
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()

# 정확도 곡선 그리기
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

 

3.3 스칼라 회귀

 회귀(Regression) 문제는 개별적인 레이블 대신에 연속적인 값을 예측하는 문제로 마지막 출력층으로 하나의 유닛을 가지고 활성화 함수가 없는 Dense층으로 사용하며, 손실함수로 평균제곱오차(MSE)를 사용한다.

 예제 문제는 1970년 중반 보스턴 외곽 지역의 범죄율, 지방세율 등의 데이터를 가지고 주택 가격의 중간값을 예측하는 문제이다.

##################
# Library Import #
##################
import keras
from keras.datasets import boston_housing
from keras import models
from keras import layers
import matplotlib.pyplot as plt

################ 
# Data Loading #
################
(train_data, train_targets), (test_data, test_targets) =  boston_housing.load_data()

mean = train_data.mean(axis=0)
train_data -= mean
std = train_data.std(axis=0)
train_data /= std

test_data -= mean
test_data /= std

########################
# Neural Network Build #
########################
def build_model():
    # 동일한 모델을 여러 번 생성할 것이므로 함수를 만들어 사용합니다
    model = models.Sequential()
    model.add(layers.Dense(64, activation='relu',
                           input_shape=(train_data.shape[1],)))
    model.add(layers.Dense(64, activation='relu'))
    model.add(layers.Dense(1))
    model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
    return model
    
###############################
# K-fold iteration evaluation #
###############################
num_epochs = 500
all_mae_histories = []
for i in range(k):
    print('처리중인 폴드 #', i)
    # 검증 데이터 준비: k번째 분할
    val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples]
    val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples]

    # 훈련 데이터 준비: 다른 분할 전체
    partial_train_data = np.concatenate(
        [train_data[:i * num_val_samples],
         train_data[(i + 1) * num_val_samples:]],
        axis=0)
    partial_train_targets = np.concatenate(
        [train_targets[:i * num_val_samples],
         train_targets[(i + 1) * num_val_samples:]],
        axis=0)

    # 케라스 모델 구성(컴파일 포함)
    model = build_model()
    # 모델 훈련(verbose=0 이므로 훈련 과정이 출력되지 않습니다)
    history = model.fit(partial_train_data, partial_train_targets,
                        validation_data=(val_data, val_targets),
                        epochs=num_epochs, batch_size=1, verbose=0)
    mae_history = history.history['val_mean_absolute_error']
    all_mae_histories.append(mae_history)
    
################
# Train Result #
################
average_mae_history = [np.mean([x[i] for x in all_mae_histories]) for i in range(num_epochs)]
    
plt.plot(range(1, len(average_mae_history) + 1), average_mae_history)
plt.xlabel('Epochs')
plt.ylabel('Validation MAE')
plt.show()

 

* 출처: 케라스 창시자에게 배우는 딥러닝 / 프랑소와 숄레 / 길벗

728x90
728x90

댓글