사전 제작 Estimator

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

경고: Estimator는 새 코드에 권장되지 않습니다. Estimator는 v1.Session 스타일 코드를 실행하는데, 이 코드는 올바르게 작성하기가 좀 더 어렵고 특히 TF 2 코드와 결합할 경우 예기치 않게 작동할 수 있습니다. Estimator는 호환성 보장이 적용되지만 보안 취약점 외에는 수정 사항이 제공되지 않습니다. 자세한 내용은 마이그레이션 가이드를 참조하세요.

이 튜토리얼은 Estimator를 사용하여 TensorFlow의 홍채 분류 문제를 해결하는 방법을 보여줍니다. Estimator는 완전한 모델에 대한 기존 TensorFlow의 고차원적 표현입니다. 자세한 내용은 Estimator를 참조하세요.

참고: TensorFlow 2.0에서 Keras API는 이와 동일한 작업을 수행할 수 있으며 배우기 더 쉬운 API로 여겨집니다. 새로 시작하는 경우 Keras로 시작하는 것이 좋습니다.

시작을 위한 준비

시작하려면 먼저 TensorFlow와 필요한 여러 라이브러리를 가져옵니다.

import tensorflow as tf

import pandas as pd
2022-12-14 22:31:12.214526: 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 22:31:12.214616: 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 22:31:12.214626: 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.

데이터세트

이 문서의 샘플 프로그램은 아이리스 꽃을 꽃받침잎꽃잎의 크기에 따라 세 가지 종으로 분류하는 모델을 빌드하고 테스트합니다.

Iris 데이터세트를 사용하여 모델을 훈련합니다. Iris 데이터세트에는 네 가지 특성과 하나의 레이블이 있습니다. 이 네 가지 특성은 개별 아이리스 꽃의 다음과 같은 식물 특성을 식별합니다.

  • 꽃받침잎 길이
  • 꽃받침잎 너비
  • 꽃잎 길이
  • 꽃잎 너비

이 정보를 바탕으로 데이터를 구문 분석하는 데 도움이 되는 몇 가지 상수를 정의할 수 있습니다.

CSV_COLUMN_NAMES = ['SepalLength', 'SepalWidth', 'PetalLength', 'PetalWidth', 'Species']
SPECIES = ['Setosa', 'Versicolor', 'Virginica']

그 다음, Keras 및 Pandas를 사용하여 Iris 데이터세트를 다운로드하고 구문 분석합니다. 훈련 및 테스트를 위해 별도의 데이터세트를 유지합니다.

train_path = tf.keras.utils.get_file(
    "iris_training.csv", "https://storage.googleapis.com/download.tensorflow.org/data/iris_training.csv")
test_path = tf.keras.utils.get_file(
    "iris_test.csv", "https://storage.googleapis.com/download.tensorflow.org/data/iris_test.csv")

train = pd.read_csv(train_path, names=CSV_COLUMN_NAMES, header=0)
test = pd.read_csv(test_path, names=CSV_COLUMN_NAMES, header=0)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/iris_training.csv
2194/2194 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/iris_test.csv
573/573 [==============================] - 0s 0us/step

데이터를 검사하여 네 개의 float 특성 열과 하나의 int32 레이블이 있는지 확인할 수 있습니다.

train.head()

각 데이터세트에 대해 예측하도록 모델을 훈련할 레이블을 분할합니다.

train_y = train.pop('Species')
test_y = test.pop('Species')

# The label column has now been removed from the features.
train.head()

Estimator를 사용한 프로그래밍 개요

이제 데이터가 설정되었으므로 TensorFlow Estimator를 사용하여 모델을 정의할 수 있습니다. Estimator는 tf.estimator.Estimator에서 파생된 클래스입니다. TensorFlow는 일반적인 ML 알고리즘을 구현하기 위해 tf.estimator(예: LinearRegressor) 모음을 제공합니다. 그 외에도 고유한 사용자 정의 Estimator를 작성할 수 있습니다. 처음 시작할 때는 미리 만들어진 Estimator를 사용하는 것이 좋습니다.

사전 제작된 Estimator를 기초로 TensorFlow 프로그램을 작성하려면 다음 작업을 수행해야 합니다.

  • 하나 이상의 입력 함수를 작성합니다.
  • 모델의 특성 열을 정의합니다.
  • 특성 열과 다양한 하이퍼 매개변수를 지정하여 Estimator를 인스턴스화합니다.
  • Estimator 객체에서 하나 이상의 메서드를 호출하여 적합한 입력 함수를 데이터 소스로 전달합니다.

