Analiza registros de AI Platform Prediction en BigQuery

Este es el segundo documento de una serie en la que se muestra cómo supervisar los modelos de aprendizaje automático (AA) que se implementan en AI Platform Prediction para ayudarte a detectar sesgos de datos. En esta guía, se muestra cómo analizar datos sin procesar en el registro de solicitudes y respuestas de AI Platform Prediction en un modelo de datos analíticos. Luego, se muestra cómo usar Data Studio a fin de analizar las solicitudes registradas para sesgos y desvíos de datos.

La serie es para ingenieros de datos e ingenieros de MLOps que desean mantener el rendimiento de sus modelos de AA en producción mediante la supervisión de los cambios en los datos de entrega a lo largo del tiempo. Se supone que tienes experiencia con Google Cloud, con BigQuery y con notebooks de Jupyter.

La serie consiste en las siguientes guías:

Las tareas que se analizan en este documento se incorporan a los notebooks de Jupyter. Los notebooks están en un repositorio de GitHub.

Descripción general

Como se explica en la primera parte de esta serie, el código del notebook de Jupyter entrena un modelo de clasificación de Keras para el conjunto de datos Covertype a fin de predecir un tipo de cubierta forestal desde las variables cartográficas. El modelo guardado exportado se implementa en AI Platform Prediction para la entrega en línea. El notebook también habilita las siguientes funciones: registro de solicitud-respuesta a fin de registrar una muestra de solicitudes de predicción en línea (instancias) y respuestas (probabilidades de etiqueta predichas) para una tabla de BigQuery.

La arquitectura general se muestra en el siguiente diagrama:

Arquitectura del flujo que se crea en esta serie de instructivos.

En esta arquitectura, el registro de solicitud-respuesta de AI Platform Prediction registra una muestra de las solicitudes en línea en una tabla de BigQuery. Después de que las instancias sin procesar y los datos de predicción se almacenan en BigQuery, puedes analizarlos, calcular estadísticas descriptivas y visualizar sesgos y desviaciones de datos.

En la siguiente tabla, se resume el esquema de la tabla de BigQuery.

Nombre del campo Tipo Modo Descripción
model STRING REQUIRED El nombre de un modelo
model_version STRING REQUIRED El nombre de una versión del modelo
time TIMESTAMP REQUIRED La fecha y hora en la que se capturó una solicitud
raw_data STRING REQUIRED El cuerpo de la solicitud en la representación JSON de AI Platform Prediction
raw_prediction STRING NULLABLE El cuerpo de la respuesta (predicciones) en la representación JSON de AI Platform Prediction
groundtruth STRING NULLABLE La verdad fundamental, si está disponible

En la siguiente tabla, se presenta una muestra de los datos almacenados en las columnas raw_data y raw_prediction de la tabla de BigQuery.

Columna Datos de muestra
raw_data

{
  "signature_name":"serving_default",
  "instances":[
    {
      "Elevation":[3158],
      "Aspect":[78],
      "Slope":[25],
      "Horizontal_Distance_To_Hydrology":[150],
      "Vertical_Distance_To_Hydrology":[53],
      "Horizontal_Distance_To_Roadways":[1080],
      "Hillshade_9am":[243],
      "Hillshade_Noon":[185],
      "Hillshade_3pm":[57],
      "Horizontal_Distance_To_Fire_Points":[2234],
      "Wilderness_Area":["Rawah"],
      "Soil_Type":["7745"],
    }
  ]
}
raw_prediction

{
 "predictions": [
   {
     "probabilities": [
       0.03593460097908974,
       0.9640452861785889,
       1.2815438710234162e-9,
       1.5712469103590365e-9,
       0.000018715836631599814,
       4.030006106603423e-9,
       0.0000013792159734293818
     ],
     "confidence":  0.9640452861785889,
     "predicted_label": "1"

   }
 ]
}

En este documento, analizas el campo raw_data en un modelo analítico para permitirte analizar el contenido de cada atributo de forma separada y, también, identificar cualquier data lake.

