1. Wide & Deep - input의 일부 또는 전체가 출력층에 연결되는 구조(wide input과 deep input 두가지로 구성되어있다) - 신경망이 깊게 쌓은 층을 바탕으로 한 복잡한 패턴과 짧은 경로를 사용한 간단한 규칙을 모두 학습할 수 있음. - 일반적인 MLP는 network에 있는 층 전체에 모든 데이터를 통과시키기 때문에, 데이터에 있는 간단한 패턴의 연속된 변환으로 왜곡이 생길 수 있음. Wide & Deep Learning for Recommender Systems. Google Inc
2. 여러 개의 출력을 반환하는 모델 - ex) 사진 상의 물체를 분류하고 물체의 좌표까지 알아내고 싶을 때 - 다중 작업 분류(multitask classification)과 같은 작업을 수행 할 때 활용됨. 하나의 출력은 얼굴 표정을 분류하고 다른 출력을 안경 여부를 구별함. - 규제 기법으로도 활용.(과적합 방지, 일반화 성능 향상). ex) 신경망 구조 안에 보조 출력을 추가할 수 있음. 보조 출력을 사용해 하위 네트워크가 나머지 네트워크에 의존하지 않고 그 자체로 유용한 것을 학습하는지 확인할 수 있음??
3. 서브클래싱 API로 동적모델 만들기 - Sequential API와 함수형 API는 모두 선언적(declarative)임. 즉, 사용할 층과 연결 방식을 먼저 정의해야 하고 그 이후 모델에 데이터를 넣어 train시킬 수 있음 - 이 방식의 장점은 모델을 저장/복사/공유가 쉬움 - 모델의 구조를 출력하거나 분석하기도 좋음. - 전체 모델이 층으로 구성된 정적 그래프이기 때문에 디버깅이 매우 쉬움. - 하지만, 유연하지 않기때문에 다양한 크기나 조건문/ 반복문을 다루기에는 부적합함. 이 경우 명령형(imperative)프로그래밍 스타일로서 서브클래싱(subclassing) API가 적합함.
- 서브클래싱 API를 어떻게 사용하냐? 간단히 Model 클래스를 상속한 다음 생성자 안에 필요한 층을 만듦. - 층을 구성하는 생성자 부분과 정방향 계산 & 저수준 연산을 넣어주는 call 메소드 부분이 있음. - call 메서드 인자에 input을 넣어줌으로써 Input 클래스 객체를 만들 필요 없음. - 유연하므로 call 부분에 새로운 아이디어들을 추가할 수 있음 - 하지만, 모델을 저장하거나 복사할 수 없으며, 케라스가 타입과 크기를 미리 확인할 수 없어 실수가 발생하기 쉬움.
# subclassing API
class WideAndDeepModel(models.Model):
# 층 구성
def __init__(self, units=30, activation='relu',**kwargs):
super().__init__(**kwargs) # name과 같은 표준 매개변수 처리
self.hidden1 = layers.Dense(units, activation=activation)
self.hidden2 = layers.Dense(units, activation=activation)
self.main_output = layers.Dense(1)
self.aux_output = layers.Dense(1)
# 정방향 계산
def call(self, inputs):
input_A, input_B = inputs
hidden1 = self.hidden1(input_B)
hidden2 = self.hidden2(hidden1)
concat = layers.concatenate([input_A, hidden2])
main_output = self.main_output(concat)
aux_output = self.aux_output(hidden2)
return main_output, aux_output
model = WideAndDeepModel(30, activation="relu")
model.compile(loss=["mse", "mse"], loss_weights=[0.9, 0.1], optimizer=SGD(learning_rate=1e-3))
history = model.fit((X_train_A, X_train_B), (y_train, y_train), epochs=10,
validation_data=((X_valid_A, X_valid_B), (y_valid,y_valid)))
df_hist = pd.DataFrame(history.history)
df_hist.plot(figsize=(8,5))
plt.grid(True)
1. 은닉층 갯수 : 복잡한 문제일수록 은닉층을 늘리는게 성능이 향상됨. * 대규모 신경망은(깊은 층) 거의 절대로 지역 최솟값에 갇히지 않음. 만약 갇히더라도 그 값은 전역 최적값에 거의 도달한 수준 임.
2.은닉층의 뉴런 갯수 : 각 층의 뉴런 수를 점점 줄여나가는 깔대기 형태로 모델을 구성하는 것을 일반적인 형태로써 생각하였음. 저수준의 많은 특성이 고 수준의 적은 특성으로 합쳐질 수 있기 때문. 하지만, 요즘엔 이러한 구성이 일반적이지 않음. 왜냐하면 모든 은닉층에 같은 크기를 사용해도 동일하거나 더 나은 성능을 내기 때문. 또한 이렇게 할 시 튜닝해야될 파라미터가 한개로 줄어들기 때문에 효율적임. 각 층의 뉴런 갯수가 각각 파라미터(층 수만큼) -> 동일하게 들어갈 뉴런 갯수 파라미터(한개)
tip1 첫번째 은닉층의 뉴런 수를 많이하는게 성능 향상에 도움이 된다.
tip2. 점진적으로 층/뉴런 수를 늘리면서 실험하기 보다는, 실제로 필요한 것보다 더 많은 층/뉴런을 가진 모델을 설계하고 과대적합이 되지 않도록 earlystopping이나 regularization을 사용하는 것이 더 효율적임.(stretch pants 방식?)
tip3. 일반적으로 층의 뉴런 수보다 층 수를 늘리는 쪽이 이득이 많음
3. Learning Rate : 고정된 학습률을 설정하기보다는 점진적으로 변화하는 학습률을 설정하는 게 좋음
4. Optimizer
5. Batch size : 큰 배치크기를 사용한 경우 속도는 빠르지만 일반화 성능이 낮을 수 있음. 작은 배치의 경우 속도는 느려도 일반화 성능은 높음. 배치 크기에 대한 여러가지 의견이 있음