이러한 작업이 Iris 분류를 위해 어떻게 구현되는지 알아보겠습니다.

입력 함수 작성하기

훈련, 평가 및 예측을 위한 데이터를 제공하려면 입력 함수를 작성해야 합니다.

입력 함수는 다음 두 요소 튜플을 출력하는 tf.data.Dataset 객체를 반환하는 함수입니다.

  • features -다음과 같은 Python 사전:
    • 각 키가 특성의 이름입니다.
    • 각 값은 해당 특성 값을 모두 포함하는 배열입니다.
  • label - 모든 예제의 레이블 값을 포함하는 배열입니다.

입력 함수의 형식을 보여주기 위해 여기에 간단한 구현을 나타냈습니다.

def input_evaluation_set():
    features = {'SepalLength': np.array([6.4, 5.0]),
                'SepalWidth':  np.array([2.8, 2.3]),
                'PetalLength': np.array([5.6, 3.3]),
                'PetalWidth':  np.array([2.2, 1.0])}
    labels = np.array([2, 1])
    return features, labels

입력 함수는 원하는 방식으로 features 사전 및 label 목록을 생성할 수 있습니다. 그러나 모든 종류의 데이터를 구문 분석할 수 있는 TensorFlow의 Dataset API를 사용하는 것이 좋습니다.

Dataset API는 많은 일반적인 경우를 자동으로 처리할 수 있습니다. 예를 들어, Dataset API를 사용하면 대규모 파일 모음에서 레코드를 병렬로 쉽게 읽고 이를 단일 스트림으로 결합할 수 있습니다.

이 예제에서는 작업을 단순화하기 위해 pandas 데이터를 로드하고 이 인메모리 데이터에서 입력 파이프라인을 빌드합니다.

def input_fn(features, labels, training=True, batch_size=256):
    """An input function for training or evaluating"""
    # Convert the inputs to a Dataset.
    dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels))

    # Shuffle and repeat if you are in training mode.
    if training:
        dataset = dataset.shuffle(1000).repeat()

    return dataset.batch(batch_size)

특성 열 정의하기

특성 열은 모델이 특성 사전의 원시 입력 데이터를 사용하는 방식을 설명하는 객체입니다. Estimator 모델을 빌드할 때는 모델에서 사용할 각 특성을 설명하는 특성 열 목록을 전달합니다. tf.feature_column 모듈은 모델에 데이터를 나타내기 위한 많은 옵션을 제공합니다.

Iris의 경우 4개의 원시 특성이 숫자 값이므로, 네 개의 특성 각각을 32비트 부동 소수점 값으로 나타내도록 Estimator 모델에 알려주는 특성 열 목록을 빌드합니다. 따라서 특성 열을 작성하는 코드는 다음과 같습니다.

# Feature columns describe how to use the input.
my_feature_columns = []
for key in train.keys():
    my_feature_columns.append(tf.feature_column.numeric_column(key=key))

특성 열은 여기에 나타낸 것보다 훨씬 정교할 수 있습니다. 이 튜토리얼에서 특성 열에 대한 자세한 내용을 읽을 수 있습니다.

모델이 원시 특성을 나타내도록 할 방식에 대한 설명이 준비되었으므로 Estimator를 빌드할 수 있습니다.

Estimator 인스턴스화하기

Iris 문제는 고전적인 분류 문제입니다. 다행히도 TensorFlow는 다음을 포함하여 여러 가지 사전 제작된 분류자 Estimator를 제공합니다.

Iris 문제의 경우 tf.estimator.DNNClassifier가 최선의 선택인 것으로 여겨집니다. 이 Estimator를 인스턴스화하는 방법은 다음과 같습니다.

# Build a DNN with 2 hidden layers with 30 and 10 hidden nodes each.
classifier = tf.estimator.DNNClassifier(
    feature_columns=my_feature_columns,
    # Two hidden layers of 30 and 10 nodes respectively.
    hidden_units=[30, 10],
    # The model must choose between 3 classes.
    n_classes=3)
INFO:tensorflow:Using default config.
WARNING:tensorflow:Using temporary folder as model directory: /tmpfs/tmp/tmpqgqcecuu
INFO:tensorflow:Using config: {'_model_dir': '/tmpfs/tmp/tmpqgqcecuu', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': allow_soft_placement: true
graph_options {
  rewrite_options {
    meta_optimizer_iterations: ONE
  }
}
, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_device_fn': None, '_protocol': None, '_eval_distribute': None, '_experimental_distribute': None, '_experimental_max_worker_delay_secs': None, '_session_creation_timeout_secs': 7200, '_checkpoint_save_graph_def': True, '_service': None, '_cluster_spec': ClusterSpec({}), '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}