Objetivos

  • Crear metadatos para el conjunto de datos
  • Generar una instrucción CREATE VIEW de SQL que sea específica del conjunto de datos
  • Usar la vista para consultar datos de registro en BigQuery
  • Crear visualizaciones de los datos de registro

Costos

En este instructivo, se usan los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios. Es posible que los usuarios nuevos de Google Cloud sean aptos para obtener una prueba gratuita.

Antes de comenzar

Antes de comenzar, debes completar la parte uno de esta serie.

Después de completar la primera parte, tendrás lo siguiente:

  • Una instancia de Notebooks que usa TensorFlow 2.3.
  • Un clon del repositorio de GitHub que tiene el notebook de Jupyter que necesitas para esta guía.

El notebook de Jupyter para esta situación

Las tareas de análisis de datos se incorporan a un notebook de Jupyter ubicado en un repositorio de GitHub. Para realizar las tareas, obtén el notebook y, luego, ejecuta las celdas de código en el notebook en orden.

En este documento, usas el notebook de Jupyter para realizar las siguientes tareas:

  • Crear una vista de SQL de BigQuery para analizar los datos de solicitud y respuesta sin procesar. Generar la vista mediante la ejecución del código que recopila información, como los metadatos del conjunto de datos y los nombres que proporciones.
  • Simular el proceso de entregar datos a lo largo de varios días con sesgos artificiales.
  • Usar Data Studio para visualizar los datos de entrega analizados como se registran en BigQuery.

Establece la configuración del notebook

En esta sección del notebook, prepararás el entorno de Python a fin de ejecutar el código para la situación. El código del notebook crea la vista según las especificaciones de atributos de tu conjunto de datos. Para generar la secuencia de comandos de SQL CREATE OR REPLACE VIEW, debes configurar una serie de variables.

  1. Si aún no tienes la instancia de AI Platform Notebooks de la parte uno abierta en Cloud Console, haz lo siguiente:

    1. Ir a la página Notebooks.

      Ir a la página Notebooks

    2. En la lista de instancias de Notebooks, selecciona el notebook y, luego, haz clic en Abrir JupyterLab. El entorno de JupyterLab se abrirá en tu navegador.

    3. En el navegador de archivos, abre mlops-on-gcp y, luego, navega al directorio skew-detection1.

  2. Abre el notebook 02-covertype-logs-parsing-analysis.ipynb.

  3. En el notebook, en Configuración, ejecuta la celda Instalar paquetes y dependencias para instalar los paquetes de Python necesarios y configurar las variables de entorno.

  4. En Establece la configuración del entorno de Google Cloud, establece las siguientes variables:

    • PROJECT_ID: El ID del proyecto de Google Cloud en el que se registra el conjunto de datos de BigQuery para los datos de solicitud-respuesta.
    • BQ_DATASET_NAME: El nombre del conjunto de datos de BigQuery para almacenar los registros de solicitud-respuesta.
    • BQ_TABLE_NAME: El nombre de la tabla de BigQuery para almacenar los registros de solicitud-respuesta.
    • MODEL_NAME: El nombre del modelo implementado en AI Platform Prediction.
    • VERSION_NAME: El nombre de la versión del modelo implementado en AI Platform Prediction. La versión tiene el formato vN; por ejemplo, v1.
  5. Ejecuta las celdas restantes en Configuración para terminar de configurar el entorno:

    1. Autentica la cuenta de GCP
    2. Importa las bibliotecas

Define metadatos para el conjunto de datos

Ejecuta la sección 1 del notebook, Define metadatos del conjunto de datos, para definir las variables que se usarán más adelante en el código que genera una secuencia de comandos de SQL. Por ejemplo, el código de esta sección crea dos variables llamadas NUMERIC_FEATURE_NAMES y CATEGORICAL_FEATURES_WITH_VOCABULARY, como se muestra en el siguiente fragmento del código:

