From 50f7756f265b726a8f06ef23ceb29d838f27f79b Mon Sep 17 00:00:00 2001 From: tmartins Date: Mon, 1 Aug 2022 06:00:01 -0300 Subject: [PATCH 1/8] add tensorflow via onnx tutorial --- .../use_cases/tensorflow-via-onnx.ipynb | 1540 +++++++++++++++++ 1 file changed, 1540 insertions(+) create mode 100644 docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb diff --git a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb new file mode 100644 index 00000000..d6b168c7 --- /dev/null +++ b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb @@ -0,0 +1,1540 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "45d00d06", + "metadata": {}, + "outputs": [], + "source": [ + "!pip3 install -Uqq pyvespa ir_datasets numpy pandas tensorflow tensorflow_ranking onnx tf2onnx" + ] + }, + { + "cell_type": "markdown", + "id": "e9b8f34d-4ece-4f3f-b01b-df7df32a279f", + "metadata": {}, + "source": [ + "This tutorial will cover the following steps:\n", + "\n", + "1. Download labeled data containing Vespa ranking features.\n", + "2. Create a listwise dataset based on a TensorFlow data pipeline.\n", + "3. Train a Learning to Rank model (LTR) model using the TensorFlow Ranking framework.\n", + "4. Simplify the LTR model to be suitable for ranking in Vespa\n", + "5. Convert to TensorFlow model to ONNX file format.\n", + "6. Create and deploy a Vespa application that uses the TensorFlow model\n", + "7. Feed data to the Vespa application\n", + "8. Ensure that prediction from the model deployed to Vespa match those obtained from the model directly." + ] + }, + { + "cell_type": "markdown", + "id": "f16ae8a4", + "metadata": {}, + "source": [ + "## Get the data" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "10c34b6b-fc26-4e6d-b28a-e20fd32c08c7", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd" + ] + }, + { + "cell_type": "markdown", + "id": "2df15e9c-31da-4e67-a9dd-0d2bf8f0478c", + "metadata": {}, + "source": [ + "Download labaled data containing Vespa ranking features collected from a MS Marco passage ranking application." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "fd0dede9", + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.read_csv(\"https://data.vespa.oath.cloud/blog/ranking/train_sample.csv\")\n", + "df = df[\n", + " [\"document_id\", \n", + " \"query_id\", \n", + " \"label\", \n", + " \"fieldMatch(body).queryCompleteness\",\n", + " \"fieldMatch(body).significance\",\n", + " \"nativeRank\",\n", + " ]\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "228e5b70", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(100000, 6)" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.shape" + ] + }, + { + "cell_type": "markdown", + "id": "4f7136b0-64e3-4f44-a665-c7a53713e7f9", + "metadata": {}, + "source": [ + "For each `query_id`, there is 9 irrelevant `document_id` with `label = 0` and 1 relevant `document_id` with `label = 1`." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "7757b80d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
document_idquery_idlabelfieldMatch(body).queryCompletenessfieldMatch(body).significancenativeRank
027061300.6250.5663110.042421
1257300.6250.5825700.039192
2363300.5000.4660300.034418
322682300.6250.5663110.061149
4160300.5000.4378080.035017
5228300.5000.4378080.032697
63901893300.7500.7480640.074917
71142680310.7500.7480640.099112
8141300.5000.4428790.038093
93060834300.7500.7639330.075347
\n", + "
" + ], + "text/plain": [ + " document_id query_id label fieldMatch(body).queryCompleteness \\\n", + "0 27061 3 0 0.625 \n", + "1 257 3 0 0.625 \n", + "2 363 3 0 0.500 \n", + "3 22682 3 0 0.625 \n", + "4 160 3 0 0.500 \n", + "5 228 3 0 0.500 \n", + "6 3901893 3 0 0.750 \n", + "7 1142680 3 1 0.750 \n", + "8 141 3 0 0.500 \n", + "9 3060834 3 0 0.750 \n", + "\n", + " fieldMatch(body).significance nativeRank \n", + "0 0.566311 0.042421 \n", + "1 0.582570 0.039192 \n", + "2 0.466030 0.034418 \n", + "3 0.566311 0.061149 \n", + "4 0.437808 0.035017 \n", + "5 0.437808 0.032697 \n", + "6 0.748064 0.074917 \n", + "7 0.748064 0.099112 \n", + "8 0.442879 0.038093 \n", + "9 0.763933 0.075347 " + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head(10)" + ] + }, + { + "cell_type": "markdown", + "id": "d90857ac", + "metadata": {}, + "source": [ + "## Create a listwise dataset" + ] + }, + { + "cell_type": "markdown", + "id": "1df6ee38-dec1-44d9-af15-b819f2a6614c", + "metadata": {}, + "source": [ + "Define some parameters required to setup the listwise data pipeline." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "18b36a0f", + "metadata": {}, + "outputs": [], + "source": [ + "number_documents_per_query = 10 \n", + "feature_names = [ \n", + " \"fieldMatch(body).queryCompleteness\", \n", + " \"fieldMatch(body).significance\", \n", + " \"nativeRank\"\n", + "]\n", + "number_features = len(feature_names)\n", + "batch_size=32" + ] + }, + { + "cell_type": "markdown", + "id": "92617ab4-59eb-46f7-85c8-17ea949230a3", + "metadata": {}, + "source": [ + "Each feature data point will have the shape equal to `(batch_size, number_documents_per_query, number_features)` and each label data point will have shape equal to `(batch_size, number_documents_per_query)`." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "b5fc4197-cfa6-44b9-8d4a-797ee1a45eba", + "metadata": {}, + "outputs": [], + "source": [ + "import tensorflow as tf" + ] + }, + { + "cell_type": "markdown", + "id": "898d702f-78e4-4b38-820c-7efe64b8511f", + "metadata": {}, + "source": [ + "The code below creates a TensorFlow data pipeline (`tf.data.Dataset`) from our DataFrame and group the rows by the `query_id` variable to form a listwise dataset. We then configure the data pipeline to shuffle and set a batch size." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "dfa6061f", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-08-01 05:46:20.107665: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA\n", + "To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n" + ] + } + ], + "source": [ + "shuffle_buffer_size = 10000\n", + "ds = tf.data.Dataset.from_tensor_slices(\n", + " {\n", + " \"features\": tf.cast(df[feature_names].values, tf.float32),\n", + " \"label\": tf.cast(df[\"label\"].values, tf.float32),\n", + " \"query_id\": tf.cast(df[\"query_id\"].values, tf.int64),\n", + " }\n", + ")\n", + "\n", + "key_func = lambda x: x[\"query_id\"]\n", + "reduce_func = lambda key, dataset: dataset.batch(\n", + " number_documents_per_query, drop_remainder=True\n", + ")\n", + "listwise_ds = ds.group_by_window(\n", + " key_func=key_func,\n", + " reduce_func=reduce_func,\n", + " window_size=number_documents_per_query,\n", + ")\n", + "listwise_ds = listwise_ds.map(lambda x: (x[\"features\"], x[\"label\"]))\n", + "listwise_ds = listwise_ds.shuffle(buffer_size=shuffle_buffer_size).batch(\n", + " batch_size=batch_size\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "f465be76-0794-4269-9567-b5dd99b21221", + "metadata": {}, + "source": [ + "We can see the shape of the `features` and of the `labels` are as expected." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "273144fe", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(32, 10, 3)\n", + "(32, 10)\n" + ] + } + ], + "source": [ + "for d in listwise_ds.take(1):\n", + " print(d[0].shape)\n", + " print(d[1].shape)" + ] + }, + { + "cell_type": "markdown", + "id": "1a96ae0e", + "metadata": {}, + "source": [ + "## Create and compile model" + ] + }, + { + "cell_type": "markdown", + "id": "4d79f9cb-4971-4a09-a2d3-c6b2eaacb7a6", + "metadata": {}, + "source": [ + "We are going to create a linear model that can take a listwise data as input with shape `(batch_size, number_documents_per_query, number_features)` and output one prediction per document with shape `(batch_size, number_documents_per_query)`" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "3870f9df", + "metadata": {}, + "outputs": [], + "source": [ + "input_layer = tf.keras.layers.Input(shape=(number_documents_per_query, number_features))\n", + "dense_layer = tf.keras.layers.Dense(\n", + " 1,\n", + " use_bias=False,\n", + " activation=None,\n", + " name=\"dense\"\n", + ")\n", + "output_layer = tf.keras.layers.Reshape((number_documents_per_query,))" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "c247e8a3", + "metadata": {}, + "outputs": [], + "source": [ + "model = tf.keras.Sequential(layers=[input_layer, dense_layer, output_layer])" + ] + }, + { + "cell_type": "markdown", + "id": "f92a6ecc-0579-4ff3-8430-f96f33e417e7", + "metadata": {}, + "source": [ + "In this tutorial, we want to optimize the [Normalized Discounted Cumulative Gain](https://en.wikipedia.org/wiki/Discounted_cumulative_gain#Normalized_DCG) at position 10 (NDCG@10). We then select a loss function that is a smooth approximation of the NDCG metric and create a stateless NDCG@10 metric to use when compiling the model defined above." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "b1df7a81", + "metadata": {}, + "outputs": [], + "source": [ + "import tensorflow_ranking as tfr\n", + "\n", + "ndcg = tfr.keras.metrics.NDCGMetric(topn=10)\n", + "def ndcg_stateless(y_true, y_pred):\n", + " \"\"\"\n", + " Create stateless metric so that we can compute the validation metric \n", + " from scratch at the end of each epoch.\n", + " \"\"\"\n", + " ndcg.reset_states()\n", + " return ndcg(y_true, y_pred)\n", + "\n", + "optimizer = tf.keras.optimizers.Adagrad(learning_rate=2)\n", + "model.compile(\n", + " optimizer=optimizer,\n", + " loss=tfr.keras.losses.ApproxNDCGLoss(),\n", + " metrics=ndcg_stateless,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "cef81f6a-2276-49f8-ab3d-fd588076085b", + "metadata": {}, + "source": [ + "Use the listwise dataset to fit the model:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0fbce1d3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/20\n", + "304/304 [==============================] - 4s 2ms/step - loss: -0.5840 - ndcg_stateless: 0.6154\n", + "Epoch 2/20\n", + "304/304 [==============================] - 1s 1ms/step - loss: -0.6966 - ndcg_stateless: 0.7193\n", + "Epoch 3/20\n", + "304/304 [==============================] - 1s 1ms/step - loss: -0.7205 - ndcg_stateless: 0.7542\n", + "Epoch 4/20\n", + "304/304 [==============================] - 1s 1ms/step - loss: -0.7328 - ndcg_stateless: 0.7633\n", + "Epoch 5/20\n", + "304/304 [==============================] - 1s 950us/step - loss: -0.7384 - ndcg_stateless: 0.7660\n", + "Epoch 6/20\n", + "304/304 [==============================] - 1s 953us/step - loss: -0.7418 - ndcg_stateless: 0.7674\n", + "Epoch 7/20\n", + "304/304 [==============================] - 1s 1ms/step - loss: -0.7439 - ndcg_stateless: 0.7662\n", + "Epoch 8/20\n", + "304/304 [==============================] - 1s 1ms/step - loss: -0.7455 - ndcg_stateless: 0.7688\n", + "Epoch 9/20\n", + "304/304 [==============================] - 1s 1ms/step - loss: -0.7468 - ndcg_stateless: 0.7685\n", + "Epoch 10/20\n", + "304/304 [==============================] - 1s 1ms/step - loss: -0.7478 - ndcg_stateless: 0.7700\n", + "Epoch 11/20\n", + "304/304 [==============================] - 1s 1ms/step - loss: -0.7488 - ndcg_stateless: 0.7685\n", + "Epoch 12/20\n", + "304/304 [==============================] - 1s 1ms/step - loss: -0.7494 - ndcg_stateless: 0.7680\n", + "Epoch 13/20\n", + "304/304 [==============================] - 1s 954us/step - loss: -0.7501 - ndcg_stateless: 0.7704\n", + "Epoch 14/20\n", + "304/304 [==============================] - 1s 956us/step - loss: -0.7506 - ndcg_stateless: 0.7690\n", + "Epoch 15/20\n", + "304/304 [==============================] - 1s 959us/step - loss: -0.7513 - ndcg_stateless: 0.7689\n", + "Epoch 16/20\n", + "304/304 [==============================] - 1s 934us/step - loss: -0.7516 - ndcg_stateless: 0.7686\n", + "Epoch 17/20\n", + "304/304 [==============================] - 1s 963us/step - loss: -0.7521 - ndcg_stateless: 0.7691\n", + "Epoch 18/20\n", + "304/304 [==============================] - 1s 980us/step - loss: -0.7524 - ndcg_stateless: 0.7689\n", + "Epoch 19/20\n", + "304/304 [==============================] - 1s 1ms/step - loss: -0.7528 - ndcg_stateless: 0.7692\n", + "Epoch 20/20\n", + "304/304 [==============================] - 1s 940us/step - loss: -0.7531 - ndcg_stateless: 0.7700\n" + ] + } + ], + "source": [ + "history = model.fit(listwise_ds, epochs=20)" + ] + }, + { + "cell_type": "markdown", + "id": "4a8624f1", + "metadata": {}, + "source": [ + "## Simplify model input/output for deployment" + ] + }, + { + "cell_type": "markdown", + "id": "11289353-1363-47da-a57a-2c8c93d90732", + "metadata": {}, + "source": [ + "After training the model by minimizing a listwise loss function, we can simplify the model before deploying it to Vespa. At inference time, Vespa will evaluate each document individually and use a ranking function to rank documents.\n", + "\n", + "Therefore, the input layer will expect a tensor named `input` with shape equal to `(1, number_features)`." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "63458df7", + "metadata": {}, + "outputs": [], + "source": [ + "simpler_model = tf.keras.Sequential(\n", + " [tf.keras.layers.Input(shape=(number_features,), batch_size=1, name=\"input\"), \n", + " dense_layer\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "211dd9d1-6a54-435a-b129-35cf465bf483", + "metadata": {}, + "source": [ + "We are going to save the `simpler_model` to disk and then use the tf2onnx tool to convert the model to ONNX format." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "07e3084d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING:tensorflow:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.\n", + "INFO:tensorflow:Assets written to: simpler_keras_model/assets\n" + ] + } + ], + "source": [ + "simpler_model.save(\"simpler_keras_model\")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "0ac7602c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/usr/local/Cellar/python@3.8/3.8.13_1/Frameworks/Python.framework/Versions/3.8/lib/python3.8/runpy.py:127: RuntimeWarning: 'tf2onnx.convert' found in sys.modules after import of package 'tf2onnx', but prior to execution of 'tf2onnx.convert'; this may result in unpredictable behaviour\n", + " warn(RuntimeWarning(msg))\n", + "2022-08-01 05:46:51,978 - WARNING - '--tag' not specified for saved_model. Using --tag serve\n", + "2022-08-01 05:46:52,055 - INFO - Signatures found in model: [serving_default].\n", + "2022-08-01 05:46:52,055 - WARNING - '--signature_def' not specified, using first signature: serving_default\n", + "2022-08-01 05:46:52,056 - INFO - Output names: ['dense']\n", + "WARNING:tensorflow:From /Users/tmartins/.local/share/virtualenvs/_notebooks-Uz0RYSIe/lib/python3.8/site-packages/tf2onnx/tf_loader.py:711: extract_sub_graph (from tensorflow.python.framework.graph_util_impl) is deprecated and will be removed in a future version.\n", + "Instructions for updating:\n", + "Use `tf.compat.v1.graph_util.extract_sub_graph`\n", + "2022-08-01 05:46:52,084 - WARNING - From /Users/tmartins/.local/share/virtualenvs/_notebooks-Uz0RYSIe/lib/python3.8/site-packages/tf2onnx/tf_loader.py:711: extract_sub_graph (from tensorflow.python.framework.graph_util_impl) is deprecated and will be removed in a future version.\n", + "Instructions for updating:\n", + "Use `tf.compat.v1.graph_util.extract_sub_graph`\n", + "2022-08-01 05:46:52,095 - INFO - Using tensorflow=2.9.1, onnx=1.12.0, tf2onnx=1.12.0/a58786\n", + "2022-08-01 05:46:52,095 - INFO - Using opset \n", + "2022-08-01 05:46:52,098 - INFO - Computed 0 values for constant folding\n", + "2022-08-01 05:46:52,105 - INFO - Optimizing ONNX model\n", + "2022-08-01 05:46:52,120 - INFO - After optimization: Identity -5 (5->0)\n", + "2022-08-01 05:46:52,122 - INFO - \n", + "2022-08-01 05:46:52,122 - INFO - Successfully converted TensorFlow model simpler_keras_model to ONNX\n", + "2022-08-01 05:46:52,122 - INFO - Model inputs: ['input']\n", + "2022-08-01 05:46:52,122 - INFO - Model outputs: ['dense']\n", + "2022-08-01 05:46:52,123 - INFO - ONNX model is saved at simpler_keras_model.onnx\n" + ] + } + ], + "source": [ + "from tf2onnx import convert\n", + "\n", + "!python3 -m tf2onnx.convert --saved-model simpler_keras_model --output simpler_keras_model.onnx" + ] + }, + { + "cell_type": "markdown", + "id": "18e41cd5-23bb-4fe2-863b-1e5d29b7d45f", + "metadata": {}, + "source": [ + "We can inspect the onnx model input and output. We first load the ONNX model:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "3c61ed44", + "metadata": {}, + "outputs": [], + "source": [ + "import onnx \n", + "\n", + "m = onnx.load(\"simpler_keras_model.onnx\")" + ] + }, + { + "cell_type": "markdown", + "id": "e82fd69f-64d2-4503-8b63-1490ff846987", + "metadata": {}, + "source": [ + "As mentioned before, the model expects a tensor named `input` with shape `(1, 3)`." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "2b903c6a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[name: \"input\"\n", + "type {\n", + " tensor_type {\n", + " elem_type: 1\n", + " shape {\n", + " dim {\n", + " dim_value: 1\n", + " }\n", + " dim {\n", + " dim_value: 3\n", + " }\n", + " }\n", + " }\n", + "}\n", + "]" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m.graph.input" + ] + }, + { + "cell_type": "markdown", + "id": "ac7ce858-5b83-4a18-82cf-91b6a45cbb2d", + "metadata": {}, + "source": [ + "The output will be a tensor named `dense` with shape `(1,1)`." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "5e3e0cd7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[name: \"dense\"\n", + "type {\n", + " tensor_type {\n", + " elem_type: 1\n", + " shape {\n", + " dim {\n", + " dim_value: 1\n", + " }\n", + " dim {\n", + " dim_value: 1\n", + " }\n", + " }\n", + " }\n", + "}\n", + "]" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "m.graph.output" + ] + }, + { + "cell_type": "markdown", + "id": "adf25667", + "metadata": {}, + "source": [ + "## Define the application package" + ] + }, + { + "cell_type": "markdown", + "id": "5a38f0be-7f8c-41c0-8bcd-b29e708ea6e2", + "metadata": {}, + "source": [ + "This section will use the Vespa python API `pyvespa` to create an application package with a ranking function that uses the tensorflow model exported to ONNX. " + ] + }, + { + "cell_type": "markdown", + "id": "ae9584db-bdb4-408b-b4fd-99365c49d60f", + "metadata": {}, + "source": [ + "The data used to train the model was derived from a Vespa application based on the ms marco passage dataset. So, we are going to name the application `msmarco`, and start by adding two fields: `id` to hold the document id and `text` to hold the passages from the msmarco dataset." + ] + }, + { + "cell_type": "markdown", + "id": "429a8185-4207-4b92-87dc-262d8fa11f14", + "metadata": {}, + "source": [ + "`indexing` configuration: We add `\"summary\"` to the `indexing` parameter because we want to include both the `id` and the `text` field in the query results. The `\"attribute\"` indicates that the field `id` will be stored in-memory. The `\"index\"` indicates that Vespa will create a search index for the `text` field." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "8216ee71-3f90-437c-8162-aed12175a947", + "metadata": {}, + "outputs": [], + "source": [ + "from vespa.package import ApplicationPackage, Field\n", + "\n", + "app_package = ApplicationPackage(name=\"msmarco\")\n", + "\n", + "app_package.schema.add_fields(\n", + " Field(name=\"id\", type=\"string\", indexing=[\"summary\", \"attribute\"]),\n", + " Field(name=\"text\", type=\"string\", indexing=[\"summary\", \"index\"])\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "594b155c-ccc5-4d55-bed6-726883c106bf", + "metadata": {}, + "source": [ + "Note that at each step along the application package definition, we can inspect the content of the Vespa search definition file:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "e3390ae4-f915-4175-9483-2afc0f3433d4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "schema msmarco {\n", + " document msmarco {\n", + " field id type string {\n", + " indexing: summary | attribute\n", + " }\n", + " field text type string {\n", + " indexing: summary | index\n", + " }\n", + " }\n", + "}\n" + ] + } + ], + "source": [ + "print(app_package.schema.schema_to_text)" + ] + }, + { + "cell_type": "markdown", + "id": "901179db-54e7-4bac-b734-b294072da120", + "metadata": {}, + "source": [ + "Add `simpler_keras_model.onnx` to the schema. \n", + "* The `model_name` is an id that can be used in the ranking function to identify which model to use. \n", + "* The `model_file_path` is the current path of the .onnx file. When deploying the application, `pyvespa` will move the file to the correct location inside the Vespa application package folder.\n", + "* The `inputs` maps the name of the inputs contained in the ONNX model to the name of the Vespa source that will be used as input to the model. In this case we will create a function called `vespa_input` that output a tensor of type float with the expected shape `(1, 3)`.\n", + "* The `outputs` maps the output name in the ONNX file to the output name that will be recognized by Vespa." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "26d8c14a-5f3a-4ab7-a7f3-77c0ec7fa2c3", + "metadata": {}, + "outputs": [], + "source": [ + "from vespa.package import OnnxModel\n", + "\n", + "app_package.schema.add_model(\n", + " OnnxModel(\n", + " model_name=\"ltr_tensorflow\",\n", + " model_file_path=\"simpler_keras_model.onnx\",\n", + " inputs={\"input\": \"vespa_input\"},\n", + " outputs={\"dense\": \"dense\"},\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "58c77a85-b85b-4e6e-bbee-c50a115b55a5", + "metadata": {}, + "source": [ + "It is possible to see the addition of the `onnx-model` section in the search definition below. Note that the model file is expected to be under the `files` folder inside the final application package folder, but `pyvespa` takes care of the model file placement when deploying the application." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "7fa5a806-5976-4085-967a-35534e02421b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "schema msmarco {\n", + " document msmarco {\n", + " field id type string {\n", + " indexing: summary | attribute\n", + " }\n", + " field text type string {\n", + " indexing: summary | index\n", + " }\n", + " }\n", + " onnx-model ltr_tensorflow {\n", + " file: files/ltr_tensorflow.onnx\n", + " input input: vespa_input\n", + " output dense: dense\n", + " }\n", + "}\n" + ] + } + ], + "source": [ + "print(app_package.schema.schema_to_text)" + ] + }, + { + "cell_type": "markdown", + "id": "936807d9-3103-40cf-a82e-b1ccd26d8081", + "metadata": {}, + "source": [ + "Add a rank profile named `tensorflow` that uses the TensorFlow model to rank documents. \n", + "* `first_phase`: We use the Vespa ranking feature `onnx` to access the ONNX model named `ltr_tensorflow` and use the output `dense`. We apply the `sum` because Vespa requires the relevance score to be a scaler and the output of the ONNX model in this case is a tensor of shape `(1,1)`.\n", + "* `vespa_input` function: The ONNX model was trained with the features `fieldMatch(text).queryCompleteness`, `fieldMatch(text).significance` and `nativeRank(text)` and expects and tensor of shape `(1,3)` containing those features.\n", + "* `summary_features`: Summary features allow us to specify Vespa features to be included in the output of a query. In this case, we want to access to the model inputs and output to check if the Vespa model evaluation is the same as if we use the original TensorFlow model." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "8cc8dc31", + "metadata": {}, + "outputs": [], + "source": [ + "from vespa.package import RankProfile, Function\n", + "\n", + "app_package.schema.add_rank_profile(\n", + " RankProfile(\n", + " name=\"tensorflow\", \n", + " first_phase=\"sum(onnx(ltr_tensorflow).dense)\", \n", + " functions=[\n", + " Function(\n", + " name=\"vespa_input\", \n", + " expression=\"tensor(x[1],y[3]):[[\"\n", + " \"fieldMatch(text).queryCompleteness, \"\n", + " \"fieldMatch(text).significance, \"\n", + " \"nativeRank(text)\"\n", + " \"]]\"\n", + " )\n", + " ],\n", + " summary_features=[\n", + " \"onnx(ltr_tensorflow)\", \n", + " \"fieldMatch(text).queryCompleteness\", \n", + " \"fieldMatch(text).significance\", \n", + " \"nativeRank(text)\"\n", + " ]\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "dd65efef-8e79-44b9-9d2c-bca8f4e3faf6", + "metadata": {}, + "source": [ + "The `rank-profile` called tensorflow can be seen below:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "a750f2d2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "schema msmarco {\n", + " document msmarco {\n", + " field id type string {\n", + " indexing: summary | attribute\n", + " }\n", + " field text type string {\n", + " indexing: summary | index\n", + " }\n", + " }\n", + " onnx-model ltr_tensorflow {\n", + " file: files/ltr_tensorflow.onnx\n", + " input input: vespa_input\n", + " output dense: dense\n", + " }\n", + " rank-profile tensorflow {\n", + " function vespa_input() {\n", + " expression {\n", + " tensor(x[1],y[3]):[[fieldMatch(text).queryCompleteness, fieldMatch(text).significance, nativeRank(text)]]\n", + " }\n", + " }\n", + " first-phase {\n", + " expression: sum(onnx(ltr_tensorflow).dense)\n", + " }\n", + " summary-features {\n", + " onnx(ltr_tensorflow)\n", + " fieldMatch(text).queryCompleteness\n", + " fieldMatch(text).significance\n", + " nativeRank(text)\n", + " }\n", + " }\n", + "}\n" + ] + } + ], + "source": [ + "print(app_package.schema.schema_to_text)" + ] + }, + { + "cell_type": "markdown", + "id": "82c6d94c-870b-4824-a6cb-7ef5ef85bd05", + "metadata": {}, + "source": [ + "Now that we are done with the application package definition. We can deploy the application:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "91408c5b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Waiting for configuration server, 0/300 seconds...\n", + "Waiting for configuration server, 5/300 seconds...\n", + "Waiting for configuration server, 10/300 seconds...\n", + "Waiting for configuration server, 15/300 seconds...\n", + "Waiting for application status, 0/300 seconds...\n", + "Waiting for application status, 5/300 seconds...\n", + "Waiting for application status, 10/300 seconds...\n", + "Waiting for application status, 15/300 seconds...\n", + "Waiting for application status, 20/300 seconds...\n", + "Waiting for application status, 25/300 seconds...\n", + "Waiting for application status, 30/300 seconds...\n", + "Finished deployment.\n" + ] + } + ], + "source": [ + "from vespa.deployment import VespaDocker\n", + "\n", + "vespa_docker = VespaDocker()\n", + "app = vespa_docker.deploy(application_package=app_package)" + ] + }, + { + "cell_type": "markdown", + "id": "78607f9a", + "metadata": {}, + "source": [ + "## Feed the application" + ] + }, + { + "cell_type": "markdown", + "id": "172242da-a942-4ff4-8095-c7f16a2f9ee7", + "metadata": {}, + "source": [ + "Once the application is running, it is time to feed msmarco passage data to it. The code below use the awesome `ir_datasets`. Be aware that the first time you `load` a dataset, it will download it and it might take some time depending on your internet speed." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "fa1b3f60", + "metadata": {}, + "outputs": [], + "source": [ + "import ir_datasets\n", + "\n", + "dataset = ir_datasets.load(\"msmarco-passage\")" + ] + }, + { + "cell_type": "markdown", + "id": "c65ae672-f618-41a2-b6a8-39ff3ba24762", + "metadata": {}, + "source": [ + "We are going to use only 10 documents because our goal here is to show that Vespa returns the correct predictions from the TensorFlow model." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "b9a79d1c", + "metadata": {}, + "outputs": [], + "source": [ + "data = pd.DataFrame(dataset.docs_iter()[:10])\n", + "data.rename(columns={'doc_id': 'id'}, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "4c9d972a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
idtext
00The presence of communication amid scientific ...
11The Manhattan Project and its atomic bomb help...
22Essay on The Manhattan Project - The Manhattan...
33The Manhattan Project was the name for a proje...
44versions of each volume as well as complementa...
\n", + "
" + ], + "text/plain": [ + " id text\n", + "0 0 The presence of communication amid scientific ...\n", + "1 1 The Manhattan Project and its atomic bomb help...\n", + "2 2 Essay on The Manhattan Project - The Manhattan...\n", + "3 3 The Manhattan Project was the name for a proje...\n", + "4 4 versions of each volume as well as complementa..." + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "f4be6af3-8cfe-440f-ac90-51f3b0cce802", + "metadata": {}, + "source": [ + "Feed the `data` to the application." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "a0521de2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Successful documents fed: 10/10.\n", + "Batch progress: 1/1.\n" + ] + } + ], + "source": [ + "result = app.feed_df(df=data, include_id=True)" + ] + }, + { + "cell_type": "markdown", + "id": "eb7df3f0", + "metadata": {}, + "source": [ + "## Validate Vespa predictions" + ] + }, + { + "cell_type": "markdown", + "id": "ca2a90f9-1ea9-4737-93df-bf667c2f5f23", + "metadata": {}, + "source": [ + "Get query from the small dev set to use to validate Vespa TensorFlow predictions." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "ed63f2fc", + "metadata": {}, + "outputs": [], + "source": [ + "dev_small = ir_datasets.load(\"msmarco-passage/dev/small\")" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "e9fd5566", + "metadata": {}, + "outputs": [], + "source": [ + "for query in dev_small.queries_iter()[:1]:\n", + " query_text = query[1].replace(\"'\", \"\")" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "433696e4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'what is paula deens brother'" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "query_text" + ] + }, + { + "cell_type": "markdown", + "id": "e0ec295b-07cf-4047-92ea-57547c8d4094", + "metadata": {}, + "source": [ + "The code below shows the YQL expression that will be used to select the documents to be ranked." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "6ee901a2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"select * from sources * where ({'grammar': 'any', 'defaultIndex': 'text'}userInput('what is paula deens brother'));\"" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"select * from sources * where ({{'grammar': 'any', 'defaultIndex': 'text'}}userInput('{}'));\".format(query_text)" + ] + }, + { + "cell_type": "markdown", + "id": "8a6943a3-93e2-476b-8b69-70ce30cff93b", + "metadata": {}, + "source": [ + "The function `get_vespa_prediction_and_features` will match documents using the YQL expression above and rank the documents with the rank-profile `tensorflow` that we defined in the Vespa application package." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "198733ee", + "metadata": {}, + "outputs": [], + "source": [ + "def get_vespa_prediction_and_features(query_text):\n", + " # Send query and extract hits\n", + " hits = app.query(\n", + " body={\n", + " \"yql\": \"select * from sources * where ({{'grammar': 'any', 'defaultIndex': 'text'}}userInput('{}'));\".format(query_text),\n", + " \"ranking\": \"tensorflow\"\n", + " }\n", + " ).hits\n", + " result =[]\n", + " # For each hit, extract the inputs to the model along with model predictions computed by Vespa\n", + " for hit in hits:\n", + " result.append({\n", + " \"fieldMatch(text).queryCompleteness\": hit[\"fields\"][\"summaryfeatures\"][\"fieldMatch(text).queryCompleteness\"],\n", + " \"fieldMatch(text).significance\": hit[\"fields\"][\"summaryfeatures\"][\"fieldMatch(text).significance\"],\n", + " \"nativeRank(text)\": hit[\"fields\"][\"summaryfeatures\"][\"nativeRank(text)\"],\n", + " \"vespa_prediction\": hit[\"relevance\"], \n", + " })\n", + " return pd.DataFrame.from_records(result)" + ] + }, + { + "cell_type": "markdown", + "id": "90f4db93-4b50-4536-9d2c-df4c3733b4d8", + "metadata": {}, + "source": [ + "Inputs and vespa predictions:" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "73763ede", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
fieldMatch(text).queryCompletenessfieldMatch(text).significancenativeRank(text)vespa_prediction
00.20.1347910.016299-0.597079
10.40.2756390.038767-0.914343
\n", + "
" + ], + "text/plain": [ + " fieldMatch(text).queryCompleteness fieldMatch(text).significance \\\n", + "0 0.2 0.134791 \n", + "1 0.4 0.275639 \n", + "\n", + " nativeRank(text) vespa_prediction \n", + "0 0.016299 -0.597079 \n", + "1 0.038767 -0.914343 " + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "predictions = get_vespa_prediction_and_features(query_text=query_text)\n", + "predictions" + ] + }, + { + "cell_type": "markdown", + "id": "11a4cbf6-af0e-4329-aaff-819d677424fc", + "metadata": {}, + "source": [ + "Compute predictions from the TensorFlow model `simpler_model` directly:" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "09e6a7fa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1/1 [==============================] - 0s 150ms/step\n", + "1/1 [==============================] - 0s 32ms/step\n" + ] + } + ], + "source": [ + "predictions[\"tf_prediction\"] = predictions[\n", + " [\"fieldMatch(text).queryCompleteness\", \"fieldMatch(text).significance\", \"nativeRank(text)\"]\n", + "].apply(lambda x: simpler_model.predict([x.tolist()])[0][0], axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "241a332c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
fieldMatch(text).queryCompletenessfieldMatch(text).significancenativeRank(text)vespa_predictiontf_prediction
00.20.1347910.016299-0.597079-0.597079
10.40.2756390.038767-0.914343-0.914342
\n", + "
" + ], + "text/plain": [ + " fieldMatch(text).queryCompleteness fieldMatch(text).significance \\\n", + "0 0.2 0.134791 \n", + "1 0.4 0.275639 \n", + "\n", + " nativeRank(text) vespa_prediction tf_prediction \n", + "0 0.016299 -0.597079 -0.597079 \n", + "1 0.038767 -0.914343 -0.914342 " + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "predictions" + ] + }, + { + "cell_type": "markdown", + "id": "b53bbed0-2f59-4b0a-8a7a-fb28fde5b144", + "metadata": {}, + "source": [ + "Check that the predictions from the model deployed in Vespa are (almost) equal to the predictions obtained directly from the model." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "8e8802d6", + "metadata": {}, + "outputs": [], + "source": [ + "from numpy.testing import assert_almost_equal\n", + "\n", + "assert_almost_equal(predictions[\"vespa_prediction\"].tolist(), predictions[\"tf_prediction\"].tolist(), 5)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "blog", + "language": "python", + "name": "blog" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From c36d50a083ac928a7b3f11a8d2c5046ffcaf39eb Mon Sep 17 00:00:00 2001 From: tmartins Date: Mon, 1 Aug 2022 06:08:34 -0300 Subject: [PATCH 2/8] add to the docs --- docs/sphinx/source/usecases.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sphinx/source/usecases.rst b/docs/sphinx/source/usecases.rst index 75bb3e34..5ea549aa 100644 --- a/docs/sphinx/source/usecases.rst +++ b/docs/sphinx/source/usecases.rst @@ -16,3 +16,4 @@ This space will highlight use cases built with Vespa_. use_cases/sequence-classification-task use_cases/lightgbm-with-categorical use_cases/lightgbm-with-categorical-mapping + use_cases/tensorflow-via-onnx From 63664a2661d4da15a5608fb1a106cc46b4da67bc Mon Sep 17 00:00:00 2001 From: tmartins Date: Mon, 1 Aug 2022 06:40:47 -0300 Subject: [PATCH 3/8] change kernel to python3 --- docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb index d6b168c7..80fc042b 100644 --- a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb +++ b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb @@ -1518,9 +1518,9 @@ ], "metadata": { "kernelspec": { - "display_name": "blog", + "display_name": "Python 3", "language": "python", - "name": "blog" + "name": "python3" }, "language_info": { "codemirror_mode": { From e8ca453d3e8b11d1e1df1a7220f14bebc7a8a380 Mon Sep 17 00:00:00 2001 From: "Thiago G. Martins" Date: Tue, 2 Aug 2022 05:04:44 -0300 Subject: [PATCH 4/8] typo Co-authored-by: Kristian Aune --- docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb index 80fc042b..95e02b2e 100644 --- a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb +++ b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb @@ -50,7 +50,7 @@ "id": "2df15e9c-31da-4e67-a9dd-0d2bf8f0478c", "metadata": {}, "source": [ - "Download labaled data containing Vespa ranking features collected from a MS Marco passage ranking application." + "Download labeled data containing Vespa ranking features collected from an MS Marco passage ranking application." ] }, { From 5362127d88e2bbe459e0eb643fbeb45e587cd189 Mon Sep 17 00:00:00 2001 From: "Thiago G. Martins" Date: Tue, 2 Aug 2022 05:05:37 -0300 Subject: [PATCH 5/8] Typo Co-authored-by: Kristian Aune --- docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb index 95e02b2e..6669b6fa 100644 --- a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb +++ b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb @@ -763,7 +763,7 @@ "id": "ae9584db-bdb4-408b-b4fd-99365c49d60f", "metadata": {}, "source": [ - "The data used to train the model was derived from a Vespa application based on the ms marco passage dataset. So, we are going to name the application `msmarco`, and start by adding two fields: `id` to hold the document id and `text` to hold the passages from the msmarco dataset." + "The data used to train the model was derived from a Vespa application based on the MS Marco passage dataset. So, we are going to name the application `msmarco`, and start by adding two fields: `id` to hold the document id and `text` to hold the passages from the msmarco dataset." ] }, { From f1d0293df773da9fe7ae69b90862da95647e5b79 Mon Sep 17 00:00:00 2001 From: "Thiago G. Martins" Date: Tue, 2 Aug 2022 05:06:53 -0300 Subject: [PATCH 6/8] Simplify YQL Co-authored-by: Kristian Aune --- docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb index 6669b6fa..7275506f 100644 --- a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb +++ b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb @@ -1274,7 +1274,7 @@ } ], "source": [ - "\"select * from sources * where ({{'grammar': 'any', 'defaultIndex': 'text'}}userInput('{}'));\".format(query_text)" + "\"select * from sources * where ({{grammar: 'any', defaultIndex: 'text'}}userInput('{}'))\".format(query_text)" ] }, { From 2870f323250fc328f173d7d4bf8cd895b013ad24 Mon Sep 17 00:00:00 2001 From: tmartins Date: Tue, 2 Aug 2022 05:26:56 -0300 Subject: [PATCH 7/8] remove the warning --- .../use_cases/tensorflow-via-onnx.ipynb | 138 ++++++++---------- 1 file changed, 64 insertions(+), 74 deletions(-) diff --git a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb index 7275506f..e1ab4fc6 100644 --- a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb +++ b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "45d00d06", "metadata": {}, "outputs": [], @@ -37,7 +37,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "id": "10c34b6b-fc26-4e6d-b28a-e20fd32c08c7", "metadata": {}, "outputs": [], @@ -55,7 +55,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "id": "fd0dede9", "metadata": {}, "outputs": [], @@ -74,7 +74,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "id": "228e5b70", "metadata": {}, "outputs": [ @@ -84,7 +84,7 @@ "(100000, 6)" ] }, - "execution_count": 5, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -103,7 +103,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "id": "7757b80d", "metadata": {}, "outputs": [ @@ -257,7 +257,7 @@ "9 0.763933 0.075347 " ] }, - "execution_count": 6, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -284,7 +284,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "id": "18b36a0f", "metadata": {}, "outputs": [], @@ -309,7 +309,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "id": "b5fc4197-cfa6-44b9-8d4a-797ee1a45eba", "metadata": {}, "outputs": [], @@ -330,16 +330,7 @@ "execution_count": 9, "id": "dfa6061f", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2022-08-01 05:46:20.107665: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA\n", - "To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n" - ] - } - ], + "outputs": [], "source": [ "shuffle_buffer_size = 10000\n", "ds = tf.data.Dataset.from_tensor_slices(\n", @@ -362,7 +353,7 @@ "listwise_ds = listwise_ds.map(lambda x: (x[\"features\"], x[\"label\"]))\n", "listwise_ds = listwise_ds.shuffle(buffer_size=shuffle_buffer_size).batch(\n", " batch_size=batch_size\n", - ")\n" + ")" ] }, { @@ -490,45 +481,45 @@ "output_type": "stream", "text": [ "Epoch 1/20\n", - "304/304 [==============================] - 4s 2ms/step - loss: -0.5840 - ndcg_stateless: 0.6154\n", + "304/304 [==============================] - 4s 2ms/step - loss: -0.5089 - ndcg_stateless: 0.5346\n", "Epoch 2/20\n", - "304/304 [==============================] - 1s 1ms/step - loss: -0.6966 - ndcg_stateless: 0.7193\n", + "304/304 [==============================] - 1s 975us/step - loss: -0.7020 - ndcg_stateless: 0.7352\n", "Epoch 3/20\n", - "304/304 [==============================] - 1s 1ms/step - loss: -0.7205 - ndcg_stateless: 0.7542\n", + "304/304 [==============================] - 1s 902us/step - loss: -0.7267 - ndcg_stateless: 0.7621\n", "Epoch 4/20\n", - "304/304 [==============================] - 1s 1ms/step - loss: -0.7328 - ndcg_stateless: 0.7633\n", + "304/304 [==============================] - 1s 930us/step - loss: -0.7357 - ndcg_stateless: 0.7654\n", "Epoch 5/20\n", - "304/304 [==============================] - 1s 950us/step - loss: -0.7384 - ndcg_stateless: 0.7660\n", + "304/304 [==============================] - 1s 905us/step - loss: -0.7399 - ndcg_stateless: 0.7669\n", "Epoch 6/20\n", - "304/304 [==============================] - 1s 953us/step - loss: -0.7418 - ndcg_stateless: 0.7674\n", + "304/304 [==============================] - 1s 948us/step - loss: -0.7426 - ndcg_stateless: 0.7675\n", "Epoch 7/20\n", - "304/304 [==============================] - 1s 1ms/step - loss: -0.7439 - ndcg_stateless: 0.7662\n", + "304/304 [==============================] - 1s 921us/step - loss: -0.7448 - ndcg_stateless: 0.7678\n", "Epoch 8/20\n", - "304/304 [==============================] - 1s 1ms/step - loss: -0.7455 - ndcg_stateless: 0.7688\n", + "304/304 [==============================] - 1s 963us/step - loss: -0.7463 - ndcg_stateless: 0.7675\n", "Epoch 9/20\n", - "304/304 [==============================] - 1s 1ms/step - loss: -0.7468 - ndcg_stateless: 0.7685\n", + "304/304 [==============================] - 1s 923us/step - loss: -0.7474 - ndcg_stateless: 0.7680\n", "Epoch 10/20\n", - "304/304 [==============================] - 1s 1ms/step - loss: -0.7478 - ndcg_stateless: 0.7700\n", + "304/304 [==============================] - 1s 925us/step - loss: -0.7484 - ndcg_stateless: 0.7700\n", "Epoch 11/20\n", - "304/304 [==============================] - 1s 1ms/step - loss: -0.7488 - ndcg_stateless: 0.7685\n", + "304/304 [==============================] - 1s 1ms/step - loss: -0.7491 - ndcg_stateless: 0.7679\n", "Epoch 12/20\n", - "304/304 [==============================] - 1s 1ms/step - loss: -0.7494 - ndcg_stateless: 0.7680\n", + "304/304 [==============================] - 1s 953us/step - loss: -0.7500 - ndcg_stateless: 0.7693\n", "Epoch 13/20\n", - "304/304 [==============================] - 1s 954us/step - loss: -0.7501 - ndcg_stateless: 0.7704\n", + "304/304 [==============================] - 1s 915us/step - loss: -0.7504 - ndcg_stateless: 0.7697\n", "Epoch 14/20\n", - "304/304 [==============================] - 1s 956us/step - loss: -0.7506 - ndcg_stateless: 0.7690\n", + "304/304 [==============================] - 1s 1ms/step - loss: -0.7511 - ndcg_stateless: 0.7702\n", "Epoch 15/20\n", - "304/304 [==============================] - 1s 959us/step - loss: -0.7513 - ndcg_stateless: 0.7689\n", + "304/304 [==============================] - 1s 909us/step - loss: -0.7515 - ndcg_stateless: 0.7689\n", "Epoch 16/20\n", - "304/304 [==============================] - 1s 934us/step - loss: -0.7516 - ndcg_stateless: 0.7686\n", + "304/304 [==============================] - 1s 935us/step - loss: -0.7519 - ndcg_stateless: 0.7696\n", "Epoch 17/20\n", - "304/304 [==============================] - 1s 963us/step - loss: -0.7521 - ndcg_stateless: 0.7691\n", + "304/304 [==============================] - 1s 902us/step - loss: -0.7525 - ndcg_stateless: 0.7686\n", "Epoch 18/20\n", - "304/304 [==============================] - 1s 980us/step - loss: -0.7524 - ndcg_stateless: 0.7689\n", + "304/304 [==============================] - 1s 972us/step - loss: -0.7524 - ndcg_stateless: 0.7689\n", "Epoch 19/20\n", - "304/304 [==============================] - 1s 1ms/step - loss: -0.7528 - ndcg_stateless: 0.7692\n", + "304/304 [==============================] - 1s 946us/step - loss: -0.7530 - ndcg_stateless: 0.7691\n", "Epoch 20/20\n", - "304/304 [==============================] - 1s 940us/step - loss: -0.7531 - ndcg_stateless: 0.7700\n" + "304/304 [==============================] - 1s 922us/step - loss: -0.7532 - ndcg_stateless: 0.7688\n" ] } ], @@ -605,28 +596,28 @@ "name": "stdout", "output_type": "stream", "text": [ - "/usr/local/Cellar/python@3.8/3.8.13_1/Frameworks/Python.framework/Versions/3.8/lib/python3.8/runpy.py:127: RuntimeWarning: 'tf2onnx.convert' found in sys.modules after import of package 'tf2onnx', but prior to execution of 'tf2onnx.convert'; this may result in unpredictable behaviour\n", + "/usr/local/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/runpy.py:127: RuntimeWarning: 'tf2onnx.convert' found in sys.modules after import of package 'tf2onnx', but prior to execution of 'tf2onnx.convert'; this may result in unpredictable behaviour\n", " warn(RuntimeWarning(msg))\n", - "2022-08-01 05:46:51,978 - WARNING - '--tag' not specified for saved_model. Using --tag serve\n", - "2022-08-01 05:46:52,055 - INFO - Signatures found in model: [serving_default].\n", - "2022-08-01 05:46:52,055 - WARNING - '--signature_def' not specified, using first signature: serving_default\n", - "2022-08-01 05:46:52,056 - INFO - Output names: ['dense']\n", - "WARNING:tensorflow:From /Users/tmartins/.local/share/virtualenvs/_notebooks-Uz0RYSIe/lib/python3.8/site-packages/tf2onnx/tf_loader.py:711: extract_sub_graph (from tensorflow.python.framework.graph_util_impl) is deprecated and will be removed in a future version.\n", + "2022-08-02 05:21:29,786 - WARNING - '--tag' not specified for saved_model. Using --tag serve\n", + "2022-08-02 05:21:29,853 - INFO - Signatures found in model: [serving_default].\n", + "2022-08-02 05:21:29,853 - WARNING - '--signature_def' not specified, using first signature: serving_default\n", + "2022-08-02 05:21:29,853 - INFO - Output names: ['dense']\n", + "WARNING:tensorflow:From /Users/tmartins/.local/share/virtualenvs/source-bd9eBXOq/lib/python3.9/site-packages/tf2onnx/tf_loader.py:711: extract_sub_graph (from tensorflow.python.framework.graph_util_impl) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Use `tf.compat.v1.graph_util.extract_sub_graph`\n", - "2022-08-01 05:46:52,084 - WARNING - From /Users/tmartins/.local/share/virtualenvs/_notebooks-Uz0RYSIe/lib/python3.8/site-packages/tf2onnx/tf_loader.py:711: extract_sub_graph (from tensorflow.python.framework.graph_util_impl) is deprecated and will be removed in a future version.\n", + "2022-08-02 05:21:29,874 - WARNING - From /Users/tmartins/.local/share/virtualenvs/source-bd9eBXOq/lib/python3.9/site-packages/tf2onnx/tf_loader.py:711: extract_sub_graph (from tensorflow.python.framework.graph_util_impl) is deprecated and will be removed in a future version.\n", "Instructions for updating:\n", "Use `tf.compat.v1.graph_util.extract_sub_graph`\n", - "2022-08-01 05:46:52,095 - INFO - Using tensorflow=2.9.1, onnx=1.12.0, tf2onnx=1.12.0/a58786\n", - "2022-08-01 05:46:52,095 - INFO - Using opset \n", - "2022-08-01 05:46:52,098 - INFO - Computed 0 values for constant folding\n", - "2022-08-01 05:46:52,105 - INFO - Optimizing ONNX model\n", - "2022-08-01 05:46:52,120 - INFO - After optimization: Identity -5 (5->0)\n", - "2022-08-01 05:46:52,122 - INFO - \n", - "2022-08-01 05:46:52,122 - INFO - Successfully converted TensorFlow model simpler_keras_model to ONNX\n", - "2022-08-01 05:46:52,122 - INFO - Model inputs: ['input']\n", - "2022-08-01 05:46:52,122 - INFO - Model outputs: ['dense']\n", - "2022-08-01 05:46:52,123 - INFO - ONNX model is saved at simpler_keras_model.onnx\n" + "2022-08-02 05:21:29,881 - INFO - Using tensorflow=2.9.1, onnx=1.12.0, tf2onnx=1.12.0/a58786\n", + "2022-08-02 05:21:29,881 - INFO - Using opset \n", + "2022-08-02 05:21:29,885 - INFO - Computed 0 values for constant folding\n", + "2022-08-02 05:21:29,891 - INFO - Optimizing ONNX model\n", + "2022-08-02 05:21:29,906 - INFO - After optimization: Identity -5 (5->0)\n", + "2022-08-02 05:21:29,907 - INFO - \n", + "2022-08-02 05:21:29,907 - INFO - Successfully converted TensorFlow model simpler_keras_model to ONNX\n", + "2022-08-02 05:21:29,907 - INFO - Model inputs: ['input']\n", + "2022-08-02 05:21:29,907 - INFO - Model outputs: ['dense']\n", + "2022-08-02 05:21:29,907 - INFO - ONNX model is saved at simpler_keras_model.onnx\n" ] } ], @@ -1018,7 +1009,6 @@ "Waiting for configuration server, 0/300 seconds...\n", "Waiting for configuration server, 5/300 seconds...\n", "Waiting for configuration server, 10/300 seconds...\n", - "Waiting for configuration server, 15/300 seconds...\n", "Waiting for application status, 0/300 seconds...\n", "Waiting for application status, 5/300 seconds...\n", "Waiting for application status, 10/300 seconds...\n", @@ -1265,7 +1255,7 @@ { "data": { "text/plain": [ - "\"select * from sources * where ({'grammar': 'any', 'defaultIndex': 'text'}userInput('what is paula deens brother'));\"" + "\"select * from sources * where ({grammar: 'any', defaultIndex: 'text'}userInput('what is paula deens brother'))\"" ] }, "execution_count": 35, @@ -1359,14 +1349,14 @@ " 0.2\n", " 0.134791\n", " 0.016299\n", - " -0.597079\n", + " -0.655775\n", " \n", " \n", " 1\n", " 0.4\n", " 0.275639\n", " 0.038767\n", - " -0.914343\n", + " -1.030758\n", " \n", " \n", "\n", @@ -1378,8 +1368,8 @@ "1 0.4 0.275639 \n", "\n", " nativeRank(text) vespa_prediction \n", - "0 0.016299 -0.597079 \n", - "1 0.038767 -0.914343 " + "0 0.016299 -0.655775 \n", + "1 0.038767 -1.030758 " ] }, "execution_count": 37, @@ -1410,8 +1400,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "1/1 [==============================] - 0s 150ms/step\n", - "1/1 [==============================] - 0s 32ms/step\n" + "1/1 [==============================] - 0s 75ms/step\n", + "1/1 [==============================] - 0s 25ms/step\n" ] } ], @@ -1461,16 +1451,16 @@ " 0.2\n", " 0.134791\n", " 0.016299\n", - " -0.597079\n", - " -0.597079\n", + " -0.655775\n", + " -0.655775\n", " \n", " \n", " 1\n", " 0.4\n", " 0.275639\n", " 0.038767\n", - " -0.914343\n", - " -0.914342\n", + " -1.030758\n", + " -1.030758\n", " \n", " \n", "\n", @@ -1482,8 +1472,8 @@ "1 0.4 0.275639 \n", "\n", " nativeRank(text) vespa_prediction tf_prediction \n", - "0 0.016299 -0.597079 -0.597079 \n", - "1 0.038767 -0.914343 -0.914342 " + "0 0.016299 -0.655775 -0.655775 \n", + "1 0.038767 -1.030758 -1.030758 " ] }, "execution_count": 39, @@ -1505,7 +1495,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 40, "id": "8e8802d6", "metadata": {}, "outputs": [], @@ -1518,9 +1508,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "blog", "language": "python", - "name": "python3" + "name": "blog" }, "language_info": { "codemirror_mode": { From 1d0e00535fc193e877945e3305f7835ff3a912a8 Mon Sep 17 00:00:00 2001 From: tmartins Date: Tue, 2 Aug 2022 05:49:21 -0300 Subject: [PATCH 8/8] change kernel --- docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb index e1ab4fc6..c327892e 100644 --- a/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb +++ b/docs/sphinx/source/use_cases/tensorflow-via-onnx.ipynb @@ -1508,9 +1508,9 @@ ], "metadata": { "kernelspec": { - "display_name": "blog", + "display_name": "Python 3", "language": "python", - "name": "blog" + "name": "python3" }, "language_info": { "codemirror_mode": {