훈련, 평가 및 예측하기

이제 Estimator 객체가 준비되었으므로 메서드를 호출하여 다음을 수행할 수 있습니다.

  • 모델을 훈련합니다.
  • 훈련한 모델을 평가합니다.
  • 훈련한 모델을 사용하여 예측을 수행합니다.

모델 훈련하기

다음과 같이 Estimator의 train 메서드를 호출하여 모델을 훈련합니다.

# Train the Model.
classifier.train(
    input_fn=lambda: input_fn(train, train_y, training=True),
    steps=5000)
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.9/site-packages/tensorflow/python/training/training_util.py:396: Variable.initialized_value (from tensorflow.python.ops.variables) is deprecated and will be removed in a future version.
Instructions for updating:
Use Variable.read_value. Variables in 2.X are initialized automatically both in eager and graph (inside tf.defun) contexts.
INFO:tensorflow:Calling model_fn.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.9/site-packages/keras/optimizers/optimizer_v2/adagrad.py:93: calling Constant.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.
Instructions for updating:
Call initializer instance with the dtype argument instead of passing it to the constructor
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
2022-12-14 22:31:17.844452: W tensorflow/core/common_runtime/type_inference.cc:339] Type inference failed. This indicates an invalid graph that escaped type checking. Error message: INVALID_ARGUMENT: expected compatible input types, but input 1:
type_id: TFT_OPTIONAL
args {
  type_id: TFT_PRODUCT
  args {
    type_id: TFT_TENSOR
    args {
      type_id: TFT_INT64
    }
  }
}
 is neither a subtype nor a supertype of the combined inputs preceding it:
type_id: TFT_OPTIONAL
args {
  type_id: TFT_PRODUCT
  args {
    type_id: TFT_TENSOR
    args {
      type_id: TFT_INT32
    }
  }
}

    while inferring type of node 'dnn/zero_fraction/cond/output/_18'
INFO:tensorflow:Calling checkpoint listeners before saving checkpoint 0...
INFO:tensorflow:Saving checkpoints for 0 into /tmpfs/tmp/tmpqgqcecuu/model.ckpt.
INFO:tensorflow:Calling checkpoint listeners after saving checkpoint 0...
INFO:tensorflow:loss = 1.3337237, step = 0
INFO:tensorflow:global_step/sec: 436.985
INFO:tensorflow:loss = 1.0032561, step = 100 (0.230 sec)
INFO:tensorflow:global_step/sec: 574.759
INFO:tensorflow:loss = 0.95959777, step = 200 (0.174 sec)
INFO:tensorflow:global_step/sec: 567.753
INFO:tensorflow:loss = 0.9370698, step = 300 (0.176 sec)
INFO:tensorflow:global_step/sec: 557.205
INFO:tensorflow:loss = 0.9286161, step = 400 (0.180 sec)
INFO:tensorflow:global_step/sec: 561.847
INFO:tensorflow:loss = 0.8905446, step = 500 (0.178 sec)
INFO:tensorflow:global_step/sec: 577.76
INFO:tensorflow:loss = 0.8747095, step = 600 (0.173 sec)
INFO:tensorflow:global_step/sec: 577.063
INFO:tensorflow:loss = 0.8266728, step = 700 (0.173 sec)
INFO:tensorflow:global_step/sec: 557.376
INFO:tensorflow:loss = 0.82472736, step = 800 (0.179 sec)
INFO:tensorflow:global_step/sec: 574.454
INFO:tensorflow:loss = 0.80091727, step = 900 (0.174 sec)
INFO:tensorflow:global_step/sec: 586.222
INFO:tensorflow:loss = 0.78718907, step = 1000 (0.171 sec)
INFO:tensorflow:global_step/sec: 577.173
INFO:tensorflow:loss = 0.7678418, step = 1100 (0.173 sec)
INFO:tensorflow:global_step/sec: 572.52
INFO:tensorflow:loss = 0.7386337, step = 1200 (0.175 sec)
INFO:tensorflow:global_step/sec: 604.218
INFO:tensorflow:loss = 0.72882044, step = 1300 (0.165 sec)
INFO:tensorflow:global_step/sec: 592.209
INFO:tensorflow:loss = 0.6970418, step = 1400 (0.169 sec)
INFO:tensorflow:global_step/sec: 583.268
INFO:tensorflow:loss = 0.6894151, step = 1500 (0.171 sec)
INFO:tensorflow:global_step/sec: 596.389
INFO:tensorflow:loss = 0.6778809, step = 1600 (0.167 sec)
INFO:tensorflow:global_step/sec: 608.237
INFO:tensorflow:loss = 0.6436718, step = 1700 (0.164 sec)
INFO:tensorflow:global_step/sec: 604.922
INFO:tensorflow:loss = 0.6392429, step = 1800 (0.165 sec)
INFO:tensorflow:global_step/sec: 589.543
INFO:tensorflow:loss = 0.6441903, step = 1900 (0.170 sec)
INFO:tensorflow:global_step/sec: 597.559
INFO:tensorflow:loss = 0.60938257, step = 2000 (0.167 sec)
INFO:tensorflow:global_step/sec: 589.247
INFO:tensorflow:loss = 0.6022556, step = 2100 (0.170 sec)
INFO:tensorflow:global_step/sec: 597.602
INFO:tensorflow:loss = 0.6050482, step = 2200 (0.167 sec)
INFO:tensorflow:global_step/sec: 603.46
INFO:tensorflow:loss = 0.5700802, step = 2300 (0.166 sec)
INFO:tensorflow:global_step/sec: 596.966
INFO:tensorflow:loss = 0.5673893, step = 2400 (0.168 sec)
INFO:tensorflow:global_step/sec: 601.571
INFO:tensorflow:loss = 0.57152855, step = 2500 (0.166 sec)
INFO:tensorflow:global_step/sec: 611.919
INFO:tensorflow:loss = 0.5541911, step = 2600 (0.163 sec)
INFO:tensorflow:global_step/sec: 607.58
INFO:tensorflow:loss = 0.5345268, step = 2700 (0.165 sec)
INFO:tensorflow:global_step/sec: 612.626
INFO:tensorflow:loss = 0.5243232, step = 2800 (0.163 sec)
INFO:tensorflow:global_step/sec: 603.113
INFO:tensorflow:loss = 0.51460403, step = 2900 (0.166 sec)
INFO:tensorflow:global_step/sec: 591.917
INFO:tensorflow:loss = 0.504513, step = 3000 (0.169 sec)
INFO:tensorflow:global_step/sec: 621.164
INFO:tensorflow:loss = 0.49160516, step = 3100 (0.161 sec)
INFO:tensorflow:global_step/sec: 584.335
INFO:tensorflow:loss = 0.49130887, step = 3200 (0.171 sec)
INFO:tensorflow:global_step/sec: 587.232
INFO:tensorflow:loss = 0.47286582, step = 3300 (0.170 sec)
INFO:tensorflow:global_step/sec: 581.522
INFO:tensorflow:loss = 0.4713994, step = 3400 (0.172 sec)
INFO:tensorflow:global_step/sec: 587.683
INFO:tensorflow:loss = 0.45537138, step = 3500 (0.170 sec)
INFO:tensorflow:global_step/sec: 578.348
INFO:tensorflow:loss = 0.454673, step = 3600 (0.173 sec)
INFO:tensorflow:global_step/sec: 566.947
INFO:tensorflow:loss = 0.44462803, step = 3700 (0.177 sec)
INFO:tensorflow:global_step/sec: 568.836
INFO:tensorflow:loss = 0.4355138, step = 3800 (0.176 sec)
INFO:tensorflow:global_step/sec: 552.221
INFO:tensorflow:loss = 0.4255464, step = 3900 (0.181 sec)
INFO:tensorflow:global_step/sec: 561.817
INFO:tensorflow:loss = 0.43385836, step = 4000 (0.178 sec)
INFO:tensorflow:global_step/sec: 583.059
INFO:tensorflow:loss = 0.41482735, step = 4100 (0.172 sec)
INFO:tensorflow:global_step/sec: 548.398
INFO:tensorflow:loss = 0.4114343, step = 4200 (0.182 sec)
INFO:tensorflow:global_step/sec: 562.111
INFO:tensorflow:loss = 0.41115963, step = 4300 (0.178 sec)
INFO:tensorflow:global_step/sec: 566.882
INFO:tensorflow:loss = 0.3994022, step = 4400 (0.177 sec)
INFO:tensorflow:global_step/sec: 563.74
INFO:tensorflow:loss = 0.39092743, step = 4500 (0.177 sec)
INFO:tensorflow:global_step/sec: 544.05
INFO:tensorflow:loss = 0.387455, step = 4600 (0.184 sec)
INFO:tensorflow:global_step/sec: 530.907
INFO:tensorflow:loss = 0.37600335, step = 4700 (0.188 sec)
INFO:tensorflow:global_step/sec: 560.602
INFO:tensorflow:loss = 0.37626752, step = 4800 (0.178 sec)
INFO:tensorflow:global_step/sec: 563.058
INFO:tensorflow:loss = 0.37746906, step = 4900 (0.178 sec)
INFO:tensorflow:Calling checkpoint listeners before saving checkpoint 5000...
INFO:tensorflow:Saving checkpoints for 5000 into /tmpfs/tmp/tmpqgqcecuu/model.ckpt.
INFO:tensorflow:Calling checkpoint listeners after saving checkpoint 5000...
INFO:tensorflow:Loss for final step: 0.36055747.
<tensorflow_estimator.python.estimator.canned.dnn.DNNClassifierV2 at 0x7f80203d7ee0>

Estimator가 예상한 대로 인수를 사용하지 않는 입력 함수를 제공하면서 인수를 포착하기 위해 lambda에서 input_fn 호출을 래핑합니다. steps 인수는 여러 훈련 단계를 거친 후에 훈련을 중지하도록 메서드에 지시합니다.

훈련한 모델 평가하기

모델을 훈련했으므로 성능에 대한 통계를 얻을 수 있습니다. 다음 코드 블록은 테스트 데이터에서 훈련한 모델의 정확도를 평가합니다.

eval_result = classifier.evaluate(
    input_fn=lambda: input_fn(test, test_y, training=False))

print('\nTest set accuracy: {accuracy:0.3f}\n'.format(**eval_result))
INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2022-12-14T22:31:27
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from /tmpfs/tmp/tmpqgqcecuu/model.ckpt-5000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Inference Time : 0.51326s
INFO:tensorflow:Finished evaluation at 2022-12-14-22:31:28
INFO:tensorflow:Saving dict for global step 5000: accuracy = 0.96666664, average_loss = 0.39743164, global_step = 5000, loss = 0.39743164
INFO:tensorflow:Saving 'checkpoint_path' summary for global step 5000: /tmpfs/tmp/tmpqgqcecuu/model.ckpt-5000

Test set accuracy: 0.967

train 메서드에 대한 호출과 달리 평가할 steps 인수를 전달하지 않았습니다. eval에 대한 input_fn은 단 하나의 데이터 epoch만 생성합니다.

eval_result 사전에는 average_loss(샘플당 평균 손실), loss(미니 배치당 평균 손실) 및 Estimator의 global_step 값(받은 훈련 반복 횟수)도 포함됩니다.

훈련한 모델에서 예측(추론)하기

우수한 평가 결과를 생성하는 훈련한 모델을 만들었습니다. 이제 훈련한 모델을 사용하여 레이블이 지정되지 않은 일부 측정을 바탕으로 아이리스 꽃의 종을 예측할 수 있습니다. 훈련 및 평가와 마찬가지로 단일 함수 호출을 사용하여 예측합니다.

# Generate predictions from the model
expected = ['Setosa', 'Versicolor', 'Virginica']
predict_x = {
    'SepalLength': [5.1, 5.9, 6.9],
    'SepalWidth': [3.3, 3.0, 3.1],
    'PetalLength': [1.7, 4.2, 5.4],
    'PetalWidth': [0.5, 1.5, 2.1],
}

def input_fn(features, batch_size=256):
    """An input function for prediction."""
    # Convert the inputs to a Dataset without labels.
    return tf.data.Dataset.from_tensor_slices(dict(features)).batch(batch_size)

predictions = classifier.predict(
    input_fn=lambda: input_fn(predict_x))

predict 메서드는 Python iterable을 반환하여 각 예제에 대한 예측 결과 사전을 생성합니다. 다음 코드는 몇 가지 예측과 해당 확률을 출력합니다.

for pred_dict, expec in zip(predictions, expected):
    class_id = pred_dict['class_ids'][0]
    probability = pred_dict['probabilities'][class_id]

    print('Prediction is "{}" ({:.1f}%), expected "{}"'.format(
        SPECIES[class_id], 100 * probability, expec))
INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from /tmpfs/tmp/tmpqgqcecuu/model.ckpt-5000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
Prediction is "Setosa" (85.4%), expected "Setosa"
Prediction is "Versicolor" (62.1%), expected "Versicolor"
Prediction is "Virginica" (58.5%), expected "Virginica"