Pipeline Logs Tutorial
This tutorial and the assets can be downloaded as part of the Wallaroo Tutorials repository.
Pipeline Log Tutorial
This tutorial demonstrates Wallaroo Pipeline logs and
This tutorial will demonstrate how to:
- Select or create a workspace, pipeline and upload the control model, then additional models for A/B Testing and Shadow Deploy.
- Add a pipeline step with the champion model, then deploy the pipeline and perform sample inferences.
- Display the various log types for a standard deployed pipeline.
- Swap out the pipeline step with the champion model with a shadow deploy step that compares the champion model against two competitors.
- Perform sample inferences with a shadow deployed step, then display the log files for a shadow deployed pipeline.
- Swap out the shadow deployed pipeline step with an A/B pipeline step.
- Perform sample inferences with a A/B pipeline step, then display the log files for an A/B pipeline step.
- Undeploy the pipeline.
This tutorial provides the following:
- Models:
models/rf_model.onnx
: The champion model that has been used in this environment for some time.models/xgb_model.onnx
andmodels/gbr_model.onnx
: Rival models that will be tested against the champion.
- Data:
data/xtest-1.df.json
anddata/xtest-1k.df.json
: DataFrame JSON inference inputs with 1 input and 1,000 inputs.data/xtest-1k.arrow
: Apache Arrow inference inputs with 1 input and 1,000 inputs.
Prerequisites
- A deployed Wallaroo instance
- The following Python libraries installed:
Initial Steps
Import libraries
The first step is to import the libraries needed for this notebook.
import wallaroo
from wallaroo.object import EntityNotFoundError
import pyarrow as pa
from IPython.display import display
# used to display DataFrame information without truncating
from IPython.display import display
import pandas as pd
pd.set_option('display.max_colwidth', None)
import datetime
import os
Connect to the Wallaroo Instance
The first step is to connect to Wallaroo through the Wallaroo client. The Python library is included in the Wallaroo install and available through the Jupyter Hub interface provided with your Wallaroo environment.
This is accomplished using the wallaroo.Client()
command, which provides a URL to grant the SDK permission to your specific Wallaroo environment. When displayed, enter the URL into a browser and confirm permissions. Store the connection into a variable that can be referenced later.
If logging into the Wallaroo instance through the internal JupyterHub service, use wl = wallaroo.Client()
. For more information on Wallaroo Client settings, see the Client Connection guide.
# Login through local Wallaroo instance
wl = wallaroo.Client()
Create Workspace
We will create a workspace to manage our pipeline and models. The following variables will set the name of our sample workspace then set it as the current workspace.
workspace_name = 'logworkspace'
main_pipeline_name = 'logpipeline'
model_name_control = 'logcontrol'
model_file_name_control = './models/rf_model.onnx'
def get_workspace(name):
workspace = None
for ws in wl.list_workspaces():
if ws.name() == name:
workspace= ws
if(workspace == None):
workspace = wl.create_workspace(name)
return workspace
workspace = get_workspace(workspace_name)
wl.set_current_workspace(workspace)
{'name': 'logworkspace', 'id': 26, 'archived': False, 'created_by': '4e296632-35b3-460e-85fe-565e311bc566', 'created_at': '2023-07-14T15:49:20.890382+00:00', 'models': [], 'pipelines': []}
Standard Pipeline
Upload The Champion Model
For our example, we will upload the champion model that has been trained to derive house prices from a variety of inputs. The model file is rf_model.onnx
, and is uploaded with the name housingcontrol
.
housing_model_control = wl.upload_model(model_name_control, model_file_name_control, framework=wallaroo.framework.Framework.ONNX).configure()
Build the Pipeline
This pipeline is made to be an example of an existing situation where a model is deployed and being used for inferences in a production environment. We’ll call it housepricepipeline
, set housingcontrol
as a pipeline step, then run a few sample inferences.
mainpipeline = wl.build_pipeline(main_pipeline_name)
mainpipeline.undeploy()
# in case this pipeline was run before
mainpipeline.clear()
mainpipeline.add_model_step(housing_model_control).deploy()
name | logpipeline |
---|---|
created | 2023-07-14 15:49:23.959261+00:00 |
last_updated | 2023-07-14 15:49:24.981192+00:00 |
deployed | True |
tags | |
versions | 48ec856b-9640-4a04-83f6-77a9bd205a44, 8a9d1d69-d71d-4c0a-9c95-99b3f86dcbc7 |
steps | logcontrol |
Testing
We’ll use two inferences as a quick sample test - one that has a house that should be determined around $700k, the other with a house determined to be around $1.5 million. We’ll also save the start and end periods for these events to for later log functionality.
dataframe_start = datetime.datetime.now()
normal_input = pd.DataFrame.from_records({"tensor": [[4.0, 2.5, 2900.0, 5505.0, 2.0, 0.0, 0.0, 3.0, 8.0, 2900.0, 0.0, 47.6063, -122.02, 2970.0, 5251.0, 12.0, 0.0, 0.0]]})
result = mainpipeline.infer(normal_input)
display(result)
time | in.tensor | out.variable | check_failures | |
---|---|---|---|---|
0 | 2023-07-14 15:49:36.579 | [4.0, 2.5, 2900.0, 5505.0, 2.0, 0.0, 0.0, 3.0, 8.0, 2900.0, 0.0, 47.6063, -122.02, 2970.0, 5251.0, 12.0, 0.0, 0.0] | [718013.7] | 0 |
large_house_input = pd.DataFrame.from_records({'tensor': [[4.0, 3.0, 3710.0, 20000.0, 2.0, 0.0, 2.0, 5.0, 10.0, 2760.0, 950.0, 47.6696, -122.261, 3970.0, 20000.0, 79.0, 0.0, 0.0]]})
large_house_result = mainpipeline.infer(large_house_input)
display(large_house_result)
import time
time.sleep(10)
dataframe_end = datetime.datetime.now()
time | in.tensor | out.variable | check_failures | |
---|---|---|---|---|
0 | 2023-07-14 15:49:36.996 | [4.0, 3.0, 3710.0, 20000.0, 2.0, 0.0, 2.0, 5.0, 10.0, 2760.0, 950.0, 47.6696, -122.261, 3970.0, 20000.0, 79.0, 0.0, 0.0] | [1514079.4] | 0 |
As one last sample, we’ll run through roughly 1,000 inferences at once and show a few of the results. For this example we’ll use an Apache Arrow table, which has a smaller file size compared to uploading a pandas DataFrame JSON file. The inference result is returned as an arrow table, which we’ll convert into a pandas DataFrame to display the first 20 results.
batch_inferences = mainpipeline.infer_from_file('./data/xtest-1k.arrow')
large_inference_result = batch_inferences.to_pandas()
display(large_inference_result.head(20))
time | in.tensor | out.variable | check_failures | |
---|---|---|---|---|
0 | 2023-07-14 15:49:47.621 | [4.0, 2.5, 2900.0, 5505.0, 2.0, 0.0, 0.0, 3.0, 8.0, 2900.0, 0.0, 47.6063, -122.02, 2970.0, 5251.0, 12.0, 0.0, 0.0] | [718013.75] | 0 |
1 | 2023-07-14 15:49:47.621 | [2.0, 2.5, 2170.0, 6361.0, 1.0, 0.0, 2.0, 3.0, 8.0, 2170.0, 0.0, 47.7109, -122.017, 2310.0, 7419.0, 6.0, 0.0, 0.0] | [615094.56] | 0 |
2 | 2023-07-14 15:49:47.621 | [3.0, 2.5, 1300.0, 812.0, 2.0, 0.0, 0.0, 3.0, 8.0, 880.0, 420.0, 47.5893, -122.317, 1300.0, 824.0, 6.0, 0.0, 0.0] | [448627.72] | 0 |
3 | 2023-07-14 15:49:47.621 | [4.0, 2.5, 2500.0, 8540.0, 2.0, 0.0, 0.0, 3.0, 9.0, 2500.0, 0.0, 47.5759, -121.994, 2560.0, 8475.0, 24.0, 0.0, 0.0] | [758714.2] | 0 |
4 | 2023-07-14 15:49:47.621 | [3.0, 1.75, 2200.0, 11520.0, 1.0, 0.0, 0.0, 4.0, 7.0, 2200.0, 0.0, 47.7659, -122.341, 1690.0, 8038.0, 62.0, 0.0, 0.0] | [513264.7] | 0 |
5 | 2023-07-14 15:49:47.621 | [3.0, 2.0, 2140.0, 4923.0, 1.0, 0.0, 0.0, 4.0, 8.0, 1070.0, 1070.0, 47.6902, -122.339, 1470.0, 4923.0, 86.0, 0.0, 0.0] | [668288.0] | 0 |
6 | 2023-07-14 15:49:47.621 | [4.0, 3.5, 3590.0, 5334.0, 2.0, 0.0, 2.0, 3.0, 9.0, 3140.0, 450.0, 47.6763, -122.267, 2100.0, 6250.0, 9.0, 0.0, 0.0] | [1004846.5] | 0 |
7 | 2023-07-14 15:49:47.621 | [3.0, 2.0, 1280.0, 960.0, 2.0, 0.0, 0.0, 3.0, 9.0, 1040.0, 240.0, 47.602, -122.311, 1280.0, 1173.0, 0.0, 0.0, 0.0] | [684577.2] | 0 |
8 | 2023-07-14 15:49:47.621 | [4.0, 2.5, 2820.0, 15000.0, 2.0, 0.0, 0.0, 4.0, 9.0, 2820.0, 0.0, 47.7255, -122.101, 2440.0, 15000.0, 29.0, 0.0, 0.0] | [727898.1] | 0 |
9 | 2023-07-14 15:49:47.621 | [3.0, 2.25, 1790.0, 11393.0, 1.0, 0.0, 0.0, 3.0, 8.0, 1790.0, 0.0, 47.6297, -122.099, 2290.0, 11894.0, 36.0, 0.0, 0.0] | [559631.1] | 0 |
10 | 2023-07-14 15:49:47.621 | [3.0, 1.5, 1010.0, 7683.0, 1.5, 0.0, 0.0, 5.0, 7.0, 1010.0, 0.0, 47.72, -122.318, 1550.0, 7271.0, 61.0, 0.0, 0.0] | [340764.53] | 0 |
11 | 2023-07-14 15:49:47.621 | [3.0, 2.0, 1270.0, 1323.0, 3.0, 0.0, 0.0, 3.0, 8.0, 1270.0, 0.0, 47.6934, -122.342, 1330.0, 1323.0, 8.0, 0.0, 0.0] | [442168.06] | 0 |
12 | 2023-07-14 15:49:47.621 | [4.0, 1.75, 2070.0, 9120.0, 1.0, 0.0, 0.0, 4.0, 7.0, 1250.0, 820.0, 47.6045, -122.123, 1650.0, 8400.0, 57.0, 0.0, 0.0] | [630865.6] | 0 |
13 | 2023-07-14 15:49:47.621 | [4.0, 1.0, 1620.0, 4080.0, 1.5, 0.0, 0.0, 3.0, 7.0, 1620.0, 0.0, 47.6696, -122.324, 1760.0, 4080.0, 91.0, 0.0, 0.0] | [559631.1] | 0 |
14 | 2023-07-14 15:49:47.621 | [4.0, 3.25, 3990.0, 9786.0, 2.0, 0.0, 0.0, 3.0, 9.0, 3990.0, 0.0, 47.6784, -122.026, 3920.0, 8200.0, 10.0, 0.0, 0.0] | [909441.1] | 0 |
15 | 2023-07-14 15:49:47.621 | [4.0, 2.0, 1780.0, 19843.0, 1.0, 0.0, 0.0, 3.0, 7.0, 1780.0, 0.0, 47.4414, -122.154, 2210.0, 13500.0, 52.0, 0.0, 0.0] | [313096.0] | 0 |
16 | 2023-07-14 15:49:47.621 | [4.0, 2.5, 2130.0, 6003.0, 2.0, 0.0, 0.0, 3.0, 8.0, 2130.0, 0.0, 47.4518, -122.12, 1940.0, 4529.0, 11.0, 0.0, 0.0] | [404040.8] | 0 |
17 | 2023-07-14 15:49:47.621 | [3.0, 1.75, 1660.0, 10440.0, 1.0, 0.0, 0.0, 3.0, 7.0, 1040.0, 620.0, 47.4448, -121.77, 1240.0, 10380.0, 36.0, 0.0, 0.0] | [292859.5] | 0 |
18 | 2023-07-14 15:49:47.621 | [3.0, 2.5, 2110.0, 4118.0, 2.0, 0.0, 0.0, 3.0, 8.0, 2110.0, 0.0, 47.3878, -122.153, 2110.0, 4044.0, 25.0, 0.0, 0.0] | [338357.88] | 0 |
19 | 2023-07-14 15:49:47.621 | [4.0, 2.25, 2200.0, 11250.0, 1.5, 0.0, 0.0, 5.0, 7.0, 1300.0, 900.0, 47.6845, -122.201, 2320.0, 10814.0, 94.0, 0.0, 0.0] | [682284.6] | 0 |
Standard Pipeline Logs
Pipeline logs with standard pipeline steps are retrieved either with:
- Pipeline
logs
which returns either a pandas DataFrame or Apache Arrow table. - Pipeline
export_logs
which saves the logs either a pandas DataFrame JSON file or Apache Arrow table.
For full details, see the Wallaroo Documentation Pipeline Log Management guide.
Pipeline Log Method
The Pipeline logs
method includes the following parameters. For a complete list, see the Wallaroo SDK Essentials Guide: Pipeline Log Management.
Parameter | Type | Description |
---|---|---|
limit | Int (Optional) | Limits how many log records to display. Defaults to 100 . If there are more pipeline logs than are being displayed, the Warning message Pipeline log record limit exceeded will be displayed. For example, if 100 log files were requested and there are a total of 1,000, the warning message will be displayed. |
start_datetime and end_datetime | DateTime (Optional) | Limits logs to all logs between the start and end DateTime parameters. Both parameters must be provided. Submitting a logs() request with only start_datetime or end_datetime will generate an exception.If start_datetime and end_datetime are provided as parameters, then the records are returned in chronological order, with the oldest record displayed first. |
dataset | List (OPTIONAL) | The datasets to be returned. The datasets available are:
metadata.elapsed : IMPORTANT NOTE: See Metadata Requests Restrictionsfor specifications on how this dataset can be used with other datasets.
|
arrow | Boolean (Optional) | Defaults to False. If arrow is set to True , then the logs are returned as an Apache Arrow table. If arrow=False , then the logs are returned as a pandas DataFrame. |
Pipeline Log Warnings
If the total number of logs the either the set limit or 10 MB in file size, the following warning is returned:
Warning: There are more logs available. Please set a larger limit or request a file using export_logs.
If the total number of logs requested either through the limit or through the start_datetime
and end_datetime
request is greater than 10 MB in size, the following error is displayed:
Warning: Pipeline log size limit exceeded. Only displaying 509 log messages. Please request a file using export_logs.
The following examples demonstrate displaying the logs, then displaying the logs between the control_model_start
and control_model_end
periods, then again retrieved as an Arrow table with the logs limited to only 5 entries.
# pipeline log retrieval - reverse chronological order
regular_logs = mainpipeline.logs()
display("Standard Logs")
display(len(regular_logs))
display(regular_logs)
# Display metadata
metadatalogs = mainpipeline.logs(dataset=["time", "out.variable", "metadata"])
display("Metadata Logs")
# Only showing the pipeline version for space reasons
display(metadatalogs.loc[:, ["time", "out.variable", "metadata.pipeline_version"]])
# Display logs restricted by date and limit
display("Logs restricted by date")
arrow_logs = mainpipeline.logs(start_datetime=dataframe_start, end_datetime=dataframe_end, limit=50)
display(len(arrow_logs))
display(arrow_logs)
# # pipeline log retrieval limited to the last 5 an an arrow table
display("Arrow logs by limit")
display(mainpipeline.logs(arrow=True))
Warning: There are more logs available. Please set a larger limit or request a file using export_logs.
‘Standard Logs’
100
time | in.tensor | out.variable | check_failures | |
---|---|---|---|---|
0 | 2023-07-14 15:49:47.621 | [3.0, 2.0, 2005.0, 7000.0, 1.0, 0.0, 0.0, 3.0, 7.0, 1605.0, 400.0, 47.6039, -122.298, 1750.0, 4500.0, 34.0, 0.0, 0.0] | [581003.0] | 0 |
1 | 2023-07-14 15:49:47.621 | [3.0, 1.75, 2910.0, 37461.0, 1.0, 0.0, 0.0, 4.0, 7.0, 1530.0, 1380.0, 47.7015, -122.164, 2520.0, 18295.0, 47.0, 0.0, 0.0] | [706823.56] | 0 |
2 | 2023-07-14 15:49:47.621 | [4.0, 3.25, 2910.0, 1880.0, 2.0, 0.0, 3.0, 5.0, 9.0, 1830.0, 1080.0, 47.616, -122.282, 3100.0, 8200.0, 100.0, 0.0, 0.0] | [1060847.5] | 0 |
3 | 2023-07-14 15:49:47.621 | [4.0, 1.75, 2700.0, 7875.0, 1.5, 0.0, 0.0, 4.0, 8.0, 2700.0, 0.0, 47.454, -122.144, 2220.0, 7875.0, 46.0, 0.0, 0.0] | [441960.38] | 0 |
4 | 2023-07-14 15:49:47.621 | [3.0, 2.5, 2900.0, 23550.0, 1.0, 0.0, 0.0, 3.0, 10.0, 1490.0, 1410.0, 47.5708, -122.153, 2900.0, 19604.0, 27.0, 0.0, 0.0] | [827411.0] | 0 |
... | ... | ... | ... | ... |
95 | 2023-07-14 15:49:47.621 | [2.0, 1.5, 1070.0, 1236.0, 2.0, 0.0, 0.0, 3.0, 8.0, 1000.0, 70.0, 47.5619, -122.382, 1170.0, 1888.0, 10.0, 0.0, 0.0] | [435628.56] | 0 |
96 | 2023-07-14 15:49:47.621 | [3.0, 2.5, 2830.0, 6000.0, 1.0, 0.0, 3.0, 3.0, 9.0, 1730.0, 1100.0, 47.5751, -122.378, 2040.0, 5300.0, 60.0, 0.0, 0.0] | [981676.6] | 0 |
97 | 2023-07-14 15:49:47.621 | [4.0, 1.75, 1720.0, 8750.0, 1.0, 0.0, 0.0, 3.0, 7.0, 860.0, 860.0, 47.726, -122.21, 1790.0, 8750.0, 43.0, 0.0, 0.0] | [437177.84] | 0 |
98 | 2023-07-14 15:49:47.621 | [4.0, 2.25, 4470.0, 60373.0, 2.0, 0.0, 0.0, 3.0, 11.0, 4470.0, 0.0, 47.7289, -122.127, 3210.0, 40450.0, 26.0, 0.0, 0.0] | [1208638.0] | 0 |
99 | 2023-07-14 15:49:47.621 | [3.0, 1.0, 1150.0, 3000.0, 1.0, 0.0, 0.0, 5.0, 6.0, 1150.0, 0.0, 47.6867, -122.345, 1460.0, 3200.0, 108.0, 0.0, 0.0] | [448627.72] | 0 |
100 rows × 4 columns
Warning: There are more logs available. Please set a larger limit or request a file using export_logs.
‘Metadata Logs’
time | out.variable | metadata.pipeline_version | |
---|---|---|---|
0 | 2023-07-14 15:49:47.621 | [581003.0] | |
1 | 2023-07-14 15:49:47.621 | [706823.56] | |
2 | 2023-07-14 15:49:47.621 | [1060847.5] | |
3 | 2023-07-14 15:49:47.621 | [441960.38] | |
4 | 2023-07-14 15:49:47.621 | [827411.0] | |
... | ... | ... | ... |
95 | 2023-07-14 15:49:47.621 | [435628.56] | |
96 | 2023-07-14 15:49:47.621 | [981676.6] | |
97 | 2023-07-14 15:49:47.621 | [437177.84] | |
98 | 2023-07-14 15:49:47.621 | [1208638.0] | |
99 | 2023-07-14 15:49:47.621 | [448627.72] |
100 rows × 3 columns
'Logs restricted by date'
2
time | in.tensor | out.variable | check_failures | |
---|---|---|---|---|
0 | 2023-07-14 15:49:36.579 | [4.0, 2.5, 2900.0, 5505.0, 2.0, 0.0, 0.0, 3.0, 8.0, 2900.0, 0.0, 47.6063, -122.02, 2970.0, 5251.0, 12.0, 0.0, 0.0] | [718013.7] | 0 |
1 | 2023-07-14 15:49:36.996 | [4.0, 3.0, 3710.0, 20000.0, 2.0, 0.0, 2.0, 5.0, 10.0, 2760.0, 950.0, 47.6696, -122.261, 3970.0, 20000.0, 79.0, 0.0, 0.0] | [1514079.4] | 0 |
'Arrow logs by limit'
Warning: There are more logs available. Please set a larger limit or request a file using export_logs.
pyarrow.Table
time: timestamp[ms]
in.tensor: list<item: float> not null
child 0, item: float
out.variable: list<inner: float not null> not null
child 0, inner: float not null
check_failures: int8
----
time: [[2023-07-14 15:49:47.621,2023-07-14 15:49:47.621,2023-07-14 15:49:47.621,2023-07-14 15:49:47.621,2023-07-14 15:49:47.621,...,2023-07-14 15:49:47.621,2023-07-14 15:49:47.621,2023-07-14 15:49:47.621,2023-07-14 15:49:47.621,2023-07-14 15:49:47.621]]
in.tensor: [[[3,2,2005,7000,1,...,1750,4500,34,0,0],[3,1.75,2910,37461,1,...,2520,18295,47,0,0],...,[4,2.25,4470,60373,2,...,3210,40450,26,0,0],[3,1,1150,3000,1,...,1460,3200,108,0,0]]]
out.variable: [[[581003],[706823.56],...,[1208638],[448627.72]]]
check_failures: [[0,0,0,0,0,...,0,0,0,0,0]]
Pipeline Limits
In a previous step we performed 10,000 inferences at once. If we attempt to pull them at once, we’ll likely run into the size limit for this pipeline and receive the following warning message indicating that the pipeline size limits were exceeded and we should use export_logs
instead.
Warning: Pipeline log size limit exceeded. Only displaying 1000 log messages (of 10000 requested). Please request a file using export_logs.
logs = mainpipeline.logs(limit=10000)
display(logs)
Warning: Pipeline log size limit exceeded. Please request logs using export_logs
time | in.tensor | out.variable | check_failures | |
---|---|---|---|---|
0 | 2023-07-14 15:49:47.621 | [3.0, 2.0, 2005.0, 7000.0, 1.0, 0.0, 0.0, 3.0, 7.0, 1605.0, 400.0, 47.6039, -122.298, 1750.0, 4500.0, 34.0, 0.0, 0.0] | [581003.0] | 0 |
1 | 2023-07-14 15:49:47.621 | [3.0, 1.75, 2910.0, 37461.0, 1.0, 0.0, 0.0, 4.0, 7.0, 1530.0, 1380.0, 47.7015, -122.164, 2520.0, 18295.0, 47.0, 0.0, 0.0] | [706823.56] | 0 |
2 | 2023-07-14 15:49:47.621 | [4.0, 3.25, 2910.0, 1880.0, 2.0, 0.0, 3.0, 5.0, 9.0, 1830.0, 1080.0, 47.616, -122.282, 3100.0, 8200.0, 100.0, 0.0, 0.0] | [1060847.5] | 0 |
3 | 2023-07-14 15:49:47.621 | [4.0, 1.75, 2700.0, 7875.0, 1.5, 0.0, 0.0, 4.0, 8.0, 2700.0, 0.0, 47.454, -122.144, 2220.0, 7875.0, 46.0, 0.0, 0.0] | [441960.38] | 0 |
4 | 2023-07-14 15:49:47.621 | [3.0, 2.5, 2900.0, 23550.0, 1.0, 0.0, 0.0, 3.0, 10.0, 1490.0, 1410.0, 47.5708, -122.153, 2900.0, 19604.0, 27.0, 0.0, 0.0] | [827411.0] | 0 |
... | ... | ... | ... | ... |
661 | 2023-07-14 15:49:47.621 | [5.0, 3.25, 3160.0, 10587.0, 1.0, 0.0, 0.0, 5.0, 7.0, 2190.0, 970.0, 47.7238, -122.165, 2200.0, 7761.0, 55.0, 0.0, 0.0] | [573403.1] | 0 |
662 | 2023-07-14 15:49:47.621 | [3.0, 2.5, 2210.0, 7620.0, 2.0, 0.0, 0.0, 3.0, 8.0, 2210.0, 0.0, 47.6938, -122.13, 1920.0, 7440.0, 20.0, 0.0, 0.0] | [677870.9] | 0 |
663 | 2023-07-14 15:49:47.621 | [3.0, 1.75, 1960.0, 8136.0, 1.0, 0.0, 0.0, 3.0, 7.0, 980.0, 980.0, 47.5208, -122.364, 1070.0, 7480.0, 66.0, 0.0, 0.0] | [365436.25] | 0 |
664 | 2023-07-14 15:49:47.621 | [3.0, 2.0, 1260.0, 8092.0, 1.0, 0.0, 0.0, 3.0, 7.0, 1260.0, 0.0, 47.3635, -122.054, 1950.0, 8092.0, 28.0, 0.0, 0.0] | [253958.75] | 0 |
665 | 2023-07-14 15:49:47.621 | [4.0, 2.5, 2650.0, 18295.0, 2.0, 0.0, 0.0, 3.0, 8.0, 2650.0, 0.0, 47.6075, -122.154, 2230.0, 19856.0, 28.0, 0.0, 0.0] | [706407.4] | 0 |
666 rows × 4 columns
Pipeline export_logs Method
The Pipeline method export_logs
returns the Pipeline records as either a DataFrame JSON file, or an Apache Arrow table file. For a complete list, see the Wallaroo SDK Essentials Guide: Pipeline Log Management.
The export_logs
method takes the following parameters:
Parameter | Type | Description |
---|---|---|
directory | String (Optional) (Default: logs ) | Logs are exported to a file from current working directory to directory . |
data_size_limit | String (Optional) ((Default: 100MB ) | The maximum size for the exported data in bytes. Note that file size is approximate to the request; a request of 10MiB may return 10.3MB of data. The fields are in the format “{size as number} {unit value}”, and can include a space so “10 MiB” and “10MiB” are the same. The accepted unit values are:
|
file_prefix | String (Optional) (Default: The name of the pipeline) | The name of the exported files. By default, this will the name of the pipeline and is segmented by pipeline version between the limits or the start and end period. For example: ’logpipeline-1.json`, etc. |
limit | Int (Optional) | Limits how many log records to display. Defaults to 100 . If there are more pipeline logs than are being displayed, the Warning message Pipeline log record limit exceeded will be displayed. For example, if 100 log files were requested and there are a total of 1,000, the warning message will be displayed. |
start and end | DateTime (Optional) | Limits logs to all logs between the start and end DateTime parameters. Both parameters must be provided. Submitting a logs() request with only start or end will generate an exception.If start and end are provided as parameters, then the records are returned in chronological order, with the oldest record displayed first. |
dataset | List (OPTIONAL) | The datasets to be returned. The datasets available are:
metadata.elapsed : IMPORTANT NOTE: See Metadata Requests Restrictionsfor specifications on how this dataset can be used with other datasets.
|
arrow | Boolean (Optional) | Defaults to False. If arrow is set to True , then the logs are returned as an Apache Arrow table. If arrow=False , then the logs are returned as JSON in pandas DataFrame format. |
The following examples demonstrate saving a DataFrame version of the mainpipeline
logs, then an Arrow version.
# Save the DataFrame version of the log file
mainpipeline.export_logs()
display(os.listdir('./logs'))
mainpipeline.export_logs(arrow=True)
display(os.listdir('./logs'))
Warning: There are more logs available. Please set a larger limit to export more data.
[’logpipeline-1.json']
Warning: There are more logs available. Please set a larger limit to export more data.
[’logpipeline-1.arrow’, ’logpipeline-1.json’]
Shadow Deploy Pipelines
Let’s assume that after analyzing the assay information we want to test two challenger models to our control. We do that with the Shadow Deploy pipeline step.
In Shadow Deploy, the pipeline step is added with the add_shadow_deploy
method, with the champion model listed first, then an array of challenger models after. All inference data is fed to all models, with the champion results displayed in the out.variable
column, and the shadow results in the format out_{model name}.variable
. For example, since we named our challenger models housingchallenger01
and housingchallenger02
, the columns out_housingchallenger01.variable
and out_housingchallenger02.variable
have the shadow deployed model results.
For this example, we will remove the previous pipeline step, then replace it with a shadow deploy step with rf_model.onnx
as our champion, and models xgb_model.onnx
and gbr_model.onnx
as the challengers. We’ll deploy the pipeline and prepare it for sample inferences.
# Upload the challenger models
model_name_challenger01 = 'logcontrolchallenger01'
model_file_name_challenger01 = './models/xgb_model.onnx'
model_name_challenger02 = 'logcontrolchallenger02'
model_file_name_challenger02 = './models/gbr_model.onnx'
housing_model_challenger01 = wl.upload_model(model_name_challenger01, model_file_name_challenger01, framework=wallaroo.framework.Framework.ONNX).configure()
housing_model_challenger02 = wl.upload_model(model_name_challenger02, model_file_name_challenger02, framework=wallaroo.framework.Framework.ONNX).configure()
# Undeploy the pipeline
mainpipeline.undeploy()
mainpipeline.clear()
# Add the new shadow deploy step with our challenger models
mainpipeline.add_shadow_deploy(housing_model_control, [housing_model_challenger01, housing_model_challenger02])
# Deploy the pipeline with the new shadow step
mainpipeline.deploy()
name | logpipeline |
---|---|
created | 2023-07-14 15:49:23.959261+00:00 |
last_updated | 2023-07-14 15:50:33.900128+00:00 |
deployed | True |
tags | |
versions | f5b3e05b-297d-44a0-8645-86897ded3031, 48ec856b-9640-4a04-83f6-77a9bd205a44, 8a9d1d69-d71d-4c0a-9c95-99b3f86dcbc7 |
steps | logcontrol |
Shadow Deploy Sample Inference
We’ll now use our same sample data for an inference to our shadow deployed pipeline, then display the first 20 results with just the comparative outputs.
shadow_date_start = datetime.datetime.now()
shadow_result = mainpipeline.infer_from_file('./data/xtest-1k.arrow')
shadow_outputs = shadow_result.to_pandas()
display(shadow_outputs.loc[0:20,['out.variable','out_logcontrolchallenger01.variable','out_logcontrolchallenger02.variable']])
shadow_date_end = datetime.datetime.now()
out.variable | out_logcontrolchallenger01.variable | out_logcontrolchallenger02.variable | |
---|---|---|---|
0 | [718013.75] | [659806.0] | [704901.9] |
1 | [615094.56] | [732883.5] | [695994.44] |
2 | [448627.72] | [419508.84] | [416164.8] |
3 | [758714.2] | [634028.8] | [655277.2] |
4 | [513264.7] | [427209.44] | [426854.66] |
5 | [668288.0] | [615501.9] | [632556.1] |
6 | [1004846.5] | [1139732.5] | [1100465.2] |
7 | [684577.2] | [498328.88] | [528278.06] |
8 | [727898.1] | [722664.4] | [659439.94] |
9 | [559631.1] | [525746.44] | [534331.44] |
10 | [340764.53] | [376337.1] | [377187.2] |
11 | [442168.06] | [382053.12] | [403964.3] |
12 | [630865.6] | [505608.97] | [528991.3] |
13 | [559631.1] | [603260.5] | [612201.75] |
14 | [909441.1] | [969585.4] | [893874.7] |
15 | [313096.0] | [313633.75] | [318054.94] |
16 | [404040.8] | [360413.56] | [357816.75] |
17 | [292859.5] | [316674.94] | [294034.7] |
18 | [338357.88] | [299907.44] | [323254.3] |
19 | [682284.6] | [811896.75] | [770916.7] |
20 | [583765.94] | [573618.5] | [549141.4] |
Shadow Deploy Logs
Pipelines with a shadow deployed step include the shadow inference result in the same format as the inference result: inference results from shadow deployed models are displayed as out_{model name}.{output variable}
.
# display logs with shadow deployed steps
display(mainpipeline.logs(start_datetime=shadow_date_start, end_datetime=shadow_date_end).loc[:, ["time", "out.variable", "out_logcontrolchallenger01.variable", "out_logcontrolchallenger02.variable"]])
Warning: Pipeline log size limit exceeded. Please request logs using export_logs
time | out.variable | out_logcontrolchallenger01.variable | out_logcontrolchallenger02.variable | |
---|---|---|---|---|
0 | 2023-07-14 15:50:45.925 | [718013.75] | [659806.0] | [704901.9] |
1 | 2023-07-14 15:50:45.925 | [615094.56] | [732883.5] | [695994.44] |
2 | 2023-07-14 15:50:45.925 | [448627.72] | [419508.84] | [416164.8] |
3 | 2023-07-14 15:50:45.925 | [758714.2] | [634028.8] | [655277.2] |
4 | 2023-07-14 15:50:45.925 | [513264.7] | [427209.44] | [426854.66] |
... | ... | ... | ... | ... |
663 | 2023-07-14 15:50:45.925 | [642519.75] | [390891.06] | [481425.8] |
664 | 2023-07-14 15:50:45.925 | [301714.75] | [406503.62] | [374509.53] |
665 | 2023-07-14 15:50:45.925 | [448627.72] | [473771.0] | [478128.03] |
666 | 2023-07-14 15:50:45.925 | [544392.1] | [428174.9] | [442408.25] |
667 | 2023-07-14 15:50:45.925 | [944006.75] | [902058.6] | [866622.25] |
668 rows × 4 columns
# Save shadow deployed log files as pandas DataFrame
mainpipeline.export_logs(directory="shadow", file_prefix="shadowdeploylogs")
display(os.listdir('./shadow'))
Warning: There are more logs available. Please set a larger limit to export more data.
[‘shadowdeploylogs-1.json’]
A/B Testing Pipeline
A/B testing allows inference requests to be split between a control model and one or more challenger models. For full details, see the Pipeline Management Guide: A/B Testing.
When the inference results and log entries are displayed, they include the column out._model_split
which displays:
Field | Type | Description |
---|---|---|
name | String | The model name used for the inference. |
version | String | The version of the model. |
sha | String | The sha hash of the model version. |
For this example, the shadow deployed step will be removed and replaced with an A/B Testing step with the ratio 1:1:1, so the control and each of the challenger models will be split randomly between inference requests. A set of sample inferences will be run, then the pipeline logs displayed.
pipeline = (wl.build_pipeline(“randomsplitpipeline-demo”)
.add_random_split([(2, control), (1, challenger)], “session_id”))
mainpipeline.undeploy()
# remove the shadow deploy steps
mainpipeline.clear()
# Add the a/b test step to the pipeline
mainpipeline.add_random_split([(1, housing_model_control), (1, housing_model_challenger01), (1, housing_model_challenger02)], "session_id")
mainpipeline.deploy()
# Perform sample inferences of 20 rows and display the results
ab_date_start = datetime.datetime.now()
abtesting_inputs = pd.read_json('./data/xtest-1k.df.json')
for index, row in abtesting_inputs.sample(20).iterrows():
display(mainpipeline.infer(row.to_frame('tensor').reset_index()).loc[:,["out._model_split", "out.variable"]])
ab_date_end = datetime.datetime.now()
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrolchallenger01","version":"87fc1e4e-308a-4e15-824f-dd9e237d00e8","sha":"31e92d6ccb27b041a324a7ac22cf95d9d6cc3aa7e8263a229f7c4aec4938657c"}] | [703914.5] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [1108000.0] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [296411.7] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrolchallenger01","version":"87fc1e4e-308a-4e15-824f-dd9e237d00e8","sha":"31e92d6ccb27b041a324a7ac22cf95d9d6cc3aa7e8263a229f7c4aec4938657c"}] | [1596398.5] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [612753.3] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [1066417.5] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [933591.5] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [342604.47] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [514748.5] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [244174.22] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [701940.7] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrolchallenger01","version":"87fc1e4e-308a-4e15-824f-dd9e237d00e8","sha":"31e92d6ccb27b041a324a7ac22cf95d9d6cc3aa7e8263a229f7c4aec4938657c"}] | [310098.3] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [277145.63] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [348536.3] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [509102.53] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [445993.63] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrolchallenger01","version":"87fc1e4e-308a-4e15-824f-dd9e237d00e8","sha":"31e92d6ccb27b041a324a7ac22cf95d9d6cc3aa7e8263a229f7c4aec4938657c"}] | [377534.8] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [444141.88] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrolchallenger01","version":"87fc1e4e-308a-4e15-824f-dd9e237d00e8","sha":"31e92d6ccb27b041a324a7ac22cf95d9d6cc3aa7e8263a229f7c4aec4938657c"}] | [270508.1] |
out._model_split | out.variable | |
---|---|---|
0 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [245070.95] |
## Get the logs with the a/b testing information
display(mainpipeline.logs(start_datetime=ab_date_start, end_datetime=ab_date_end).loc[:, ["time", "out._model_split", "out.variable"]])
time | out._model_split | out.variable | |
---|---|---|---|
0 | 2023-07-14 15:51:42.630 | [{"name":"logcontrolchallenger01","version":"87fc1e4e-308a-4e15-824f-dd9e237d00e8","sha":"31e92d6ccb27b041a324a7ac22cf95d9d6cc3aa7e8263a229f7c4aec4938657c"}] | [703914.5] |
1 | 2023-07-14 15:51:43.024 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [1108000.0] |
2 | 2023-07-14 15:51:43.426 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [296411.7] |
3 | 2023-07-14 15:51:43.834 | [{"name":"logcontrolchallenger01","version":"87fc1e4e-308a-4e15-824f-dd9e237d00e8","sha":"31e92d6ccb27b041a324a7ac22cf95d9d6cc3aa7e8263a229f7c4aec4938657c"}] | [1596398.5] |
4 | 2023-07-14 15:51:44.224 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [612753.3] |
5 | 2023-07-14 15:51:44.641 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [1066417.5] |
6 | 2023-07-14 15:51:45.046 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [933591.5] |
7 | 2023-07-14 15:51:45.453 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [342604.47] |
8 | 2023-07-14 15:51:45.846 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [514748.5] |
9 | 2023-07-14 15:51:46.235 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [244174.22] |
10 | 2023-07-14 15:51:46.644 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [701940.7] |
11 | 2023-07-14 15:51:47.504 | [{"name":"logcontrolchallenger01","version":"87fc1e4e-308a-4e15-824f-dd9e237d00e8","sha":"31e92d6ccb27b041a324a7ac22cf95d9d6cc3aa7e8263a229f7c4aec4938657c"}] | [310098.3] |
12 | 2023-07-14 15:51:47.944 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [277145.62] |
13 | 2023-07-14 15:51:48.377 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [348536.3] |
14 | 2023-07-14 15:51:48.783 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [509102.53] |
15 | 2023-07-14 15:51:49.196 | [{"name":"logcontrolchallenger02","version":"e4c298b0-fbf5-42e1-b352-4f752935830e","sha":"ed6065a79d841f7e96307bb20d5ef22840f15da0b587efb51425c7ad60589d6a"}] | [445993.62] |
16 | 2023-07-14 15:51:49.618 | [{"name":"logcontrolchallenger01","version":"87fc1e4e-308a-4e15-824f-dd9e237d00e8","sha":"31e92d6ccb27b041a324a7ac22cf95d9d6cc3aa7e8263a229f7c4aec4938657c"}] | [377534.8] |
17 | 2023-07-14 15:51:50.096 | [{"name":"logcontrol","version":"9d3e0500-0272-4337-863b-539657d74aaa","sha":"e22a0831aafd9917f3cc87a15ed267797f80e2afa12ad7d8810ca58f173b8cc6"}] | [444141.88] |
18 | 2023-07-14 15:51:50.491 | [{"name":"logcontrolchallenger01","version":"87fc1e4e-308a-4e15-824f-dd9e237d00e8","sha":"31e92d6ccb27b041a324a7ac22cf95d9d6cc3aa7e8263a229f7c4aec4938657c"}] | [270508.1] |
# Save a/b testing log files as DataFrame
mainpipeline.export_logs(limit=1000,directory="abtesting", file_prefix="abtests")
display(os.listdir('./abtesting'))
Note: The logs with different schemas are written to separate files in the provided directory.
[‘abtests-3.json’, ‘abtests-2.json’, ‘abtests-1.json’]
Undeploy Main Pipeline
With the examples and tutorial complete, we will undeploy the main pipeline and return the resources back to the Wallaroo instance.
mainpipeline.undeploy()
name | logpipeline |
---|---|
created | 2023-07-14 15:49:23.959261+00:00 |
last_updated | 2023-07-14 15:51:27.112803+00:00 |
deployed | False |
tags | |
versions | 76a98987-721e-4ea7-8dc2-4380ad06d6a8, f5b3e05b-297d-44a0-8645-86897ded3031, 48ec856b-9640-4a04-83f6-77a9bd205a44, 8a9d1d69-d71d-4c0a-9c95-99b3f86dcbc7 |
steps | logcontrol |