Lepsza inżynieria ML z metadanymi ML

Zobacz na TensorFlow.org Uruchom w Google Colab Wyświetl źródło na GitHub Pobierz notatnik

Załóżmy scenariusz, w którym konfigurujesz potok produkcyjnej ML do klasyfikowania pingwinów. Potok pozyskuje dane szkoleniowe, trenuje i ocenia model oraz wypycha go do środowiska produkcyjnego.

Jednak gdy później spróbujesz użyć tego modelu z większym zbiorem danych, który zawiera różne rodzaje pingwinów, zauważysz, że Twój model nie zachowuje się zgodnie z oczekiwaniami i zaczyna niepoprawnie klasyfikować gatunki.

W tym momencie chcesz wiedzieć:

  • Jaki jest najskuteczniejszy sposób debugowania modelu, gdy jedynym dostępnym artefaktem jest model w produkcji?
  • Który zestaw danych szkoleniowych został użyty do trenowania modelu?
  • Które szkolenie doprowadziło do tego błędnego modelu?
  • Gdzie są wyniki oceny modelu?
  • Od czego zacząć debugowanie?

ML Metadane (MLMD) to biblioteka, która wykorzystuje metadane związane z modelami ML aby pomóc odpowiedzieć na te pytania i wiele innych. Pomocną analogią jest myślenie o tych metadanych jako o ekwiwalencie logowania do tworzenia oprogramowania. MLMD umożliwia niezawodne śledzenie artefaktów i linii powiązanych z różnymi komponentami potoku ML.

W tym samouczku skonfigurujesz potok TFX, aby stworzyć model, który klasyfikuje pingwiny na trzy gatunki na podstawie masy ciała oraz długości i głębokości ich czubków oraz długości płetw. Następnie używasz MLMD do śledzenia rodowodu składników potoku.

Rurociągi TFX w Colab

Colab to lekkie środowisko programistyczne, które znacznie różni się od środowiska produkcyjnego. W środowisku produkcyjnym możesz mieć różne komponenty potoku, takie jak pozyskiwanie danych, transformacja, uczenie modeli, historie uruchomień itp. w wielu rozproszonych systemach. W przypadku tego samouczka należy pamiętać, że istnieją znaczące różnice w zakresie orkiestracji i przechowywania metadanych — wszystko jest obsługiwane lokalnie w Colab. Dowiedz się więcej o TFX w Colab tutaj .

Ustawiać

Najpierw instalujemy i importujemy niezbędne pakiety, ustawiamy ścieżki i pobieramy dane.

Ulepsz Pip

Aby uniknąć aktualizacji Pip w systemie uruchomionym lokalnie, upewnij się, że działamy w Colab. Systemy lokalne można oczywiście aktualizować oddzielnie.

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

Zainstaluj i zaimportuj TFX

pip install -q -U tfx

Importuj paczki

Czy uruchomiłeś ponownie środowisko wykonawcze?

Jeśli korzystasz z Google Colab, przy pierwszym uruchomieniu powyższej komórki musisz ponownie uruchomić środowisko wykonawcze, klikając powyżej przycisk „RESTART RUNTIME” lub korzystając z menu „Runtime > Restart runtime...”. Wynika to ze sposobu, w jaki Colab ładuje paczki.

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

Sprawdź wersje TFX i 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

Pobierz zbiór danych

W tym colab używamy zestawu danych Palmer Penguins , który można znaleźć na Github . Mamy zbiór danych przetwarzanych przez pozostawiając żadnych niekompletne rekordy i krople island i sex kolumn i przekształcane etykiet int32 . Zbiór danych zawiera 334 rekordy masy ciała oraz długości i głębokości wąsów pingwinów, a także długości ich płetw. Używasz tych danych do klasyfikowania pingwinów do jednego z trzech gatunków.

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>)

Utwórz interaktywny kontekst

Aby uruchomić komponenty TFX interaktywnie w tym notebooku, utwórz InteractiveContext . InteractiveContext wykorzystuje tymczasowy katalog z efemeryczny MLMD instancji bazy danych. Należy pamiętać, że rozmowy do InteractiveContext są no-ops poza środowiskiem Colab.