NUMERIC_FEATURE_NAMES = ['Aspect', 'Elevation', 'Hillshade_3pm',
                         'Hillshade_9am', 'Hillshade_Noon',
                         'Horizontal_Distance_To_Fire_Points',
                         'Horizontal_Distance_To_Hydrology',
                         'Horizontal_Distance_To_Roadways','Slope',
                         'Vertical_Distance_To_Hydrology']

CATEGORICAL_FEATURES_WITH_VOCABULARY = {
    'Soil_Type': ['2702', '2703', '2704', '2705', '2706', '2717', '3501', '3502',
                  '4201', '4703', '4704', '4744', '4758', '5101', '6101', '6102',
                  '6731', '7101', '7102', '7103', '7201', '7202', '7700', '7701',
                  '7702', '7709', '7710', '7745', '7746', '7755', '7756', '7757',
                  '7790', '8703', '8707', '8708', '8771', '8772', '8776'],
    'Wilderness_Area': ['Cache', 'Commanche', 'Neota', 'Rawah']
}

Luego, el código crea una variable llamada FEATURE_NAMES para combinar estos valores, como en la siguiente línea:

FEATURE_NAMES = list(CATEGORICAL_FEATURES_WITH_VOCABULARY.keys()) + NUMERIC_FEATURE_NAMES

Genera la secuencia de comandos CREATE VIEW SQL

Debes ejecutar las tareas de la sección 2 del notebook a fin de generar la declaración CREATE VIEW que puedes ejecutar más adelante para analizar los registros.

La primera tarea ejecuta código a fin de crear valores a partir de los metadatos de datos para las variables json_features_extraction y json_prediction_extraction. Estas variables contienen los atributos y valores de predicción en un formato que se puede insertar en una instrucción de SQL.

Este código se basa en las variables que estableciste antes, cuando configuraste el notebook y definiste los metadatos para el conjunto de datos. En el siguiente fragmento, se muestra este código.

LABEL_KEY = 'predicted_label'
SCORE_KEY = 'confidence'
SIGNATURE_NAME = 'serving_default'

def _extract_json(column, feature_name):
  return "JSON_EXTRACT({}, '$.{}')".format(column, feature_name)

def _replace_brackets(field):
  return "REPLACE(REPLACE({}, ']', ''), '[','')".format(field)

def _replace_quotes(field):
  return 'REPLACE({}, "\\"","")'.format(field)

def _cast_to_numeric(field):
  return "CAST({} AS NUMERIC)".format(field)

def _add_alias(field, feature_name):
  return "{} AS {}".format(field, feature_name)

view_name = "vw_"+BQ_TABLE_NAME+"_"+VERSION_NAME

colum_names = FEATURE_NAMES
input_features = ', \r\n  '.join(colum_names)

json_features_extraction = []
for feature_name in colum_names:
  field = _extract_json('instance', feature_name)
  field = _replace_brackets(field)
  if feature_name in NUMERIC_FEATURE_NAMES:
    field = _cast_to_numeric(field)
  else:
    field = _replace_quotes(field)
  field = _add_alias(field, feature_name)
  json_features_extraction.append(field)

json_features_extraction = ', \r\n    '.join(json_features_extraction)

json_prediction_extraction = []
for feature_name in [LABEL_KEY, SCORE_KEY]:
  field = _extract_json('prediction', feature_name)
  field = _replace_brackets(field)
  if feature_name == SCORE_KEY:
    field = _cast_to_numeric(field)
  else:
    field = _replace_quotes(field)
  field = _add_alias(field, feature_name)
  json_prediction_extraction.append(field)

json_prediction_extraction = ', \r\n    '.join(json_prediction_extraction)

La segunda tarea establece una variable llamada sql_script en una string larga, que contiene una declaración CREATE OR REPLACE VIEW. La instrucción contiene varios marcadores de posición, que se marcan en la string mediante @ como prefijo. Por ejemplo, hay marcadores de posición para los nombres del conjunto de datos y de la vista:

CREATE OR REPLACE VIEW @dataset_name.@view_name

También hay marcadores de posición para los nombres del proyecto, la tabla, el modelo y la versión:

FROM
  `@project.@dataset_name.@table_name`
  WHERE
    model = '@model_name' AND
    model_version = '@version'
)

Al final de la instrucción incluye marcadores de posición que usan las variables json_features_extraction y json_prediction_extraction que creaste cuando ejecutaste el código en la tarea anterior:

step3 AS
(SELECT
    model,
    model_version,
    time,
    @json_features_extraction,
    @json_prediction_extraction
FROM step2
)

Por último, ejecuta la siguiente celda para reemplazar los marcadores de posición en la instrucción de SQL por los valores que configuraste antes, como se muestra en el siguiente fragmento:

sql_script = sql_script.replace("@project", PROJECT_ID)
sql_script = sql_script.replace("@dataset_name", BQ_DATASET_NAME)
sql_script = sql_script.replace("@table_name", BQ_TABLE_NAME)
sql_script = sql_script.replace("@view_name", view_name)
sql_script = sql_script.replace("@model_name", MODEL_NAME)
sql_script = sql_script.replace("@version", VERSION_NAME)
sql_script = sql_script.replace("@input_features", input_features)
sql_script = sql_script.replace("@json_features_extraction", json_features_extraction)
sql_script = sql_script.replace("@json_prediction_extraction", json_prediction_extraction)

En este paso, se completa la generación de la instrucción de SQL que crea la vista para analizar los datos de solicitud y respuesta sin procesar.

Si deseas ver la secuencia de comandos que generaste, ejecuta la celda que imprime la vista. La celda contiene el siguiente código:

print(sql_script)

Ejecuta la secuencia de comandos CREATE VIEW SQL

Para ejecutar la declaración CREATE VIEW, debes ejecutar el código de la sección 3 del notebook. Cuando termines, el código mostrará el mensaje View created or replaced. Cuando veas este mensaje, la vista para analizar los datos estará lista.

En el siguiente fragmento, se muestra la declaración resultante.

CREATE OR REPLACE VIEW prediction_logs.vw_covertype_classifier_logs_v1
AS

WITH step1 AS
(
  SELECT
    model,
    model_version,
    time,
    SPLIT(JSON_EXTRACT(raw_data, '$.instances'), '}],[{') instance_list,
    SPLIT(JSON_EXTRACT(raw_prediction, '$.predictions'), '}],[{') as prediction_list
  FROM
  `sa-data-validation.prediction_logs.covertype_classifier_logs`
  WHERE
    model = 'covertype_classifier' AND
    model_version = 'v1'
),

step2 AS
(
  SELECT
    model,
    model_version,
    time,
    REPLACE(REPLACE(instance, '[{', '{'),'}]', '}') AS instance,
    REPLACE(REPLACE(prediction, '[{', '{'),'}]', '}') AS prediction,
  FROM step1
  JOIN UNNEST(step1.instance_list) AS instance
  WITH OFFSET AS f1
  JOIN UNNEST(step1.prediction_list) AS prediction
  WITH OFFSET AS f2
  ON f1=f2
),

