ML 메타 데이터로 더 나은 ML 엔지니어링

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

펭귄을 분류하기 위해 프로덕션 ML 파이프라인을 설정하는 시나리오를 가정합니다. 파이프라인은 훈련 데이터를 수집하고, 모델을 훈련 및 평가하고, 프로덕션으로 푸시합니다.

그러나 나중에 다른 종류의 펭귄이 포함된 더 큰 데이터 세트와 함께 이 모델을 사용하려고 하면 모델이 예상대로 작동하지 않고 종을 잘못 분류하기 시작하는 것을 관찰할 수 있습니다.

이 시점에서 다음 사항에 관심이 있습니다.

  • 사용 가능한 유일한 아티팩트가 프로덕션 중인 모델인 경우 모델을 디버그하는 가장 효율적인 방법은 무엇입니까?
  • 모델을 훈련하는 데 어떤 훈련 데이터 세트가 사용되었습니까?
  • 어떤 훈련 실행이 이 잘못된 모델로 이어졌습니까?
  • 모델 평가 결과는 어디에 있습니까?
  • 어디에서 디버깅을 시작해야 합니까?

ML 메타 데이터 (MLMD는) 당신이 더 이러한 문제에 대한 해답을 얻을 수 있도록 ML 모델과 관련된 메타 데이터를 활용하는 라이브러리입니다. 유용한 비유는 이 메타데이터를 소프트웨어 개발에 로그인하는 것과 동일하다고 생각하는 것입니다. MLMD를 사용하면 ML 파이프라인의 다양한 구성 요소와 관련된 아티팩트 및 계보를 안정적으로 추적할 수 있습니다.

이 튜토리얼에서는 TFX 파이프라인을 설정하여 펭귄을 체질량, 정점의 길이와 깊이, 오리발의 길이를 기준으로 3종으로 분류하는 모델을 만듭니다. 그런 다음 MLMD를 사용하여 파이프라인 구성 요소의 계보를 추적합니다.

Colab의 TFX 파이프라인

Colab은 프로덕션 환경과 크게 다른 경량 개발 환경입니다. 프로덕션 환경에는 여러 분산 시스템에 걸쳐 데이터 수집, 변환, 모델 교육, 실행 기록 등과 같은 다양한 파이프라인 구성 요소가 있을 수 있습니다. 이 튜토리얼의 경우 오케스트레이션과 메타데이터 스토리지에 상당한 차이가 있음을 알아야 합니다. 모두 Colab 내에서 로컬로 처리됩니다. Colab에 TFX에 대해 자세히 알아보십시오 여기 .

설정

먼저 필요한 패키지를 설치 및 가져오고, 경로를 설정하고, 데이터를 다운로드합니다.

핍 업그레이드

로컬에서 실행할 때 시스템에서 Pip를 업그레이드하지 않으려면 Colab에서 실행 중인지 확인하세요. 물론 로컬 시스템은 별도로 업그레이드할 수 있습니다.

try:
  import colab
  !pip install --upgrade pip
except:
  pass

TFX 설치 및 가져오기

pip install -q -U tfx

패키지 가져오기

런타임을 다시 시작하셨습니까?

Google Colab을 사용하는 경우 위의 셀을 처음 실행할 때 위의 "RESTART RUNTIME" 버튼을 클릭하거나 "런타임 > 런타임 다시 시작..." 메뉴를 사용하여 런타임을 다시 시작해야 합니다. Colab이 패키지를 로드하는 방식 때문입니다.

import os
import tempfile
import urllib
import pandas as pd

import tensorflow_model_analysis as tfma
from tfx.orchestration.experimental.interactive.interactive_context import InteractiveContext

TFX 및 MLMD 버전을 확인하십시오.

from tfx import v1 as tfx
print('TFX version: {}'.format(tfx.__version__))
import ml_metadata as mlmd
print('MLMD version: {}'.format(mlmd.__version__))
TFX version: 1.4.0
MLMD version: 1.4.0

