My Data Story
[딥러닝] 인공 신경망 - 함수형 API 구현 본문
◈ '인공 신경망' 목차 ◈
5. 함수형 API 구현
다양한 입력과 출력의 복잡한 구조를 구현할 수 있는 함수형 API 구현 방법에 대해 살펴보자.
Sequential 모델이 매우 널리 사용되지만, 입력과 출력이 여러 개이거나 더 복잡한 네트워크 토폴로지를 갖는 신경망을 만들어야 할 때가 있다. 이를 위해 케라스는 함수형 API를 제공한다.
1. 와이드 & 딥 신경망
와이드 & 딥 신경망은 입력의 일부가 또는 전체가 출력층에 바로 연결된다.
이 구조를 사용하면 신경망이 복잡한 패턴(깊게 쌓은 층을 활용)과 간단한 규칙을 모두 학습할 수 있다.
step1
가장 먼저 Input 객체를 만들어야 한다. 이 객체는 shape과 dtype을 포함하여 모델의 입력을 정의한다.
한 모델은 여러 개의 입력을 가질 수 있다.
input = keras.layers.Input(shape=X_train.shape[1:])
step2
30개의 뉴런과 ReLU 활성화 함수를 가진 Dense 층을 만든다. 이 층은 만들어지자마자 입력과 함께 함수처럼 호출된다.
이를 함수형 API라고 부르는 이유이다. 케라스에 층이 연결될 방법을 알려줬을 뿐 아직 어떤 데이터도 처리하지 않았다.
hidden1 = keras.layers.Dense(30, activation='relu')(input)
step3
두 번째 은닉층을 만들고 함수처럼 호출한다. 첫 번째 은닉층의 출력을 두 번째 은닉층의 입력으로 전달한다.
hidden2 = keras.layers.Dense(30, activation='relu')(hidden1)
step4
Concatenate 층을 만들고 또 다시 함수처럼 호출하여 두 번째 은닉층의 출려과 입력을 연결한다.
concat = keras.layers.Concatenate()([input1, hidden2])
step5
하나의 뉴런과 활성화 함수가 없는 출력층을 만들고 Concatenate층이 만든 결과를 사용해 호출한다.
output = keras.layers.Dense(1)(concat)
step6
마지막으로 사용할 입력과 출력을 지정하여 케라스 Model 을 생성한다.
model = keras.Model(inputs=[input], outputs=[output])
2. 여러 개의 입력 다루기
일부 특성은 짧은 경로로 전달하고 다른 특성들은 (특성 중복 가능) 깊은 경로로 전달하고자 할 때 아래와 같은 형태를 구현한다.
input_A = keras.layers.Input(shape=[5], name='wide_input')
input_B = keras.layers.Input(shape=[6], name='deep_input')
hidden1 = keras.layers.Dense(30, activation='relu')(Input_B)
hidden2 = keras.layers.Dense(30, activation='relu')(hidden1)
concat = keras.layers.Concatenate()([input_A, hidden2])
output = keras.layers.Dense(1)(concat)
model = keras.Model(inputs=[input_A, input_B], outputs=[output])
모델을 만들 때 inputs=[input_A, input_B] 와 같이 지정했다.
모델 컴파일은 이전과 동일하지만 fit() 메소드를 호출할 때 X_train 이 아니라,
입력마다 하나씩 행렬의 튜플 (X_train_A, X_trainB) 을 전달해야 하며 X_valid 에도 동일하게 적용된다.
evaluate() 나 predict() 호출할 때 X_test, X_new 에서도 동일한다.
model.compile(loss='mse', optimizer=keras.optimizers.SGD(lr=le-3))
X_train_A, X_train_B = X_train[:, :5], X_train[:, 2:]
X_valid_A, X_valid_B = X_valid[:, :5], X_valid[:, 2:]
X_test_A, X_test_B = X_test[:, :5], X_test[:, 2:]
X_new_A, X_new_B = X_new[:, :5], X_new[:, 2:]
history = model.fit((X_train_A, X_train_B), y_train,
epochs=20,
validation_data = ((X_valid_A, X_valid_B), y_valid))
mse = model.evaluate((X_test_A, X_test_B), y_test)
y_pred = model.predict((X_new_A, X_new_B))
3. 여러 개의 출력 다루기
여러 개의 출력이 필요한 경우는 많다.
예를 들어...
그림에서 주요 물체를 분류하고 위치를 알아야 하는 경우 회귀 작업과 분류 작업을 함께 해야 해, 여러 개의 출력이 필요하다.
얼굴 사진으로 한 출력은 표정 분류하고 다른 출력은 안경을 썼는 지 구별하는 등과 같이 동일한 데이터에 대해 독립적인 여러 작업을 수행해야 하는 경우 여러 개의 출력이 필요하다.
(물론 각 작업마다 새로운 신경망을 훈련할 수 있지만, 작업마다 하나의 출력을 가진 단일 신경망의 성능이 일반적으로 더 좋다.)
또 다른 예는 규제 기법으로 사용할 수 있다.
보조 출력을 사용하여 하위 네트워크가 나머지 네트워크에 의존하지 않고 그 자체로 유용한 것을 학습하는 지 확인할 수 있다.
여러 개의 출력을 다뤄야 하는 경우 다음과 같은 구조를 갖는다.
출력층까지는 이전 모델들과 동일하다. 모델 생성 시 outputs 에 출력층 리스트를 전달한다
output = keras.layers.Dense(1, name='main_output')(concat)
aux_output = keras.layers.Dense(1, name='aux_output')(hidden2)
model = keras.Model(inputs=[input_A, input_B], outputs=[main_output, aux_output])
각 출력은 자신만의 손실 함수가 필요하다. 모델 컴파일 시, 손실 함수 리스트 전달해야 한다.
케라스는 기본적으로 나열된 손실을 모두 더하여 최종 손실을 구해 훈련에 사용한다.
보조출력보다 주출력에 관심이 많다면, 손실 가중치를 설정한다.
model.compile(loss=['mse', 'mse'], loss_weights=[0.9, 0.1], optimizer='sgd')
모델 훈련 시킬 때 각 출력에 대한 레이블을 제공해야 한다. 여기에서 주 출력과 보조 출력이 같은 것을 예측하므로 동일한 레이블을 사용한다. 따라서 y_train 대신 (y_train, y_train) 을 전달한다. 이는 y_valid, y_test도 동일하다.
model.fit([X_train_A, X_train_B], [y_train, y_train],
epochs=20,
validation_data = ([X_valid_A, X_valid_B], [y_valid, y_valid]))
total_loss, main_loss, aux_loss = model.evaluate([X_test_A, X_test_B], [y_test, y_test])
y_pred_main, y_pred_aux = model.predict([X_new_A, X_new_B])
'Deep Learning' 카테고리의 다른 글
[딥러닝] 인공 신경망 - 모델 저장과 복원, 콜백, 텐서보드 (0) | 2021.09.05 |
---|---|
[딥러닝] 인공신경망 - 서브클래싱 API 구현 (0) | 2021.09.04 |
[딥러닝] 인공 신경망 - 시퀀셜 API 구현 (0) | 2021.09.04 |
[딥러닝] 인공 신경망 - 케라스 API 소개 (0) | 2021.09.04 |
[딥러닝] 인공 신경망 - 다층 퍼셉트론 (0) | 2021.09.04 |