[케라스(keras) 이해] 7장. 딥러닝을 위한 고급 도구
본 글은 [케라스 창시자에게 배우는 딥러닝] - (박해선 옮김) 책을 개인공부하기 위해 요약, 정리한 내용입니다.
전체 코드는 https://github.com/ingu627/deep-learning-with-python-notebooks에 기재했습니다.(원본 코드 fork)
뿐만 아니라 책에서 설명이 부족하거나 이해가 안 되는 것들은 외부 자료들을 토대로 메꿔 놓았습니다. 즉, 딥러닝은 이걸로 끝을 내보는 겁니다.
오타나 오류는 알려주시길 바라며, 도움이 되길 바랍니다.
7_1. Sequential 모델을 넘어서: 케라스의 함수형 API
- 어떤 작업은 입력 데이터에서 여러 개의 타깃 속성을 예측해야 한다.
-
다양한 입력 소스에서 전달된 데이터를 다른 종류의 신경망 층을 사용하여 처리하고 합친다.
- 다중 입력 모델
- 다중 출력 모델
- 최근에 개발된 많은 신경망 구조는 선형적이지 않은 네트워크 토폴로지가 필요하다.
- 인셉션 모듈 : 나란히 놓인 합성곱 층으로 구성된 서브그래프
- 잔차 열결 : 하위 층의 출력을 상위 층의 특성 맵에 더해서 아래층의 표현이 네트워크 위쪽으로 흘러갈 수 있도록 한다.
- 하위 층에서 학습된 정보가 데이터 처리 과정에서 손실되는 것을 방지한다.
7_1_1. 함수형 API 소개
- 함수형 API에서는 직접 텐서들의 입출력을 다룬다. 함수처럼 층을 사용하여 텐서를 입력받고 출력한다.
Sequential vs 함수형 API
- 케라스는 input_tensor에서 output_tensor로 가는 데 필요한 모든 층을 추출한다.
- 그 다음 이들을 모아 그래프 데이터 구조인 Model 객체를 만든다.
- 물론 input_tensor를 반복 변환하여 output_tensor를 만들 수 있어야 한다. 관련되지 않은 입력과 출력으로 모델을 만들면 RuntimError가 발생한다.
7_1_2. 다중 입력 모델
- 함수형 API는 다중 입력 모델을 만드는 데 사용할 수 있다.
add
,concatenate
등을 사용해 여러 텐서를 연결할 수 있는 층을 사용
- 예시의 모델은 질문-응답 모델이다. 전형적인 질문-응답 모델은 2개의 입력을 가진다.
- (자연어 질문, 답변에 필요한 정보가 담긴 텍스트)
- 그러면 모델은 답을 출력해야 한다. 가장 간단한 구조는 미리 정의한 어휘 사전에서 소프트맥스 함수를 통해 한 단어로 된 답을 출력하는 것이다.
2개의 입력을 가진 질문-응답 모델의 함수형 API 구현하기
다중 입력 모델에 데이터 주입하기
- 이렇게 입력이 2개인 모델은 2가지 방법을 훈련할 수 있다.
- 넘파이 배열의 리스트에 주입
- 입력 이름과 넘파이 배열로 이루어진 딕셔너리를 모델의 입력으로 주입 (입력 이름 설정시 가능)
7_1_3. 다중 출력 모델
- 예를 들어 소셜 미디어에서 익명 사용자의 포스트를 입력으로 받아 그 사람의 나이, 성별, 소득 수준 등을 예측한다.
다중 출력 모델의 컴파일 옵션: 다중 손실
- 이런 모델을 예측하기 위해서는 네트워크 출력마다 다른 손실 함수를 지정해야 한다.
- 손실 값을 합치는 가장 간단한 방법은 모두 더하는 것이다.
- 케라스에서는 compile 메서드에서 리스트나 딕셔너리를 사용하여 출력마다 다른 손실을 지정할 수 있다. 계산된 손실 값은 전체 손실 하나로 더해지고 훈련 과정에서 최소화된다.
다중 출력 모델의 컴파일 옵션: 손실 가중치
- 손실 값이 최종 손실에 기여하는 수준을 지정할 수 있다.
다중 출력 모델에 데이터 주입하기
- 다중 입력 모델과 마찬가지로 넘파이 배열의 리스트나 딕셔너리를 모델에 전달하여 훈련한다.
7_1_4. 층으로 구성된 비순환 유향 그래프
- 함수형 API를 사용하면 다중 입력이나 다중 출력 모델뿐만 아니라 내부 토폴로지가 복잡한 네트워크도 만들 수 있다.
- 케라스의 신경망은 층으로 구성된 어떤 비순환 유향 그래프도 만들 수 있다.
인셉션 모듈
- 인셉션은 합성곱 신경망에서 인기 있는 네트워크 구조이다.
- 나란히 분리된 가지를 따라 모듈을 쌓아 독립된 작은 네트워크처럼 구성한다.
- 가장 기본적인 인셉션 모듈 형태는 3~4개의 가지를 가진다.
- 1x1 합성곱으로 시작해섯 3x3 합성곱이 뒤따르고 마지막에 전체 출력 특성이 합쳐진다.
- 이런 구성은 네트워크가 따로따로 공간 특성과 채널 방향의 특성을 학습하도록 돕는다.
- 아래는 인셉션 V3에 있는 모듈의 예이다.
- 위에서 flowchart로 나타낸 모델은 인셉션V3로 케라스에서는
keras.applications.inception_v3.InceptionV3
에 준비되어 있으며, ImageNet에서 사전 훈련된 가중치를 포함하고 있다. - 이와 비슷한 엑셉션 모델도 케라스에 포함되어 있다. 이 합성곱 구조는 채널 방향의 학습과 공간 방향의 학습을 극단적으로 분리한다는 아이디어에 착안하여 인셉션 모듈을 깊이별 분리 합성곱으로 바꾼다.
- 이 합성곱은 깊이별 합성곱 다음에 점별 합성곱이 뒤따른다. 인셉션 모듈의 극한 형태로 공간 특성과 채널 방향 특성을 완전히 분리한다. 엑셉션은 인셉션V3와 거의 동일한 개수의 모델 파라미터를 가지지만 실행 속도가 더 빠르고 대규모 데이터셋에서 정확도가 더 높다. (효율적 사용)
잔차 연결
- 잔차 연결은 하위 층의 출력을 상위 층의 입력으로 사용한다.
- 순서대로 놓인 네트워크를 질러가는 연결이 만들어진다. 하위 층의 출력이 상위 층의 출력에 연결되는 것이 아니라 더해진다. 따라서 두 출력의 크기가 동일해야 한다. 크기가 다르면 선형 변환을 사용하여 하위 층의 활성화 출력을 목표 크기로 변환한다.
특성 맵의 크기가 다를 때 잔차 연결을 구현
7_1_5. 층 가중치 공유
- 함수형 API의 중요한 또 하나의 기능은 층 객체를 여러 번 재사용할 수 있다는 것이다.
- 층 객체를 두 번 호출하면 새로운 층 객체를 만들지 않고 각 호출에 동일한 가중치를 재사용한다. 이런 기능 때문에 공유 가지를 가진 모델을 만들 수 있다.
- 이런 가지는 가중치를 공유하고 같은 연산을 수행한다.
- 다시 말해 같은 표현을 공유하고 이런 표현을 다른 입력에서 함께 학습한다.
함수형 APi를 통해 공유 층을 사용하는 모델
7_1_6. 층과 모델
- 함수형 API에서는 모델을 층처럼 사용할 수 있다.
7_2. 케라스 콜백과 텐서보드를 사용한 딥러닝 모델 검사와 모니터링
7_2_1. 콜백을 사용하여 모델의 훈련 과정 제어하기
- 검증 손실이 더 이상 향상되지 않을 때 훈련을 멈추는 것이다. 케라스의 콜백을 사용하여 구현할 수 있다.
- 콜백은 모델의 fit() 메서드가 호출될 때 전달되는 객체(특정 메서드를 구현한 클래스 객체)이다.
- 훈련되는 동안 모델은 여러 지점에서 콜백을 호출한다.
- 콜백은 모델의 상태와 성능에 대한 모든 정보에 접근하고 훈련 중지, 모델 저장, 가중치 적재 또는 모델 상태 변경 등을 처리할 수 있다.
콜백을 사용하는 몇 가지 사례
- 모델 체크포인트 저장 : 훈련하는 동안 어떤 지점에서 모델의 현재 가중치를 저장한다.
- 조기 종료(early stopping) : 검증 손실이 더 이상 향상되지 않을 때 훈련을 중지한다.
- 훈련하는 동안 하이퍼파라미터 값을 동적으로 조정한다. : 옵티마이저의 학습률 같은 경우이다.
- 훈련과 검증 지표를 로그에 기록하거나 모델이 학습한 표현이 업데이트될 때마다 시각화한다 : 진행 표시줄이 하나의 콜백이다.
ModelCheckpoint와 EarlyStopping 콜백
EarlyStopping
콜백을 사용하면 정해진 에포크 동안 모니터링 지표가 향상되지 않을 때 훈련을 중지할 수 있다.- 일반적으로 이 콜백은 훈련하는 동안 모델을 계속 저장해주는
ModelCheckpoint
와 함께 사용한다. (선택적으로 지금까지 가장 좋은 모델만 저장할 수 있다. 에포크 마지막에 다다랐을 때 최고 성능을 달성한 모델이다.)
- 일반적으로 이 콜백은 훈련하는 동안 모델을 계속 저장해주는
ReduceLROnPlateau 콜백
ReduceLROnPlateau
을 사용하면 검증 손실이 향상되지 않을 때 학습률을 작게 할 수 있다.- 손실 곡선이 평탄할 때 학습률을 작게 하거나 크게 하면 훈련 도중 지역 최솟값에서 효과적으로 빠져나올 수 있다.
자신만의 콜백 만들기
- 내장 콜백에서 제공하지 않는 특수한 행동이 훈련 도중 필요하면 자신만의 콜백을 만들 수 있다.
- 콜백은
keras.callbacks.Callback
클래스를 상속받아 구현한다. 그 다음 훈련하는 동안 호출될 여러 지점을 나타내기 위해 약속된 다음 메서드를 구현한다.
파라미터 | 설명 |
---|---|
on_epoch_begin | 각 에포크가 시작할 때 호출한다. |
on_epoch_end | 각 에포크가 끝날 때 호출한다. |
on_batch_begin | 각 배치 처리가 시작되기 전에 호출한다. |
on_batch_end | 각 배치 처리가 끝난 후에 호출한다. |
on_train_begin | 훈련이 시작될 때 호출한다. |
on_train_end | 훈련이 끝날 때 호출한다. |
- 이 메서드들은 모두 logs 매개변수와 함께 호출된다.
- 이 매개변수에는 이전 배치, 에포크에 대한 훈련과 검증 측정값이 담겨 있는 딕셔너리가 전달된다.
- 또 콜백은 다음 속성을 참조할 수 있다.
파라미터 | 설명 |
---|---|
self.model | 콜백을 호출하는 모델 객체 |
self.validation_data:fit() | 메서드에 전달된 검증 데이터 |
7_2_2. 텐서보드 소개: 텐서플로의 시각화 프레임워크
- 좋은 연구를 하거나 좋은 모델을 개발하려면 실험하는 모델 내부에서 어떤 일이 일어나는지 자주 그리고 많은 피드백을 받아야 한다.
- 텐서보드의 핵심 목적은 훈련 모델의 내부에서 일어나는 모든 것을 시각적으로 모니터링할 수 있도록 돕는 것이다.
- 모델의 최종 손실 외에 더 많은 정보를 모니터링하면 모델 작동에 대한 명확한 그림을 그릴 수 있다.
- 훈련하는 동안 측정 지표를 시각적으로 모니터링
- 모델 구조를 시각화
- 활성화 출력과 그래디언트의 히스토그램
- 3D로 임베딩 표현
텐서보드를 사용한 텍스트 분류 모델
텐서보드 로그 파일을 위한 디렉터리 생성하기
$ mkdir my_log_dir
텐서보드 콜백과 함께 모델 훈련하기
텐서플로 연산의 그래프 외에 케라스의 keras.utils.plot_model 유틸리티는 모델의 층 그래프를 깔끔하게 그려 주는 기능을 제공한다. 이를 사용하려면 pydot과 pydot-ng, graphviz 라이브러리가 필요한다.
- 이제 명령행에서 콜백이 사용하는 로그 디렉터리를 지정하여 텐서보드 서버를 실행한다.
$ tensorboard --logdir=my_log_dir
그다음 브라우저에서 http://localhost:6006 주소에 접속하면 훈련 결과를 확인할 수 있다.
11.24 위 주소로 들어가지지만 해당 파일을 찾지 못하는 에러 발생
7_3. 모델의 성능을 최대로 끌어올리기
7_3_1. 고급 구조 패턴
배치 정규화
- 정규화는 머신 러닝 모델에 주입되는 샘플들을 균일하게 만드는 광범위한 방법이다.
- 이 방법은 모델이 학습하고 새로운 데이터에 잘 일반화되도록 돕는다.
normalized_data = (data - np.mean(data, axis=...)) / np.std(data, axis=...)
- 배치 정규화(batch normalization)는 훈련하는 동안 평균과 분산이 바귀더라도 이에 적응하여 데이터를 정규화한다. (케라스에서
BatchNormalization
) 훈련 과정에 사용된 배치 데이터의 평균과 분산에 대한 지수 이동 평균을 내부에 유지한다. - 배치 정규화의 주요 효과는 잔차 연 결과 매우 흡사하게 그래디언트의 전파를 도와주는 것이다. 결국 더 깊은 네트워크를 구성할 수 있다.
BatchNormalizaion()
층은 일반적으로 합성곱이나 완전 연결 층 다음에 사용한다.
from tensorflow.keras.layers import Conv2D, BatchNormalization, Dense
conv_model.add(Conv2D(32, 3, activation="relu"))
conv_model.add(BatchNormalization())
dense_model.add(Dense(32, activation='relu'))
dense_model.add(BatchNormalization())
깊이별 분리 합성곱
- 깊이별 분리 합성곱(depthwise separable convolution) (SeparableConv2D)층은 입력 채널별로 따로따로 공간 방향의 합성곱을 수행한다. 그다음 점별 합성곱(1x1 합성곱)을 통해 출력 채널을 합친다.
- 이는 공간 특성의 학습과 채널 방향 특성의 학습을 분리하는 효과를 낸다.
- 입력에서 공간상 위치는 상관관계가 크지만 채널별로는 매우 독립적이라고 가정한다.
- 합성곱을 통해 더 효율적으로 표현을 학습하기 때문에 적은 데이터로도 더 좋은 표현을 학습하고, 결국 성능이 더 높은 모델을 만든다.
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import SeparableConv2D, MaxPooling2D, GlobalAveragePooling2D, Dense
height = 64
width = 64
channels = 3
num_classes = 10
model = Sequential()
model.add(SeparableConv2D(32, 3,
activation='relu',
input_shape=(height, width, channels,)))
model.add(SeparableConv2D(64, 3, activation='relu'))
model.add(MaxPooling2D(2))
model.add(SeparableConv2D(64, 3, activation='relu'))
model.add(SeparableConv2D(128, 3, activation='relu'))
model.add(MaxPooling2D(2))
model.add(SeparableConv2D(64, 3, activation='relu'))
model.add(SeparableConv2D(128, 3, activation='relu'))
model.add(GlobalAveragePooling2D())
model.add(Dense(32, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')
7_3_2. 하이퍼파라미터 최적화
- 딥러닝 모델은 무작위 선택의 연속이다. 층의 수, 유닛과 필터 수, 활성화 함수의 종류 등 설계자의 이유있는 랜덤한 선택의 연속이다.
- 이런 구조에 관련된 파라미터를 역전파로 훈련되는 모델 파라미터와 구분하여 하이퍼파라미터(hyperparameter) 라고 한다.
전형적인 하이퍼파라미터 최적화 과정
- 일련의 하이퍼파라미터를 자동으로 선택합니다.
- 선택된 하이퍼파라미터로 모델을 만듭니다.
- 훈련 데이터에 학습하고 검증 데이터에서 최종 성능을 측정합니다.
- 다음으로 시도할 하이퍼파라미터를 자동으로 선택합니다.
- 이 과정을 반복합니다.
- 마지막으로 테스트 데이터에서 성능을 측정합니다.
- 하이퍼파라미터 최적화는 어느 작업에서 최고의 모델을 얻거나 머신 러닝 경연 대회에서 우승하기 위한 강력한 도구이다.
모델 앙상블
- 모델 앙상블(model ensemble)은 여러 개 다른 모델의 예측을 합쳐 더 좋은 예측을 만든다.
- 가장 기본적인 앙상블은 추론에 나온 예측을 평균내는 방법이다.
- 가중치를 주고 평균을 내는 방법도 있다.
preds_a = model_a.predict(x_val)
preds_b = model_b.predict(x_val)
preds_c = model_c.predict(x_val)
preds_d = model_d.predict(x_val)
final_preds = 0.25 * (preds_a + preds_b + preds_c + preds_d) # 예측 평균
final_preds = 0.5 * preds_a + 0.25 * preds_b + 0.1 * preds_c + 0.15 * preds_d # 가중치를 이용한 평균
- 좋은 앙상블 가중치는 랜덤 서치나 넬더-미드 방법 같은 간단한 최적화 방법이 있다. 이외에도 지수 값을 평균할 수 있다.
댓글남기기