Ogólnie rzecz biorąc, jest to dobra praktyka, aby grupy podobnych tras rurociągów pod 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.

Zbuduj potok TFX

Potok TFX składa się z kilku składników, które wykonują różne aspekty przepływu pracy ML. W tym notebooku, tworzyć i uruchamiać ExampleGen , StatisticsGen , SchemaGen i Trainer komponenty i używać Evaluator i Pusher komponent do oceny i wcisnąć wyszkolony model.

Zapoznaj się z samouczka składników , aby uzyskać więcej informacji na temat elementów rurociągowych TFX.

Utwórz wystąpienie i uruchom komponent 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.

Utwórz instancję i uruchom komponent 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.

Utwórz instancję i uruchom komponent 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

Utwórz instancję i uruchom komponent trenera

# 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

Uruchom Trainer komponent.

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

Oceń i popchnij model

Użyj Evaluator składnika ocenić i „błogosławić” modelu przed użyciem Pusher składnik push model do katalogu obsługującego.

_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

Uruchomienie potoku TFX wypełnia bazę danych MLMD. W następnej sekcji użyjesz interfejsu API MLMD do przeszukiwania tej bazy danych w celu uzyskania informacji o metadanych.

Przeszukuj bazę danych MLMD

Baza danych MLMD przechowuje trzy rodzaje metadanych:

  • Metadane dotyczące potoku i informacji o pochodzeniu powiązanych z komponentami potoku
  • Metadane dotyczące artefaktów, które zostały wygenerowane podczas działania potoku
  • Metadane o wykonaniach potoku

Typowy potok środowiska produkcyjnego obsługuje wiele modeli w miarę napływania nowych danych. W przypadku napotkania błędnych wyników w obsługiwanych modelach można wykonać zapytanie do bazy danych MLMD w celu wyizolowania błędnych modeli. Następnie możesz prześledzić pochodzenie składników potoku, które odpowiadają tym modelom, aby debugować swoje modele

Konfigurowanie metadanych (MD) Sklep z InteractiveContext zdefiniowane wcześniej do przeszukiwania bazy danych 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]

Utwórz kilka funkcji pomocniczych, aby wyświetlić dane z magazynu 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)

Po pierwsze, zapytanie sklep MD do listy wszystkich przechowywanych ArtifactTypes .

display_types(store.get_artifact_types())

Następnie zapytania wszystkie PushedModel artefakty.

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

Zapytaj sklep MD o najnowszy wypchnięty model. Ten samouczek zawiera tylko jeden model wypchnięty.

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

Jednym z pierwszych kroków debugowania modelu wypchniętego jest sprawdzenie, który wyszkolony model jest wypychany, i sprawdzenie, które dane szkoleniowe są używane do trenowania tego modelu.

MLMD udostępnia interfejsy API przechodzenia do przechodzenia przez wykres pochodzenia, którego można użyć do analizy pochodzenia modelu.

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)]

Zapytanie o artefakty nadrzędne dla wypchniętego modelu.

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

Zapytaj o właściwości modelu.

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

Zapytanie o artefakty nadrzędne dla modelu.

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

Pobierz dane szkoleniowe, z którymi trenowany jest model.

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

Teraz, gdy masz dane szkoleniowe, z których model został przeszkolony, ponownie przeprowadź zapytanie do bazy danych, aby znaleźć krok szkolenia (wykonywanie). Zapytaj magazyn MD o listę zarejestrowanych typów wykonania.

display_types(store.get_execution_types())

Etap szkolenia jest ExecutionType nazwie tfx.components.trainer.component.Trainer . Przemierz sklep MD, aby uzyskać bieg trenera, który odpowiada modelowi pchniętemu.

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)

Streszczenie

W tym samouczku dowiedziałeś się, jak wykorzystać MLMD do śledzenia pochodzenia składników potoku TFX i rozwiązywania problemów.

Aby dowiedzieć się więcej o tym, jak korzystać z MLMD, zapoznaj się z tymi dodatkowymi zasobami: