#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Explanation: Copyright 2019 The TensorFlow Authors.
End of explanation
"""


# Load the TensorBoard notebook extension.
%load_ext tensorboard

from datetime import datetime
from packaging import version

import tensorflow as tf
from tensorflow import keras

import numpy as np

print("TensorFlow version: ", tf.__version__)
assert version.parse(tf.__version__).release[0] >= 2, \
    "This notebook requires TensorFlow 2.0 or above."

"""
Explanation: TensorBoard Scalar: Keras에서 훈련 메트릭 로깅하기
<table class="tfo-notebook-buttons" align="left">
  <td><a target="_blank" href="https://www.tensorflow.org/tensorboard/scalars_and_keras"><img src="https://www.tensorflow.org/images/tf_logo_32px.png">TensorFlow.org에서 보기</a></td>
  <td><a target="_blank" href="https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/tensorboard/scalars_and_keras.ipynb"><img src="https://www.tensorflow.org/images/colab_logo_32px.png">Google Colab에서 실행</a></td>
  <td><a target="_blank" href="https://github.com/tensorflow/docs-l10n/blob/master/site/ko/tensorboard/scalars_and_keras.ipynb"><img src="https://www.tensorflow.org/images/GitHub-Mark-32px.png">GitHub에서 소스 보기</a></td>
</table>

개요
머신 러닝에서는 손실과 같은 주요 메트릭, 그리고 교육이 진행됨에 따라 이것이 달라지는 방식을 이해하는 과정에 반드시 관련됩니다. 이러한 메트릭은 예를 들어 과적합되고 있는지, 또는 너무 오랫동안 불필요하게 훈련하는지 이해하는 데 도움이 될 수 있습니다. 모델을 디버그하고 개선하는 데 도움이 되도록 다양한 훈련 실행에서 이러한 메트릭을 비교할 수 있습니다.
TensorBoard의 스칼라 대시보드를 사용하면 아주 적은 노력으로 간단한 API를 사용하여 이러한 메트릭을 시각화할 수 있습니다. 이 튜토리얼은 Keras 모델을 개발할 때 TensorBoard와 함께 이러한 API를 사용하는 방법을 배우는 데 도움이 되는 매우 기본적인 예제를 제공합니다. Keras TensorBoard 콜백 및 TensorFlow 요약 API를 사용하여 기본 및 사용자 지정 스칼라를 시각화하는 방법을 배웁니다.
설정
End of explanation
"""


data_size = 1000
# 80% of the data is for training.
train_pct = 0.8

train_size = int(data_size * train_pct)

# Create some input data between -1 and 1 and randomize it.
x = np.linspace(-1, 1, data_size)
np.random.shuffle(x)

# Generate the output data.
# y = 0.5x + 2 + noise
y = 0.5 * x + 2 + np.random.normal(0, 0.05, (data_size, ))

# Split into test and train pairs.
x_train, y_train = x[:train_size], y[:train_size]
x_test, y_test = x[train_size:], y[train_size:]

"""
Explanation: 단순 회귀에 대한 데이터 설정
이제 Keras를 사용하여 회귀를 계산할 것입니다. 즉, 쌍을 이루는 데이터세트에 가장 적합한 피팅 라인을 찾습니다. (신경망과 경사 하강법을 사용하는 것은 이런 종류의 문제에는 과도하지만 이해하기 쉬운 예로서는 좋습니다.)
TensorBoard를 사용하여 에포크를 거치면서 훈련 및 테스트 손실이 어떻게 변하는지 관찰할 것입니다. 시간이 지남에 따라 훈련 및 테스트 손실이 감소한 다음 안정적으로 유지되기를 바랍니다.
먼저, y = 0.5x + 2 라인을 따라 대략 1000개의 데이터 포인트를 생성합니다. 이들 데이터 포인트를 훈련 세트와 테스트 세트로 나눕니다. 신경망이 이 관계를 학습하기를 바랍니다.
End of explanation
"""


logdir = "logs/scalars/" + datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = keras.callbacks.TensorBoard(log_dir=logdir)

model = keras.models.Sequential([
    keras.layers.Dense(16, input_dim=1),
    keras.layers.Dense(1),
])

model.compile(
    loss='mse', # keras.losses.mean_squared_error
    optimizer=keras.optimizers.SGD(learning_rate=0.2),
)

print("Training ... With default parameters, this takes less than 10 seconds.")
training_history = model.fit(
    x_train, # input
    y_train, # output
    batch_size=train_size,
    verbose=0, # Suppress chatty output; use Tensorboard instead
    epochs=100,
    validation_data=(x_test, y_test),
    callbacks=[tensorboard_callback],
)

print("Average test loss: ", np.average(training_history.history['loss']))

"""
Explanation: 모델 학습 및 손실 로깅하기
이제 모델을 정의, 훈련 및 평가할 준비가 되었습니다.
훈련함에 따라 손실 스칼라를 기록하려면 다음을 수행합니다.