step3 AS
(
  SELECT
    model,
    model_version,
    time,
    REPLACE(REPLACE(REPLACE(JSON_EXTRACT(instance, '$.Soil_Type'), ']', ''), '[',''), "\"","") AS Soil_Type,
    REPLACE(REPLACE(REPLACE(JSON_EXTRACT(instance, '$.Wilderness_Area'), ']', ''), '[',''), "\"","") AS Wilderness_Area,
    CAST(REPLACE(REPLACE(JSON_EXTRACT(instance, '$.Aspect'), ']', ''), '[','') AS NUMERIC) AS Aspect,
    CAST(REPLACE(REPLACE(JSON_EXTRACT(instance, '$.Elevation'), ']', ''), '[','') AS NUMERIC) AS Elevation,
    CAST(REPLACE(REPLACE(JSON_EXTRACT(instance, '$.Hillshade_3pm'), ']', ''), '[','') AS NUMERIC) AS Hillshade_3pm,
    CAST(REPLACE(REPLACE(JSON_EXTRACT(instance, '$.Hillshade_9am'), ']', ''), '[','') AS NUMERIC) AS Hillshade_9am,
    CAST(REPLACE(REPLACE(JSON_EXTRACT(instance, '$.Hillshade_Noon'), ']', ''), '[','') AS NUMERIC) AS Hillshade_Noon,
    CAST(REPLACE(REPLACE(JSON_EXTRACT(instance, '$.Horizontal_Distance_To_Fire_Points'), ']', ''), '[','') AS NUMERIC) AS Horizontal_Distance_To_Fire_Points,
    CAST(REPLACE(REPLACE(JSON_EXTRACT(instance, '$.Horizontal_Distance_To_Hydrology'), ']', ''), '[','') AS NUMERIC) AS Horizontal_Distance_To_Hydrology,
    CAST(REPLACE(REPLACE(JSON_EXTRACT(instance, '$.Horizontal_Distance_To_Roadways'), ']', ''), '[','') AS NUMERIC) AS Horizontal_Distance_To_Roadways,
    CAST(REPLACE(REPLACE(JSON_EXTRACT(instance, '$.Slope'), ']', ''), '[','') AS NUMERIC) AS Slope,
    CAST(REPLACE(REPLACE(JSON_EXTRACT(instance, '$.Vertical_Distance_To_Hydrology'), ']', ''), '[','') AS NUMERIC) AS Vertical_Distance_To_Hydrology,
    REPLACE(REPLACE(REPLACE(JSON_EXTRACT(prediction, '$.predicted_label'), ']', ''), '[',''), "\"","") AS predicted_label,
    CAST(REPLACE(REPLACE(JSON_EXTRACT(prediction, '$.confidence'), ']', ''), '[','') AS NUMERIC) AS confidence
  FROM step2
)

SELECT*
FROM step3

Consulta la vista

Después de crear la vista, puedes consultarla. Para consultar la vista, ejecuta el código de la sección 4, Consulta la vista. El código usa el método pandas.io.gbq.read_gbq en el notebook, como se muestra en el siguiente fragmento de código:

query = '''
 SELECT * FROM
 `{}.{}`
 LIMIT {}
'''.format(BQ_DATASET_NAME, view_name, 3)

pd.io.gbq.read_gbq(
   query, project_id=PROJECT_ID).T

El código produce un resultado similar al siguiente:

Resultado producido mediante una consulta a la vista.

El resultado de la consulta de vista muestra lo siguiente:

  • Cada función tiene su propia entrada.
  • Las comillas se quitan de los atributos categóricos.
  • La etiqueta de clase prevista se presenta en la entrada predicted_label.
  • La probabilidad de la etiqueta de clase prevista se presenta en la entrada confidence.

Usa la consola de BigQuery

Como alternativa a consultar la vista mediante la API de pandas, puedes consultar la vista en la consola de BigQuery.

  1. Abre la consola de BigQuery.

    Ir a la consola de BigQuery

  2. En el panel Editor de consultas, ingresa una consulta como la que se muestra a continuación:

    Select*
    FROM PROJECT_ID.prediction_logs.vw_covertype_classifier_logs_v1
    Limit 10
    

    Reemplaza PROJECT_ID por el ID del proyecto de Cloud que configuraste antes.

    El resultado es similar al siguiente:

    Ventana del editor de consultas con resultado e instrucción de SQL

Simula datos de entrega (opcional)

Si trabajas con tu propio modelo y tus datos, omite esta sección y dirígete a la siguiente sección, en la que se describe cómo completar la tabla de registros de solicitud y respuesta con datos de muestra.

Puedes usar datos de muestra a fin de generar datos sesgados y, luego, simular solicitudes de predicción para la versión del modelo que se implementa en AI Platform Prediction. El modelo produce predicciones para las instancias de solicitud. Las instancias y las predicciones se almacenan en BigQuery.

Puedes generar datos de muestra (normales y sesgados) para las solicitudes de predicción y, luego, llamar al modelo de clasificación covertype que se implementa en AI Platform Prediction mediante los datos generados. El repositorio que clonaste contiene un notebook que incluye código para esta tarea o puedes cargar un archivo CSV que contenga datos de registro con sesgos.

Para generar los datos de muestra desde el notebook, haz lo siguiente:

  1. En el notebook, ve al navegador de archivos, abre mlops-on-gcp y, luego, navega al directorio skew-detection/workload_simulator.
  2. Abre el notebook covertype-data-generation.ipynb.
  3. En Configuración, configura los valores de tu ID del proyecto, nombre del bucket y región.
  4. Ejecuta todas las celdas del notebook en orden.

Puedes cambiar el tamaño de los datos que se generan y cómo se restringen. Los sesgos predeterminados que se presentan en los datos son los siguientes:

  • Sesgo de los atributos numéricos. Para el atributo Elevation, el código convierte la unidad de medida de metros a kilómetros en el 10% de los datos.
  • Sesgo de la distribución de atributos numéricos. Para el atributo Aspect, el código disminuye el valor en un 25%.
  • Sesgo de atributos categóricos. Para el atributo Wilderness_Area, el código convierte el valor de un 1% aleatorio de los datos a una nueva categoría llamada Others.
  • Sesgo de distribución de atributos categóricos. Para la función Wilderness_Area, el código aumenta la frecuencia de los valores Neota y Cache. El código lo hace mediante la conversión de un 25% de los datos seleccionados de forma aleatoria de los valores originales a los valores Neota y Cache.

Como alternativa, puedes cargar el archivo de datos workload_simulator/bq_prediction_logs.csv en tu tabla de registros de solicitudes y respuestas de BigQuery. El archivo CSV incluye registros de solicitudes y respuestas de muestra, con 2,000 datos normales y 1,000 datos sesgados. Para obtener más información, consulta cómo cargar datos a BigQuery desde datos locales.

Visualiza datos de entrega registrados

Puedes usar una herramienta de visualización para conectarte a la vista de BigQuery y visualizar los datos de entrega registrados. En los siguientes ejemplos, las visualizaciones se crearon mediante Data Studio.

En la siguiente captura de pantalla, se presenta un panel de muestra que se creó para visualizar los registros de solicitud-respuesta de predicción de esta guía.

Visualización de registros de solicitud-respuesta.

En el panel, se muestra la siguiente información:

  • La cantidad de instancias que recibió el servicio de predicción es la misma (500) todos los días, del 1 al 6 de junio.
  • Para las distribuciones de clases, la frecuencia de la etiqueta de clase prevista 3 aumentó en los últimos dos días (5 de junio y 6 de junio).
  • Para la distribución de valores Wilderness Area, los valores Neota y Cache aumentaron en los últimos dos días.
  • En cuanto a las estadísticas descriptivas de la función Elevation, los valores mínimos de los últimos dos días tienen valores significativamente menores que los de los cuatro días anteriores. Los valores de desviación estándar tienen valores significativamente más altos que para los cuatro días anteriores.

Además, como se muestra en la siguiente captura de pantalla, la distribución de los valores de la función Aspect durante los últimos dos días registra una disminución significativa en la frecuencia de los valores entre 300 y 350.

Gráfico de líneas de distribución de aspecto.

Limpia

Si piensas continuar con el resto de esta serie, conserva los recursos que ya creaste. De lo contrario, borra el proyecto que contiene los recursos o conserva el proyecto y borra los recursos individuales.

Borra el proyecto

  1. En Cloud Console, ve a la página Administrar recursos.

    Ir a Administrar recursos

  2. En la lista de proyectos, elige el proyecto que quieres borrar y haz clic en Borrar.
  3. En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

¿Qué sigue?