효과적인 Tensorflow 2

TensorFlow.org에서보기 Google Colab에서 실행하기 GitHub에서 소스 보기 노트북 다운로드하기

개요

이 가이드는 TensorFlow 2(TF2)를 사용하여 코드를 작성하기 위한 모범 사례 목록을 제공하며 최근에 TensorFlow 1(TF1)에서 전환한 사용자를 위해 작성되었습니다. TF1 코드를 TF2로 마이그레이션하는 방법에 대한 자세한 내용은 가이드의 마이그레이션 섹션을 참고하세요.

설치하기

이 가이드의 예제에서 사용하는 TensorFlow 및 기타 종속 항목을 가져옵니다.

import tensorflow as tf
import tensorflow_datasets as tfds
2022-12-14 21:55:10.524042: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory
2022-12-14 21:55:10.524133: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory
2022-12-14 21:55:10.524142: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.

관용적 텐서플로우 2.0 권장 사항

코드를 더 작은 모듈로 리팩토링

필요에 따라 호출되는 더 작은 함수로 코드를 리팩토링하는 것이 좋습니다. 최고의 성능을 위해서는 tf.function에서 가능한 가장 큰 계산 블록을 장식해야 합니다(tf.function로 호출하여 중첩한 Python 함수는 tf.function에 다른 jit_compile 설정을 사용하려는 경우가 아니면 별도의 장식이 필요하지 않음). 사용 사례에 따라 여러 훈련 단계 또는 전체 훈련 루프가 될 수도 있습니다. 추론 사용 사례는 단일 모델 전달 경로일 수 있습니다.

일부 tf.keras.optimizer의 기본 훈련률 조정하기

일부 Keras 옵티마이저는 TF2에서 다른 훈련률을 갖습니다. 모델의 수렴 동작이 변경되면 기본 훈련률을 확인해야 합니다.

optimizers.SGD, optimizers.Adam 또는 optimizers.RMSprop에는 변경사항이 없습니다.

다음 기본 훈련률이 변경되었습니다.

tf.Module 및 Keras 레이어를 사용하여 변수 관리

tf.Moduletf.keras.layers.Layer는 편리한 variablestrainable_variables 속성을 제공하고, 이는 모든 종속 변수를 재귀적으로 수집합니다. 이렇게 하면 변수가 사용되는 위치에서 로컬로 변수를 쉽게 관리할 수 있습니다.

Keras 레이어와 모델은 tf.train.Checkpointable로부터 상속하고 @tf.function과 통합되어 Keras 객체에서 저장 모델을 직접 검사하거나 내보낼 수 있도록 합니다. 이러한 통합을 활용하기 위해 반드시 Keras의 Model.fit API를 사용해야 하는 것은 아닙니다.

Keras를 사용하여 관련 변수의 하위 집합을 수집하는 방법을 알아보려면 Keras 가이드의 전이 학습 및 미세 조정 섹션을 읽어보세요.

tf.data.Datasettf.function 결합하기

TensorFlow 데이터세트 패키지(tfds)에는 사전 정의된 데이터세트를 tf.data.Dataset 객체로 로드하는 유틸리티가 포함되어 있습니다. 이 예제에서는 tfds를 사용하여 MNIST 데이터세트를 로드할 수 있습니다.

datasets, info = tfds.load(name='mnist', with_info=True, as_supervised=True)
mnist_train, mnist_test = datasets['train'], datasets['test']

그런 다음 훈련에 사용할 데이터를 준비합니다.

  • 각 이미지의 크기를 다시 조정합니다.
  • 예제의 순서를 셔플링합니다.
  • 이미지 및 레이블 배치를 수집합니다.
BUFFER_SIZE = 10 # Use a much larger value for real code
BATCH_SIZE = 64
NUM_EPOCHS = 5


def scale(image, label):
  image = tf.cast(image, tf.float32)
  image /= 255

  return image, label

이 예제를 짧게 유지하려면 5개의 배치만 반환하도록 데이터세트를 자릅니다.

train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)
test_data = mnist_test.map(scale).batch(BATCH_SIZE)

STEPS_PER_EPOCH = 5

train_data = train_data.take(STEPS_PER_EPOCH)
test_data = test_data.take(STEPS_PER_EPOCH)
image_batch, label_batch = next(iter(train_data))
2022-12-14 21:55:16.307777: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

메모리에 맞는 훈련 데이터를 반복하려면 일반 Python 반복을 사용해야 합니다. 그렇지 않을때 이 디스크에서 훈련 데이터를 스트리밍하는 가장 좋은 방법은 tf.data.Dataset입니다. 데이터세트는 반복할 수 있으며(반복기는 아님) 즉시 실행에서 다른 Python 반복기처럼 동작합니다. 코드를 tf.function로 래핑하여 데이터세트 비동기 프리페치/스트리밍 기능을 온전히 활용할 수 있습니다. 이는 AutoGraph를 사용하여 Python 반복기를 동등한 그래프 연산으로 교체합니다.

@tf.function
def train(model, dataset, optimizer):
  for x, y in dataset:
    with tf.GradientTape() as tape:
      # training=True is only needed if there are layers with different
      # behavior during training versus inference (e.g. Dropout).
      prediction = model(x, training=True)
      loss = loss_fn(prediction, y)
    gradients = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

Keras Model.fit API를 사용하면 데이터세트 반복에 대해 신경 쓸 필요가 없습니다.

model.compile(optimizer=optimizer, loss=loss_fn)
model.fit(dataset)

Keras 훈련 루프 사용하기

훈련 과정을 세부적으로 제어할 필요가 없다면 케라스의 내장 메서드인 fit, evaluate, predict를 사용하는 것이 좋습니다. 이 메서드들은 모델 구현(Sequential, 함수형 API, 클래스 상속)에 상관없이 일관된 훈련 인터페이스를 제공합니다.

이 메소드의 장점은 다음과 같습니다.

  • Numpy 배열, Python 제너레이터, tf.data.Datasets를 사용할 수 있습니다.
  • 정규화 및 활성화 손실을 자동으로 적용합니다.
  • 하드웨어 구성에 관계 없이 훈련 코드가 동일하게 유지되는 tf.distribute를 지원합니다.
  • 손실 및 메트릭으로 임의의 호출 가능 항목을 지원합니다.
  • tf.keras.callbacks.TensorBoard와 같은 콜백과 사용자 정의 콜백을 지원합니다.
  • TensorFlow 그래프를 사용하여 자동으로 성능 기준을 맞춥니다.

다음은 Dataset를 사용하여 모델을 훈련하는 예제입니다. 작동 방식에 대한 자세한 내용은 튜토리얼을 확인합니다.

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, 3, activation='relu',
                           kernel_regularizer=tf.keras.regularizers.l2(0.02),
                           input_shape=(28, 28, 1)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dense(10)
])

# Model is the full model w/o custom layers
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

model.fit(train_data, epochs=NUM_EPOCHS)
loss, acc = model.evaluate(test_data)

print("Loss {}, Accuracy {}".format(loss, acc))
Epoch 1/5
5/5 [==============================] - 3s 6ms/step - loss: 1.5373 - accuracy: 0.5000
Epoch 2/5
2022-12-14 21:55:19.700111: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
5/5 [==============================] - 0s 5ms/step - loss: 0.4361 - accuracy: 0.9312
Epoch 3/5
2022-12-14 21:55:19.979427: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
5/5 [==============================] - 0s 5ms/step - loss: 0.2826 - accuracy: 0.9656
Epoch 4/5
2022-12-14 21:55:20.289201: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
5/5 [==============================] - 0s 5ms/step - loss: 0.1974 - accuracy: 0.9875
Epoch 5/5
2022-12-14 21:55:20.576118: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
5/5 [==============================] - 0s 5ms/step - loss: 0.1499 - accuracy: 1.0000
2022-12-14 21:55:20.848689: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
5/5 [==============================] - 0s 3ms/step - loss: 1.6309 - accuracy: 0.7531
Loss 1.6308777332305908, Accuracy 0.753125011920929
2022-12-14 21:55:21.212331: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

훈련 루프 사용자 정의하기 및 자체 루프 작성하기

Keras 모델이 적합하지만 훈련 단계 또는 외부 훈련 루프에 더 많은 유연성과 제어가 필요한 경우 자체 훈련 단계 또는 전체 훈련 루프를 구현할 수 있습니다. 자세한 내용은 fit 사용자 정의하기의 Keras 가이드를 참조해 주세요.

tf.keras.callbacks.Callback으로 많은 것을 구현할 수도 있습니다.

이 메서드에는 이전에 언급한 많은 장점 외에도 훈련 단계와 외부 루프까지 제어할 수 있다는 장점도 있습니다.

표준 훈련 루프에는 세 단계가 있습니다.

  1. Python 생성기 또는 tf.data.Dataset를 반복하여 예제 배치를 가져옵니다.
  2. tf.GradientTape를 사용하여 그래디언트를 수집합니다.
  3. tf.keras.optimizers 중 하나를 사용하여 모델 변수에 가중치 업데이트를 적용합니다.

기억해야 하는 사항:

  • 서브 클래화된 레이어 및 모델의 call 메서드에 항상 training 인수를 포함합니다.
  • training 인수가 올바르게 설정된 모델을 호출하는지 확인합니다.
  • 사용법에 따라 데이터 배치에서 모델을 실행할 때까지 모델 변수가 존재하지 않을 수 있습니다.
  • 모델의 정규화 손실 등은 수동으로 처리해야 합니다.

변수 이니셜라이저를 실행하거나 수동 제어 종속성을 추가할 필요가 없습니다. tf.function은 생성 시 자동 제어 종속성과 변수 초기화를 처리합니다.

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, 3, activation='relu',
                           kernel_regularizer=tf.keras.regularizers.l2(0.02),
                           input_shape=(28, 28, 1)),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.1),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.BatchNormalization(),
    tf.keras.layers.Dense(10)
])

optimizer = tf.keras.optimizers.Adam(0.001)
loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

@tf.function
def train_step(inputs, labels):
  with tf.GradientTape() as tape:
    predictions = model(inputs, training=True)
    regularization_loss=tf.math.add_n(model.losses)
    pred_loss=loss_fn(labels, predictions)
    total_loss=pred_loss + regularization_loss

  gradients = tape.gradient(total_loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))

for epoch in range(NUM_EPOCHS):
  for inputs, labels in train_data:
    train_step(inputs, labels)
  print("Finished epoch", epoch)
2022-12-14 21:55:22.897407: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
Finished epoch 0
2022-12-14 21:55:23.185574: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
Finished epoch 1
2022-12-14 21:55:23.467763: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
Finished epoch 2
2022-12-14 21:55:23.738925: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
Finished epoch 3
Finished epoch 4
2022-12-14 21:55:24.029871: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

Python 제어 흐름으로 tf.function 활용하기

tf.function은 데이터에 따라 결정되는 제어 흐름을 tf.condtf.while_loop와 같은 그래프 모드로 변환하는 방법을 제공합니다.

데이터에 의존하는 제어 흐름이 나타나는 대표적인 곳은 시퀀스 모델입니다. tf.keras.layers.RNN은 RNN 셀을 래핑하여 반복을 정적으로 또는 동적으로 전개할 수 있도록 합니다. 예를 들어 다음과 같은 동적 언롤을 다시 구현할 수 있습니다.

class DynamicRNN(tf.keras.Model):

  def __init__(self, rnn_cell):
    super(DynamicRNN, self).__init__(self)
    self.cell = rnn_cell

  @tf.function(input_signature=[tf.TensorSpec(dtype=tf.float32, shape=[None, None, 3])])
  def call(self, input_data):

    # [batch, time, features] -> [time, batch, features]
    input_data = tf.transpose(input_data, [1, 0, 2])
    timesteps =  tf.shape(input_data)[0]
    batch_size = tf.shape(input_data)[1]
    outputs = tf.TensorArray(tf.float32, timesteps)
    state = self.cell.get_initial_state(batch_size = batch_size, dtype=tf.float32)
    for i in tf.range(timesteps):
      output, state = self.cell(input_data[i], state)
      outputs = outputs.write(i, output)
    return tf.transpose(outputs.stack(), [1, 0, 2]), state
lstm_cell = tf.keras.layers.LSTMCell(units = 13)