Keras TensorBoard 콜백을 생성합니다.
로그 디렉토리를 지정합니다.
TensorBoard 콜백을 Keras의 Model.fit()에 전달합니다.

TensorBoard는 로그 디렉토리 계층 구조에서 로그 데이터를 읽습니다. 이 노트북에서 루트 로그 디렉토리는 logs/scalars이며, 타임스탬프가 지정된 하위 디렉토리가 앞에 옵니다. 타임스탬프가 지정된 하위 디렉토리를 사용하면 TensorBoard를 사용하고 모델을 반복할 때 학습 실행을 쉽게 식별하고 선택할 수 있습니다.
End of explanation
"""


%tensorboard --logdir logs/scalars

"""
Explanation: TensorBoard를 사용하여 손실 검사하기
이제 위에서 사용한 루트 로그 디렉토리를 지정하여 TensorBoard를 시작합니다.
TensorBoard의 UI가 작동할 때까지 몇 초 동안 기다립니다.
End of explanation
"""


print(model.predict([60, 25, 2]))
# True values to compare predictions against: 
# [[32.0]
#  [14.5]
#  [ 3.0]]

"""
Explanation: <!-- <img class="tfo-display-only-on-site" src="https://github.com/tensorflow/tensorboard/blob/master/docs/images/scalars_loss.png?raw=1"/> -->