데이터세트 다운로드

이 colab에서, 우리는 사용 팔머 펭귄 데이터 세트 에서 찾을 수 있습니다 Github에서를 . 우리는 불완전한 기록을 남겨하여 데이터 집합을 처리하고, 떨어 islandsex 열을하고, 라벨을 변환 int32 . 데이터 세트에는 체질량, 펭귄의 정점 길이와 깊이, 오리발 길이에 대한 334개의 기록이 포함되어 있습니다. 이 데이터를 사용하여 펭귄을 세 종 중 하나로 분류합니다.

DATA_PATH = 'https://raw.githubusercontent.com/tensorflow/tfx/master/tfx/examples/penguin/data/labelled/penguins_processed.csv'
_data_root = tempfile.mkdtemp(prefix='tfx-data')
_data_filepath = os.path.join(_data_root, "penguins_processed.csv")
urllib.request.urlretrieve(DATA_PATH, _data_filepath)
('/tmp/tfx-datal9104odr/penguins_processed.csv',
 <http.client.HTTPMessage at 0x7f9c6d8d2290>)

InteractiveContext 생성

이 노트북에서 대화 형으로 TFX 구성 요소를 실행하기 위해, 생성 InteractiveContext . InteractiveContext 임시 MLMD 데이터베이스 인스턴스와 임시 디렉토리를 사용합니다. 참고로 호출하는 InteractiveContext Colab 환경 외부에는 작전이 없습니다.

일반적으로, 그것은 아래 그룹 유사한 파이프 라인 실행에 좋은 연습입니다 Context .

interactive_context = InteractiveContext()
WARNING:absl:InteractiveContext pipeline_root argument not provided: using temporary directory /tmp/tfx-interactive-2021-12-05T11_15_56.285625-5hcexlo8 as root for pipeline outputs.
WARNING:absl:InteractiveContext metadata_connection_config not provided: using SQLite ML Metadata database at /tmp/tfx-interactive-2021-12-05T11_15_56.285625-5hcexlo8/metadata.sqlite.

TFX 파이프라인 구축

TFX 파이프라인은 ML 워크플로의 다양한 측면을 수행하는 여러 구성 요소로 구성됩니다. 이 노트북에서 작성하고 실행 ExampleGen , StatisticsGen , SchemaGenTrainer 구성 요소와 사용 EvaluatorPusher 평가하고 훈련 모델을 밀어 구성 요소를.

참고하여주십시오 부품 튜토리얼 TFX 파이프 라인 구성 요소에 대한 자세한 내용은.

ExampleGen 구성 요소 인스턴스화 및 실행

example_gen = tfx.components.CsvExampleGen(input_base=_data_root)
interactive_context.run(example_gen)
WARNING:apache_beam.runners.interactive.interactive_environment:Dependencies required for Interactive Beam PCollection visualization are not available, please use: `pip install apache-beam[interactive]` to install necessary dependencies to enable all data visualization features.
WARNING:root:Make sure that locally built Python SDK docker image has Python 3.7 interpreter.
WARNING:apache_beam.io.tfrecordio:Couldn't find python-snappy so the implementation of _TFRecordUtil._masked_crc32c is not as fast as it could be.

StatisticsGen 구성 요소 인스턴스화 및 실행

statistics_gen = tfx.components.StatisticsGen(
    examples=example_gen.outputs['examples'])
interactive_context.run(statistics_gen)
WARNING:root:Make sure that locally built Python SDK docker image has Python 3.7 interpreter.

SchemaGen 구성 요소 인스턴스화 및 실행

infer_schema = tfx.components.SchemaGen(
    statistics=statistics_gen.outputs['statistics'], infer_feature_shape=True)
interactive_context.run(infer_schema)
WARNING: Logging before InitGoogleLogging() is written to STDERR
I1205 11:16:00.941947  6108 rdbms_metadata_access_object.cc:686] No property is defined for the Type

Trainer 구성 요소 인스턴스화 및 실행