my_rnn = DynamicRNN(lstm_cell)
outputs, state = my_rnn(tf.random.normal(shape=[10,20,3]))
print(outputs.shape)
(10, 20, 13)

자세한 정보는 tf.function 가이드를 참고합니다.

새로운 스타일의 메트릭 및 손실

메트릭과 손실은 모두 tf.function에서 즉시 작동하는 객체입니다.

손실 객체는 호출할 수 있으며 (y_true, y_pred)를 인수로 예상합니다.

cce = tf.keras.losses.CategoricalCrossentropy(from_logits=True)
cce([[1, 0]], [[-1.0,3.0]]).numpy()
4.01815

메트릭을 사용하여 데이터를 수집하고 표시하기

tf.metrics를 사용하여 데이터를 집계하고 tf.summary를 사용하여 요약문을 기록하고 컨텍스트 관리자를 사용하여 작성자에게 리디렉션할 수 있습니다. 요약문은 작성자에게 직접 내보내지므로 호출 사이트에서 step 값을 제공해야 합니다.

summary_writer = tf.summary.create_file_writer('/tmp/summaries')
with summary_writer.as_default():
  tf.summary.scalar('loss', 0.1, step=42)

요약문으로 기록하기 전에 tf.metrics를 사용하여 데이터를 집계합니다. 메트릭은 정적(Stateful)이기에 result 메서드(예: Mean.result)를 호출하면 값이 누적되고 누적 결과가 반환됩니다. Model.reset_states로 누적된 값을 삭제합니다.

def train(model, optimizer, dataset, log_freq=10):
  avg_loss = tf.keras.metrics.Mean(name='loss', dtype=tf.float32)
  for images, labels in dataset:
    loss = train_step(model, optimizer, images, labels)
    avg_loss.update_state(loss)
    if tf.equal(optimizer.iterations % log_freq, 0):
      tf.summary.scalar('loss', avg_loss.result(), step=optimizer.iterations)
      avg_loss.reset_states()

def test(model, test_x, test_y, step_num):
  # training=False is only needed if there are layers with different
  # behavior during training versus inference (e.g. Dropout).
  loss = loss_fn(model(test_x, training=False), test_y)
  tf.summary.scalar('loss', loss, step=step_num)

train_summary_writer = tf.summary.create_file_writer('/tmp/summaries/train')
test_summary_writer = tf.summary.create_file_writer('/tmp/summaries/test')

with train_summary_writer.as_default():
  train(model, optimizer, dataset)

with test_summary_writer.as_default():
  test(model, test_x, test_y, optimizer.iterations)

텐서보드(TensorBoard)에서 요약문 로그 디렉터리를 지정하여 생성된 요약문을 시각화합니다.

tensorboard --logdir /tmp/summaries

텐서보드에서 시각화를 생성할 수 있도록 tf.summary API를 사용하여 요약문 데이터를 작성합니다. 자세한 정보는 tf.summary 가이드를 참고합니다.

# Create the metrics
loss_metric = tf.keras.metrics.Mean(name='train_loss')
accuracy_metric = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')

@tf.function
def train_step(inputs, labels):
  with tf.GradientTape() as tape:
    predictions = model(inputs, training=True)
    regularization_loss=tf.math.add_n(model.losses)
    pred_loss=loss_fn(labels, predictions)
    total_loss=pred_loss + regularization_loss

  gradients = tape.gradient(total_loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))
  # Update the metrics
  loss_metric.update_state(total_loss)
  accuracy_metric.update_state(labels, predictions)


for epoch in range(NUM_EPOCHS):
  # Reset the metrics
  loss_metric.reset_states()
  accuracy_metric.reset_states()

  for inputs, labels in train_data:
    train_step(inputs, labels)
  # Get the metric results
  mean_loss=loss_metric.result()
  mean_accuracy = accuracy_metric.result()

  print('Epoch: ', epoch)
  print('  loss:     {:.3f}'.format(mean_loss))
  print('  accuracy: {:.3f}'.format(mean_accuracy))
2022-12-14 21:55:24.963973: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
Epoch:  0
  loss:     0.133
  accuracy: 0.991