TensorBoard에 "현재 데이터세트에 대해 활성화된 대시보드가 없습니다"라는 메시지가 표시될 수 있습니다. 아직 초기 로깅 데이터가 저장되지 않았기 때문입니다. 학습이 진행됨에 따라 Keras 모델이 데이터 로깅을 시작합니다. TensorBoard는 주기적으로 새로고침하여 스칼라 메트릭을 표시합니다. 기다리기 싫다면 오른쪽 상단의 '새로고침' 화살표를 탭할 수 있습니다.
훈련 진행 상황을 관찰하면서 훈련 및 검증 손실이 어떻게 급격히 감소한 다음 안정적으로 유지되는지 확인하세요. 실제로, 25 에포크 후에는 훈련이 크게 개선되지 않았기 때문에 훈련을 중단할 수 있습니다.
특정 데이터 포인트를 보려면 그래프 위로 마우스를 가져갑니다. 마우스로 확대하거나 일부를 선택하여 더 자세히 볼 수도 있습니다.
왼쪽의 "실행" 선택기를 확인하세요. "실행"은 훈련 라운드의 로그 세트를 나타내며, 이 경우 Model.fit()의 결과입니다. 개발자는 일반적으로 시간이 지남에 따라 모델을 실험하고 개발할 때 많은 실행을 합니다.
실행 선택기를 사용하여 특정 실행을 선택하거나 훈련 또는 검증만 선택합니다. 실행을 비교하면 문제를 더 잘 해결하는 코드 버전을 평가하는 데 도움이 됩니다.
좋습니다. TensorBoard의 손실 그래프는 손실이 훈련과 검증 모두에서 일관되게 감소한 다음 안정화되었음을 보여줍니다. 이는 모델의 메트릭이 매우 우수할 가능성이 높음을 의미합니다! 이제 모델이 실제로 어떻게 작동하는지 확인하세요.
입력 데이터(60, 25, 2)가 주어지면 라인 y = 0.5x + 2는 (32, 14.5, 3)을 산출해야 합니다. 모델이 그렇게 작동합니까?
End of explanation
"""


logdir = "logs/scalars/" + datetime.now().strftime("%Y%m%d-%H%M%S")
file_writer = tf.summary.create_file_writer(logdir + "/metrics")
file_writer.set_as_default()

def lr_schedule(epoch):
  """
  Returns a custom learning rate that decreases as epochs progress.
  """
  learning_rate = 0.2
  if epoch > 10:
    learning_rate = 0.02
  if epoch > 20:
    learning_rate = 0.01
  if epoch > 50:
    learning_rate = 0.005

  tf.summary.scalar('learning rate', data=learning_rate, step=epoch)
  return learning_rate

lr_callback = keras.callbacks.LearningRateScheduler(lr_schedule)
tensorboard_callback = keras.callbacks.TensorBoard(log_dir=logdir)

model = keras.models.Sequential([
    keras.layers.Dense(16, input_dim=1),
    keras.layers.Dense(1),
])

model.compile(
    loss='mse', # keras.losses.mean_squared_error
    optimizer=keras.optimizers.SGD(),
)

training_history = model.fit(
    x_train, # input
    y_train, # output
    batch_size=train_size,
    verbose=0, # Suppress chatty output; use Tensorboard instead
    epochs=100,
    validation_data=(x_test, y_test),
    callbacks=[tensorboard_callback, lr_callback],
)

"""
Explanation: 나쁘지 않군요!
사용자 지정 스칼라 로깅하기
동적 학습률과 같은 사용자 지정 값을 로깅하려면 어떻게 해야 할까요? 그렇게 하려면 TensorFlow 요약 API를 사용해야 합니다.
회귀 모델을 다시 훈련시키고 사용자 지정 학습률을 기록합니다. 방법은 다음과 같습니다.

tf.summary.create_file_writer()를 사용하여 파일 작성자를 만듭니다.
사용자 지정 학습률 함수를 정의합니다. 이 함수는 Keras LearningRateScheduler 콜백으로 전달됩니다.
학습률 함수 내에서 tf.summary.scalar()를 사용하여 사용자 지정 학습률을 로깅합니다.
Model.fit()에 LearningRateScheduler 콜백을 전달합니다.

일반적으로, 사용자 지정 스칼라를 로깅하려면 파일 작성기와 함께 tf.summary.scalar()를 사용해야 합니다. 파일 작성기는 이 실행에 대한 데이터를 지정된 디렉토리에 작성하는 역할을 하며 tf.summary.scalar()를 사용할 때 암시적으로 사용됩니다.
End of explanation
"""


%tensorboard --logdir logs/scalars

"""
Explanation: TensorBoard를 다시 살펴보겠습니다.
End of explanation
"""


print(model.predict([60, 25, 2]))
# True values to compare predictions against: 
# [[32.0]
#  [14.5]
#  [ 3.0]]

"""
Explanation: <!-- <img class="tfo-display-only-on-site" src="https://github.com/tensorflow/tensorboard/blob/master/docs/images/scalars_custom_lr.png?raw=1"/> -->

왼쪽의 "실행" 선택기를 사용하여 &lt;timestamp&gt;/metrics가 실행됨을 확인합니다. 이 실행을 선택하면 이 실행 중 학습률의 진행 상황을 확인할 수 있는 "학습률" 그래프가 표시됩니다.
이 실행의 훈련 및 검증 손실 곡선을 이전 실행과 비교할 수도 있습니다. 또한 학습률 일정이 에포크에 따라 이산 값을 반환했지만 학습률 플롯은 매끄럽게 나타날 수 있음을 알 수 있습니다. TensorBoard에는 평활화 매개변수가 있으며 평활화되지 않은 값을 보려면 값을 0으로 낮춰야 할 수 있습니다.
이 모델이 어떻게 작동합니까?
End of explanation
"""