# Define the module file for the Trainer component
trainer_module_file = 'penguin_trainer.py'
%%writefile {trainer_module_file}

# Define the training algorithm for the Trainer module file
import os
from typing import List, Text

import tensorflow as tf
from tensorflow import keras

from tfx import v1 as tfx
from tfx_bsl.public import tfxio

from tensorflow_metadata.proto.v0 import schema_pb2

# Features used for classification - culmen length and depth, flipper length,
# body mass, and species.

_LABEL_KEY = 'species'

_FEATURE_KEYS = [
    'culmen_length_mm', 'culmen_depth_mm', 'flipper_length_mm', 'body_mass_g'
]


def _input_fn(file_pattern: List[Text],
              data_accessor: tfx.components.DataAccessor,
              schema: schema_pb2.Schema, batch_size: int) -> tf.data.Dataset:
  return data_accessor.tf_dataset_factory(
      file_pattern,
      tfxio.TensorFlowDatasetOptions(
          batch_size=batch_size, label_key=_LABEL_KEY), schema).repeat()


def _build_keras_model():
  inputs = [keras.layers.Input(shape=(1,), name=f) for f in _FEATURE_KEYS]
  d = keras.layers.concatenate(inputs)
  d = keras.layers.Dense(8, activation='relu')(d)
  d = keras.layers.Dense(8, activation='relu')(d)
  outputs = keras.layers.Dense(3)(d)
  model = keras.Model(inputs=inputs, outputs=outputs)
  model.compile(
      optimizer=keras.optimizers.Adam(1e-2),
      loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
      metrics=[keras.metrics.SparseCategoricalAccuracy()])
  return model


def run_fn(fn_args: tfx.components.FnArgs):
  schema = schema_pb2.Schema()
  tfx.utils.parse_pbtxt_file(fn_args.schema_path, schema)
  train_dataset = _input_fn(
      fn_args.train_files, fn_args.data_accessor, schema, batch_size=10)
  eval_dataset = _input_fn(
      fn_args.eval_files, fn_args.data_accessor, schema, batch_size=10)
  model = _build_keras_model()
  model.fit(
      train_dataset,
      epochs=int(fn_args.train_steps / 20),
      steps_per_epoch=20,
      validation_data=eval_dataset,
      validation_steps=fn_args.eval_steps)
  model.save(fn_args.serving_model_dir, save_format='tf')
Writing penguin_trainer.py

실행 Trainer 구성 요소를.

trainer = tfx.components.Trainer(
    module_file=os.path.abspath(trainer_module_file),
    examples=example_gen.outputs['examples'],
    schema=infer_schema.outputs['schema'],
    train_args=tfx.proto.TrainArgs(num_steps=100),
    eval_args=tfx.proto.EvalArgs(num_steps=50))
interactive_context.run(trainer)
running bdist_wheel
running build
running build_py
creating build
creating build/lib
copying penguin_trainer.py -> build/lib
installing to /tmp/tmpum1crtxy
running install
running install_lib
copying build/lib/penguin_trainer.py -> /tmp/tmpum1crtxy
running install_egg_info
running egg_info
creating tfx_user_code_Trainer.egg-info
writing tfx_user_code_Trainer.egg-info/PKG-INFO
writing dependency_links to tfx_user_code_Trainer.egg-info/dependency_links.txt
writing top-level names to tfx_user_code_Trainer.egg-info/top_level.txt
writing manifest file 'tfx_user_code_Trainer.egg-info/SOURCES.txt'
reading manifest file 'tfx_user_code_Trainer.egg-info/SOURCES.txt'
writing manifest file 'tfx_user_code_Trainer.egg-info/SOURCES.txt'
Copying tfx_user_code_Trainer.egg-info to /tmp/tmpum1crtxy/tfx_user_code_Trainer-0.0+fef7c4ed90dc336ca26daee59d65660cf8da5fa988b2ca0c89df2f558fda10f4-py3.7.egg-info
running install_scripts
creating /tmp/tmpum1crtxy/tfx_user_code_Trainer-0.0+fef7c4ed90dc336ca26daee59d65660cf8da5fa988b2ca0c89df2f558fda10f4.dist-info/WHEEL
creating '/tmp/tmpo87nn6ey/tfx_user_code_Trainer-0.0+fef7c4ed90dc336ca26daee59d65660cf8da5fa988b2ca0c89df2f558fda10f4-py3-none-any.whl' and adding '/tmp/tmpum1crtxy' to it
adding 'penguin_trainer.py'
adding 'tfx_user_code_Trainer-0.0+fef7c4ed90dc336ca26daee59d65660cf8da5fa988b2ca0c89df2f558fda10f4.dist-info/METADATA'
adding 'tfx_user_code_Trainer-0.0+fef7c4ed90dc336ca26daee59d65660cf8da5fa988b2ca0c89df2f558fda10f4.dist-info/WHEEL'
adding 'tfx_user_code_Trainer-0.0+fef7c4ed90dc336ca26daee59d65660cf8da5fa988b2ca0c89df2f558fda10f4.dist-info/top_level.txt'
adding 'tfx_user_code_Trainer-0.0+fef7c4ed90dc336ca26daee59d65660cf8da5fa988b2ca0c89df2f558fda10f4.dist-info/RECORD'
removing /tmp/tmpum1crtxy
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/setuptools/command/install.py:37: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
  setuptools.SetuptoolsDeprecationWarning,
listing git files failed - pretending there aren't any
I1205 11:16:01.389324  6108 rdbms_metadata_access_object.cc:686] No property is defined for the Type
I1205 11:16:01.392832  6108 rdbms_metadata_access_object.cc:686] No property is defined for the Type
Processing /tmp/tfx-interactive-2021-12-05T11_15_56.285625-5hcexlo8/_wheels/tfx_user_code_Trainer-0.0+fef7c4ed90dc336ca26daee59d65660cf8da5fa988b2ca0c89df2f558fda10f4-py3-none-any.whl
Installing collected packages: tfx-user-code-Trainer
Successfully installed tfx-user-code-Trainer-0.0+fef7c4ed90dc336ca26daee59d65660cf8da5fa988b2ca0c89df2f558fda10f4
Epoch 1/5
20/20 [==============================] - 1s 11ms/step - loss: 0.9891 - sparse_categorical_accuracy: 0.4300 - val_loss: 0.9594 - val_sparse_categorical_accuracy: 0.4800
Epoch 2/5
20/20 [==============================] - 0s 6ms/step - loss: 0.8369 - sparse_categorical_accuracy: 0.6350 - val_loss: 0.7484 - val_sparse_categorical_accuracy: 0.8200
Epoch 3/5
20/20 [==============================] - 0s 6ms/step - loss: 0.5289 - sparse_categorical_accuracy: 0.8350 - val_loss: 0.5068 - val_sparse_categorical_accuracy: 0.7800
Epoch 4/5
20/20 [==============================] - 0s 6ms/step - loss: 0.4481 - sparse_categorical_accuracy: 0.7800 - val_loss: 0.4125 - val_sparse_categorical_accuracy: 0.8600
Epoch 5/5
20/20 [==============================] - 0s 6ms/step - loss: 0.3068 - sparse_categorical_accuracy: 0.8650 - val_loss: 0.3279 - val_sparse_categorical_accuracy: 0.8300
2021-12-05 11:16:06.493168: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/tfx-interactive-2021-12-05T11_15_56.285625-5hcexlo8/Trainer/model/4/Format-Serving/assets
INFO:tensorflow:Assets written to: /tmp/tfx-interactive-2021-12-05T11_15_56.285625-5hcexlo8/Trainer/model/4/Format-Serving/assets

모델 평가 및 푸시

사용 Evaluator 평가하고 사용하기 전에 모델을 '축복'하는 구성 요소를 Pusher 서빙 디렉토리에 모델을 밀어 구성 요소를.

_serving_model_dir = os.path.join(tempfile.mkdtemp(),
                                  'serving_model/penguins_classification')
eval_config = tfma.EvalConfig(
    model_specs=[
        tfma.ModelSpec(label_key='species', signature_name='serving_default')
    ],
    metrics_specs=[
        tfma.MetricsSpec(metrics=[
            tfma.MetricConfig(
                class_name='SparseCategoricalAccuracy',
                threshold=tfma.MetricThreshold(
                    value_threshold=tfma.GenericValueThreshold(
                        lower_bound={'value': 0.6})))
        ])
    ],
    slicing_specs=[tfma.SlicingSpec()])
evaluator = tfx.components.Evaluator(
    examples=example_gen.outputs['examples'],
    model=trainer.outputs['model'],
    schema=infer_schema.outputs['schema'],
    eval_config=eval_config)
interactive_context.run(evaluator)
I1205 11:16:07.075275  6108 rdbms_metadata_access_object.cc:686] No property is defined for the Type
I1205 11:16:07.078761  6108 rdbms_metadata_access_object.cc:686] No property is defined for the Type
WARNING:root:Make sure that locally built Python SDK docker image has Python 3.7 interpreter.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_model_analysis/writers/metrics_plots_and_validations_writer.py:114: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.
Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_model_analysis/writers/metrics_plots_and_validations_writer.py:114: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.
Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`
pusher = tfx.components.Pusher(
    model=trainer.outputs['model'],
    model_blessing=evaluator.outputs['blessing'],
    push_destination=tfx.proto.PushDestination(
        filesystem=tfx.proto.PushDestination.Filesystem(
            base_directory=_serving_model_dir)))
interactive_context.run(pusher)
I1205 11:16:11.935312  6108 rdbms_metadata_access_object.cc:686] No property is defined for the Type

TFX 파이프라인을 실행하면 MLMD 데이터베이스가 채워집니다. 다음 섹션에서는 MLMD API를 사용하여 이 데이터베이스에서 메타데이터 정보를 쿼리합니다.

MLMD 데이터베이스 쿼리

MLMD 데이터베이스는 세 가지 유형의 메타데이터를 저장합니다.

  • 파이프라인 구성 요소와 관련된 파이프라인 및 계보 정보에 대한 메타데이터
  • 파이프라인 실행 중에 생성된 아티팩트에 대한 메타데이터
  • 파이프라인 실행에 대한 메타데이터

일반적인 프로덕션 환경 파이프라인은 새 데이터가 도착하면 여러 모델을 제공합니다. 제공된 모델에서 잘못된 결과가 발생하면 MLMD 데이터베이스를 쿼리하여 잘못된 모델을 격리할 수 있습니다. 그런 다음 이러한 모델에 해당하는 파이프라인 구성 요소의 계보를 추적하여 모델을 디버그할 수 있습니다.

와 메타 데이터 (MD) 저장소를 설정 InteractiveContext MLMD 데이터베이스를 쿼리 이전에 정의.

connection_config = interactive_context.metadata_connection_config
store = mlmd.MetadataStore(connection_config)

# All TFX artifacts are stored in the base directory
base_dir = connection_config.sqlite.filename_uri.split('metadata.sqlite')[0]

MD 저장소에서 데이터를 보려면 몇 가지 도우미 함수를 만듭니다.

def display_types(types):
  # Helper function to render dataframes for the artifact and execution types
  table = {'id': [], 'name': []}
  for a_type in types:
    table['id'].append(a_type.id)
    table['name'].append(a_type.name)
  return pd.DataFrame(data=table)
def display_artifacts(store, artifacts):
  # Helper function to render dataframes for the input artifacts
  table = {'artifact id': [], 'type': [], 'uri': []}
  for a in artifacts:
    table['artifact id'].append(a.id)
    artifact_type = store.get_artifact_types_by_id([a.type_id])[0]
    table['type'].append(artifact_type.name)
    table['uri'].append(a.uri.replace(base_dir, './'))
  return pd.DataFrame(data=table)
def display_properties(store, node):
  # Helper function to render dataframes for artifact and execution properties
  table = {'property': [], 'value': []}
  for k, v in node.properties.items():
    table['property'].append(k)
    table['value'].append(
        v.string_value if v.HasField('string_value') else v.int_value)
  for k, v in node.custom_properties.items():
    table['property'].append(k)
    table['value'].append(
        v.string_value if v.HasField('string_value') else v.int_value)
  return pd.DataFrame(data=table)

첫째, 모든 저장 목록에 대한 쿼리 MD 저장소 ArtifactTypes .

display_types(store.get_artifact_types())

다음, 쿼리 모든 PushedModel 유물.

pushed_models = store.get_artifacts_by_type("PushedModel")
display_artifacts(store, pushed_models)

푸시된 최신 모델에 대해 MD 저장소를 쿼리합니다. 이 자습서에는 푸시된 모델이 하나만 있습니다.

pushed_model = pushed_models[-1]
display_properties(store, pushed_model)

푸시된 모델을 디버깅하는 첫 번째 단계 중 하나는 어떤 훈련된 모델이 푸시되었는지 살펴보고 해당 모델을 훈련하는 데 어떤 훈련 데이터가 사용되는지 확인하는 것입니다.

MLMD는 모델 출처를 분석하는 데 사용할 수 있는 출처 그래프를 살펴보기 위한 순회 API를 제공합니다.

def get_one_hop_parent_artifacts(store, artifacts):
  # Get a list of artifacts within a 1-hop of the artifacts of interest
  artifact_ids = [artifact.id for artifact in artifacts]
  executions_ids = set(
      event.execution_id
      for event in store.get_events_by_artifact_ids(artifact_ids)
      if event.type == mlmd.proto.Event.OUTPUT)
  artifacts_ids = set(
      event.artifact_id
      for event in store.get_events_by_execution_ids(executions_ids)
      if event.type == mlmd.proto.Event.INPUT)
  return [artifact for artifact in store.get_artifacts_by_id(artifacts_ids)]

푸시된 모델의 상위 아티팩트를 쿼리합니다.

parent_artifacts = get_one_hop_parent_artifacts(store, [pushed_model])
display_artifacts(store, parent_artifacts)

모델의 속성을 쿼리합니다.

exported_model = parent_artifacts[0]
display_properties(store, exported_model)

모델의 업스트림 아티팩트를 쿼리합니다.

model_parents = get_one_hop_parent_artifacts(store, [exported_model])
display_artifacts(store, model_parents)

모델이 훈련된 훈련 데이터를 가져옵니다.

used_data = model_parents[0]
display_properties(store, used_data)

이제 모델이 훈련한 훈련 데이터가 있으므로 데이터베이스를 다시 쿼리하여 훈련 단계(실행)를 찾습니다. 등록된 실행 유형 목록에 대해 MD 저장소를 쿼리합니다.

display_types(store.get_execution_types())

훈련 단계는 것입니다 ExecutionType 이름 tfx.components.trainer.component.Trainer . MD 저장소를 탐색하여 푸시된 모델에 해당하는 트레이너 실행을 가져옵니다.

def find_producer_execution(store, artifact):
  executions_ids = set(
      event.execution_id
      for event in store.get_events_by_artifact_ids([artifact.id])
      if event.type == mlmd.proto.Event.OUTPUT)
  return store.get_executions_by_id(executions_ids)[0]

trainer = find_producer_execution(store, exported_model)
display_properties(store, trainer)

요약

이 자습서에서는 MLMD를 활용하여 TFX 파이프라인 구성 요소의 계보를 추적하고 문제를 해결하는 방법에 대해 배웠습니다.

MLMD 사용 방법에 대해 자세히 알아보려면 다음 추가 리소스를 확인하세요.