# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: keras_study
#     language: python
#     name: keras_study
# ---

# ## <span style="color:orange">Q2.</span>
# <b>Fashion-MNIST 문제에서 과대적합에 대해 설명했습니다.  
# <span style="color:red">데이터가 충분하지 않다면, 모델의 깊이가 깊은 경우 과대적합 문제에 노출될 확률이 매우 높은데요.</span>
#
# 필자는 이를 어느정도 조절하기 위해 매우 깊은 Dense층을 사용하지 않은 상태로 여러분들에게 예제 코드를 제공했습니다.
#
# Fashion-MNIST에서 총 세 가지의 실험을 진행해보았으면 좋겠습니다.  
# 각 실험에서 모델의 수렴 속도와 과대적합이 어느 구간에서 발생하는지 확인할 수 있어야 합니다.
#
# 끝까지 학습시켜보고, 일어나는 변화를 관찰하세요.</b>
# <hr>

# +
from tensorflow.keras.datasets.fashion_mnist import load_data

# Fashion-MNIST 데이터를 다운받습니다.
(x_train, y_train), (x_test, y_test) = load_data()

# 값의 범위를 0 ~ 1로 만들어줍니다.
x_train = x_train / 255
x_test = x_test / 255

from tensorflow.keras.utils import to_categorical

# 각 데이터의 레이블을 범주형 형태로 변경합니다.
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

# 검증 데이터 세트를 만듭니다.
from sklearn.model_selection import train_test_split

# 훈련/테스트 데이터를 0.7/0.3의 비율로 분리합니다.
x_train, x_val, y_train, y_val = train_test_split(x_train, y_train, test_size = 0.3, random_state = 777)
# -

# ### 1. 매우 적은 개수의 은닉 유닛과 적은 개수의 Dense층을 통한 학습

# +
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten

small_model = Sequential()
# 입력 데이터의 형태를 꼭 명시해야 합니다.
small_model.add(Flatten(input_shape = (28, 28))) # (28, 28) -> .(28 * 28)
small_model.add(Dense(10, activation = 'relu'))
small_model.add(Dense(10, activation = 'softmax'))

small_model.compile(optimizer='adam', # 옵티마이저 : Adam
              loss = 'categorical_crossentropy', # 손실 함수 : categorical_crossentropy
              metrics=['acc']) # 모니터링 할 평가지표 : acc

# loss, metrics, 학습 속도, 학습 여부 등 변화를 관찰하고, 
# 책의 예제 코드 결과와 비교해보세요.
small_model.fit(x_train, y_train, 
                epochs = 30, 
                batch_size = 128, 
                validation_data = (x_val, y_val))
# -

# ### 2. 이 책의 예제코드를 통한 학습(책 코드 참고)

# ### 3. 많은 개수의 은닉 유닛과 많은 개수의 Dense층을 통한 학습

# +
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten

big_model = Sequential()
# 입력 데이터의 형태를 꼭 명시해야 합니다.
# 은닉 유닛 개수는 컴퓨팅 환경에 따라 조절하세요.
# 너무 크면 Out Of Memory 에러가 발생할 수 있습니다.
big_model.add(Flatten(input_shape = (28, 28))) # (28, 28) -> .(28 * 28)
big_model.add(Dense(1024, activation = 'relu'))
big_model.add(Dense(512, activation = 'relu'))
big_model.add(Dense(256, activation = 'relu'))
big_model.add(Dense(128, activation = 'relu'))
big_model.add(Dense(64, activation = 'relu'))
big_model.add(Dense(10, activation = 'softmax'))

big_model.compile(optimizer='adam', # 옵티마이저 : Adam
              loss = 'categorical_crossentropy', # 손실 함수 : categorical_crossentropy
              metrics=['acc']) # 모니터링 할 평가지표 : acc

# loss, metrics, 학습 속도, 학습 여부 등 변화를 관찰하고, 
# 책의 예제 코드 결과와 비교해보세요.
# 과대적합 여부도 확인해보세요.
# 과대적합은 train_loss는 감소하나, val_loss가 증가하는 경향을 보입니다.
big_model.fit(x_train, y_train, 
                epochs = 30, 
                batch_size = 128, 
                validation_data = (x_val, y_val))
# -

# ### 4. 더 많은 개수의 은닉 유닛과 더 많은 개수의 Dense층을 통한 학습

# +
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten

big_model = Sequential()
# 입력 데이터의 형태를 꼭 명시해야 합니다.
# 은닉 유닛 개수는 컴퓨팅 환경에 따라 조절하세요.
# 너무 크면 Out Of Memory 에러가 발생할 수 있습니다.
big_model.add(Flatten(input_shape = (28, 28))) # (28, 28) -> .(28 * 28)
big_model.add(Dense(2048, activation = 'relu'))
big_model.add(Dense(1024, activation = 'relu'))
big_model.add(Dense(512, activation = 'relu'))
big_model.add(Dense(256, activation = 'relu'))
big_model.add(Dense(128, activation = 'relu'))
big_model.add(Dense(10, activation = 'softmax'))

big_model.compile(optimizer='adam', # 옵티마이저 : Adam
              loss = 'categorical_crossentropy', # 손실 함수 : categorical_crossentropy
              metrics=['acc']) # 모니터링 할 평가지표 : acc

# loss, metrics, 학습 속도, 학습 여부 등 변화를 관찰하고, 
# 책의 예제 코드 결과와 비교해보세요.
# 과대적합 여부도 확인해보세요.
# 과대적합은 train_loss는 감소하나, val_loss가 증가하는 경향을 보입니다.
big_model.fit(x_train, y_train, 
                epochs = 30, 
                batch_size = 128, 
                validation_data = (x_val, y_val))

StarcoderdataJupyterScriptsDedupFiltered