2022-12-14 21:55:25.238740: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
Epoch:  1
  loss:     0.113
  accuracy: 1.000
2022-12-14 21:55:25.538122: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
Epoch:  2
  loss:     0.101
  accuracy: 1.000
2022-12-14 21:55:25.844832: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
Epoch:  3
  loss:     0.088
  accuracy: 1.000
Epoch:  4
  loss:     0.079
  accuracy: 1.000
2022-12-14 21:55:26.131845: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

저장과 복원

Keras 모델은 메트릭 이름을 일관성 있게 처리합니다. 메트릭 목록의 문자열을 전달하면 일치하는 문자열을 메트릭의 name으로 사용합니다. 이러한 이름은 model.fit로 반환한 기록 객체와 keras.callbacks에 전달된 로그에서 볼 수 있습니다. 메트릭 목록에서 전달한 문자열로 설정됩니다.

model.compile(
    optimizer = tf.keras.optimizers.Adam(0.001),
    loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics = ['acc', 'accuracy', tf.keras.metrics.SparseCategoricalAccuracy(name="my_accuracy")])
history = model.fit(train_data)
5/5 [==============================] - 2s 5ms/step - loss: 0.0902 - acc: 0.9969 - accuracy: 0.9969 - my_accuracy: 0.9969
2022-12-14 21:55:27.804136: W tensorflow/core/kernels/data/cache_dataset_ops.cc:856] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.
history.history.keys()
dict_keys(['loss', 'acc', 'accuracy', 'my_accuracy'])

디버깅

즉시 실행을 사용하여 코드를 단계별로 실행하고 형상, 데이터 유형 및 값을 검사할 수 있습니다. tf.function, tf.keras 등과 같은 특정 API는 성능 및 이식성을 위해 그래프 실행을 사용하도록 설계되었습니다. 디버깅할 때 이 코드 내에서 즉시 실행을 사용하려면 tf.config.run_functions_eagerly(True)를 사용합니다.

예제:

@tf.function
def f(x):
  if x > 0:
    import pdb
    pdb.set_trace()
    x = x + 1
  return x

tf.config.run_functions_eagerly(True)
f(tf.constant(1))
>>> f()
-> x = x + 1
(Pdb) l
  6     @tf.function
  7     def f(x):
  8       if x > 0:
  9         import pdb
 10         pdb.set_trace()
 11  ->     x = x + 1
 12       return x
 13
 14     tf.config.run_functions_eagerly(True)
 15     f(tf.constant(1))
[EOF]

이는 Keras 모델 및 즉시 실행을 지원하는 기타 API에서도 작동합니다.

class CustomModel(tf.keras.models.Model):

  @tf.function
  def call(self, input_data):
    if tf.reduce_mean(input_data) > 0:
      return input_data
    else:
      import pdb
      pdb.set_trace()
      return input_data // 2


tf.config.run_functions_eagerly(True)
model = CustomModel()
model(tf.constant([-2, -4]))
>>> call()
-> return input_data // 2
(Pdb) l
 10         if tf.reduce_mean(input_data) > 0:
 11           return input_data
 12         else:
 13           import pdb
 14           pdb.set_trace()
 15  ->       return input_data // 2
 16
 17
 18     tf.config.run_functions_eagerly(True)
 19     model = CustomModel()
 20     model(tf.constant([-2, -4]))

참고 사항:

객체에 tf.Tensors 유지 금지

이러한 텐서 객체는 tf.function 또는 Eager 컨텍스트에서 생성될 수 있으며 이러한 텐서는 다르게 동작합니다. 중간 값에는 항상 tf.Tensor를 사용합니다.

상태를 추적하려면 양쪽 컨텍스트에서 항상 사용할 수 있는 tf.Variable을 사용합니다. 자세히 알아보려면tf.Variable 가이드를 읽어보세요.

리소스 및 추가 읽을거리

  • TF2 사용 방법에 대해 자세히 알아보려면 TF2 가이드튜토리얼을 읽어보세요.

  • 이전에 TF1.x를 사용한 경우 코드를 TF2로 마이그레이션하는 것이 좋습니다. 자세히 알아보려면 마이그레이션 가이드를 읽어보세요.