From 4fa1beaff8d2cf5438e419d9e3dc529d12ad3608 Mon Sep 17 00:00:00 2001 From: Tim Liu Date: Wed, 24 Jul 2024 15:37:45 +0800 Subject: [PATCH 01/10] Init version 24.10.0-SNAPSHOT Signed-off-by: Tim Liu --- examples/UDF-Examples/RAPIDS-accelerated-UDFs/pom.xml | 2 +- .../RAPIDS-accelerated-UDFs/src/main/cpp/CMakeLists.txt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/UDF-Examples/RAPIDS-accelerated-UDFs/pom.xml b/examples/UDF-Examples/RAPIDS-accelerated-UDFs/pom.xml index 7e573964a..72ec93ad3 100644 --- a/examples/UDF-Examples/RAPIDS-accelerated-UDFs/pom.xml +++ b/examples/UDF-Examples/RAPIDS-accelerated-UDFs/pom.xml @@ -25,7 +25,7 @@ user defined functions for use with the RAPIDS Accelerator for Apache Spark - 24.08.0-SNAPSHOT + 24.10.0-SNAPSHOT 1.8 diff --git a/examples/UDF-Examples/RAPIDS-accelerated-UDFs/src/main/cpp/CMakeLists.txt b/examples/UDF-Examples/RAPIDS-accelerated-UDFs/src/main/cpp/CMakeLists.txt index ddea97125..3b0ed6a58 100755 --- a/examples/UDF-Examples/RAPIDS-accelerated-UDFs/src/main/cpp/CMakeLists.txt +++ b/examples/UDF-Examples/RAPIDS-accelerated-UDFs/src/main/cpp/CMakeLists.txt @@ -16,7 +16,7 @@ cmake_minimum_required(VERSION 3.23.1 FATAL_ERROR) -file(DOWNLOAD https://raw.githubusercontent.com/rapidsai/rapids-cmake/branch-24.08/RAPIDS.cmake +file(DOWNLOAD https://raw.githubusercontent.com/rapidsai/rapids-cmake/branch-24.10/RAPIDS.cmake ${CMAKE_BINARY_DIR}/RAPIDS.cmake) include(${CMAKE_BINARY_DIR}/RAPIDS.cmake) @@ -32,7 +32,7 @@ if(DEFINED GPU_ARCHS) endif() rapids_cuda_init_architectures(UDFEXAMPLESJNI) -project(UDFEXAMPLESJNI VERSION 24.08.0 LANGUAGES C CXX CUDA) +project(UDFEXAMPLESJNI VERSION 24.10.0 LANGUAGES C CXX CUDA) option(PER_THREAD_DEFAULT_STREAM "Build with per-thread default stream" OFF) option(BUILD_UDF_BENCHMARKS "Build the benchmarks" OFF) @@ -84,10 +84,10 @@ set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -w --expt-extended-lambda --expt-relax set(CUDA_USE_STATIC_CUDA_RUNTIME ON) rapids_cpm_init() -rapids_cpm_find(cudf 24.08.00 +rapids_cpm_find(cudf 24.10.00 CPM_ARGS GIT_REPOSITORY https://github.com/rapidsai/cudf.git - GIT_TAG branch-24.08 + GIT_TAG branch-24.10 GIT_SHALLOW TRUE SOURCE_SUBDIR cpp OPTIONS "BUILD_TESTS OFF" From 2c0407a4cca60ddad8fb1530122b3e65cfad5499 Mon Sep 17 00:00:00 2001 From: Peixin Date: Thu, 5 Sep 2024 12:55:28 +0800 Subject: [PATCH 02/10] Update signoff usage (#432) Signed-off-by: Peixin Li --- .github/workflows/signoff-check.yml | 18 +++-- .github/workflows/signoff-check/Dockerfile | 22 ------ .github/workflows/signoff-check/action.yml | 19 ----- .github/workflows/signoff-check/signoff-check | 69 ------------------- 4 files changed, 8 insertions(+), 120 deletions(-) delete mode 100644 .github/workflows/signoff-check/Dockerfile delete mode 100644 .github/workflows/signoff-check/action.yml delete mode 100644 .github/workflows/signoff-check/signoff-check diff --git a/.github/workflows/signoff-check.yml b/.github/workflows/signoff-check.yml index 1c7c229d5..d0ca12673 100644 --- a/.github/workflows/signoff-check.yml +++ b/.github/workflows/signoff-check.yml @@ -1,4 +1,4 @@ -# Copyright (c) 2021, NVIDIA CORPORATION. +# Copyright (c) 2021-2024, NVIDIA CORPORATION. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -23,12 +23,10 @@ jobs: signoff-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - - name: sigoff-check job - uses: ./.github/workflows/signoff-check - env: - OWNER: NVIDIA - REPO_NAME: spark-rapids-examples - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PULL_NUMBER: ${{ github.event.number }} + - name: signoff + uses: NVIDIA/spark-rapids-common/signoff-check@main + with: + owner: ${{ github.repository_owner }} + repo: spark-rapids-examples + pull_number: ${{ github.event.number }} + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/signoff-check/Dockerfile b/.github/workflows/signoff-check/Dockerfile deleted file mode 100644 index 0157ffc92..000000000 --- a/.github/workflows/signoff-check/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2021-2022, NVIDIA CORPORATION. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -FROM python:3.8-slim-buster - -WORKDIR / -COPY signoff-check . -RUN pip install PyGithub && chmod +x /signoff-check - -# require envs: OWNER,REPO_NAME,GITHUB_TOKEN,PULL_NUMBER -ENTRYPOINT ["/signoff-check"] diff --git a/.github/workflows/signoff-check/action.yml b/.github/workflows/signoff-check/action.yml deleted file mode 100644 index 93fe0b362..000000000 --- a/.github/workflows/signoff-check/action.yml +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2021, NVIDIA CORPORATION. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: 'signoff check action' -description: 'check if PR got signed off' -runs: - using: 'docker' - image: 'Dockerfile' \ No newline at end of file diff --git a/.github/workflows/signoff-check/signoff-check b/.github/workflows/signoff-check/signoff-check deleted file mode 100644 index 54afa22e8..000000000 --- a/.github/workflows/signoff-check/signoff-check +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2021, NVIDIA CORPORATION. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""A signoff check -The tool checks if any commit got signoff in a pull request. -NOTE: this script is for github actions only, you should not use it anywhere else. -""" -import os -import re -import sys -from argparse import ArgumentParser - -from github import Github - -SIGNOFF_REGEX = re.compile('Signed-off-by:') - - -def signoff(token: str, owner: str, repo_name: str, pull_number: int): - gh = Github(token, per_page=100, user_agent='signoff-check', verify=True) - pr = gh.get_repo(f"{owner}/{repo_name}").get_pull(pull_number) - for c in pr.get_commits(): - if SIGNOFF_REGEX.search(c.commit.message): - print('Found signoff.\n') - print(f"Commit sha:\n{c.commit.sha}") - print(f"Commit message:\n{c.commit.message}") - return True - return False - - -def main(token: str, owner: str, repo_name: str, pull_number: int): - try: - if not signoff(token, owner, repo_name, pull_number): - raise Exception('No commits w/ signoff') - except Exception as e: # pylint: disable=broad-except - print(e) - sys.exit(1) - - -if __name__ == '__main__': - parser = ArgumentParser(description="signoff check") - parser.add_argument("--owner", help="repo owner", default='') - parser.add_argument("--repo_name", help="repo name", default='') - parser.add_argument("--token", help="github token, will use GITHUB_TOKEN if empty", default='') - parser.add_argument("--pull_number", help="pull request number", type=int) - args = parser.parse_args() - - GITHUB_TOKEN = args.token if args.token else os.environ.get('GITHUB_TOKEN') - assert GITHUB_TOKEN, 'env GITHUB_TOKEN should not be empty' - OWNER = args.owner if args.owner else os.environ.get('OWNER') - assert OWNER, 'env OWNER should not be empty' - REPO_NAME = args.repo_name if args.repo_name else os.environ.get('REPO_NAME') - assert REPO_NAME, 'env REPO_NAME should not be empty' - PULL_NUMBER = args.pull_number if args.pull_number else int(os.environ.get('PULL_NUMBER')) - assert PULL_NUMBER, 'env PULL_NUMBER should not be empty' - - main(token=GITHUB_TOKEN, owner=OWNER, repo_name=REPO_NAME, pull_number=PULL_NUMBER) \ No newline at end of file From 3cca58ba75d67aae923c0af45b62adf82fcb7361 Mon Sep 17 00:00:00 2001 From: Peixin Date: Thu, 19 Sep 2024 10:30:03 +0800 Subject: [PATCH 03/10] Use reusable auto-merge workflow (#434) Signed-off-by: Peixin Li --- .github/workflows/auto-merge.yml | 25 ++--- .github/workflows/auto-merge/Dockerfile | 22 ---- .github/workflows/auto-merge/action.yml | 20 ---- .github/workflows/auto-merge/automerge | 137 ------------------------ 4 files changed, 8 insertions(+), 196 deletions(-) delete mode 100644 .github/workflows/auto-merge/Dockerfile delete mode 100644 .github/workflows/auto-merge/action.yml delete mode 100755 .github/workflows/auto-merge/automerge diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index 9473dae4e..61a06b478 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -18,25 +18,16 @@ name: auto-merge HEAD to BASE on: pull_request_target: branches: - - branch-24.08 + - branch-* types: [closed] jobs: auto-merge: if: github.event.pull_request.merged == true - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - with: - ref: branch-24.08 # force to fetch from latest upstream instead of PR ref - - - name: auto-merge job - uses: ./.github/workflows/auto-merge - env: - OWNER: NVIDIA - REPO_NAME: spark-rapids-examples - HEAD: branch-24.08 - BASE: branch-24.10 - AUTOMERGE_TOKEN: ${{ secrets.AUTOMERGE_TOKEN }} # use to merge PR - + uses: NVIDIA/spark-rapids-common/.github/workflows/auto-merge.yml@main + with: + owner: ${{ github.repository_owner }} + repo: spark-rapids-examples + branch: ${{ github.event.pull_request.base.ref }} + secrets: + token: ${{ secrets.AUTOMERGE_TOKEN }} diff --git a/.github/workflows/auto-merge/Dockerfile b/.github/workflows/auto-merge/Dockerfile deleted file mode 100644 index e98b1a487..000000000 --- a/.github/workflows/auto-merge/Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2022, NVIDIA CORPORATION. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -FROM python:alpine - -WORKDIR / -COPY automerge . -RUN pip install requests && chmod +x /automerge - -# require envs: OWNER,REPO_NAME,HEAD,BASE,GITHUB_TOKEN -ENTRYPOINT ["/automerge"] diff --git a/.github/workflows/auto-merge/action.yml b/.github/workflows/auto-merge/action.yml deleted file mode 100644 index ee5577313..000000000 --- a/.github/workflows/auto-merge/action.yml +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) 2022, NVIDIA CORPORATION. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: 'auto-merge action' -description: 'auto-merge HEAD to BASE' -runs: - using: 'docker' - image: 'Dockerfile' - diff --git a/.github/workflows/auto-merge/automerge b/.github/workflows/auto-merge/automerge deleted file mode 100755 index 7ea9b1bd9..000000000 --- a/.github/workflows/auto-merge/automerge +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2022, NVIDIA CORPORATION. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""A auto-merge tool - -Create a PR to merge HEAD to BASE branch. -NOTE: - The generated PR should be automatically merged if no conflict. Otherwise, manual operation will be required. -""" - -import os -import sys -import time - -import requests - -# ENV -OWNER = os.environ.get('OWNER') -assert OWNER, 'env OWNER should not be empty' -REPO_NAME = os.environ.get('REPO_NAME') -assert REPO_NAME, 'env REPO_NAME should not be empty' -HEAD = os.environ.get('HEAD') -assert HEAD, 'env HEAD should not be empty' -BASE = os.environ.get('BASE') -assert BASE, 'env BASE should not be empty' -AUTOMERGE_TOKEN = os.environ.get('AUTOMERGE_TOKEN') -assert AUTOMERGE_TOKEN, 'env AUTOMERGE_TOKEN should not be empty' -# static -API_URL = 'https://api.github.com' -AUTH_HEADERS = { - 'Authorization': 'token ' + AUTOMERGE_TOKEN -} - - -def create(): - url = f'{API_URL}/repos/{OWNER}/{REPO_NAME}/pulls' - params = { - 'title': f'[auto-merge] {HEAD} to {BASE} [skip ci] [bot]', - 'head': HEAD, - 'base': BASE, - 'body': f'auto-merge triggered by github actions on `{HEAD}` to create a PR keeping `{BASE}` up-to-date. If ' - 'this PR is unable to be merged due to conflicts, it will remain open until manually fix.', - 'maintainer_can_modify': True - } - r = requests.post(url, headers=AUTH_HEADERS, json=params) - if r.status_code == 201: - print('SUCCESS - create PR') - pull = r.json() - number = str(pull['number']) - sha = str(pull['head']['sha']) - return number, sha, False - if r.status_code == 422: # early-terminate if no commits between HEAD and BASE - print('SUCCESS - No commits') - print(r.json()) - return '', '', True - # FAILURE - print('FAILURE - create PR') - print(f'status code: {r.status_code}') - print(r.json()) - sys.exit(1) - - -def auto_merge(number, sha): - url = f'{API_URL}/repos/{OWNER}/{REPO_NAME}/pulls/{number}/merge' - params = { - 'sha': sha, - 'merge_method': 'merge' - } - r = requests.put(url, headers=AUTH_HEADERS, json=params) - if r.status_code == 200: - comment(number, '**SUCCESS** - auto-merge') - print('SUCCESS - auto-merge') - sys.exit(0) - else: - print('FAILURE - auto-merge') - comment(number=number, content=f"""**FAILURE** - Unable to auto-merge. Manual operation is required. -``` -{r.json()} -``` - -Please use the following steps to fix the merge conflicts manually: -``` -# Assume upstream is NVIDIA/spark-rapids-examples remote -git fetch upstream {HEAD} {BASE} -git checkout -b fix-auto-merge-conflict-{number} upstream/{BASE} -git merge upstream/{HEAD} -# Fix any merge conflicts caused by this merge -git commit -am "Merge {HEAD} into {BASE}" -git push fix-auto-merge-conflict-{number} -# Open a PR targets NVIDIA/spark-rapids-examples {BASE} -``` -**IMPORTANT:** Before merging this PR, be sure to change the merging strategy to `Create a merge commit` (repo admin only). - -Once this PR is merged, the auto-merge PR should automatically be closed since it contains the same commit hashes -""") - print(f'status code: {r.status_code}') - print(r.json()) - sys.exit(1) - - -def comment(number, content): - url = f'{API_URL}/repos/{OWNER}/{REPO_NAME}/issues/{number}/comments' - params = { - 'body': content - } - r = requests.post(url, headers=AUTH_HEADERS, json=params) - if r.status_code == 201: - print('SUCCESS - create comment') - else: - print('FAILURE - create comment') - print(f'status code: {r.status_code}') - print(r.json()) - - -def main(): - number, sha, term = create() - if term: - sys.exit(0) - - auto_merge(number, sha) - - -if __name__ == '__main__': - main() From 7bf3931a462afb842d2ca9bd1550a5ce0e66a273 Mon Sep 17 00:00:00 2001 From: Bobby Wang Date: Wed, 25 Sep 2024 21:11:39 +0800 Subject: [PATCH 04/10] [XGBoost] update xgboost dependency to the 2.2.0-SNAPSHOT (#435) Signed-off-by: Bobby Wang --- examples/XGBoost-Examples/pom.xml | 7 +------ .../com/nvidia/spark/examples/utility/XGBoostArgs.scala | 4 +--- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/examples/XGBoost-Examples/pom.xml b/examples/XGBoost-Examples/pom.xml index 22b1a1315..d23c57e49 100644 --- a/examples/XGBoost-Examples/pom.xml +++ b/examples/XGBoost-Examples/pom.xml @@ -38,18 +38,13 @@ UTF-8 - 2.1.0-SNAPSHOT + 2.2.0-SNAPSHOT 3.5.0 2.12.8 2.12 - - ml.dmlc - xgboost4j-gpu_${scala.binary.version} - ${xgboost.version} - ml.dmlc xgboost4j-spark-gpu_${scala.binary.version} diff --git a/examples/XGBoost-Examples/utility/scala/src/com/nvidia/spark/examples/utility/XGBoostArgs.scala b/examples/XGBoost-Examples/utility/scala/src/com/nvidia/spark/examples/utility/XGBoostArgs.scala index d58e8e94b..2e8cf0fc8 100644 --- a/examples/XGBoost-Examples/utility/scala/src/com/nvidia/spark/examples/utility/XGBoostArgs.scala +++ b/examples/XGBoost-Examples/utility/scala/src/com/nvidia/spark/examples/utility/XGBoostArgs.scala @@ -22,8 +22,6 @@ import com.google.common.base.CaseFormat import scala.collection.mutable import scala.util.Try -import ml.dmlc.xgboost4j.scala.spark.TrackerConf - private case class XGBoostArg( required: Boolean = false, parse: String => Any = value => value, @@ -202,7 +200,7 @@ class XGBoostArgs private[utility] ( val hostIp = params.getOrElse("rabit_tracker_host", "").toString if (!hostIp.isEmpty) { - params ++ Map("tracker_conf" -> TrackerConf(0, hostIp)) + params ++ Map("rabitTrackerHostIp" -> hostIp) } else params } From 8bc8f9e4d9d3098acbf524ae1f61837758f00982 Mon Sep 17 00:00:00 2001 From: Rishi <77904151+rishic3@users.noreply.github.com> Date: Tue, 8 Oct 2024 00:31:00 -0400 Subject: [PATCH 05/10] Update Spark-RAPIDS-ML PCA (#440) * Update Spark-RAPIDS-ML PCA Signed-off-by: Rishi Chandra * Reran with standalone * Fix typo * Delete Scala example, remove mean-centering * Update README * Update standalone setup script, README * SparkSession init for CI * remove sparkcontext --------- Signed-off-by: Rishi Chandra --- .../Spark-Rapids-ML/pca/README.md | 32 + .../Spark-Rapids-ML/pca/notebooks/pca.ipynb | 556 ++++++++++++++++++ .../Spark-Rapids-ML/pca/start-spark-rapids.sh | 80 +++ .../ML+DL-Examples/Spark-cuML/pca/Dockerfile | 80 --- .../ML+DL-Examples/Spark-cuML/pca/README.md | 102 ---- .../ML+DL-Examples/Spark-cuML/pca/main.scala | 53 -- .../pca/notebooks/Spark_PCA_End_to_End.ipynb | 544 ----------------- .../ML+DL-Examples/Spark-cuML/pca/pom.xml | 87 --- .../com/nvidia/spark/examples/pca/Main.scala | 83 --- .../Spark-cuML/pca/spark-env.sh | 19 - .../Spark-cuML/pca/spark-submit.sh | 43 -- .../Spark-cuML/pca/start-spark.sh | 19 - 12 files changed, 668 insertions(+), 1030 deletions(-) create mode 100644 examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md create mode 100644 examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb create mode 100755 examples/ML+DL-Examples/Spark-Rapids-ML/pca/start-spark-rapids.sh delete mode 100644 examples/ML+DL-Examples/Spark-cuML/pca/Dockerfile delete mode 100644 examples/ML+DL-Examples/Spark-cuML/pca/README.md delete mode 100644 examples/ML+DL-Examples/Spark-cuML/pca/main.scala delete mode 100644 examples/ML+DL-Examples/Spark-cuML/pca/notebooks/Spark_PCA_End_to_End.ipynb delete mode 100644 examples/ML+DL-Examples/Spark-cuML/pca/pom.xml delete mode 100644 examples/ML+DL-Examples/Spark-cuML/pca/scala/src/com/nvidia/spark/examples/pca/Main.scala delete mode 100644 examples/ML+DL-Examples/Spark-cuML/pca/spark-env.sh delete mode 100755 examples/ML+DL-Examples/Spark-cuML/pca/spark-submit.sh delete mode 100755 examples/ML+DL-Examples/Spark-cuML/pca/start-spark.sh diff --git a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md new file mode 100644 index 000000000..2879b94a8 --- /dev/null +++ b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md @@ -0,0 +1,32 @@ +# Spark-Rapids-ML PCA example + +This is an example of the GPU accelerated PCA algorithm from the [Spark-Rapids-ML](https://github.com/NVIDIA/spark-rapids-ml) library, which provides PySpark ML compatible algorithms powered by RAPIDS cuML. +The notebook uses PCA to reduce a random dataset with 2048 feature dimensions to 3 dimensions. We train both the GPU and CPU algorithms for comparison. + +## Build + +Please refer to the Spark-Rapids-ML [README](https://github.com/NVIDIA/spark-rapids-ml/blob/HEAD/python) for environment setup instructions and API usage. + +## Download RAPIDS Jar from Maven Central + +Download the RAPIDS jar from Maven Central: [rapids-4-spark_2.12-24.08.1.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar) +Alternatively, see the Spark-Rapids [download page](https://nvidia.github.io/spark-rapids/docs/download.html#download-rapids-accelerator-for-apache-spark-v24081) for version selection. + +## Running the Notebooks + +Once you have built your environment, please follow these instructions to run the notebooks. Make sure `jupyterlab` is installed in the environment. + +**Note**: for demonstration purposes, these examples just use a local Spark Standalone cluster with a single executor, but you should be able to run them on any distributed Spark cluster. +``` +# setup environment variables +export SPARK_HOME=/path/to/spark +export RAPIDS_JAR=/path/to/rapids.jar + +# launches the standalone cluster and jupyter with pyspark +./start-spark-rapids.sh + +# BROWSE to localhost:8888 to view/run notebooks + +# stop spark standalone cluster +${SPARK_HOME}/sbin/stop-worker.sh; ${SPARK_HOME}/sbin/stop-master.sh +``` diff --git a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb new file mode 100644 index 000000000..9f41e03eb --- /dev/null +++ b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb @@ -0,0 +1,556 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Principal Component Analysis (PCA)\n", + "\n", + "In this notebook, we will demonstrate the end-to-end workflow of Spark RAPIDS accelerated PCA." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "No active Spark session found, initializing manually.\n", + "File already exists. Skipping download.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "24/10/04 18:04:27 WARN Utils: Your hostname, cb4ae00-lcedt resolves to a loopback address: 127.0.1.1; using 10.110.47.100 instead (on interface eno1)\n", + "24/10/04 18:04:27 WARN Utils: Set SPARK_LOCAL_IP if you need to bind to another address\n", + "24/10/04 18:04:27 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n", + "Setting default log level to \"WARN\".\n", + "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", + "24/10/04 18:04:27 WARN RapidsPluginUtils: RAPIDS Accelerator 24.08.1 using cudf 24.08.0, private revision 9fac64da220ddd6bf5626bd7bd1dd74c08603eac\n", + "24/10/04 18:04:27 WARN RapidsPluginUtils: RAPIDS Accelerator is enabled, to disable GPU support set `spark.rapids.sql.enabled` to false.\n", + "24/10/04 18:04:31 WARN GpuDeviceManager: RMM pool is disabled since spark.rapids.memory.gpu.pooling.enabled is set to false; however, this configuration is deprecated and the behavior may change in a future release.\n" + ] + } + ], + "source": [ + "from pyspark.sql import SparkSession\n", + "from pyspark import SparkConf\n", + "\n", + "def get_rapids_jar():\n", + " import os\n", + " import requests\n", + "\n", + " SPARK_RAPIDS_VERSION = \"24.08.1\"\n", + " rapids_jar = f\"rapids-4-spark_2.12-{SPARK_RAPIDS_VERSION}.jar\"\n", + "\n", + " if not os.path.exists(rapids_jar):\n", + " print(\"Downloading spark rapids jar\")\n", + " url = f\"https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/{SPARK_RAPIDS_VERSION}/{rapids_jar}\"\n", + " response = requests.get(url)\n", + " if response.status_code == 200:\n", + " with open(rapids_jar, \"wb\") as f:\n", + " f.write(response.content)\n", + " print(f\"File '{rapids_jar}' downloaded and saved successfully.\")\n", + " else:\n", + " print(f\"Failed to download the file. Status code: {response.status_code}\")\n", + " else:\n", + " print(\"File already exists. Skipping download.\")\n", + " \n", + " return rapids_jar\n", + "\n", + "def initialize_spark(rapids_jar: str):\n", + " '''\n", + " If no active Spark session is found, initialize and configure a new one. \n", + " '''\n", + " conf = SparkConf()\n", + " conf.set(\"spark.task.maxFailures\", \"1\")\n", + " conf.set(\"spark.driver.memory\", \"10g\")\n", + " conf.set(\"spark.executor.memory\", \"8g\")\n", + " conf.set(\"spark.rpc.message.maxSize\", \"1024\")\n", + " conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", + " conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", + " conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + " conf.set(\"spark.python.worker.reuse\", \"true\")\n", + " conf.set(\"spark.rapids.ml.uvm.enabled\", \"true\")\n", + " conf.set(\"spark.jars\", rapids_jar)\n", + " conf.set(\"spark.executorEnv.PYTHONPATH\", rapids_jar)\n", + " conf.set(\"spark.rapids.memory.gpu.minAllocFraction\", \"0.0001\")\n", + " conf.set(\"spark.plugins\", \"com.nvidia.spark.SQLPlugin\")\n", + " conf.set(\"spark.locality.wait\", \"0s\")\n", + " conf.set(\"spark.sql.cache.serializer\", \"com.nvidia.spark.ParquetCachedBatchSerializer\")\n", + " conf.set(\"spark.rapids.memory.gpu.pooling.enabled\", \"false\")\n", + " conf.set(\"spark.sql.execution.sortBeforeRepartition\", \"false\")\n", + " conf.set(\"spark.rapids.sql.format.parquet.reader.type\", \"MULTITHREADED\")\n", + " conf.set(\"spark.rapids.sql.format.parquet.multiThreadedRead.maxNumFilesParallel\", \"20\")\n", + " conf.set(\"spark.rapids.sql.multiThreadedRead.numThreads\", \"20\")\n", + " conf.set(\"spark.rapids.sql.python.gpu.enabled\", \"true\")\n", + " conf.set(\"spark.rapids.memory.pinnedPool.size\", \"2G\")\n", + " conf.set(\"spark.python.daemon.module\", \"rapids.daemon\")\n", + " conf.set(\"spark.rapids.sql.batchSizeBytes\", \"512m\")\n", + " conf.set(\"spark.sql.adaptive.enabled\", \"false\")\n", + " conf.set(\"spark.sql.files.maxPartitionBytes\", \"512m\")\n", + " conf.set(\"spark.rapids.sql.concurrentGpuTasks\", \"1\")\n", + " conf.set(\"spark.sql.execution.arrow.maxRecordsPerBatch\", \"20000\")\n", + " conf.set(\"spark.rapids.sql.explain\", \"NONE\")\n", + " \n", + " spark = SparkSession.builder.appName(\"spark-rapids-ml-pca\").config(conf=conf).getOrCreate()\n", + " return spark\n", + "\n", + "# Check if Spark session is already active, if not, initialize it\n", + "if 'spark' not in globals():\n", + " print(\"No active Spark session found, initializing manually.\")\n", + " rapids_jar = get_rapids_jar()\n", + " spark = initialize_spark(rapids_jar)\n", + "else:\n", + " print(\"Using existing Spark session.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Generate synthetic dataset\n", + "\n", + "Here we generate a 100,000 x 2048 random dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "24/10/04 18:04:45 WARN TaskSetManager: Stage 0 contains a task of very large size (160085 KiB). The maximum recommended task size is 1000 KiB.\n", + " \r" + ] + } + ], + "source": [ + "rows = 100000\n", + "dim = 2048\n", + "dtype = 'float32'\n", + "np.random.seed(42)\n", + "\n", + "data = np.random.rand(rows, dim).astype(dtype)\n", + "pd_data = pd.DataFrame({\"features\": list(data)})\n", + "prepare_df = spark.createDataFrame(pd_data)\n", + "prepare_df.write.mode(\"overwrite\").parquet(\"PCA_data.parquet\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Spark-RAPIDS-ML accepts ArrayType input\n", + "\n", + "Note that in the original Spark-ML PCA, we must `Vectorize` the input column:\n", + "\n", + "```python\n", + "from pyspark.ml.linalg import Vectors\n", + "data = [(Vectors.sparse(5, [(1, 1.0), (3, 7.0)]),),\n", + " (Vectors.dense([2.0, 0.0, 3.0, 4.0, 5.0]),),\n", + " (Vectors.dense([4.0, 0.0, 0.0, 6.0, 7.0]),)]\n", + "df = spark.createDataFrame(data,[\"features\"])\n", + "df.show()\n", + "```\n", + "\n", + "...whereas the Spark-RAPIDS-ML version does not require extra Vectorization, and can accept an ArrayType column as the input column:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "root\n", + " |-- features: array (nullable = true)\n", + " | |-- element: float (containsNull = true)\n", + "\n" + ] + } + ], + "source": [ + "data_df = spark.read.parquet(\"PCA_data.parquet\")\n", + "data_df.printSchema()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using Spark-RAPIDS-ML PCA (GPU)\n", + "\n", + "Compared to the Spark-ML PCA training API:\n", + "\n", + "```python\n", + "from pyspark.ml.feature import PCA\n", + "pca = PCA(k=3, inputCol=\"features\")\n", + "pca.setOutputCol(\"pca_features\")\n", + "```\n", + "\n", + "We use a customized class which requires **no code change** from the user to enjoy GPU acceleration:\n", + "\n", + "```python\n", + "from spark_rapids_ml.feature import PCA\n", + "pca = PCA(k=3, inputCol=\"features\")\n", + "pca.setOutputCol(\"pca_features\")\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "PCA_570681141389" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from spark_rapids_ml.feature import PCA\n", + "\n", + "gpu_pca = PCA(k=2, inputCol=\"features\")\n", + "gpu_pca.setOutputCol(\"pca_features\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The PCA estimator object can be persisted and reloaded." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "estimator_path = \"/tmp/pca_estimator\"\n", + "gpu_pca.write().overwrite().save(estimator_path)\n", + "gpu_pca_loaded = PCA.load(estimator_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Fit" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "24/10/04 18:04:58 WARN MultiFileReaderThreadPool: Configuring the file reader thread pool with a max of 32 threads instead of spark.rapids.sql.multiThreadedRead.numThreads = 20\n", + "2024-10-04 18:04:58,487 - spark_rapids_ml.feature.PCA - INFO - CUDA managed memory enabled.\n", + "2024-10-04 18:04:58,570 - spark_rapids_ml.feature.PCA - INFO - Training spark-rapids-ml with 1 worker(s) ...\n", + "INFO: Process 2762394 found CUDA visible device(s): 0\n", + "2024-10-04 18:05:01,613 - spark_rapids_ml.feature.PCA - INFO - Loading data into python worker memory\n", + "2024-10-04 18:05:02,551 - spark_rapids_ml.feature.PCA - INFO - Initializing cuml context\n", + "2024-10-04 18:05:03,795 - spark_rapids_ml.feature.PCA - INFO - Invoking cuml fit\n", + "2024-10-04 18:05:05,326 - spark_rapids_ml.feature.PCA - INFO - Cuml fit complete\n", + "2024-10-04 18:05:06,858 - spark_rapids_ml.feature.PCA - INFO - Finished training\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "GPU PCA fit took: 8.90433144569397 sec\n" + ] + } + ], + "source": [ + "start_time = time.time()\n", + "gpu_pca_model = gpu_pca_loaded.fit(data_df)\n", + "gpu_fit_time = time.time() - start_time\n", + "print(f\"GPU PCA fit took: {gpu_fit_time} sec\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Transform" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+---------------------------+\n", + "|pca_features |\n", + "+---------------------------+\n", + "|[0.062363233, 0.4037608] |\n", + "|[0.49734917, 0.703541] |\n", + "|[0.0035427138, 0.29358602] |\n", + "|[-0.06798951, 0.37400067] |\n", + "|[0.10075127, 0.34651726] |\n", + "|[-0.22320557, 0.6660976] |\n", + "|[0.49608234, 0.6761328] |\n", + "|[0.25515205, 0.20352581] |\n", + "|[-0.5102935, 0.319284] |\n", + "|[-0.5109488, 0.2756377] |\n", + "|[0.411546, -0.17954555] |\n", + "|[0.21616393, -0.46268395] |\n", + "|[-0.0924304, 0.65660465] |\n", + "|[0.12355948, 0.9478601] |\n", + "|[0.49234354, 0.63746333] |\n", + "|[-0.86077166, 0.0037032962]|\n", + "|[-0.013956882, 0.663955] |\n", + "|[-0.30510652, 0.02372247] |\n", + "|[-0.05999008, 0.28261736] |\n", + "|[0.36605445, 0.9674797] |\n", + "+---------------------------+\n", + "only showing top 20 rows\n", + "\n", + "GPU PCA transform took: 0.43911027908325195 sec\n" + ] + } + ], + "source": [ + "start_time = time.time()\n", + "embeddings = gpu_pca_model.transform(data_df).select(\"pca_features\").show(truncate=False)\n", + "gpu_transform_time = time.time() - start_time\n", + "print(f\"GPU PCA transform took: {gpu_transform_time} sec\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using Spark-ML PCA (CPU)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "PCA_58add243f20d" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from pyspark.ml.feature import PCA\n", + "\n", + "cpu_pca = PCA(k=2, inputCol=\"features\")\n", + "cpu_pca.setOutputCol(\"pca_features\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "root\n", + " |-- features: vector (nullable = true)\n", + "\n" + ] + } + ], + "source": [ + "from pyspark.ml.functions import array_to_vector\n", + "\n", + "vector_df = data_df.select(array_to_vector(\"features\").alias(\"features\"))\n", + "vector_df.printSchema()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Fit" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "24/10/04 17:07:07 WARN InstanceBuilder: Failed to load implementation from:dev.ludovic.netlib.lapack.JNILAPACK\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU PCA fit took: 63.37388610839844 sec\n" + ] + } + ], + "source": [ + "start_time = time.time()\n", + "cpu_pca_model = cpu_pca.fit(vector_df)\n", + "pca_fit_time = time.time() - start_time\n", + "print(f\"CPU PCA fit took: {pca_fit_time} sec\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Transform" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+-------------------------------------------+\n", + "|pca_features |\n", + "+-------------------------------------------+\n", + "|[0.24926765828229927,0.3425432972889563] |\n", + "|[-0.5175207040808384,0.48893065865444574] |\n", + "|[-0.2505049373829902,0.381272141155778] |\n", + "|[-0.39046980420292005,0.4870705091697811] |\n", + "|[-0.4024088726395023,0.707133448810984] |\n", + "|[-0.3061227832285992,0.5363554872099332] |\n", + "|[-0.6065136982526093,0.5205197626985932] |\n", + "|[-0.21870566838630084,0.6516598402789231] |\n", + "|[0.1910036552854184,0.6336513389989592] |\n", + "|[0.6139537641786907,0.6055187085018856] |\n", + "|[-0.026502904776425647,-0.0366087508156753]|\n", + "|[-0.2989311781309336,-0.05136110567458389] |\n", + "|[-0.5474468086054212,-0.18779964958125014] |\n", + "|[-0.6644746232216499,0.10351178251944647] |\n", + "|[-0.12685301272617464,0.47394431583661295] |\n", + "|[-0.4355221246718862,-0.00346289187881239] |\n", + "|[0.6222719258951077,0.5488293416698503] |\n", + "|[0.04966907735703511,0.7138677407505005] |\n", + "|[0.6260486995906139,0.3553228450428632] |\n", + "|[0.16396683091519929,0.7382693234881972] |\n", + "+-------------------------------------------+\n", + "only showing top 20 rows\n", + "\n", + "CPU PCA transform took: 0.19607114791870117 sec\n" + ] + } + ], + "source": [ + "start_time = time.time()\n", + "embeddings = cpu_pca_model.transform(vector_df).select(\"pca_features\").show(truncate=False)\n", + "pca_transform_time = time.time() - start_time\n", + "print(f\"CPU PCA transform took: {pca_transform_time} sec\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Summary" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU runtime: (64.02s + 0.20s)\n", + "GPU runtime: (8.76s + 0.42s)\n", + "End-to-end speedup: CPU / GPU = 7.00x\n" + ] + } + ], + "source": [ + "speedup = (pca_fit_time + pca_transform_time) / (gpu_fit_time + gpu_transform_time)\n", + "print(f\"CPU runtime: ({pca_fit_time:.2f}s + {pca_transform_time:.2f}s)\")\n", + "print(f\"GPU runtime: ({gpu_fit_time:.2f}s + {gpu_transform_time:.2f}s)\")\n", + "print(f\"End-to-end speedup: CPU / GPU = {speedup:.2f}x\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "rapids-24.08", + "language": "python", + "name": "python3" + }, + "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.11.10" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/start-spark-rapids.sh b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/start-spark-rapids.sh new file mode 100755 index 000000000..4e292bb4e --- /dev/null +++ b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/start-spark-rapids.sh @@ -0,0 +1,80 @@ +#!/bin/bash +# +# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Check if SPARK_HOME is set +if [ -z "$SPARK_HOME" ]; then + echo "Please set the SPARK_HOME environment variable before running this script." + exit 1 +fi + +# Check if RAPIDS_JAR is set +if [ -z "$RAPIDS_JAR" ]; then + echo "Please set the RAPIDS_JAR environment variable before running this script." + exit 1 +fi + +# Configuration +MASTER_HOSTNAME=$(hostname) +MASTER=spark://${MASTER_HOSTNAME}:7077 +CORES_PER_WORKER=8 +MEMORY_PER_WORKER=16G + +# Environment variables +export SPARK_HOME=${SPARK_HOME} +export MASTER=${MASTER} +export SPARK_WORKER_INSTANCES=1 +export CORES_PER_WORKER=${CORES_PER_WORKER} +export PYSPARK_DRIVER_PYTHON=jupyter +export PYSPARK_DRIVER_PYTHON_OPTS='lab' + +# Start standalone cluster +echo "Starting Spark standalone cluster..." +${SPARK_HOME}/sbin/start-master.sh +${SPARK_HOME}/sbin/start-worker.sh -c ${CORES_PER_WORKER} -m ${MEMORY_PER_WORKER} ${MASTER} + +# Start Jupyter with PySpark +echo "Launching PySpark with Jupyter..." +${SPARK_HOME}/bin/pyspark --master ${MASTER} \ +--driver-memory 10G \ +--executor-memory 8G \ +--conf spark.task.maxFailures=1 \ +--conf spark.rpc.message.maxSize=1024 \ +--conf spark.sql.pyspark.jvmStacktrace.enabled=true \ +--conf spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled=false \ +--conf spark.sql.execution.arrow.pyspark.enabled=true \ +--conf spark.python.worker.reuse=true \ +--conf spark.rapids.ml.uvm.enabled=true \ +--conf spark.jars=${RAPIDS_JAR} \ +--conf spark.executorEnv.PYTHONPATH=${RAPIDS_JAR} \ +--conf spark.rapids.memory.gpu.minAllocFraction=0.0001 \ +--conf spark.plugins=com.nvidia.spark.SQLPlugin \ +--conf spark.locality.wait=0s \ +--conf spark.sql.cache.serializer=com.nvidia.spark.ParquetCachedBatchSerializer \ +--conf spark.rapids.memory.gpu.pooling.enabled=false \ +--conf spark.sql.execution.sortBeforeRepartition=false \ +--conf spark.rapids.sql.format.parquet.reader.type=MULTITHREADED \ +--conf spark.rapids.sql.format.parquet.multiThreadedRead.maxNumFilesParallel=20 \ +--conf spark.rapids.sql.multiThreadedRead.numThreads=20 \ +--conf spark.rapids.sql.python.gpu.enabled=true \ +--conf spark.rapids.memory.pinnedPool.size=2G \ +--conf spark.python.daemon.module=rapids.daemon \ +--conf spark.rapids.sql.batchSizeBytes=512m \ +--conf spark.sql.adaptive.enabled=false \ +--conf spark.sql.files.maxPartitionBytes=512m \ +--conf spark.rapids.sql.concurrentGpuTasks=1 \ +--conf spark.sql.execution.arrow.maxRecordsPerBatch=20000 \ +--conf spark.rapids.sql.explain=NONE \ No newline at end of file diff --git a/examples/ML+DL-Examples/Spark-cuML/pca/Dockerfile b/examples/ML+DL-Examples/Spark-cuML/pca/Dockerfile deleted file mode 100644 index deaef0ffd..000000000 --- a/examples/ML+DL-Examples/Spark-cuML/pca/Dockerfile +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -ARG CUDA_VER=11.8.0 -FROM nvidia/cuda:${CUDA_VER}-devel-ubuntu20.04 -# Please do not update the BRANCH_VER version -ARG BRANCH_VER=24.08 - -RUN apt-get update -RUN apt-get install -y wget ninja-build git - -ENV PATH="/root/miniconda3/bin:${PATH}" -ARG PATH="/root/miniconda3/bin:${PATH}" -RUN wget --quiet \ - https://repo.anaconda.com/miniconda/Miniconda3-py38_4.10.3-Linux-x86_64.sh \ - && mkdir /root/.conda \ - && bash Miniconda3-py38_4.10.3-Linux-x86_64.sh -b \ - && rm -f Miniconda3-py38_4.10.3-Linux-x86_64.sh \ - && conda init - -SHELL ["conda", "run", "--no-capture-output", "-n", "base", "/bin/bash", "-c"] -RUN echo $PATH -RUN echo $CONDA_PREFIX -RUN conda --version - -RUN conda install -c conda-forge openjdk=8 maven=3.8.1 -y - -# install cuDF dependency. -RUN conda install -c rapidsai-nightly -c nvidia -c conda-forge cudf=${BRANCH_VER} python=3.8 -y - -RUN wget --quiet \ - https://github.com/Kitware/CMake/releases/download/v3.26.4/cmake-3.26.4-linux-x86_64.tar.gz \ - && tar -xzf cmake-3.21.3-linux-x86_64.tar.gz \ - && rm -rf cmake-3.21.3-linux-x86_64.tar.gz - -ENV PATH="/cmake-3.21.3-linux-x86_64/bin:${PATH}" - -RUN git clone -b branch-${BRANCH_VER} https://github.com/rapidsai/raft.git - -ENV RAFT_PATH=/raft - -#use main branch to download release jars -RUN git clone -b main https://github.com/NVIDIA/spark-rapids-ml.git \ - && cd spark-rapids-ml \ - && mvn clean -RUN cd /spark-rapids-ml \ - && mvn install -DskipTests - -ADD scala /workspace/scala -ADD pom.xml /workspace/ - -RUN cd /workspace/ \ - && mvn clean package - -# install spark-3.1.2-bin-hadoop3.2 -RUN wget --quiet \ - https://archive.apache.org/dist/spark/spark-3.1.2/spark-3.1.2-bin-hadoop3.2.tgz \ - && tar -xzf spark-3.1.2-bin-hadoop3.2.tgz -C /opt/ \ - && rm spark-3.1.2-bin-hadoop3.2.tgz -ENV SPARK_HOME=/opt/spark-3.1.2-bin-hadoop3.2 -# add spark env to conf -ADD spark-env.sh /opt/spark-3.1.2-bin-hadoop3.2/conf/ -ADD start-spark.sh /workspace/ -ADD spark-submit.sh /workspace/ - -WORKDIR /workspace diff --git a/examples/ML+DL-Examples/Spark-cuML/pca/README.md b/examples/ML+DL-Examples/Spark-cuML/pca/README.md deleted file mode 100644 index 75ced6296..000000000 --- a/examples/ML+DL-Examples/Spark-cuML/pca/README.md +++ /dev/null @@ -1,102 +0,0 @@ -# PCA example - -This is an example of the GPU accelerated PCA algorithm running on Spark. - -## Build - -Please refer to [README](https://github.com/NVIDIA/spark-rapids-ml#readme) in the [spark-rapids-ml](https://github.com/NVIDIA/spark-rapids-ml) github repository for build instructions and API usage. - -## Get jars from Maven Central - -User can also download the release jar from Maven central: - -[rapids-4-spark-ml_2.12-22.02.0-cuda11.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark-ml_2.12/22.02.0/rapids-4-spark-ml_2.12-22.02.0-cuda11.jar) - -[rapids-4-spark_2.12-23.04.0.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/23.04.0/rapids-4-spark_2.12-23.04.0.jar) - -Note: This demo could only work with v22.02.0 spark-ml version, and only compatible with spark-rapids versions prior to 23.04.0 . Please do not update the version in release. - -## Sample code - -User can find sample scala code in [`main.scala`](main.scala). In the sample code, we will generate random data with 2048 feature dimensions. Then we use PCA to reduce number of features to 3. - -Just copy the sample code into the spark-shell launched according to [this section](https://github.com/NVIDIA/spark-rapids-ml#how-to-use) and REPL will give out the algorithm results. - -## Notebook - -[Apache Toree](https://toree.apache.org/) is required to run PCA sample code in a Jupyter Notebook. - -It is assumed that a Standalone Spark cluster has been set up, the `SPARK_MASTER` and `SPARK_HOME` environment variables are defined and point to the master spark URL (e.g. `spark://localhost:7077`), and the home directory for Apache Spark respectively. - -1. Make sure you have jupyter notebook and [sbt](https://www.scala-sbt.org/1.x/docs/Installing-sbt-on-Linux.html) installed first. -2. Build the 'toree' locally to support scala 2.12, and install it. - - ``` bash - # Download toree - wget https://github.com/apache/incubator-toree/archive/refs/tags/v0.5.0-incubating-rc4.tar.gz - - tar -xvzf v0.5.0-incubating-rc4.tar.gz - - # Build the Toree pip package. - cd incubator-toree-0.5.0-incubating-rc4 - make pip-release - - # Install Toree - pip install dist/toree-pip/toree-0.5.0.tar.gz - ``` - -3. Install a new kernel with the jar(use $RAPIDS_ML_JAR for reference) built from section [Build](#build) and launch - - ``` bash - RAPIDS_ML_JAR=PATH_TO_rapids-4-spark-ml_2.12-22.02.0-cuda11.jar - PLUGIN_JAR=PATH_TO_rapids-4-spark_2.12-23.04.0.jar - - jupyter toree install \ - --spark_home=${SPARK_HOME} \ - --user \ - --toree_opts='--nosparkcontext' \ - --kernel_name="spark-rapids-ml-pca" \ - --spark_opts='--master ${SPARK_MASTER} \ - --jars ${RAPIDS_ML_JAR},${PLUGIN_JAR} \ - --conf spark.driver.memory=10G \ - --conf spark.executor.memory=10G \ - --conf spark.executor.heartbeatInterval=20s \ - --conf spark.rapids.sql.enabled=true \ - --conf spark.plugins=com.nvidia.spark.SQLPlugin \ - --conf spark.rapids.memory.gpu.allocFraction=0.35 \ - --conf spark.rapids.memory.gpu.maxAllocFraction=0.6 \ - --conf spark.executor.resource.gpu.amount=1 \ - --conf spark.task.resource.gpu.amount=1 \ - --conf spark.executor.resource.gpu.discoveryScript=./getGpusResources.sh \ - --files $SPARK_HOME/examples/src/main/scripts/getGpusResources.sh' - ``` - - Launch the notebook: - - ``` bash - jupyter notebook - ``` - - Please choose "spark-rapids-ml-pca" as your notebook kernel. - - - -## Submit app jar - -We also provide the spark-submit way to run the PCA example. We suggest using Dockerfile to get a clean runnning environment: - -```bash -docker build -f Dockerfile -t nvspark/pca:0.1 . -``` -Then get into the container of this image(`nvidia-docker` is required as we will use GPU then): -```bash -nvidia-docker run -it nvspark/pca:0.1 bash -``` - -In this docker image, we assume that user has 2 GPUs in his machine. If you are not the condition, please modify the `-Dspark.worker.resource.gpu.amount` in `spark-env.sh` according to your actual environment. - -Then just start the standalone Spark and submit the job: -``` bash -./start-spark.sh -./spark-submit.sh -``` diff --git a/examples/ML+DL-Examples/Spark-cuML/pca/main.scala b/examples/ML+DL-Examples/Spark-cuML/pca/main.scala deleted file mode 100644 index 408d6cb40..000000000 --- a/examples/ML+DL-Examples/Spark-cuML/pca/main.scala +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import com.nvidia.spark.ml.feature.PCA -import org.apache.spark.ml.linalg._ -import org.apache.spark.sql.functions._ -val dim = 2048 -val rows = 1000 -val r = new scala.util.Random(0) - -// generate dummy data -val dataDf = spark.createDataFrame( - (0 until rows).map(_ => Tuple1(Array.fill(dim)(r.nextDouble)))).withColumnRenamed("_1", "feature") - - -// use RAPIDS PCA class and enable cuBLAS gemm -val pcaGpu = new com.nvidia.spark.ml.feature.PCA().setInputCol("feature").setOutputCol("pca_features").setK(3) - -// train -val pcaModelGpu = spark.time(pcaGpu.fit(dataDf)) - -// transform -pcaModelGpu.transform(dataDf).select("pca_features").show(false) - -// use original Spark ML PCA class -val pcaCpu = new org.apache.spark.ml.feature.PCA().setInputCol("feature_vec").setOutputCol("pca_features").setK(3) - -// use udf to meet standard CPU ML algo input requirement: Vector input -val convertToVector = udf((array: Seq[Double]) => { - Vectors.dense(array.map(_.toDouble).toArray) -}) - -val vectorDf = dataDf.withColumn("feature_vec", convertToVector(col("feature"))) - -// train -val pcaModelCpu = spark.time(pcaCpu.fit(vectorDf)) - -// transform -pcaModelCpu.transform(vectorDf).select("pca_features").show(false) - diff --git a/examples/ML+DL-Examples/Spark-cuML/pca/notebooks/Spark_PCA_End_to_End.ipynb b/examples/ML+DL-Examples/Spark-cuML/pca/notebooks/Spark_PCA_End_to_End.ipynb deleted file mode 100644 index 277505bd0..000000000 --- a/examples/ML+DL-Examples/Spark-cuML/pca/notebooks/Spark_PCA_End_to_End.ipynb +++ /dev/null @@ -1,544 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "90826259", - "metadata": {}, - "source": [ - "## Introduction\n", - "\n", - "In this notebook, we will show the integrated workflow of Spark RAPIDS accelerated ETL and PCA train & transform." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "0f555c95", - "metadata": {}, - "outputs": [], - "source": [ - "import org.apache.spark.ml.linalg._\n", - "import org.apache.spark.sql.functions._" - ] - }, - { - "cell_type": "markdown", - "id": "6d47a7f0", - "metadata": {}, - "source": [ - "### Generate dummy data for PCA benchmark\n", - "\n", - "Generate the sample data of 2048 columns and 50,000 rows" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "18e00096", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Waiting for a Spark session to start..." - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "rows = 50000\n", - "dim = 2048\n", - "r = scala.util.Random@18a448de\n", - "prepareDf = [array_feature[0]: double, array_feature[1]: double ... 2046 more fields]\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "[array_feature[0]: double, array_feature[1]: double ... 2046 more fields]" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "val rows = 50000\n", - "val dim = 2048\n", - "val r = new scala.util.Random(0)\n", - "var prepareDf = spark.createDataFrame(\n", - " (0 until rows).map(_ => Tuple1(Array.fill(dim)(r.nextDouble))))\n", - " .withColumnRenamed(\"_1\", \"array_feature\")\n", - " .select((0 until dim).map(i => col(\"array_feature\").getItem(i)): _*)\n", - "prepareDf.write.mode(\"overwrite\").parquet(\"PCA_raw_parquet\")" - ] - }, - { - "cell_type": "markdown", - "id": "f2ed419b", - "metadata": {}, - "source": [ - "### Read raw parquet data\n", - "\n", - "The parquet file contains the raw data for PCA train and transform.\n", - "\n", - "There're 2048 columns in the table naming as \"array_feature[0], array_feature[1] ... array_feature[2047]\"." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "0084a38f", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "df = [array_feature[0]: double, array_feature[1]: double ... 2046 more fields]\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "[array_feature[0]: double, array_feature[1]: double ... 2046 more fields]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "val df = spark.read.parquet(\"PCA_raw_parquet\")" - ] - }, - { - "cell_type": "markdown", - "id": "58a33554", - "metadata": {}, - "source": [ - "### ETL: Calculate mean value for each column\n", - "\n", - "PCA algorithm is expecting mean centered data as input, so use a simple ETL process to do mean centering." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "a152bd3d", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "dim = 2048\n", - "avgValue = [0.5014784341440235,0.5007938298214618,0.4988382739107633,0.5004857021518329,0.4976086737881863,0.501459317390976,0.4998871629299758,0.5003749032337383,0.5004268051953419,0.4992212831312325,0.5002230208274252,0.49916485476370304,0.49928552249125024,0.5001192271170941,0.4974153011145406,0.500340861041902,0.500511698285404,0.5029175790341269,0.5000848064753295,0.49946358217105435,0.4991402970341374,0.4999057035861329,0.4993188619485362,0.49782509547668896,0.5001573241354326,0.4991954590903186,0.4988846878237177,0.5008673384728016,0.4982505290656533,0.5000069827383224,0.49830672380384944,0.49849188876978057,0.502253148518209,0.4995624384114367,0.5006052199700368,0.49922409882583835,0.4996825327694508,0.4983465266402566,0.5001149704952238...\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "[0.5014784341440235,0.5007938298214618,0.4988382739107633,0.5004857021518329,0.4976086737881863,0.501459317390976,0.4998871629299758,0.5003749032337383,0.5004268051953419,0.4992212831312325,0.5002230208274252,0.49916485476370304,0.49928552249125024,0.5001192271170941,0.4974153011145406,0.500340861041902,0.500511698285404,0.5029175790341269,0.5000848064753295,0.49946358217105435,0.4991402970341374,0.4999057035861329,0.4993188619485362,0.49782509547668896,0.5001573241354326,0.4991954590903186,0.4988846878237177,0.5008673384728016,0.4982505290656533,0.5000069827383224,0.49830672380384944,0.49849188876978057,0.502253148518209,0.4995624384114367,0.5006052199700368,0.49922409882583835,0.4996825327694508,0.4983465266402566,0.5001149704952238..." - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "val dim = 2048\n", - "val avgValue = df.select(\n", - " (0 until dim).map(\"array_feature[\" + _ + \"]\").map(col).map(avg): _*).first()\n", - "val inputCols = (0 until dim).map(i =>\n", - " (col(\"array_feature[\" + i + \"]\") - avgValue.getDouble(i)).alias(\"feature_\"+i)\n", - " )\n", - "val meanCenterDf = df.select(inputCols:_*)" - ] - }, - { - "cell_type": "markdown", - "id": "0bc302cd", - "metadata": {}, - "source": [ - "### Spark RAPIDS accelerated PCA can accept ArrayType column as the input column.\n", - "\n", - "Comparing to the original Spark PCA requirement, there's no need to do extra `Vectorize` work for the input column.\n", - "\n", - "For example, the following code is required when using standard Spark PCA:\n", - "\n", - "```scala\n", - "val convertToVector = udf((array: Seq[Double]) => {\n", - " Vectors.dense(array.map(_.toDouble).toArray)\n", - "})\n", - "val vectorDf = dataDf.withColumn(\"feature_vec\", convertToVector(col(\"feature\")))\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "ac57b415", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "dataDf = [feature_0: double, feature_1: double ... 2047 more fields]\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "[feature_0: double, feature_1: double ... 2047 more fields]" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "val dataDf = meanCenterDf.withColumn(\"feature\",array(meanCenterDf.columns.map(col):_*))" - ] - }, - { - "cell_type": "markdown", - "id": "ec1138d3", - "metadata": {}, - "source": [ - "### Use Spark RAPIDS accelerated PCA\n", - "\n", - "Comparing to the original PCA training API:\n", - "\n", - "```scala\n", - "val pca = new org.apache.spark.ml.feature.PCA()\n", - " .setInputCol(\"feature\")\n", - " .setOutputCol(\"pca_features\")\n", - " .setK(3)\n", - " .fit(vectorDf)\n", - "```\n", - "\n", - "We used a customized class and user will need to do `no code change` to enjoy the GPU acceleration:\n", - "\n", - "```scala\n", - "val pca = new com.nvidia.spark.ml.feature.PCA()\n", - "...\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "8d9fb9bd", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pcaGpu = pca_6b8d054604e4\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "pca_6b8d054604e4" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "val pcaGpu = new com.nvidia.spark.ml.feature.PCA().setInputCol(\"feature\").setOutputCol(\"pca_features\").setK(3)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "d95ce4f9", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/plain": [ - "pcaModelGpu = PCAModel: uid=pca_6b8d054604e4, k=3\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Time taken: 8280 ms\n" - ] - }, - { - "data": { - "text/plain": [ - "PCAModel: uid=pca_6b8d054604e4, k=3" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "val pcaModelGpu = spark.time(pcaGpu.fit(dataDf))" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "0263a1b2", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+-----------------------------------------+\n", - "|pca_features |\n", - "+-----------------------------------------+\n", - "|[0.568805417, 0.041445481, 0.621107902] |\n", - "|[0.378405859, -0.244389411, -0.358809445]|\n", - "|[0.421817533, -0.309621711, -0.159095405]|\n", - "|[0.424088954, 0.09907811, 0.252832213] |\n", - "|[0.481344556, 0.303004001, 0.06884068] |\n", - "|[0.837941281, 0.113648256, -0.319001501] |\n", - "|[0.093790516, -0.364140016, -0.33318393] |\n", - "|[0.103996026, -0.174265839, 0.226559042] |\n", - "|[-0.283206201, -0.487276589, 0.174362571]|\n", - "|[0.101710379, 0.569866637, 0.118964435] |\n", - "+-----------------------------------------+\n", - "only showing top 10 rows\n", - "\n", - "Time taken: 3284 ms\n" - ] - } - ], - "source": [ - "spark.time(pcaModelGpu.transform(dataDf).select(\"pca_features\").show(10, false))" - ] - }, - { - "cell_type": "markdown", - "id": "4e09e7fa", - "metadata": {}, - "source": [ - "### Use original Spark PCA" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "6db8b704", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "convertToVector = SparkUserDefinedFunction($Lambda$4927/1016137095@128d5536,org.apache.spark.ml.linalg.VectorUDT@3bfc3ba7,List(Some(class[value[0]: array])),None,true,true)\n", - "vectorDf = [feature_0: double, feature_1: double ... 2048 more fields]\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "[feature_0: double, feature_1: double ... 2048 more fields]" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "val convertToVector = udf((array: Seq[Double]) => {\n", - " Vectors.dense(array.map(_.toDouble).toArray)\n", - "})\n", - "val vectorDf = dataDf.withColumn(\"feature_vec\", convertToVector(col(\"feature\")))" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "b870173b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pcaCpu = pca_3f8feb827742\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "pca_3f8feb827742" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "val pcaCpu = new org.apache.spark.ml.feature.PCA().setInputCol(\"feature_vec\").setOutputCol(\"pca_features\").setK(3)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "e3e1a9ca", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "pcaModelCpu = PCAModel: uid=pca_3f8feb827742, k=3\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Time taken: 140539 ms\n" - ] - }, - { - "data": { - "text/plain": [ - "PCAModel: uid=pca_3f8feb827742, k=3" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "val pcaModelCpu = spark.time(pcaCpu.fit(vectorDf))" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "504f0bb7", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------------------------------------------------+\n", - "|pca_features |\n", - "+--------------------------------------------------------------+\n", - "|[0.5688054172628585,-0.04144548077183109,-0.6211079018457807] |\n", - "|[0.37840585922945796,0.24438941118757604,0.3588094451238177] |\n", - "|[0.4218175332258925,0.3096217108376109,0.15909540520858537] |\n", - "|[0.4240889539599815,-0.09907811042793396,-0.2528322129752815] |\n", - "|[0.4813445560531313,-0.3030040008580291,-0.06884068037876276] |\n", - "|[0.8379412808563966,-0.11364825624115062,0.3190015014324452] |\n", - "|[0.09379051625949268,0.3641400160124998,0.33318393004824964] |\n", - "|[0.10399602625088979,0.17426583892592548,-0.2265590421381768] |\n", - "|[-0.2832062006131796,0.4872765894121887,-0.1743625713365004] |\n", - "|[0.10171037937872408,-0.5698666372294762,-0.11896443456600647]|\n", - "+--------------------------------------------------------------+\n", - "only showing top 10 rows\n", - "\n", - "Time taken: 12738 ms\n" - ] - } - ], - "source": [ - "spark.time(pcaModelCpu.transform(vectorDf).select(\"pca_features\").show(10, false))" - ] - }, - { - "cell_type": "markdown", - "id": "d486eb9a", - "metadata": {}, - "source": [ - "### Summary\n", - "\n", - "With the data of 50,000 rows, we achived:\n", - "\n", - "the speedup for training: 140539 / 8280 = `16.97`\n", - "\n", - "the speedup for transform: 12738 / 3284 = `3.87`" - ] - }, - { - "cell_type": "markdown", - "id": "671bc74d", - "metadata": {}, - "source": [ - "### Note\n", - "\n", - "Some columns in GPU output have different signs from that in CPU output, this is due to the calculation nature of SVD algorithm which doesn't impact the effectiveness of the SVD results. More details could be found in the [wiki](https://en.wikipedia.org/wiki/Singular_value_decomposition#Relation_to_eigenvalue_decomposition)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4d53fb76", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "spark-rapids-ml-pca - Scala", - "language": "scala", - "name": "spark-rapids-ml-pca_scala" - }, - "language_info": { - "codemirror_mode": "text/x-scala", - "file_extension": ".scala", - "mimetype": "text/x-scala", - "name": "scala", - "pygments_lexer": "scala", - "version": "2.12.12" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/ML+DL-Examples/Spark-cuML/pca/pom.xml b/examples/ML+DL-Examples/Spark-cuML/pca/pom.xml deleted file mode 100644 index 3d7f28b48..000000000 --- a/examples/ML+DL-Examples/Spark-cuML/pca/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - 4.0.0 - - com.nvidia - PCAExample - jar - 23.04.0-SNAPSHOT - - - 8 - 8 - - - - - org.apache.spark - spark-core_2.12 - 3.1.2 - - - - org.apache.spark - spark-sql_2.12 - 3.1.2 - provided - - - - org.apache.spark - spark-mllib_2.12 - 3.1.2 - provided - - - com.nvidia - rapids-4-spark-ml_2.12 - 22.02.0 - - - - - - scala/src - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - 1.8 - 1.8 - - - - org.scala-tools - maven-scala-plugin - 2.15.2 - - - - compile - testCompile - - - - - - - - diff --git a/examples/ML+DL-Examples/Spark-cuML/pca/scala/src/com/nvidia/spark/examples/pca/Main.scala b/examples/ML+DL-Examples/Spark-cuML/pca/scala/src/com/nvidia/spark/examples/pca/Main.scala deleted file mode 100644 index 46a3dab85..000000000 --- a/examples/ML+DL-Examples/Spark-cuML/pca/scala/src/com/nvidia/spark/examples/pca/Main.scala +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package com.nvidia.spark.examples.pca - -import org.apache.spark.ml.linalg._ -import org.apache.spark.sql.SparkSession -import org.apache.spark.sql.functions._ - -object Main { - def main(args: Array[String]): Unit = { - val spark = SparkSession.builder().appName("PCA Example").getOrCreate() - val dim = 2048 - val rows = 50000 - val r = new scala.util.Random(0) - - // generate dummy data - var prepareDf = spark.createDataFrame( - (0 until rows).map(_ => Tuple1(Array.fill(dim)(r.nextDouble)))) - .withColumnRenamed("_1", "array_feature") - .select((0 until dim).map(i => col("array_feature").getItem(i)): _*) - // save to parquet files - prepareDf.write.mode("overwrite").parquet("PCA_raw_parquet") - - // load the parquet files - val df = spark.read.parquet("PCA_raw_parquet") - - // mean centering via ETL - val avgValue = df.select( - (0 until dim).map("array_feature[" + _ + "]").map(col).map(avg): _*).first() - val inputCols = (0 until dim).map(i => - (col("array_feature[" + i + "]") - avgValue.getDouble(i)).alias("feature_"+i) - ) - val meanCenterDf = df.select(inputCols:_*) - - val dataDf = meanCenterDf.withColumn("feature",array(meanCenterDf.columns.map(col):_*)) - - val pcaGpu = new com.nvidia.spark.ml.feature.PCA().setInputCol("feature").setOutputCol("pca_features").setK(3) - // GPU train - val gpuStart = System.currentTimeMillis() - val pcaModelGpu = pcaGpu.fit(dataDf) - val gpuEnd = System.currentTimeMillis() - - // use udf to meet standard CPU ML algo input requirement: Vector input - val convertToVector = udf((array: Seq[Double]) => { - Vectors.dense(array.map(_.toDouble).toArray) - }) - - val vectorDf = dataDf.withColumn("feature_vec", convertToVector(col("feature"))) - - // use original Spark ML PCA class - val pcaCpu = new org.apache.spark.ml.feature.PCA().setInputCol("feature_vec").setOutputCol("pca_features").setK(3) - - // CPU train - val cpuStart = System.currentTimeMillis() - val pcaModelCpu = pcaCpu.fit(vectorDf) - val cpuEnd = System.currentTimeMillis() - - - println("GPU training: ") - println( (gpuEnd - gpuStart) / 1000 + " seconds") - println("CPU training: ") - println( (cpuEnd - cpuStart) / 1000 + " seconds") - - // transform - pcaModelGpu.transform(vectorDf).select("pca_features").show(false) - pcaModelCpu.transform(vectorDf).select("pca_features").show(false) - } -} diff --git a/examples/ML+DL-Examples/Spark-cuML/pca/spark-env.sh b/examples/ML+DL-Examples/Spark-cuML/pca/spark-env.sh deleted file mode 100644 index 82ead37c5..000000000 --- a/examples/ML+DL-Examples/Spark-cuML/pca/spark-env.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -SPARK_MASTER_HOST=127.0.0.1 -SPARK_WORKER_OPTS="-Dspark.worker.resource.gpu.amount=2 -Dspark.worker.resource.gpu.discoveryScript=/opt/spark-3.1.2-bin-hadoop3.2/examples/src/main/scripts/getGpusResources.sh" diff --git a/examples/ML+DL-Examples/Spark-cuML/pca/spark-submit.sh b/examples/ML+DL-Examples/Spark-cuML/pca/spark-submit.sh deleted file mode 100755 index 55a5c5057..000000000 --- a/examples/ML+DL-Examples/Spark-cuML/pca/spark-submit.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2021-2024, NVIDIA CORPORATION. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Note that the last rapids-4-spark-ml release version is 22.02.0, snapshot version is 23.04.0-SNAPSHOT, please do not update the version in release -ML_JAR=/root/.m2/repository/com/nvidia/rapids-4-spark-ml_2.12/22.02.0/rapids-4-spark-ml_2.12-22.02.0.jar -PLUGIN_JAR=/root/.m2/repository/com/nvidia/rapids-4-spark_2.12/23.04.0/rapids-4-spark_2.12-23.04.0.jar -Note: The last rapids-4-spark-ml release version is 22.02.0, snapshot version is 23.04.0-SNAPSHOT. - -$SPARK_HOME/bin/spark-submit \ ---master spark://127.0.0.1:7077 \ ---conf spark.executor.cores=12 \ ---conf spark.executor.instances=2 \ ---driver-memory 30G \ ---executor-memory 30G \ ---conf spark.driver.maxResultSize=8G \ ---conf spark.rapids.sql.enabled=true \ ---conf spark.plugins=com.nvidia.spark.SQLPlugin \ ---conf spark.rapids.memory.gpu.allocFraction=0.35 \ ---conf spark.rapids.memory.gpu.maxAllocFraction=0.6 \ ---conf spark.task.resource.gpu.amount=0.08 \ ---conf spark.executor.extraClassPath=$ML_JAR:$PLUGIN_JAR \ ---conf spark.driver.extraClassPath=$ML_JAR:$PLUGIN_JAR \ ---conf spark.executor.resource.gpu.amount=1 \ ---conf spark.rpc.message.maxSize=2046 \ ---conf spark.executor.heartbeatInterval=500s \ ---conf spark.network.timeout=1000s \ ---jars $ML_JAR,$PLUGIN_JAR \ ---class com.nvidia.spark.examples.pca.Main \ -/workspace/target/PCAExample-23.04.0-SNAPSHOT.jar diff --git a/examples/ML+DL-Examples/Spark-cuML/pca/start-spark.sh b/examples/ML+DL-Examples/Spark-cuML/pca/start-spark.sh deleted file mode 100755 index c622e1cb4..000000000 --- a/examples/ML+DL-Examples/Spark-cuML/pca/start-spark.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -/opt/spark-3.1.2-bin-hadoop3.2/sbin/start-master.sh -/opt/spark-3.1.2-bin-hadoop3.2/sbin/start-slave.sh spark://127.0.0.1:7077 From 47ae101fff2723f28a3f953d20e973d861a502e5 Mon Sep 17 00:00:00 2001 From: Rishi <77904151+rishic3@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:13:17 -0400 Subject: [PATCH 06/10] Add setmaster to PCA (#442) * Add setmaster for standalone runs on CI/CD * signoff Signed-off-by: Rishi Chandra --------- Signed-off-by: Rishi Chandra --- .../ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb index 9f41e03eb..3bf570feb 100644 --- a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb +++ b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb @@ -78,7 +78,11 @@ " '''\n", " If no active Spark session is found, initialize and configure a new one. \n", " '''\n", + " import socket\n", + " hostname = socket.gethostname()\n", + "\n", " conf = SparkConf()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # Assuming master is on host and default port. \n", " conf.set(\"spark.task.maxFailures\", \"1\")\n", " conf.set(\"spark.driver.memory\", \"10g\")\n", " conf.set(\"spark.executor.memory\", \"8g\")\n", From fc23a571b7674e272e785846f971cd5c057b2b85 Mon Sep 17 00:00:00 2001 From: "Rishi C." <77904151+rishic3@users.noreply.github.com> Date: Tue, 15 Oct 2024 02:22:06 -0400 Subject: [PATCH 07/10] Fix Spark-DL notebooks for CI/CD and update to latest dependencies (#439) * Update Spark-DL examples Signed-off-by: Rishi Chandra * Update README.md * Update README.md * update numpy versions * Update readme/reqs, cond_gen_tf works * update image_classif * update torch examples with dynamo compilation * Test modelopt warning * torch examples updated for aot compilation * Separate conditional generation to tf/torch on triton * Huggingface ex's updated with standalone * Reran TF ex's with standalone * Remove setMaster for nbconvert * Update installation instructions * Address TF warnings/errors * Addressing comments * Update README * Update Spark tensorrt compilation note, truncate keras outputs * Fix resource warnings, update arrow check * Update SetMaster, fix caching issue * Correctly set max_length for conditional generation * Disable tokenizer parallelism * Update README to include DL inference * Update README.md * Enable tokenizer parallelism * Update suffixes for CI/CD, add table to readme * Finish updating suffix * Update README.md * Update README.md * Enable tokenizer parallelism * Separate requirements files * Fix typo * Reference requirements.txt --------- Signed-off-by: Rishi Chandra --- README.md | 9 +- .../Spark-DL/dl_inference/README.md | 42 +- .../conditional_generation_tf.ipynb | 1795 ++++++++++++ ...ynb => conditional_generation_torch.ipynb} | 879 +++--- .../models_config/hf_generation_tf/1/model.py | 150 + .../config.pbtxt | 4 +- .../1/model.py | 3 +- .../hf_generation_torch/config.pbtxt | 52 + .../models_config/hf_pipeline_tf/1/model.py | 147 + .../config.pbtxt | 4 +- .../1/model.py | 6 +- .../hf_pipeline_torch/config.pbtxt | 57 + .../1/model.py | 0 .../config.pbtxt | 4 +- .../huggingface/pipelines_tf.ipynb | 1056 +++++++ ...{pipelines.ipynb => pipelines_torch.ipynb} | 426 +-- ...pynb => sentence_transformers_torch.ipynb} | 503 ++-- .../pytorch/image_classification.ipynb | 2180 --------------- .../pytorch/image_classification_torch.ipynb | 2367 ++++++++++++++++ ...egression.ipynb => regression_torch.ipynb} | 1114 +++++--- .../Spark-DL/dl_inference/requirements.txt | 23 +- ...columns.ipynb => feature_columns_tf.ipynb} | 731 ++--- .../tensorflow/image_classification.ipynb | 1412 +++++----- .../tensorflow/image_classification_tf.ipynb | 2460 +++++++++++++++++ ...metadata.ipynb => keras-metadata_tf.ipynb} | 517 ++-- .../models_config/feature_columns/1/model.py | 4 +- .../text_classification/1/model.py | 9 +- .../tensorflow/text_classification.ipynb | 1638 ----------- .../tensorflow/text_classification_tf.ipynb | 1850 +++++++++++++ .../Spark-DL/dl_inference/tf_requirements.txt | 3 + .../dl_inference/torch_requirements.txt | 8 + 31 files changed, 13040 insertions(+), 6413 deletions(-) create mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_tf.ipynb rename examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/{conditional_generation.ipynb => conditional_generation_torch.ipynb} (53%) create mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_tf/1/model.py rename examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/{hf_generation => hf_generation_tf}/config.pbtxt (98%) rename examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/{hf_generation => hf_generation_torch}/1/model.py (98%) create mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_torch/config.pbtxt create mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_tf/1/model.py rename examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/{hf_pipeline => hf_pipeline_tf}/config.pbtxt (98%) rename examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/{hf_pipeline => hf_pipeline_torch}/1/model.py (96%) create mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_torch/config.pbtxt rename examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/{hf_transformer => hf_transformer_torch}/1/model.py (100%) rename examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/{hf_transformer => hf_transformer_torch}/config.pbtxt (97%) create mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_tf.ipynb rename examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/{pipelines.ipynb => pipelines_torch.ipynb} (65%) rename examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/{sentence_transformers.ipynb => sentence_transformers_torch.ipynb} (50%) delete mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification.ipynb create mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification_torch.ipynb rename examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/{regression.ipynb => regression_torch.ipynb} (55%) rename examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/{feature_columns.ipynb => feature_columns_tf.ipynb} (63%) create mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification_tf.ipynb rename examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/{keras-metadata.ipynb => keras-metadata_tf.ipynb} (58%) delete mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/text_classification.ipynb create mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/text_classification_tf.ipynb create mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/tf_requirements.txt create mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/torch_requirements.txt diff --git a/README.md b/README.md index 0a3e9c704..8e439ae5b 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,10 @@ RAPIDS Accelerator for Apache Spark accelerates Spark applications with no code You can download the latest version of RAPIDS Accelerator [here](https://nvidia.github.io/spark-rapids/docs/download.html). This repo contains examples and applications that showcases the performance and benefits of using RAPIDS Accelerator in data processing and machine learning pipelines. -There are broadly four categories of examples in this repo: +There are broadly five categories of examples in this repo: 1. [SQL/Dataframe](./examples/SQL+DF-Examples) 2. [Spark XGBoost](./examples/XGBoost-Examples) -3. [Deep Learning/Machine Learning](./examples/ML+DL-Examples) +3. [Machine Learning/Deep Learning](./examples/ML+DL-Examples) 4. [RAPIDS UDF](./examples/UDF-Examples) 5. [Databricks Tools demo notebooks](./tools/databricks) @@ -23,7 +23,8 @@ Here is the list of notebooks in this repo: | 3 | XGBoost | Agaricus (Scala) | Uses XGBoost classifier function to create model that can accurately differentiate between edible and poisonous mushrooms with the [agaricus dataset](https://archive.ics.uci.edu/ml/datasets/mushroom) | 4 | XGBoost | Mortgage (Scala) | End-to-end ETL + XGBoost example to predict mortgage default with [Fannie Mae Single-Family Loan Performance Data](https://capitalmarkets.fanniemae.com/credit-risk-transfer/single-family-credit-risk-transfer/fannie-mae-single-family-loan-performance-data) | 5 | XGBoost | Taxi (Scala) | End-to-end ETL + XGBoost example to predict taxi trip fare amount with [NYC taxi trips data set](https://www1.nyc.gov/site/tlc/about/tlc-trip-record-data.page) -| 6 | ML/DL | PCA End-to-End | Spark MLlib based PCA example to train and transform with a synthetic dataset +| 6 | ML/DL | PCA | [Spark-Rapids-ML](https://github.com/NVIDIA/spark-rapids-ml) based PCA example to train and transform with a synthetic dataset +| 7 | ML/DL | DL Inference | 11 notebooks demonstrating distributed model inference on Spark using the `predict_batch_udf` across various frameworks: PyTorch, HuggingFace, and TensorFlow Here is the list of Apache Spark applications (Scala and PySpark) that can be built for running on GPU with RAPIDS Accelerator in this repo: @@ -33,7 +34,7 @@ can be built for running on GPU with RAPIDS Accelerator in this repo: | 1 | XGBoost | Agaricus (Scala) | Uses XGBoost classifier function to create model that can accurately differentiate between edible and poisonous mushrooms with the [agaricus dataset](https://archive.ics.uci.edu/ml/datasets/mushroom) | 2 | XGBoost | Mortgage (Scala) | End-to-end ETL + XGBoost example to predict mortgage default with [Fannie Mae Single-Family Loan Performance Data](https://capitalmarkets.fanniemae.com/credit-risk-transfer/single-family-credit-risk-transfer/fannie-mae-single-family-loan-performance-data) | 3 | XGBoost | Taxi (Scala) | End-to-end ETL + XGBoost example to predict taxi trip fare amount with [NYC taxi trips data set](https://www1.nyc.gov/site/tlc/about/tlc-trip-record-data.page) -| 4 | ML/DL | PCA End-to-End | Spark MLlib based PCA example to train and transform with a synthetic dataset +| 4 | ML/DL | PCA | [Spark-Rapids-ML](https://github.com/NVIDIA/spark-rapids-ml) based PCA example to train and transform with a synthetic dataset | 5 | UDF | URL Decode | Decodes URL-encoded strings using the [Java APIs of RAPIDS cudf](https://docs.rapids.ai/api/cudf-java/legacy/) | 6 | UDF | URL Encode | URL-encodes strings using the [Java APIs of RAPIDS cudf](https://docs.rapids.ai/api/cudf-java/legacy/) | 7 | UDF | [CosineSimilarity](./examples/UDF-Examples/RAPIDS-accelerated-UDFs/src/main/java/com/nvidia/spark/rapids/udf/java/CosineSimilarity.java) | Computes the cosine similarity between two float vectors using [native code](./examples/UDF-Examples/RAPIDS-accelerated-UDFs/src/main/cpp/src) diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/README.md b/examples/ML+DL-Examples/Spark-DL/dl_inference/README.md index 177af9072..782db87c6 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/README.md +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/README.md @@ -30,17 +30,49 @@ predictions = df.withColumn("preds", mnist("data")).collect() In this simple case, the `predict_batch_fn` will use TensorFlow APIs to load the model and return a simple `predict` function which operates on numpy arrays. The `predict_batch_udf` will automatically convert the Spark DataFrame columns to the expected numpy inputs. -All notebooks have been saved with sample outputs for quick browsing. +All notebooks have been saved with sample outputs for quick browsing. +Here is a full list of the notebooks with their published example links: + +| | Category | Notebook Name | Description | Link +| ------------- | ------------- | ------------- | ------------- | ------------- +| 1 | PyTorch | Image Classification | Training a model to predict clothing categories in FashionMNIST, including accelerated inference with Torch-TensorRT. | [Link](https://pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html) +| 2 | PyTorch | Regression | Training a model to predict housing prices in the California Housing Dataset, including accelerated inference with Torch-TensorRT. | [Link](https://github.com/christianversloot/machine-learning-articles/blob/main/how-to-create-a-neural-network-for-regression-with-pytorch.md) +| 3 | Tensorflow | Image Classification | Training a model to predict hand-written digits in MNIST. | [Link](https://www.tensorflow.org/tutorials/keras/save_and_load) +| 4 | Tensorflow | Feature Columns | Training a model with preprocessing layers to predict likelihood of pet adoption in the PetFinder mini dataset. | [Link](https://www.tensorflow.org/tutorials/structured_data/preprocessing_layers) +| 5 | Tensorflow | Keras Metadata | Training ResNet-50 to perform flower recognition on Databricks. | [Link](https://docs.databricks.com/en/_extras/notebooks/source/deep-learning/keras-metadata.html) +| 6 | Tensorflow | Text Classification | Training a model to perform sentiment analysis on the IMDB dataset. | [Link](https://www.tensorflow.org/tutorials/keras/text_classification) +| 7+8 | HuggingFace | Conditional Generation | Sentence translation using the T5 text-to-text transformer, with notebooks demoing both Torch and Tensorflow. | [Link](https://huggingface.co/docs/transformers/model_doc/t5#t5) +| 9+10 | HuggingFace | Pipelines | Sentiment analysis using Huggingface pipelines, with notebooks demoing both Torch and Tensorflow. | [Link](https://huggingface.co/docs/transformers/quicktour#pipeline-usage) +| 11 | HuggingFace | Sentence Transformers | Sentence embeddings using the SentenceTransformers framework in Torch. | [Link](https://huggingface.co/sentence-transformers) ## Running the Notebooks If you want to run the notebooks yourself, please follow these instructions. -**Note**: for demonstration purposes, these examples just use a local Spark Standalone cluster with a single executor, but you should be able to run them on any distributed Spark cluster. +**Notes**: +- The notebooks require a GPU environment for the executors. +- Please create separate environments for PyTorch and Tensorflow examples as specified below. This will avoid conflicts between the CUDA libraries bundled with their respective versions. The Huggingface examples will have a `_torch` or `_tf` suffix to specify the environment used. +- The PyTorch notebooks include model compilation and accelerated inference with TensorRT. While not included in the notebooks, Tensorflow also supports [integration with TensorRT](https://docs.nvidia.com/deeplearning/frameworks/tf-trt-user-guide/index.html), but may require downgrading the TF version. +- For demonstration purposes, these examples just use a local Spark Standalone cluster with a single executor, but you should be able to run them on any distributed Spark cluster. + +#### Create environment + +**For PyTorch:** +``` +conda create -n spark-dl-torch python=3.11 +conda activate spark-dl-torch +pip install -r torch_requirements.txt +``` +**For TensorFlow:** ``` -# install dependencies for example notebooks -pip install -r requirements.txt +conda create -n spark-dl-tf python=3.11 +conda activate spark-dl-tf +pip install -r tf_requirements.txt +``` + +#### Launch Jupyter + Spark +``` # setup environment variables export SPARK_HOME=/path/to/spark export MASTER=spark://$(hostname):7077 @@ -70,4 +102,4 @@ The example notebooks also demonstrate integration with [Triton Inference Server **Note**: Some examples may require special configuration of server as highlighted in the notebooks. -**Note**: for demonstration purposes, the Triton Inference Server integrations just launch the server in a docker container on the local host, so you will need to [install docker](https://docs.docker.com/engine/install/) on your local host. Most real-world deployments will likely be hosted on remote machines. \ No newline at end of file +**Note**: for demonstration purposes, the Triton Inference Server integrations just launch the server in a docker container on the local host, so you will need to [install docker](https://docs.docker.com/engine/install/) on your local host. Most real-world deployments will likely be hosted on remote machines. diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_tf.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_tf.ipynb new file mode 100644 index 000000000..e2c67eb98 --- /dev/null +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_tf.ipynb @@ -0,0 +1,1795 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "777fc40d", + "metadata": {}, + "source": [ + "# PySpark Huggingface Inferencing\n", + "## Conditional generation with Tensorflow\n", + "\n", + "From: https://huggingface.co/docs/transformers/model_doc/t5" + ] + }, + { + "cell_type": "markdown", + "id": "05c79ac4-bf25-421e-b55e-020d6d9e15d5", + "metadata": {}, + "source": [ + "### Using TensorFlow\n", + "Note that cuFFT/cuDNN/cuBLAS registration errors are expected with `tf=2.17.0` and will not affect behavior, as noted in [this issue.](https://github.com/tensorflow/tensorflow/issues/62075) \n", + "This notebook does not demonstrate inference with TensorRT, as [TF-TRT](https://docs.nvidia.com/deeplearning/tensorrt/release-notes/index.html#tensorrt-10) does not yet support `tf=2.17.0`. See the `pytorch` notebooks for TensorRT demos." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "f6f0dbf3-712b-4c58-85eb-261ce15bb2be", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-11 00:16:59.451769: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2024-10-11 00:16:59.459246: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", + "2024-10-11 00:16:59.467162: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", + "2024-10-11 00:16:59.469569: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", + "2024-10-11 00:16:59.475888: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2024-10-11 00:16:59.818338: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" + ] + } + ], + "source": [ + "from transformers import AutoTokenizer, TFT5ForConditionalGeneration" + ] + }, + { + "cell_type": "markdown", + "id": "5346a20c", + "metadata": {}, + "source": [ + "Enabling Huggingface tokenizer parallelism so that it is not automatically disabled with Python parallelism. See [this thread](https://github.com/huggingface/transformers/issues/5486) for more info. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "a1008e27", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "os.environ[\"TOKENIZERS_PARALLELISM\"] = \"true\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "275890d7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.17.0\n" + ] + } + ], + "source": [ + "import tensorflow as tf\n", + "\n", + "# Enable GPU memory growth\n", + "gpus = tf.config.experimental.list_physical_devices('GPU')\n", + "if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)\n", + " \n", + "print(tf.__version__)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "2684fb41-9467-40c0-9d7e-a1cc867c5a3c", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-11 00:17:00.886565: I tensorflow/core/common_runtime/gpu/gpu_device.cc:2021] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 46024 MB memory: -> device: 0, name: NVIDIA RTX A6000, pci bus id: 0000:01:00.0, compute capability: 8.6\n", + "All PyTorch model weights were used when initializing TFT5ForConditionalGeneration.\n", + "\n", + "All the weights of TFT5ForConditionalGeneration were initialized from the PyTorch model.\n", + "If your task is similar to the task the model of the checkpoint was trained on, you can already use TFT5ForConditionalGeneration for predictions without further training.\n" + ] + } + ], + "source": [ + "tokenizer = AutoTokenizer.from_pretrained(\"google-t5/t5-small\")\n", + "model = TFT5ForConditionalGeneration.from_pretrained(\"google-t5/t5-small\")\n", + "\n", + "task_prefix = \"translate English to German: \"\n", + "\n", + "lines = [\n", + " \"The house is wonderful\",\n", + " \"Welcome to NYC\",\n", + " \"HuggingFace is a company\"\n", + "]\n", + "\n", + "input_sequences = [task_prefix + l for l in lines]" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "6eb2dfdb-0ad3-4d0f-81a4-268d92c53759", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n", + "I0000 00:00:1728605822.106234 276792 service.cc:146] XLA service 0x7f53a8003630 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:\n", + "I0000 00:00:1728605822.106259 276792 service.cc:154] StreamExecutor device (0): NVIDIA RTX A6000, Compute Capability 8.6\n", + "2024-10-11 00:17:02.108842: I tensorflow/compiler/mlir/tensorflow/utils/dump_mlir_util.cc:268] disabling MLIR crash reproducer, set env var `MLIR_CRASH_REPRODUCER_DIRECTORY` to enable.\n", + "2024-10-11 00:17:02.117215: I external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:531] Loaded cuDNN version 8907\n", + "I0000 00:00:1728605822.137920 276792 device_compiler.h:188] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process.\n" + ] + } + ], + "source": [ + "input_ids = tokenizer(input_sequences, \n", + " padding=\"longest\", \n", + " max_length=512,\n", + " truncation=True,\n", + " return_tensors=\"tf\").input_ids\n", + "outputs = model.generate(input_ids, max_length=20)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "720158d4-e0e0-4904-b096-e5aede756afd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['Das Haus ist wunderbar',\n", + " 'Willkommen in NYC',\n", + " 'HuggingFace ist ein Unternehmen']" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[tokenizer.decode(o, skip_special_tokens=True) for o in outputs]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "8d4b364b-13cb-48ea-a97a-ccfc9e408075", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'tf'" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.framework" + ] + }, + { + "cell_type": "markdown", + "id": "546eabe0", + "metadata": {}, + "source": [ + "## PySpark" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "2f6db1f0-7d68-4af7-8bd6-c9fa45906c61", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from pathlib import Path\n", + "from datasets import load_dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "68121304-f1df-466e-9347-c9d2b36a9b3a", + "metadata": {}, + "outputs": [], + "source": [ + "from pyspark.sql.types import *\n", + "from pyspark.sql import SparkSession\n", + "from pyspark import SparkConf\n", + "import socket" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "6279a849", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "24/10/11 00:17:03 WARN Utils: Your hostname, cb4ae00-lcedt resolves to a loopback address: 127.0.1.1; using 10.110.47.100 instead (on interface eno1)\n", + "24/10/11 00:17:03 WARN Utils: Set SPARK_LOCAL_IP if you need to bind to another address\n", + "Setting default log level to \"WARN\".\n", + "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", + "24/10/11 00:17:03 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n" + ] + } + ], + "source": [ + "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", + "hostname = socket.gethostname()\n", + "\n", + "conf = SparkConf()\n", + "if 'spark' not in globals():\n", + " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", + " import socket\n", + " hostname = socket.gethostname()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", + "conf.set(\"spark.task.maxFailures\", \"1\")\n", + "conf.set(\"spark.driver.memory\", \"8g\")\n", + "conf.set(\"spark.executor.memory\", \"8g\")\n", + "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", + "conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.maxRecordsPerBatch\", \"512\")\n", + "conf.set(\"spark.python.worker.reuse\", \"true\")\n", + "# Create Spark Session\n", + "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", + "sc = spark.sparkContext" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "b8453111-d068-49bb-ab91-8ae3d8bcdb7a", + "metadata": {}, + "outputs": [], + "source": [ + "# load IMDB reviews (test) dataset\n", + "data = load_dataset(\"imdb\", split=\"test\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "7ad01d4a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "25000" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lines = []\n", + "for example in data:\n", + " lines.append([example[\"text\"].split(\".\")[0]])\n", + "\n", + "len(lines)" + ] + }, + { + "cell_type": "markdown", + "id": "6fd5b472-47e8-4804-9907-772793fedb2b", + "metadata": {}, + "source": [ + "### Create PySpark DataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "d24d9404-0269-476e-a9dd-1842667c915a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "StructType([StructField('lines', StringType(), True)])" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = spark.createDataFrame(lines, ['lines']).repartition(8)\n", + "df.schema" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "4384c762-1f79-4f60-876c-94b1f552e8fb", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "[Row(lines='(Some Spoilers) Dull as dishwater slasher flick that has this deranged homeless man Harry, Darwyn Swalve, out murdering real-estate agent all over the city of L')]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.take(1)" + ] + }, + { + "cell_type": "markdown", + "id": "42ba3513-82dd-47e7-8193-eb4389458757", + "metadata": {}, + "source": [ + "### Save the test dataset as parquet files" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "e7eec8ec-4126-4890-b957-025809fad67d", + "metadata": {}, + "outputs": [], + "source": [ + "df.write.mode(\"overwrite\").parquet(\"imdb_test\")" + ] + }, + { + "cell_type": "markdown", + "id": "304e1fc8-42a3-47dd-b3c0-47efd5be1040", + "metadata": {}, + "source": [ + "### Check arrow memory configuration" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "20554ea5-01be-4a30-8607-db5d87786fec", + "metadata": {}, + "outputs": [], + "source": [ + "if int(spark.conf.get(\"spark.sql.execution.arrow.maxRecordsPerBatch\")) > 512:\n", + " print(\"Decreasing `spark.sql.execution.arrow.maxRecordsPerBatch` to ensure the vectorized reader won't run out of memory\")\n", + " spark.conf.set(\"spark.sql.execution.arrow.maxRecordsPerBatch\", \"512\")\n", + "assert len(df.head()) > 0, \"`df` should not be empty\"" + ] + }, + { + "cell_type": "markdown", + "id": "06a4ecab-c9d9-466f-ba49-902ad1fd5488", + "metadata": {}, + "source": [ + "## Inference using Spark DL API\n", + "Note: you can restart the kernel and run from this point to simulate running in a different node or environment." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "e7a00479-1347-4de8-8431-faa77f8cdf4c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "from pyspark.ml.functions import predict_batch_udf\n", + "from pyspark.sql.functions import col, pandas_udf, struct\n", + "from pyspark.sql.types import StringType" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "b9a0889a-35b4-493a-8197-1146fc7efd53", + "metadata": {}, + "outputs": [], + "source": [ + "# only use first sentence and add prefix for conditional generation\n", + "def preprocess(text: pd.Series, prefix: str = \"\") -> pd.Series:\n", + " @pandas_udf(\"string\")\n", + " def _preprocess(text: pd.Series) -> pd.Series:\n", + " return pd.Series([prefix + s.split(\".\")[0] for s in text])\n", + " return _preprocess(text)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "c483e4d4-9ab1-416f-a766-694e17490fd3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+------------------------------------------------------------------------------------------------------------------------+\n", + "| lines|\n", + "+------------------------------------------------------------------------------------------------------------------------+\n", + "| This is so overly clichéd you'll want to switch it off after the first 45 minutes|\n", + "| I am a big fan of The ABC Movies of the Week genre|\n", + "|In the early 1990's \"Step-by-Step\" came as a tedious combination of the ultra-cheesy \"Full House\" and the long-defunc...|\n", + "|When The Spirits Within was released, all you heard from Final Fantasy fans was how awful the movie was because it di...|\n", + "| I like to think of myself as a bad movie connoisseur|\n", + "|This film did well at the box office, and the producers of this mess thought the stars had such good chemistry in thi...|\n", + "|Following the pleasingly atmospheric original and the amusingly silly second one, this incredibly dull, slow, and une...|\n", + "| I like CKY and Viva La Bam, so I couldn't resist this when I saw it for £1|\n", + "| I have read all of the reviews for this direct to video movie|\n", + "|Yes, it was an awful movie, but there was a song near the beginning of the movie, I think, called \"I got a Woody\" or ...|\n", + "| This was the most uninteresting horror flick I have seen to date|\n", + "|I don't know if this exceptionally dull movie was intended as an unofficial sequel to 'The French Connection\", but it...|\n", + "|Heart of Darkness Movie Review Could a book that is well known for its eloquent wording and complicated concepts ever...|\n", + "| A bad movie ABOUT a bad movie|\n", + "|Apart from the fact that this film was made ( I suppose it seemed a good idea at the time considering BOTTOM was so p...|\n", + "|Watching this movie, you just have to ask: What were they thinking? There are so many noticeably bad parts of this mo...|\n", + "| OK, lets start with the best|\n", + "| Anna Christie (Greta Garbo) returns to see her father Chris (George F Marion) after 15 years|\n", + "| C|\n", + "| Tom and Jerry are transporting goods via airplane to Africa|\n", + "+------------------------------------------------------------------------------------------------------------------------+\n", + "only showing top 20 rows\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "100" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# only use first N examples, since this is slow\n", + "df = spark.read.parquet(\"imdb_test\").limit(100)\n", + "df.show(truncate=120)\n", + "df.count()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "831bc52c-a5c6-4c29-a6da-0566b5167773", + "metadata": {}, + "outputs": [], + "source": [ + "# only use first 100 rows, since generation takes a while\n", + "df1 = df.withColumn(\"input\", preprocess(col(\"lines\"), \"Translate English to German: \")).select(\"input\").limit(100).cache()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "46dac59c-5a54-4576-91e0-279c8b375b95", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "100" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df1.count()" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "fef1d846-5852-4762-8527-602f32c0d7cd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+------------------------------------------------------------------------------------------------------------------------+\n", + "| input|\n", + "+------------------------------------------------------------------------------------------------------------------------+\n", + "| Translate English to German: This is so overly clichéd you'll want to switch it off after the first 45 minutes|\n", + "| Translate English to German: I am a big fan of The ABC Movies of the Week genre|\n", + "|Translate English to German: In the early 1990's \"Step-by-Step\" came as a tedious combination of the ultra-cheesy \"Fu...|\n", + "|Translate English to German: When The Spirits Within was released, all you heard from Final Fantasy fans was how awfu...|\n", + "| Translate English to German: I like to think of myself as a bad movie connoisseur|\n", + "|Translate English to German: This film did well at the box office, and the producers of this mess thought the stars h...|\n", + "|Translate English to German: Following the pleasingly atmospheric original and the amusingly silly second one, this i...|\n", + "| Translate English to German: I like CKY and Viva La Bam, so I couldn't resist this when I saw it for £1|\n", + "| Translate English to German: I have read all of the reviews for this direct to video movie|\n", + "|Translate English to German: Yes, it was an awful movie, but there was a song near the beginning of the movie, I thin...|\n", + "| Translate English to German: This was the most uninteresting horror flick I have seen to date|\n", + "|Translate English to German: I don't know if this exceptionally dull movie was intended as an unofficial sequel to 'T...|\n", + "|Translate English to German: Heart of Darkness Movie Review Could a book that is well known for its eloquent wording ...|\n", + "| Translate English to German: A bad movie ABOUT a bad movie|\n", + "|Translate English to German: Apart from the fact that this film was made ( I suppose it seemed a good idea at the tim...|\n", + "|Translate English to German: Watching this movie, you just have to ask: What were they thinking? There are so many no...|\n", + "| Translate English to German: OK, lets start with the best|\n", + "|Translate English to German: Anna Christie (Greta Garbo) returns to see her father Chris (George F Marion) after 15 y...|\n", + "| Translate English to German: C|\n", + "| Translate English to German: Tom and Jerry are transporting goods via airplane to Africa|\n", + "+------------------------------------------------------------------------------------------------------------------------+\n", + "only showing top 20 rows\n", + "\n" + ] + } + ], + "source": [ + "df1.show(truncate=120)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "e7ae69d3-70c2-4765-928f-c96a7ba59829", + "metadata": {}, + "outputs": [], + "source": [ + "def predict_batch_fn():\n", + " import tensorflow as tf\n", + " import numpy as np\n", + " from transformers import TFT5ForConditionalGeneration, AutoTokenizer\n", + "\n", + " # Enable GPU memory growth\n", + " gpus = tf.config.experimental.list_physical_devices('GPU')\n", + " if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)\n", + "\n", + " model = TFT5ForConditionalGeneration.from_pretrained(\"google-t5/t5-small\")\n", + " tokenizer = AutoTokenizer.from_pretrained(\"google-t5/t5-small\")\n", + "\n", + " def predict(inputs):\n", + " flattened = np.squeeze(inputs).tolist() # convert 2d numpy array of string into flattened python list\n", + " input_ids = tokenizer(flattened, \n", + " padding=\"longest\", \n", + " max_length=512,\n", + " return_tensors=\"tf\").input_ids\n", + " output_ids = model.generate(input_ids, max_length=20)\n", + " string_outputs = np.array([tokenizer.decode(o, skip_special_tokens=True) for o in output_ids])\n", + " print(\"predict: {}\".format(len(flattened)))\n", + "\n", + " return string_outputs\n", + " \n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "36684f59-d947-43f8-a2e8-c7a423764e88", + "metadata": {}, + "outputs": [], + "source": [ + "generate = predict_batch_udf(predict_batch_fn,\n", + " return_type=StringType(),\n", + " batch_size=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "6a01c855-8fa1-4765-a3a5-2c9dd872df10", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 21:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 9.39 ms, sys: 2.14 ms, total: 11.5 ms\n", + "Wall time: 11.4 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "# first pass caches model/fn\n", + "preds = df1.withColumn(\"preds\", generate(struct(\"input\")))\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "d912d4b0-cd0b-44ea-859a-b23455cc2700", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 23:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 3.62 ms, sys: 4.01 ms, total: 7.64 ms\n", + "Wall time: 8.53 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "preds = df1.withColumn(\"preds\", generate(\"input\"))\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "5fe3d88b-30f7-468f-8db8-1f4118d0f26c", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 25:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 5.37 ms, sys: 2.51 ms, total: 7.88 ms\n", + "Wall time: 8.52 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "preds = df1.withColumn(\"preds\", generate(col(\"input\")))\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "4ad9b365-4b9a-438e-8fdf-47da55cb1cf4", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 27:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+------------------------------------------------------------+------------------------------------------------------------+\n", + "| input| preds|\n", + "+------------------------------------------------------------+------------------------------------------------------------+\n", + "|Translate English to German: This is so overly clichéd yo...| Das ist so übertrieben klischeehaft, dass Sie es nach den|\n", + "|Translate English to German: I am a big fan of The ABC Mo...| Ich bin ein großer Fan von The ABC Movies of the Week|\n", + "|Translate English to German: In the early 1990's \"Step-by...| Anfang der 1990er Jahre kam \"Step-by-Step\" als müh|\n", + "|Translate English to German: When The Spirits Within was ...|Als The Spirits Within veröffentlicht wurde, hörten Sie v...|\n", + "|Translate English to German: I like to think of myself as...| Ich halte mich gerne als schlechter Filmliebhaber|\n", + "|Translate English to German: This film did well at the bo...|Dieser Film hat sich gut an der Boxoffice ereignet, und d...|\n", + "|Translate English to German: Following the pleasingly atm...|Nach dem erfreulich stimmungsvollen Original und dem amüsant|\n", + "|Translate English to German: I like CKY and Viva La Bam, ...| Ich mag CKY und Viva La Bam, also konnte ich mich nicht|\n", + "|Translate English to German: I have read all of the revie...| Ich habe alle Rezensionen zu diesem direkten Film gelesen.|\n", + "|Translate English to German: Yes, it was an awful movie, ...| Ja, es war ein schrecklicher Film, aber es gab|\n", + "|Translate English to German: This was the most uninterest...|Dies war der größte Horrorfilm, den ich bisher gesehen habe.|\n", + "|Translate English to German: I don't know if this excepti...|Ich weiß nicht, ob dieser außergewöhnlich langweilige Fil...|\n", + "|Translate English to German: Heart of Darkness Movie Revi...|Herz der Dunkelheit Film Review Kann ein Buch, das für se...|\n", + "| Translate English to German: A bad movie ABOUT a bad movie| Ein schlechter Film ABOUT a bad movie|\n", + "|Translate English to German: Apart from the fact that thi...| Dieser Film wurde zwar fertiggestellt, aber es schien mir |\n", + "|Translate English to German: Watching this movie, you jus...|Wenn man diesen Film anschaut, muss man einfach fragen: W...|\n", + "| Translate English to German: OK, lets start with the best| OK, lets start with the best|\n", + "|Translate English to German: Anna Christie (Greta Garbo) ...| Anna Christie (Greta Garbo) kehrt nach 15 Jahren zurück,|\n", + "| Translate English to German: C| C|\n", + "|Translate English to German: Tom and Jerry are transporti...|Tom und Jerry transportieren Güter über Flugzeug nach Afrika|\n", + "+------------------------------------------------------------+------------------------------------------------------------+\n", + "only showing top 20 rows\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "preds.show(truncate=60)" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "1eb0c83b-d91b-4f8c-a5e7-c35f55c88108", + "metadata": {}, + "outputs": [], + "source": [ + "# only use first 100 rows, since generation takes a while\n", + "df2 = df.withColumn(\"input\", preprocess(col(\"lines\"), \"Translate English to French: \")).select(\"input\").limit(100).cache()" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "054f94fd-fe79-41e7-b1c7-6124083acc72", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+------------------------------------------------------------------------------------------------------------------------+\n", + "| input|\n", + "+------------------------------------------------------------------------------------------------------------------------+\n", + "| Translate English to French: This is so overly clichéd you'll want to switch it off after the first 45 minutes|\n", + "| Translate English to French: I am a big fan of The ABC Movies of the Week genre|\n", + "|Translate English to French: In the early 1990's \"Step-by-Step\" came as a tedious combination of the ultra-cheesy \"Fu...|\n", + "|Translate English to French: When The Spirits Within was released, all you heard from Final Fantasy fans was how awfu...|\n", + "| Translate English to French: I like to think of myself as a bad movie connoisseur|\n", + "|Translate English to French: This film did well at the box office, and the producers of this mess thought the stars h...|\n", + "|Translate English to French: Following the pleasingly atmospheric original and the amusingly silly second one, this i...|\n", + "| Translate English to French: I like CKY and Viva La Bam, so I couldn't resist this when I saw it for £1|\n", + "| Translate English to French: I have read all of the reviews for this direct to video movie|\n", + "|Translate English to French: Yes, it was an awful movie, but there was a song near the beginning of the movie, I thin...|\n", + "| Translate English to French: This was the most uninteresting horror flick I have seen to date|\n", + "|Translate English to French: I don't know if this exceptionally dull movie was intended as an unofficial sequel to 'T...|\n", + "|Translate English to French: Heart of Darkness Movie Review Could a book that is well known for its eloquent wording ...|\n", + "| Translate English to French: A bad movie ABOUT a bad movie|\n", + "|Translate English to French: Apart from the fact that this film was made ( I suppose it seemed a good idea at the tim...|\n", + "|Translate English to French: Watching this movie, you just have to ask: What were they thinking? There are so many no...|\n", + "| Translate English to French: OK, lets start with the best|\n", + "|Translate English to French: Anna Christie (Greta Garbo) returns to see her father Chris (George F Marion) after 15 y...|\n", + "| Translate English to French: C|\n", + "| Translate English to French: Tom and Jerry are transporting goods via airplane to Africa|\n", + "+------------------------------------------------------------------------------------------------------------------------+\n", + "only showing top 20 rows\n", + "\n" + ] + } + ], + "source": [ + "df2.show(truncate=120)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "6f6b70f9-188a-402b-9143-78a5788140e4", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 33:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.9 ms, sys: 5.97 ms, total: 8.87 ms\n", + "Wall time: 11.7 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "# first pass caches model/fn\n", + "preds = df2.withColumn(\"preds\", generate(struct(\"input\")))\n", + "result = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "031a6a5e-7999-4653-b394-19ed478d8c96", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 35:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 4.41 ms, sys: 1.59 ms, total: 5.99 ms\n", + "Wall time: 8.23 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "preds = df2.withColumn(\"preds\", generate(\"input\"))\n", + "result = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "229b6515-82f6-4e9c-90f0-a9c3cfb26301", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 37:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 5.46 ms, sys: 1.17 ms, total: 6.63 ms\n", + "Wall time: 8.08 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "preds = df2.withColumn(\"preds\", generate(col(\"input\")))\n", + "result = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "8be750ac-fa39-452e-bb4c-c2270bc2f70d", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 39:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+------------------------------------------------------------+------------------------------------------------------------+\n", + "| input| preds|\n", + "+------------------------------------------------------------+------------------------------------------------------------+\n", + "|Translate English to French: This is so overly clichéd yo...| Vous ne pouvez pas en tirer d'un tel cliché|\n", + "|Translate English to French: I am a big fan of The ABC Mo...| Je suis un grand fan du genre The ABC Movies of the Week|\n", + "|Translate English to French: In the early 1990's \"Step-by...| Au début des années 1990, «Step-by-Step» a été une|\n", + "|Translate English to French: When The Spirits Within was ...|Lorsque The Spirits Within a été publié, tout ce que vous...|\n", + "|Translate English to French: I like to think of myself as...| Je me considère comme un mauvais réalisateur de films|\n", + "|Translate English to French: This film did well at the bo...| Ce film a bien avancé à la salle de cinéma et|\n", + "|Translate English to French: Following the pleasingly atm...|Après l'original agréablement atmosphérique et la seconde...|\n", + "|Translate English to French: I like CKY and Viva La Bam, ...| Je m'aime CKY et Viva La Bam, |\n", + "|Translate English to French: I have read all of the revie...| J'ai lu tous les commentaires pour ce film direct à vidéo|\n", + "|Translate English to French: Yes, it was an awful movie, ...| Oui, c'était un film terrible, mais il y avait une chanson|\n", + "|Translate English to French: This was the most uninterest...| Ce fut le plus inquiétant et le plus inquiétant d'h|\n", + "|Translate English to French: I don't know if this excepti...|Je ne sais pas si ce film extrêmement tacheté était desti...|\n", + "|Translate English to French: Heart of Darkness Movie Revi...| Un livre connu pour son éloquence et ses concepts complexes|\n", + "| Translate English to French: A bad movie ABOUT a bad movie| Un mauvais film ABOUT a bad movie|\n", + "|Translate English to French: Apart from the fact that thi...|En plus du fait que ce film a été réalisé (je suppose quil s|\n", + "|Translate English to French: Watching this movie, you jus...|Vous devez simplement vous demander : « Que pense-t-il? » Il|\n", + "| Translate English to French: OK, lets start with the best| OK, s'il y a lieu de commencer par le meilleur|\n", + "|Translate English to French: Anna Christie (Greta Garbo) ...|Anna Christie (Greta Garbo) retourne pour voir son père C...|\n", + "| Translate English to French: C| C|\n", + "|Translate English to French: Tom and Jerry are transporti...| Tom et Jerry transportent des marchandises par avion en |\n", + "+------------------------------------------------------------+------------------------------------------------------------+\n", + "only showing top 20 rows\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "preds.show(truncate=60)" + ] + }, + { + "cell_type": "markdown", + "id": "bcabb2a8-3880-46ec-8e01-5a10f71fe83d", + "metadata": {}, + "source": [ + "### Using Triton Inference Server\n", + "\n", + "Note: you can restart the kernel and run from this point to simulate running in a different node or environment. " + ] + }, + { + "cell_type": "markdown", + "id": "5d98fa52-7665-49bf-865a-feec86effe23", + "metadata": {}, + "source": [ + "This notebook uses the [Python backend with a custom execution environment](https://github.com/triton-inference-server/python_backend#creating-custom-execution-environments) with the compatible versions of Python/Numpy for Triton 24.08, using a conda-pack environment created as follows:\n", + "```\n", + "conda create -n huggingface-tf -c conda-forge python=3.10.0\n", + "conda activate huggingface-tf\n", + "\n", + "export PYTHONNOUSERSITE=True\n", + "pip install numpy==1.26.4 tensorflow[and-cuda] tf-keras transformers conda-pack \n", + "\n", + "conda-pack # huggingface-tf.tar.gz\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "b858cf85-82e6-41ef-905b-d8c5d6fea492", + "metadata": {}, + "outputs": [], + "source": [ + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "05ce7c77-d562-45e8-89bb-cd656aba5a5f", + "metadata": {}, + "outputs": [], + "source": [ + "%%bash\n", + "# copy custom model to expected layout for Triton\n", + "rm -rf models\n", + "mkdir -p models\n", + "cp -r models_config/hf_generation_tf models\n", + "\n", + "# add custom execution environment\n", + "cp huggingface-tf.tar.gz models" + ] + }, + { + "cell_type": "markdown", + "id": "a552865c-5dad-4f25-8834-f41e253ac2f6", + "metadata": { + "tags": [] + }, + "source": [ + "#### Start Triton Server on each executor" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "afd00b7e-8150-4c95-a2e4-037e9c90f92a", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "[True]" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "num_executors = 1\n", + "triton_models_dir = \"{}/models\".format(os.getcwd())\n", + "huggingface_cache_dir = \"{}/.cache/huggingface\".format(os.path.expanduser('~'))\n", + "nodeRDD = sc.parallelize(list(range(num_executors)), num_executors)\n", + "\n", + "def start_triton(it):\n", + " import docker\n", + " import time\n", + " import tritonclient.grpc as grpcclient\n", + " \n", + " client=docker.from_env()\n", + " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", + " if containers:\n", + " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", + " else:\n", + " try:\n", + " container=client.containers.run(\n", + " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", + " detach=True,\n", + " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", + " environment=[\n", + " \"TRANSFORMERS_CACHE=/cache\"\n", + " ],\n", + " name=\"spark-triton\",\n", + " network_mode=\"host\",\n", + " remove=True,\n", + " shm_size=\"1G\",\n", + " volumes={\n", + " triton_models_dir: {\"bind\": \"/models\", \"mode\": \"ro\"},\n", + " huggingface_cache_dir: {\"bind\": \"/cache\", \"mode\": \"rw\"}\n", + " }\n", + " )\n", + " print(\">>>> starting triton: {}\".format(container.short_id))\n", + " except Exception as e:\n", + " print(\">>>> failed to start triton: {}\".format(e))\n", + " # wait for triton to be running\n", + " time.sleep(15)\n", + " client = grpcclient.InferenceServerClient(\"localhost:8001\")\n", + " ready = False\n", + " while not ready:\n", + " try:\n", + " ready = client.is_server_ready()\n", + " except Exception as e:\n", + " time.sleep(5)\n", + "\n", + " return [True]\n", + "\n", + "nodeRDD.barrier().mapPartitions(start_triton).collect()" + ] + }, + { + "cell_type": "markdown", + "id": "528d2df6-49fc-4be7-a534-a087dfe31c84", + "metadata": {}, + "source": [ + "#### Run inference" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "1a997c33-5202-466d-8304-b8c30f32978f", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "from functools import partial\n", + "from pyspark.ml.functions import predict_batch_udf\n", + "from pyspark.sql.functions import col, pandas_udf, struct\n", + "from pyspark.sql.types import StringType" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "9dea1875-6b95-4fc0-926d-a625a441b33d", + "metadata": {}, + "outputs": [], + "source": [ + "# only use first N examples, since this is slow\n", + "df = spark.read.parquet(\"imdb_test\").limit(100).cache()" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "5d6c54e7-534d-406f-b8e6-fd592efd0ab2", + "metadata": {}, + "outputs": [], + "source": [ + "# only use first sentence and add prefix for conditional generation\n", + "def preprocess(text: pd.Series, prefix: str = \"\") -> pd.Series:\n", + " @pandas_udf(\"string\")\n", + " def _preprocess(text: pd.Series) -> pd.Series:\n", + " return pd.Series([prefix + s.split(\".\")[0] for s in text])\n", + " return _preprocess(text)" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "dc1bbbe3-4232-49e5-80f6-99976524b73b", + "metadata": {}, + "outputs": [], + "source": [ + "# only use first 100 rows, since generation takes a while\n", + "df1 = df.withColumn(\"input\", preprocess(col(\"lines\"), \"Translate English to German: \")).select(\"input\").limit(100)" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "5d10c61c-6102-4d19-8dd6-0c7b5b65343e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+------------------------------------------------------------------------------------------------------------------------+\n", + "| input|\n", + "+------------------------------------------------------------------------------------------------------------------------+\n", + "| Translate English to German: This is so overly clichéd you'll want to switch it off after the first 45 minutes|\n", + "| Translate English to German: I am a big fan of The ABC Movies of the Week genre|\n", + "|Translate English to German: In the early 1990's \"Step-by-Step\" came as a tedious combination of the ultra-cheesy \"Fu...|\n", + "|Translate English to German: When The Spirits Within was released, all you heard from Final Fantasy fans was how awfu...|\n", + "| Translate English to German: I like to think of myself as a bad movie connoisseur|\n", + "|Translate English to German: This film did well at the box office, and the producers of this mess thought the stars h...|\n", + "|Translate English to German: Following the pleasingly atmospheric original and the amusingly silly second one, this i...|\n", + "| Translate English to German: I like CKY and Viva La Bam, so I couldn't resist this when I saw it for £1|\n", + "| Translate English to German: I have read all of the reviews for this direct to video movie|\n", + "|Translate English to German: Yes, it was an awful movie, but there was a song near the beginning of the movie, I thin...|\n", + "| Translate English to German: This was the most uninteresting horror flick I have seen to date|\n", + "|Translate English to German: I don't know if this exceptionally dull movie was intended as an unofficial sequel to 'T...|\n", + "|Translate English to German: Heart of Darkness Movie Review Could a book that is well known for its eloquent wording ...|\n", + "| Translate English to German: A bad movie ABOUT a bad movie|\n", + "|Translate English to German: Apart from the fact that this film was made ( I suppose it seemed a good idea at the tim...|\n", + "|Translate English to German: Watching this movie, you just have to ask: What were they thinking? There are so many no...|\n", + "| Translate English to German: OK, lets start with the best|\n", + "|Translate English to German: Anna Christie (Greta Garbo) returns to see her father Chris (George F Marion) after 15 y...|\n", + "| Translate English to German: C|\n", + "| Translate English to German: Tom and Jerry are transporting goods via airplane to Africa|\n", + "+------------------------------------------------------------------------------------------------------------------------+\n", + "only showing top 20 rows\n", + "\n" + ] + } + ], + "source": [ + "df1.show(truncate=120)" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "2e0907da-a5d9-4c3b-9db4-ce5e70ca9bb4", + "metadata": {}, + "outputs": [], + "source": [ + "def triton_fn(triton_uri, model_name):\n", + " import numpy as np\n", + " import tritonclient.grpc as grpcclient\n", + " \n", + " np_types = {\n", + " \"BOOL\": np.dtype(np.bool_),\n", + " \"INT8\": np.dtype(np.int8),\n", + " \"INT16\": np.dtype(np.int16),\n", + " \"INT32\": np.dtype(np.int32),\n", + " \"INT64\": np.dtype(np.int64),\n", + " \"FP16\": np.dtype(np.float16),\n", + " \"FP32\": np.dtype(np.float32),\n", + " \"FP64\": np.dtype(np.float64),\n", + " \"FP64\": np.dtype(np.double),\n", + " \"BYTES\": np.dtype(object)\n", + " }\n", + "\n", + " client = grpcclient.InferenceServerClient(triton_uri)\n", + " model_meta = client.get_model_metadata(model_name)\n", + " \n", + " def predict(inputs):\n", + " if isinstance(inputs, np.ndarray):\n", + " # single ndarray input\n", + " request = [grpcclient.InferInput(model_meta.inputs[0].name, inputs.shape, model_meta.inputs[0].datatype)]\n", + " request[0].set_data_from_numpy(inputs.astype(np_types[model_meta.inputs[0].datatype]))\n", + " else:\n", + " # dict of multiple ndarray inputs\n", + " request = [grpcclient.InferInput(i.name, inputs[i.name].shape, i.datatype) for i in model_meta.inputs]\n", + " for i in request:\n", + " i.set_data_from_numpy(inputs[i.name()].astype(np_types[i.datatype()]))\n", + " \n", + " response = client.infer(model_name, inputs=request)\n", + " \n", + " if len(model_meta.outputs) > 1:\n", + " # return dictionary of numpy arrays\n", + " return {o.name: response.as_numpy(o.name) for o in model_meta.outputs}\n", + " else:\n", + " # return single numpy array\n", + " return response.as_numpy(model_meta.outputs[0].name)\n", + " \n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "9308bdd7-6f67-484d-8b51-dd1e1b2960ba", + "metadata": {}, + "outputs": [], + "source": [ + "generate = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"hf_generation_tf\"),\n", + " return_type=StringType(),\n", + " input_tensor_shapes=[[1]],\n", + " batch_size=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "38484ffd-370d-492b-8ca4-9eff9f242a9f", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 45:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 5.88 ms, sys: 3.96 ms, total: 9.84 ms\n", + "Wall time: 2.66 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "# first pass caches model/fn\n", + "preds = df1.withColumn(\"preds\", generate(struct(\"input\")))\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "ebcb6699-3ac2-4529-ab0f-fab0a5e792da", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 47:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.82 ms, sys: 1.05 ms, total: 3.87 ms\n", + "Wall time: 1.03 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "preds = df1.withColumn(\"preds\", generate(\"input\"))\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "e2ed18ad-d00b-472c-b2c3-047932f2105d", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 49:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 1.55 ms, sys: 2.49 ms, total: 4.03 ms\n", + "Wall time: 967 ms\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "preds = df1.withColumn(\"preds\", generate(col(\"input\")))\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "0cd64a1c-beb8-47d5-ac6f-e8525bb61176", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 51:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+------------------------------------------------------------+------------------------------------------------------------+\n", + "| input| preds|\n", + "+------------------------------------------------------------+------------------------------------------------------------+\n", + "|Translate English to German: This is so overly clichéd yo...| Das ist so übertrieben klischeehaft, dass Sie es nach den|\n", + "|Translate English to German: I am a big fan of The ABC Mo...| Ich bin ein großer Fan von The ABC Movies of the Week|\n", + "|Translate English to German: In the early 1990's \"Step-by...| Anfang der 1990er Jahre kam \"Step-by-Step\" als müh|\n", + "|Translate English to German: When The Spirits Within was ...|Als The Spirits Within veröffentlicht wurde, hörten Sie v...|\n", + "|Translate English to German: I like to think of myself as...| Ich halte mich gerne als schlechter Filmliebhaber|\n", + "|Translate English to German: This film did well at the bo...|Dieser Film hat sich gut an der Boxoffice ereignet, und d...|\n", + "|Translate English to German: Following the pleasingly atm...|Nach dem erfreulich stimmungsvollen Original und dem amüsant|\n", + "|Translate English to German: I like CKY and Viva La Bam, ...| Ich mag CKY und Viva La Bam, also konnte ich mich nicht|\n", + "|Translate English to German: I have read all of the revie...| Ich habe alle Rezensionen zu diesem direkten Film gelesen.|\n", + "|Translate English to German: Yes, it was an awful movie, ...| Ja, es war ein schrecklicher Film, aber es gab|\n", + "|Translate English to German: This was the most uninterest...|Dies war der größte Horrorfilm, den ich bisher gesehen habe.|\n", + "|Translate English to German: I don't know if this excepti...|Ich weiß nicht, ob dieser außergewöhnlich langweilige Fil...|\n", + "|Translate English to German: Heart of Darkness Movie Revi...|Herz der Dunkelheit Film Review Kann ein Buch, das für se...|\n", + "| Translate English to German: A bad movie ABOUT a bad movie| Ein schlechter Film ABOUT a bad movie|\n", + "|Translate English to German: Apart from the fact that thi...| Dieser Film wurde zwar fertiggestellt, aber es schien mir |\n", + "|Translate English to German: Watching this movie, you jus...|Wenn man diesen Film anschaut, muss man einfach fragen: W...|\n", + "| Translate English to German: OK, lets start with the best| OK, lets start with the best|\n", + "|Translate English to German: Anna Christie (Greta Garbo) ...| Anna Christie (Greta Garbo) kehrt nach 15 Jahren zurück,|\n", + "| Translate English to German: C| C|\n", + "|Translate English to German: Tom and Jerry are transporti...|Tom und Jerry transportieren Güter über Flugzeug nach Afrika|\n", + "+------------------------------------------------------------+------------------------------------------------------------+\n", + "only showing top 20 rows\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "preds.show(truncate=60)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "af70fed8-0f2b-4ea7-841c-476afdf9b1c0", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "24/10/11 00:18:52 WARN CacheManager: Asked to cache already cached data.\n" + ] + } + ], + "source": [ + "# only use first 100 rows, since generation takes a while\n", + "df2 = df.withColumn(\"input\", preprocess(col(\"lines\"), \"Translate English to French: \")).select(\"input\").limit(100).cache()" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "ef075e10-e22c-4236-9e0b-cb47cf2d3d06", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+------------------------------------------------------------------------------------------------------------------------+\n", + "| input|\n", + "+------------------------------------------------------------------------------------------------------------------------+\n", + "| Translate English to French: This is so overly clichéd you'll want to switch it off after the first 45 minutes|\n", + "| Translate English to French: I am a big fan of The ABC Movies of the Week genre|\n", + "|Translate English to French: In the early 1990's \"Step-by-Step\" came as a tedious combination of the ultra-cheesy \"Fu...|\n", + "|Translate English to French: When The Spirits Within was released, all you heard from Final Fantasy fans was how awfu...|\n", + "| Translate English to French: I like to think of myself as a bad movie connoisseur|\n", + "|Translate English to French: This film did well at the box office, and the producers of this mess thought the stars h...|\n", + "|Translate English to French: Following the pleasingly atmospheric original and the amusingly silly second one, this i...|\n", + "| Translate English to French: I like CKY and Viva La Bam, so I couldn't resist this when I saw it for £1|\n", + "| Translate English to French: I have read all of the reviews for this direct to video movie|\n", + "|Translate English to French: Yes, it was an awful movie, but there was a song near the beginning of the movie, I thin...|\n", + "| Translate English to French: This was the most uninteresting horror flick I have seen to date|\n", + "|Translate English to French: I don't know if this exceptionally dull movie was intended as an unofficial sequel to 'T...|\n", + "|Translate English to French: Heart of Darkness Movie Review Could a book that is well known for its eloquent wording ...|\n", + "| Translate English to French: A bad movie ABOUT a bad movie|\n", + "|Translate English to French: Apart from the fact that this film was made ( I suppose it seemed a good idea at the tim...|\n", + "|Translate English to French: Watching this movie, you just have to ask: What were they thinking? There are so many no...|\n", + "| Translate English to French: OK, lets start with the best|\n", + "|Translate English to French: Anna Christie (Greta Garbo) returns to see her father Chris (George F Marion) after 15 y...|\n", + "| Translate English to French: C|\n", + "| Translate English to French: Tom and Jerry are transporting goods via airplane to Africa|\n", + "+------------------------------------------------------------------------------------------------------------------------+\n", + "only showing top 20 rows\n", + "\n" + ] + } + ], + "source": [ + "df2.show(truncate=120)" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "2e7e4af8-b815-4375-b851-8368309ee8e1", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 55:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 3.91 ms, sys: 1.34 ms, total: 5.25 ms\n", + "Wall time: 1.27 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "preds = df2.withColumn(\"preds\", generate(struct(\"input\")))\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "7b0aefb0-a96b-4791-a23c-1ce9b24eb20c", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 57:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 4.31 ms, sys: 0 ns, total: 4.31 ms\n", + "Wall time: 1 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "preds = df2.withColumn(\"preds\", generate(\"input\"))\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "1214b75b-a373-4579-b4c6-0cb8627da776", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 59:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.84 ms, sys: 1.31 ms, total: 4.15 ms\n", + "Wall time: 990 ms\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "preds = df2.withColumn(\"preds\", generate(col(\"input\")))\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "c9dbd21f-9e37-4221-b765-80ba8c80b884", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 61:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+------------------------------------------------------------+------------------------------------------------------------+\n", + "| input| preds|\n", + "+------------------------------------------------------------+------------------------------------------------------------+\n", + "|Translate English to French: This is so overly clichéd yo...| Vous ne pouvez pas en tirer d'un tel cliché|\n", + "|Translate English to French: I am a big fan of The ABC Mo...| Je suis un grand fan du genre The ABC Movies of the Week|\n", + "|Translate English to French: In the early 1990's \"Step-by...| Au début des années 1990, «Step-by-Step» a été une|\n", + "|Translate English to French: When The Spirits Within was ...|Lorsque The Spirits Within a été publié, tout ce que vous...|\n", + "|Translate English to French: I like to think of myself as...| Je me considère comme un mauvais réalisateur de films|\n", + "|Translate English to French: This film did well at the bo...| Ce film a bien avancé à la salle de cinéma et|\n", + "|Translate English to French: Following the pleasingly atm...|Après l'original agréablement atmosphérique et la seconde...|\n", + "|Translate English to French: I like CKY and Viva La Bam, ...| Je m'aime CKY et Viva La Bam, |\n", + "|Translate English to French: I have read all of the revie...| J'ai lu tous les commentaires pour ce film direct à vidéo|\n", + "|Translate English to French: Yes, it was an awful movie, ...| Oui, c'était un film terrible, mais il y avait une chanson|\n", + "|Translate English to French: This was the most uninterest...| Ce fut le plus inquiétant et le plus inquiétant d'h|\n", + "|Translate English to French: I don't know if this excepti...|Je ne sais pas si ce film extrêmement tacheté était desti...|\n", + "|Translate English to French: Heart of Darkness Movie Revi...| Un livre connu pour son éloquence et ses concepts complexes|\n", + "| Translate English to French: A bad movie ABOUT a bad movie| Un mauvais film ABOUT a bad movie|\n", + "|Translate English to French: Apart from the fact that thi...|En plus du fait que ce film a été réalisé (je suppose quil s|\n", + "|Translate English to French: Watching this movie, you jus...|Vous devez simplement vous demander : « Que pense-t-il? » Il|\n", + "| Translate English to French: OK, lets start with the best| OK, s'il y a lieu de commencer par le meilleur|\n", + "|Translate English to French: Anna Christie (Greta Garbo) ...|Anna Christie (Greta Garbo) retourne pour voir son père C...|\n", + "| Translate English to French: C| C|\n", + "|Translate English to French: Tom and Jerry are transporti...| Tom et Jerry transportent des marchandises par avion en |\n", + "+------------------------------------------------------------+------------------------------------------------------------+\n", + "only showing top 20 rows\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "preds.show(truncate=60)" + ] + }, + { + "cell_type": "markdown", + "id": "919e3113-64dd-482a-9233-6607b3f63c1e", + "metadata": { + "tags": [] + }, + "source": [ + "#### Stop Triton Server on each executor" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "425d3b28-7705-45ba-8a18-ad34fc895219", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "[True]" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def stop_triton(it):\n", + " import docker\n", + " import time\n", + " \n", + " client=docker.from_env()\n", + " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", + " print(\">>>> stopping containers: {}\".format([c.short_id for c in containers]))\n", + " if containers:\n", + " container=containers[0]\n", + " container.stop(timeout=120)\n", + "\n", + " return [True]\n", + "\n", + "nodeRDD.barrier().mapPartitions(stop_triton).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "2dec80ca-7a7c-46a9-97c0-7afb1572f5b9", + "metadata": {}, + "outputs": [], + "source": [ + "spark.stop()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f43118ab-fc0a-4f64-a126-4302e615654a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "spark-dl-tf", + "language": "python", + "name": "python3" + }, + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_torch.ipynb similarity index 53% rename from examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation.ipynb rename to examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_torch.ipynb index d3949f846..a09bede39 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_torch.ipynb @@ -6,42 +6,57 @@ "metadata": {}, "source": [ "# PySpark Huggingface Inferencing\n", - "## Conditional generation\n", + "## Conditional generation with PyTorch\n", "\n", "From: https://huggingface.co/docs/transformers/model_doc/t5" ] }, - { - "cell_type": "markdown", - "id": "6bcbccb1-3f82-425b-a82d-12d4f2f91d6e", - "metadata": {}, - "source": [ - "### Using PyTorch" - ] - }, { "cell_type": "code", "execution_count": 1, - "id": "731faab7-a700-46f8-bba5-1c8764e5eacb", + "id": "c0eed0e8", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/home/leey/.pyenv/versions/3.9.10/envs/spark_rapids_examples/lib/python3.9/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n" + "You are using the default legacy behaviour of the . This is expected, and simply means that the `legacy` (previous) behavior will be used so nothing changes for you. If you want to use the new behaviour, set `legacy=False`. This should only be set if you understand what it means, and thoroughly read the reason why this was added as explained in https://github.com/huggingface/transformers/pull/24565\n" ] } ], "source": [ - "from transformers import T5Tokenizer, T5ForConditionalGeneration\n", - "\n", - "tokenizer = T5Tokenizer.from_pretrained(\"t5-small\")\n", - "model = T5ForConditionalGeneration.from_pretrained(\"t5-small\")\n", - "\n", - "max_source_length = 512\n", - "max_target_length = 128\n", + "from transformers import T5Tokenizer, T5ForConditionalGeneration" + ] + }, + { + "cell_type": "markdown", + "id": "041ca559", + "metadata": {}, + "source": [ + "Enabling Huggingface tokenizer parallelism so that it is not automatically disabled with Python parallelism. See [this thread](https://github.com/huggingface/transformers/issues/5486) for more info. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6695a3e5", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "os.environ[\"TOKENIZERS_PARALLELISM\"] = \"true\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "900d6506", + "metadata": {}, + "outputs": [], + "source": [ + "tokenizer = T5Tokenizer.from_pretrained(\"google-t5/t5-small\")\n", + "model = T5ForConditionalGeneration.from_pretrained(\"google-t5/t5-small\")\n", "\n", "task_prefix = \"translate English to German: \"\n", "\n", @@ -57,30 +72,23 @@ { "cell_type": "code", "execution_count": 2, - "id": "45abfa26-02da-4d4a-a925-85b387de0ada", + "id": "73655aea", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/leey/.pyenv/versions/3.9.10/envs/spark_rapids_examples/lib/python3.9/site-packages/transformers/generation/utils.py:1346: UserWarning: Using `max_length`'s default (20) to control the generation length. This behaviour is deprecated and will be removed from the config in v5 of Transformers -- we recommend using `max_new_tokens` to control the maximum length of the generation.\n", - " warnings.warn(\n" - ] - } - ], + "outputs": [], "source": [ "input_ids = tokenizer(input_sequences, \n", " padding=\"longest\", \n", - " max_length=max_source_length,\n", + " max_length=512,\n", + " truncation=True,\n", " return_tensors=\"pt\").input_ids\n", - "outputs = model.generate(input_ids)" + "\n", + "outputs = model.generate(input_ids, max_length=20)" ] }, { "cell_type": "code", "execution_count": 3, - "id": "72972ade-3a97-4bb3-9efa-31039a1a9442", + "id": "90e54262", "metadata": {}, "outputs": [ { @@ -103,7 +111,7 @@ { "cell_type": "code", "execution_count": 4, - "id": "18d060a1-19ef-4101-a9a6-2fdc184e07b0", + "id": "6b11c89a", "metadata": {}, "outputs": [ { @@ -123,159 +131,94 @@ }, { "cell_type": "markdown", - "id": "05c79ac4-bf25-421e-b55e-020d6d9e15d5", + "id": "546eabe0", "metadata": {}, "source": [ - "### Using TensorFlow" + "## PySpark" ] }, { "cell_type": "code", - "execution_count": 5, - "id": "f6f0dbf3-712b-4c58-85eb-261ce15bb2be", + "execution_count": 1, + "id": "2f6db1f0-7d68-4af7-8bd6-c9fa45906c61", "metadata": {}, "outputs": [], "source": [ - "from transformers import T5Tokenizer, TFT5ForConditionalGeneration" + "import os\n", + "from pathlib import Path\n", + "from datasets import load_dataset" ] }, { "cell_type": "code", - "execution_count": 6, - "id": "2684fb41-9467-40c0-9d7e-a1cc867c5a3c", + "execution_count": 2, + "id": "68121304-f1df-466e-9347-c9d2b36a9b3a", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "All model checkpoint layers were used when initializing TFT5ForConditionalGeneration.\n", - "\n", - "All the layers of TFT5ForConditionalGeneration were initialized from the model checkpoint at t5-small.\n", - "If your task is similar to the task the model of the checkpoint was trained on, you can already use TFT5ForConditionalGeneration for predictions without further training.\n" - ] - } - ], + "outputs": [], "source": [ - "tokenizer = T5Tokenizer.from_pretrained(\"t5-small\")\n", - "model = TFT5ForConditionalGeneration.from_pretrained(\"t5-small\")\n", - "\n", - "max_source_length = 512\n", - "max_target_length = 128\n", - "\n", - "task_prefix = \"translate English to German: \"\n", - "\n", - "lines = [\n", - " \"The house is wonderful\",\n", - " \"Welcome to NYC\",\n", - " \"HuggingFace is a company\"\n", - "]\n", - "\n", - "input_sequences = [task_prefix + l for l in lines]" + "from pyspark.sql.types import *\n", + "from pyspark.sql import SparkSession\n", + "from pyspark import SparkConf" ] }, { "cell_type": "code", - "execution_count": 7, - "id": "6eb2dfdb-0ad3-4d0f-81a4-268d92c53759", + "execution_count": 3, + "id": "6279a849", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/home/leey/.pyenv/versions/3.9.10/envs/spark_rapids_examples/lib/python3.9/site-packages/transformers/generation/tf_utils.py:854: UserWarning: Using `max_length`'s default (20) to control the generation length. This behaviour is deprecated and will be removed from the config in v5 of Transformers -- we recommend using `max_new_tokens` to control the maximum length of the generation.\n", - " warnings.warn(\n" + "24/10/10 00:10:48 WARN Utils: Your hostname, cb4ae00-lcedt resolves to a loopback address: 127.0.1.1; using 10.110.47.100 instead (on interface eno1)\n", + "24/10/10 00:10:48 WARN Utils: Set SPARK_LOCAL_IP if you need to bind to another address\n", + "Setting default log level to \"WARN\".\n", + "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", + "24/10/10 00:10:48 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n" ] } ], - "source": [ - "input_ids = tokenizer(input_sequences, \n", - " padding=\"longest\", \n", - " max_length=max_source_length,\n", - " return_tensors=\"tf\").input_ids\n", - "outputs = model.generate(input_ids)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "720158d4-e0e0-4904-b096-e5aede756afd", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['Das Haus ist wunderbar',\n", - " 'Willkommen in NYC',\n", - " 'HuggingFace ist ein Unternehmen']" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[tokenizer.decode(o, skip_special_tokens=True) for o in outputs]" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "8d4b364b-13cb-48ea-a97a-ccfc9e408075", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'tf'" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.framework" - ] - }, - { - "cell_type": "markdown", - "id": "546eabe0", - "metadata": {}, - "source": [ - "## PySpark" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "2f6db1f0-7d68-4af7-8bd6-c9fa45906c61", - "metadata": {}, - "outputs": [], "source": [ "import os\n", - "from pathlib import Path\n", - "from torchtext.datasets import IMDB" + "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", + "\n", + "conf = SparkConf()\n", + "if 'spark' not in globals():\n", + " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", + " import socket\n", + " hostname = socket.gethostname()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", + "conf.set(\"spark.task.maxFailures\", \"1\")\n", + "conf.set(\"spark.driver.memory\", \"8g\")\n", + "conf.set(\"spark.executor.memory\", \"8g\")\n", + "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", + "conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.maxRecordsPerBatch\", \"512\")\n", + "conf.set(\"spark.python.worker.reuse\", \"true\")\n", + "# Create Spark Session\n", + "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", + "sc = spark.sparkContext" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 4, "id": "b8453111-d068-49bb-ab91-8ae3d8bcdb7a", "metadata": {}, "outputs": [], "source": [ "# load IMDB reviews (test) dataset\n", - "data = IMDB(split='test')" + "data = load_dataset(\"imdb\", split=\"test\")" ] }, { "cell_type": "code", - "execution_count": 12, - "id": "6d5bb49d-9a5b-4d1c-949e-24d01a7cd9a5", + "execution_count": 5, + "id": "7ad01d4a", "metadata": {}, "outputs": [ { @@ -284,17 +227,16 @@ "25000" ] }, - "execution_count": 12, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# convert to nested array of string for pyspark\n", "lines = []\n", - "for label, text in data:\n", - " # only take first sentence of IMDB review\n", - " lines.append([text])\n", + "for example in data:\n", + " lines.append([example[\"text\"].split(\".\")[0]])\n", + "\n", "len(lines)" ] }, @@ -308,17 +250,7 @@ }, { "cell_type": "code", - "execution_count": 13, - "id": "68121304-f1df-466e-9347-c9d2b36a9b3a", - "metadata": {}, - "outputs": [], - "source": [ - "from pyspark.sql.types import *" - ] - }, - { - "cell_type": "code", - "execution_count": 14, + "execution_count": 6, "id": "d24d9404-0269-476e-a9dd-1842667c915a", "metadata": {}, "outputs": [ @@ -328,19 +260,19 @@ "StructType([StructField('lines', StringType(), True)])" ] }, - "execution_count": 14, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "df = spark.createDataFrame(lines, ['lines']).repartition(10)\n", + "df = spark.createDataFrame(lines, ['lines']).repartition(8)\n", "df.schema" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 7, "id": "4384c762-1f79-4f60-876c-94b1f552e8fb", "metadata": {}, "outputs": [ @@ -348,17 +280,16 @@ "name": "stderr", "output_type": "stream", "text": [ - "23/05/19 19:03:36 WARN TaskSetManager: Stage 0 contains a task of very large size (3858 KiB). The maximum recommended task size is 1000 KiB.\n", " \r" ] }, { "data": { "text/plain": [ - "[Row(lines='Now and again, a film comes around purely by accident that makes you doubt your sanity. We just finished studying the novel, \"Northanger Abbey\", at school and decided to refresh our memory of this unexciting piece of humourless garbage with the BBC adaptation.

The funny thing about Northanger Abbey is that it actually makes you want to kill yourself. The film is NOTHING like the book, for example, the subtly evil characters seem to have been turned into transparent stereotypes. John Thorpe looks like a leprechaun on acid while Isabella plays the role of slut. Catherine, the main character, is the most depressingly stupid and irritating actress on god\\'s earth (she looks like a coffee addict, her eyes are like basketballs) whilst Mr Tilney looks and acts like a retired porno stunt double. The plot goes completely off the rails at certain points of the film, I don\\'t know what the hell the director was thinking when for no reason at all, a 7 year old black kid who we\\'ve never met before takes the main character out of the abbey and starts cartwheeling in front of her. Yes, that\\'s right, cartwheeling. Nonsense of this kind is occasionally interrupted by Catherines \"fantasies\" in which she is being carried around a cathedral by an ogre.

Northanger Abbey is basically visual euthanasia so if you want to murder your boss or something like that, BBC have basically discovered a new way to kill someone. Northanger is a barely laughably bad film. Don\\'t watch it unless you\\'re in a padded cell.')]" + "[Row(lines='(Some Spoilers) Dull as dishwater slasher flick that has this deranged homeless man Harry, Darwyn Swalve, out murdering real-estate agent all over the city of L')]" ] }, - "execution_count": 15, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -377,19 +308,10 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 8, "id": "e7eec8ec-4126-4890-b957-025809fad67d", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/05/19 19:03:39 WARN TaskSetManager: Stage 3 contains a task of very large size (3858 KiB). The maximum recommended task size is 1000 KiB.\n", - " \r" - ] - } - ], + "outputs": [], "source": [ "df.write.mode(\"overwrite\").parquet(\"imdb_test\")" ] @@ -404,21 +326,14 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 9, "id": "20554ea5-01be-4a30-8607-db5d87786fec", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/05/19 19:03:40 WARN TaskSetManager: Stage 6 contains a task of very large size (3858 KiB). The maximum recommended task size is 1000 KiB.\n" - ] - } - ], + "outputs": [], "source": [ - "spark.conf.set(\"spark.sql.execution.arrow.maxRecordsPerBatch\", \"512\")\n", - "# This line will fail if the vectorized reader runs out of memory\n", + "if int(spark.conf.get(\"spark.sql.execution.arrow.maxRecordsPerBatch\")) > 512:\n", + " print(\"Decreasing `spark.sql.execution.arrow.maxRecordsPerBatch` to ensure the vectorized reader won't run out of memory\")\n", + " spark.conf.set(\"spark.sql.execution.arrow.maxRecordsPerBatch\", \"512\")\n", "assert len(df.head()) > 0, \"`df` should not be empty\"" ] }, @@ -427,13 +342,13 @@ "id": "06a4ecab-c9d9-466f-ba49-902ad1fd5488", "metadata": {}, "source": [ - "## Inference using Spark DL API (PyTorch)\n", + "## Inference using Spark DL API\n", "Note: you can restart the kernel and run from this point to simulate running in a different node or environment." ] }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 10, "id": "e7a00479-1347-4de8-8431-faa77f8cdf4c", "metadata": { "tags": [] @@ -448,7 +363,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 11, "id": "b9a0889a-35b4-493a-8197-1146fc7efd53", "metadata": {}, "outputs": [], @@ -463,7 +378,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 12, "id": "c483e4d4-9ab1-416f-a766-694e17490fd3", "metadata": {}, "outputs": [ @@ -474,26 +389,26 @@ "+------------------------------------------------------------------------------------------------------------------------+\n", "| lines|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", - "|...But not this one! I always wanted to know \"what happened\" next. We will never know for sure what happened because ...|\n", - "|Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pimp story without the gratuitous sex scen...|\n", - "|I watched this movie to see the direction one of the most promising young talents in movies was going. Unfortunately,...|\n", - "|This movie makes you wish imdb would let you vote a zero. One of the two movies I've ever walked out of. It's very ha...|\n", - "|I never want to see this movie again!

Not only is it dreadfully bad, but I can't stand seeing my hero Stan...|\n", - "|(As a note, I'd like to say that I saw this movie at my annual church camp, where the entire youth group laughed at i...|\n", - "|Don't get me wrong, I love the TV series of League Of Gentlemen. It was funny, twisted and completely inspired. I was...|\n", - "|Did you ever think, like after watching a horror movie with a group of friends: \"Wow, this is so cool! We have got to...|\n", - "|Awful, awful, awful...

I loved the original film. It was funny, charming, and had heart... this piece of j...|\n", - "|This movie seems a little clunky around the edges, like not quite enough zaniness was thrown it when it should have b...|\n", - "|I rented this movie hoping that it would provide some good entertainment and some cool poker knowledge or stories. Wh...|\n", - "|Well, where to start describing this celluloid debacle? You already know the big fat NADA passing as a plot, so let's...|\n", - "|I hoped for this show to be somewhat realistic. It stroke me as just another mainstream show after I watched it. I di...|\n", - "|All I have to say is one word...SUCKS!!!!. The only reason I gave this a 2 is because Josh Hartnett was in it and he'...|\n", - "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy screenplay.

The lighting at is s...|\n", - "|This critique tells the story of 4 little friends who went to watch Angels and Demons the movie on the first night it...|\n", - "|This review contains a partial spoiler.

Shallow from the outset, 'D.O.A.' at least starts as if it might b...|\n", - "|I'm rather surprised that anybody found this film touching or moving.

The basic premise of the film sounde...|\n", - "|If you like bad movies (and you must to watch this one) here's a good one. Not quite as funny as the first, but much ...|\n", - "|This is really bad, the characters were bland, the story was boring, and there is no sex scene. Furthermore, it lacks...|\n", + "| This is so overly clichéd you'll want to switch it off after the first 45 minutes|\n", + "| I am a big fan of The ABC Movies of the Week genre|\n", + "|In the early 1990's \"Step-by-Step\" came as a tedious combination of the ultra-cheesy \"Full House\" and the long-defunc...|\n", + "|When The Spirits Within was released, all you heard from Final Fantasy fans was how awful the movie was because it di...|\n", + "| I like to think of myself as a bad movie connoisseur|\n", + "|This film did well at the box office, and the producers of this mess thought the stars had such good chemistry in thi...|\n", + "|Following the pleasingly atmospheric original and the amusingly silly second one, this incredibly dull, slow, and une...|\n", + "| I like CKY and Viva La Bam, so I couldn't resist this when I saw it for £1|\n", + "| I have read all of the reviews for this direct to video movie|\n", + "|Yes, it was an awful movie, but there was a song near the beginning of the movie, I think, called \"I got a Woody\" or ...|\n", + "| This was the most uninteresting horror flick I have seen to date|\n", + "|I don't know if this exceptionally dull movie was intended as an unofficial sequel to 'The French Connection\", but it...|\n", + "|Heart of Darkness Movie Review Could a book that is well known for its eloquent wording and complicated concepts ever...|\n", + "| A bad movie ABOUT a bad movie|\n", + "|Apart from the fact that this film was made ( I suppose it seemed a good idea at the time considering BOTTOM was so p...|\n", + "|Watching this movie, you just have to ask: What were they thinking? There are so many noticeably bad parts of this mo...|\n", + "| OK, lets start with the best|\n", + "| Anna Christie (Greta Garbo) returns to see her father Chris (George F Marion) after 15 years|\n", + "| C|\n", + "| Tom and Jerry are transporting goods via airplane to Africa|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n" @@ -505,7 +420,7 @@ "100" ] }, - "execution_count": 20, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -519,7 +434,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 13, "id": "831bc52c-a5c6-4c29-a6da-0566b5167773", "metadata": {}, "outputs": [], @@ -530,24 +445,17 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 14, "id": "46dac59c-5a54-4576-91e0-279c8b375b95", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, { "data": { "text/plain": [ "100" ] }, - "execution_count": 22, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -558,7 +466,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 15, "id": "fef1d846-5852-4762-8527-602f32c0d7cd", "metadata": {}, "outputs": [ @@ -569,26 +477,26 @@ "+------------------------------------------------------------------------------------------------------------------------+\n", "| input|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", - "| Translate English to German: |\n", - "|Translate English to German: Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pimp story wi...|\n", - "|Translate English to German: I watched this movie to see the direction one of the most promising young talents in mov...|\n", - "| Translate English to German: This movie makes you wish imdb would let you vote a zero|\n", - "|Translate English to German: I never want to see this movie again!

Not only is it dreadfully bad, but I ca...|\n", - "|Translate English to German: (As a note, I'd like to say that I saw this movie at my annual church camp, where the en...|\n", - "| Translate English to German: Don't get me wrong, I love the TV series of League Of Gentlemen|\n", - "|Translate English to German: Did you ever think, like after watching a horror movie with a group of friends: \"Wow, th...|\n", - "| Translate English to German: Awful, awful, awful|\n", - "|Translate English to German: This movie seems a little clunky around the edges, like not quite enough zaniness was th...|\n", - "|Translate English to German: I rented this movie hoping that it would provide some good entertainment and some cool p...|\n", - "|Translate English to German: Well, where to start describing this celluloid debacle? You already know the big fat NAD...|\n", - "| Translate English to German: I hoped for this show to be somewhat realistic|\n", - "| Translate English to German: All I have to say is one word|\n", - "| Translate English to German: Honestly awful film, bad editing, awful lighting, dire dialog and scrappy screenplay|\n", - "|Translate English to German: This critique tells the story of 4 little friends who went to watch Angels and Demons th...|\n", - "| Translate English to German: This review contains a partial spoiler|\n", - "| Translate English to German: I'm rather surprised that anybody found this film touching or moving|\n", - "| Translate English to German: If you like bad movies (and you must to watch this one) here's a good one|\n", - "|Translate English to German: This is really bad, the characters were bland, the story was boring, and there is no sex...|\n", + "| Translate English to German: This is so overly clichéd you'll want to switch it off after the first 45 minutes|\n", + "| Translate English to German: I am a big fan of The ABC Movies of the Week genre|\n", + "|Translate English to German: In the early 1990's \"Step-by-Step\" came as a tedious combination of the ultra-cheesy \"Fu...|\n", + "|Translate English to German: When The Spirits Within was released, all you heard from Final Fantasy fans was how awfu...|\n", + "| Translate English to German: I like to think of myself as a bad movie connoisseur|\n", + "|Translate English to German: This film did well at the box office, and the producers of this mess thought the stars h...|\n", + "|Translate English to German: Following the pleasingly atmospheric original and the amusingly silly second one, this i...|\n", + "| Translate English to German: I like CKY and Viva La Bam, so I couldn't resist this when I saw it for £1|\n", + "| Translate English to German: I have read all of the reviews for this direct to video movie|\n", + "|Translate English to German: Yes, it was an awful movie, but there was a song near the beginning of the movie, I thin...|\n", + "| Translate English to German: This was the most uninteresting horror flick I have seen to date|\n", + "|Translate English to German: I don't know if this exceptionally dull movie was intended as an unofficial sequel to 'T...|\n", + "|Translate English to German: Heart of Darkness Movie Review Could a book that is well known for its eloquent wording ...|\n", + "| Translate English to German: A bad movie ABOUT a bad movie|\n", + "|Translate English to German: Apart from the fact that this film was made ( I suppose it seemed a good idea at the tim...|\n", + "|Translate English to German: Watching this movie, you just have to ask: What were they thinking? There are so many no...|\n", + "| Translate English to German: OK, lets start with the best|\n", + "|Translate English to German: Anna Christie (Greta Garbo) returns to see her father Chris (George F Marion) after 15 y...|\n", + "| Translate English to German: C|\n", + "| Translate English to German: Tom and Jerry are transporting goods via airplane to Africa|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n" @@ -601,7 +509,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 16, "id": "e7ae69d3-70c2-4765-928f-c96a7ba59829", "metadata": {}, "outputs": [], @@ -609,6 +517,7 @@ "def predict_batch_fn():\n", " import numpy as np\n", " from transformers import T5ForConditionalGeneration, T5Tokenizer\n", + "\n", " model = T5ForConditionalGeneration.from_pretrained(\"t5-small\")\n", " tokenizer = T5Tokenizer.from_pretrained(\"t5-small\")\n", "\n", @@ -617,10 +526,12 @@ " input_ids = tokenizer(flattened, \n", " padding=\"longest\", \n", " max_length=128,\n", + " truncation=True,\n", " return_tensors=\"pt\").input_ids\n", - " output_ids = model.generate(input_ids)\n", + " output_ids = model.generate(input_ids, max_length=20)\n", " string_outputs = np.array([tokenizer.decode(o, skip_special_tokens=True) for o in output_ids])\n", " print(\"predict: {}\".format(len(flattened)))\n", + " \n", " return string_outputs\n", " \n", " return predict" @@ -628,7 +539,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 17, "id": "36684f59-d947-43f8-a2e8-c7a423764e88", "metadata": {}, "outputs": [], @@ -640,7 +551,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 18, "id": "6a01c855-8fa1-4765-a3a5-2c9dd872df10", "metadata": {}, "outputs": [ @@ -655,8 +566,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 23.1 ms, sys: 4.47 ms, total: 27.6 ms\n", - "Wall time: 22.6 s\n" + "CPU times: user 6.58 ms, sys: 4.68 ms, total: 11.3 ms\n", + "Wall time: 7.41 s\n" ] }, { @@ -676,7 +587,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 19, "id": "d912d4b0-cd0b-44ea-859a-b23455cc2700", "metadata": {}, "outputs": [ @@ -691,8 +602,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 15.7 ms, sys: 2.96 ms, total: 18.7 ms\n", - "Wall time: 16 s\n" + "CPU times: user 1.87 ms, sys: 1.8 ms, total: 3.67 ms\n", + "Wall time: 5.71 s\n" ] }, { @@ -711,7 +622,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 20, "id": "5fe3d88b-30f7-468f-8db8-1f4118d0f26c", "metadata": {}, "outputs": [ @@ -726,8 +637,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 9.34 ms, sys: 4.6 ms, total: 13.9 ms\n", - "Wall time: 16 s\n" + "CPU times: user 2.99 ms, sys: 1.42 ms, total: 4.42 ms\n", + "Wall time: 5.69 s\n" ] }, { @@ -746,7 +657,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 21, "id": "4ad9b365-4b9a-438e-8fdf-47da55cb1cf4", "metadata": {}, "outputs": [ @@ -764,26 +675,26 @@ "+------------------------------------------------------------+------------------------------------------------------------+\n", "| input| preds|\n", "+------------------------------------------------------------+------------------------------------------------------------+\n", - "| Translate English to German: | Übersetzen Sie Englisch.|\n", - "|Translate English to German: Hard up, No proper jobs goin...| Warum nicht die Kinder mieten?|\n", - "|Translate English to German: I watched this movie to see ...|Ich habe diesen Film gesehen, um zu sehen, in welche Rich...|\n", - "|Translate English to German: This movie makes you wish im...|Dieser Film macht Sie sich wünschen, dass imdb Sie es Ihn...|\n", - "|Translate English to German: I never want to see this mov...| Ich möchte diesen Film nie wieder sehen!br />br|\n", - "|Translate English to German: (As a note, I'd like to say ...| (Als eine Bemerkung, möchte ich sagen, dass ich diesen|\n", - "|Translate English to German: Don't get me wrong, I love t...|Verstehen Sie mich nicht falsch, ich liebe die TV-Serie L...|\n", - "|Translate English to German: Did you ever think, like aft...|Haben Sie jemals glaubt, wie nach einem Horrorfilm mit ei...|\n", - "| Translate English to German: Awful, awful, awful| Wüstenlos, schrecklich, schrecklich|\n", - "|Translate English to German: This movie seems a little cl...|Dieser Film scheint etwas schlank um die Ecken zu sein, w...|\n", - "|Translate English to German: I rented this movie hoping t...|Ich miete diesen Film in der Hoffnung, dass er einige gut...|\n", - "|Translate English to German: Well, where to start describ...| Wie kann man dieses Celluloid-Debakel beschreiben?|\n", - "|Translate English to German: I hoped for this show to be ...| Ich hoffe, dass diese Show etwas realistisch sein wird.|\n", - "| Translate English to German: All I have to say is one word| Ich muss nur ein Wort sagen|\n", - "|Translate English to German: Honestly awful film, bad edi...|Honestly awful film, bad editing, awful lighting, dire di...|\n", - "|Translate English to German: This critique tells the stor...|Diese Kritik erzählt die Geschichte von 4 kleinen Freunde...|\n", - "|Translate English to German: This review contains a parti...| Dieses Review enthält einen Teil-Störer|\n", - "|Translate English to German: I'm rather surprised that an...|Ich bin ziemlich überrascht, dass jemand diesen Film berü...|\n", - "|Translate English to German: If you like bad movies (and ...|Wenn Sie schlechte Filme (und Sie müssen diesen schauen) ...|\n", - "|Translate English to German: This is really bad, the char...|Das ist wirklich schlecht, die Charaktere waren schmeiche...|\n", + "|Translate English to German: This is so overly clichéd yo...| Das ist so übertrieben klischeehaft, dass Sie es nach den|\n", + "|Translate English to German: I am a big fan of The ABC Mo...| Ich bin ein großer Fan von The ABC Movies of the Week|\n", + "|Translate English to German: In the early 1990's \"Step-by...| Anfang der 1990er Jahre kam \"Step-by-Step\" als müh|\n", + "|Translate English to German: When The Spirits Within was ...|Als The Spirits Within veröffentlicht wurde, hörten Sie v...|\n", + "|Translate English to German: I like to think of myself as...| Ich halte mich gerne als schlechter Filmliebhaber|\n", + "|Translate English to German: This film did well at the bo...|Dieser Film hat sich gut an der Boxoffice ereignet, und d...|\n", + "|Translate English to German: Following the pleasingly atm...|Nach dem erfreulich stimmungsvollen Original und dem amüsant|\n", + "|Translate English to German: I like CKY and Viva La Bam, ...| Ich mag CKY und Viva La Bam, also konnte ich mich nicht|\n", + "|Translate English to German: I have read all of the revie...| Ich habe alle Rezensionen zu diesem direkten Film gelesen.|\n", + "|Translate English to German: Yes, it was an awful movie, ...| Ja, es war ein schrecklicher Film, aber es gab|\n", + "|Translate English to German: This was the most uninterest...|Dies war der größte Horrorfilm, den ich bisher gesehen habe.|\n", + "|Translate English to German: I don't know if this excepti...|Ich weiß nicht, ob dieser außergewöhnlich langweilige Fil...|\n", + "|Translate English to German: Heart of Darkness Movie Revi...|Herz der Dunkelheit Film Review Kann ein Buch, das für se...|\n", + "| Translate English to German: A bad movie ABOUT a bad movie| Ein schlechter Film ABOUT a bad movie|\n", + "|Translate English to German: Apart from the fact that thi...| Dieser Film wurde zwar fertiggestellt, aber es schien mir|\n", + "|Translate English to German: Watching this movie, you jus...|Wenn man diesen Film anschaut, muss man einfach fragen: W...|\n", + "| Translate English to German: OK, lets start with the best| OK, lets start with the best|\n", + "|Translate English to German: Anna Christie (Greta Garbo) ...| Anna Christie (Greta Garbo) kehrt nach 15 Jahren zurück,|\n", + "| Translate English to German: C| C|\n", + "|Translate English to German: Tom and Jerry are transporti...|Tom und Jerry transportieren Güter über Flugzeug nach Afrika|\n", "+------------------------------------------------------------+------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n" @@ -803,7 +714,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 22, "id": "1eb0c83b-d91b-4f8c-a5e7-c35f55c88108", "metadata": {}, "outputs": [], @@ -814,17 +725,10 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 23, "id": "054f94fd-fe79-41e7-b1c7-6124083acc72", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 28:=============================================> (8 + 2) / 10]\r" - ] - }, { "name": "stdout", "output_type": "stream", @@ -832,37 +736,30 @@ "+------------------------------------------------------------------------------------------------------------------------+\n", "| input|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", - "| Translate English to French: |\n", - "|Translate English to French: Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pimp story wi...|\n", - "|Translate English to French: I watched this movie to see the direction one of the most promising young talents in mov...|\n", - "| Translate English to French: This movie makes you wish imdb would let you vote a zero|\n", - "|Translate English to French: I never want to see this movie again!

Not only is it dreadfully bad, but I ca...|\n", - "|Translate English to French: (As a note, I'd like to say that I saw this movie at my annual church camp, where the en...|\n", - "| Translate English to French: Don't get me wrong, I love the TV series of League Of Gentlemen|\n", - "|Translate English to French: Did you ever think, like after watching a horror movie with a group of friends: \"Wow, th...|\n", - "| Translate English to French: Awful, awful, awful|\n", - "|Translate English to French: This movie seems a little clunky around the edges, like not quite enough zaniness was th...|\n", - "|Translate English to French: I rented this movie hoping that it would provide some good entertainment and some cool p...|\n", - "|Translate English to French: Well, where to start describing this celluloid debacle? You already know the big fat NAD...|\n", - "| Translate English to French: I hoped for this show to be somewhat realistic|\n", - "| Translate English to French: All I have to say is one word|\n", - "| Translate English to French: Honestly awful film, bad editing, awful lighting, dire dialog and scrappy screenplay|\n", - "|Translate English to French: This critique tells the story of 4 little friends who went to watch Angels and Demons th...|\n", - "| Translate English to French: This review contains a partial spoiler|\n", - "| Translate English to French: I'm rather surprised that anybody found this film touching or moving|\n", - "| Translate English to French: If you like bad movies (and you must to watch this one) here's a good one|\n", - "|Translate English to French: This is really bad, the characters were bland, the story was boring, and there is no sex...|\n", + "| Translate English to French: This is so overly clichéd you'll want to switch it off after the first 45 minutes|\n", + "| Translate English to French: I am a big fan of The ABC Movies of the Week genre|\n", + "|Translate English to French: In the early 1990's \"Step-by-Step\" came as a tedious combination of the ultra-cheesy \"Fu...|\n", + "|Translate English to French: When The Spirits Within was released, all you heard from Final Fantasy fans was how awfu...|\n", + "| Translate English to French: I like to think of myself as a bad movie connoisseur|\n", + "|Translate English to French: This film did well at the box office, and the producers of this mess thought the stars h...|\n", + "|Translate English to French: Following the pleasingly atmospheric original and the amusingly silly second one, this i...|\n", + "| Translate English to French: I like CKY and Viva La Bam, so I couldn't resist this when I saw it for £1|\n", + "| Translate English to French: I have read all of the reviews for this direct to video movie|\n", + "|Translate English to French: Yes, it was an awful movie, but there was a song near the beginning of the movie, I thin...|\n", + "| Translate English to French: This was the most uninteresting horror flick I have seen to date|\n", + "|Translate English to French: I don't know if this exceptionally dull movie was intended as an unofficial sequel to 'T...|\n", + "|Translate English to French: Heart of Darkness Movie Review Could a book that is well known for its eloquent wording ...|\n", + "| Translate English to French: A bad movie ABOUT a bad movie|\n", + "|Translate English to French: Apart from the fact that this film was made ( I suppose it seemed a good idea at the tim...|\n", + "|Translate English to French: Watching this movie, you just have to ask: What were they thinking? There are so many no...|\n", + "| Translate English to French: OK, lets start with the best|\n", + "|Translate English to French: Anna Christie (Greta Garbo) returns to see her father Chris (George F Marion) after 15 y...|\n", + "| Translate English to French: C|\n", + "| Translate English to French: Tom and Jerry are transporting goods via airplane to Africa|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n" ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] } ], "source": [ @@ -871,7 +768,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 24, "id": "6f6b70f9-188a-402b-9143-78a5788140e4", "metadata": {}, "outputs": [ @@ -879,15 +776,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 31:> (0 + 1) / 1]\r" + "[Stage 33:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 20.3 ms, sys: 0 ns, total: 20.3 ms\n", - "Wall time: 22 s\n" + "CPU times: user 2.46 ms, sys: 2.2 ms, total: 4.67 ms\n", + "Wall time: 7.38 s\n" ] }, { @@ -907,7 +804,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 25, "id": "031a6a5e-7999-4653-b394-19ed478d8c96", "metadata": {}, "outputs": [ @@ -915,15 +812,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 33:> (0 + 1) / 1]\r" + "[Stage 35:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 16.8 ms, sys: 0 ns, total: 16.8 ms\n", - "Wall time: 15.4 s\n" + "CPU times: user 3.34 ms, sys: 1.13 ms, total: 4.47 ms\n", + "Wall time: 6.1 s\n" ] }, { @@ -942,7 +839,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 26, "id": "229b6515-82f6-4e9c-90f0-a9c3cfb26301", "metadata": {}, "outputs": [ @@ -950,15 +847,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 35:> (0 + 1) / 1]\r" + "[Stage 37:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 12.6 ms, sys: 791 µs, total: 13.3 ms\n", - "Wall time: 15.4 s\n" + "CPU times: user 1.72 ms, sys: 2.89 ms, total: 4.6 ms\n", + "Wall time: 5.93 s\n" ] }, { @@ -977,7 +874,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 27, "id": "8be750ac-fa39-452e-bb4c-c2270bc2f70d", "metadata": {}, "outputs": [ @@ -985,7 +882,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 37:> (0 + 1) / 1]\r" + "[Stage 39:> (0 + 1) / 1]\r" ] }, { @@ -995,26 +892,26 @@ "+------------------------------------------------------------+------------------------------------------------------------+\n", "| input| preds|\n", "+------------------------------------------------------------+------------------------------------------------------------+\n", - "| Translate English to French: | :|\n", - "|Translate English to French: Hard up, No proper jobs goin...| Vous ne pouvez pas louer vos enfants!|\n", - "|Translate English to French: I watched this movie to see ...|J’ai regardé ce film pour voir la direction d’un des jeun...|\n", - "|Translate English to French: This movie makes you wish im...|Ce film vous fait envie de voir imdb vous laisser voter zéro|\n", - "|Translate English to French: I never want to see this mov...| Je ne veux jamais voir ce film à nouveau!br /|\n", - "|Translate English to French: (As a note, I'd like to say ...| ( titre de note, je voudrais dire que j'ai vu ce film|\n", - "|Translate English to French: Don't get me wrong, I love t...|Ne m'oubliez pas, je m'aime la série de télévision de League|\n", - "|Translate English to French: Did you ever think, like aft...|Vous avez jamais pensé, comme après avoir vu un film d'horre|\n", - "| Translate English to French: Awful, awful, awful| Awful, awful, awful|\n", - "|Translate English to French: This movie seems a little cl...| Ce film semble un peu cloné autour des bords, comme il|\n", - "|Translate English to French: I rented this movie hoping t...| J'ai loué ce film en espérant qu'il fournirait|\n", - "|Translate English to French: Well, where to start describ...|Vous savez déjà que la grande graisse NADA passe comme un...|\n", - "|Translate English to French: I hoped for this show to be ...| J'espère que ce spectacle sera quelque peu réaliste|\n", - "| Translate English to French: All I have to say is one word| Je n'ai qu'à dire un mot|\n", - "|Translate English to French: Honestly awful film, bad edi...| l'instar de l'arrière-plan, il|\n", - "|Translate English to French: This critique tells the stor...|Cette critique raconte l'histoire de 4 petits amis qui on...|\n", - "|Translate English to French: This review contains a parti...| Cet examen contient un spoiler partiel|\n", - "|Translate English to French: I'm rather surprised that an...|Je suis plutôt surpris que quelqu'un ait trouvé ce film t...|\n", - "|Translate English to French: If you like bad movies (and ...|Si vous aimez des films mauvais (et vous devez regarder c...|\n", - "|Translate English to French: This is really bad, the char...| C'est vraiment mauvais, les personnages étaient bourds, l|\n", + "|Translate English to French: This is so overly clichéd yo...| Vous ne pouvez pas en tirer d'un tel cliché|\n", + "|Translate English to French: I am a big fan of The ABC Mo...| Je suis un grand fan du genre The ABC Movies of the Week|\n", + "|Translate English to French: In the early 1990's \"Step-by...| Au début des années 1990, «Step-by-Step» a été une|\n", + "|Translate English to French: When The Spirits Within was ...|Lorsque The Spirits Within a été publié, tout ce que vous...|\n", + "|Translate English to French: I like to think of myself as...| Je me considère comme un mauvais réalisateur de films|\n", + "|Translate English to French: This film did well at the bo...| Ce film a bien avancé à la salle de cinéma et|\n", + "|Translate English to French: Following the pleasingly atm...|Après l'original agréablement atmosphérique et la seconde...|\n", + "|Translate English to French: I like CKY and Viva La Bam, ...| Je m'aime CKY et Viva La Bam,|\n", + "|Translate English to French: I have read all of the revie...| J'ai lu tous les commentaires pour ce film direct à vidéo|\n", + "|Translate English to French: Yes, it was an awful movie, ...| Oui, c'était un film terrible, mais il y avait une chanson|\n", + "|Translate English to French: This was the most uninterest...| Ce fut le plus inquiétant et le plus inquiétant d'h|\n", + "|Translate English to French: I don't know if this excepti...|Je ne sais pas si ce film extrêmement tacheté était desti...|\n", + "|Translate English to French: Heart of Darkness Movie Revi...| Un livre connu pour son éloquence et ses concepts complexes|\n", + "| Translate English to French: A bad movie ABOUT a bad movie| Un mauvais film ABOUT a bad movie|\n", + "|Translate English to French: Apart from the fact that thi...|En plus du fait que ce film a été réalisé (je suppose quil s|\n", + "|Translate English to French: Watching this movie, you jus...|Vous devez simplement vous demander : « Que pense-t-il? » Il|\n", + "| Translate English to French: OK, lets start with the best| OK, s'il y a lieu de commencer par le meilleur|\n", + "|Translate English to French: Anna Christie (Greta Garbo) ...|Anna Christie (Greta Garbo) retourne pour voir son père C...|\n", + "| Translate English to French: C| C|\n", + "|Translate English to French: Tom and Jerry are transporti...| Tom et Jerry transportent des marchandises par avion en|\n", "+------------------------------------------------------------+------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n" @@ -1047,36 +944,31 @@ "id": "5d98fa52-7665-49bf-865a-feec86effe23", "metadata": {}, "source": [ - "This notebook uses the [Python backend with a custom execution environment](https://github.com/triton-inference-server/python_backend#creating-custom-execution-environments), using a conda-pack environment created as follows:\n", + "This notebook uses the [Python backend with a custom execution environment](https://github.com/triton-inference-server/python_backend#creating-custom-execution-environments) with the compatible versions of Python/Numpy for Triton 24.08, using a conda-pack environment created as follows:\n", "```\n", - "conda create -n huggingface -c conda-forge python=3.8\n", - "conda activate huggingface\n", + "conda create -n huggingface-torch -c conda-forge python=3.10.0\n", + "conda activate huggingface-torch\n", "\n", - "export PYTHONUSERSITE=True\n", - "pip install conda-pack sentencepiece sentence_transformers transformers\n", + "export PYTHONNOUSERSITE=True\n", + "pip install numpy==1.26.4 conda-pack sentencepiece sentence_transformers transformers\n", "\n", - "conda-pack # huggingface.tar.gz\n", + "conda-pack # huggingface-torch.tar.gz\n", "```" ] }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 28, "id": "b858cf85-82e6-41ef-905b-d8c5d6fea492", "metadata": {}, "outputs": [], "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "import os\n", - "from pyspark.ml.functions import predict_batch_udf\n", - "from pyspark.sql.functions import col, struct, pandas_udf\n", - "from pyspark.sql.types import FloatType, StringType, StructField, StructType" + "import os" ] }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 29, "id": "05ce7c77-d562-45e8-89bb-cd656aba5a5f", "metadata": {}, "outputs": [], @@ -1085,10 +977,10 @@ "# copy custom model to expected layout for Triton\n", "rm -rf models\n", "mkdir -p models\n", - "cp -r models_config/hf_generation models\n", + "cp -r models_config/hf_generation_torch models\n", "\n", "# add custom execution environment\n", - "cp huggingface.tar.gz models" + "cp huggingface-torch.tar.gz models" ] }, { @@ -1103,7 +995,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 30, "id": "afd00b7e-8150-4c95-a2e4-037e9c90f92a", "metadata": {}, "outputs": [ @@ -1120,7 +1012,7 @@ "[True]" ] }, - "execution_count": 38, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -1142,7 +1034,7 @@ " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", " else:\n", " container=client.containers.run(\n", - " \"nvcr.io/nvidia/tritonserver:23.04-py3\", \"tritonserver --model-repository=/models\",\n", + " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", " detach=True,\n", " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", " environment=[\n", @@ -1151,7 +1043,7 @@ " name=\"spark-triton\",\n", " network_mode=\"host\",\n", " remove=True,\n", - " shm_size=\"256M\",\n", + " shm_size=\"1G\",\n", " volumes={\n", " triton_models_dir: {\"bind\": \"/models\", \"mode\": \"ro\"},\n", " huggingface_cache_dir: {\"bind\": \"/cache\", \"mode\": \"rw\"}\n", @@ -1184,7 +1076,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 31, "id": "1a997c33-5202-466d-8304-b8c30f32978f", "metadata": { "tags": [] @@ -1200,7 +1092,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 32, "id": "9dea1875-6b95-4fc0-926d-a625a441b33d", "metadata": {}, "outputs": [], @@ -1211,7 +1103,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 33, "id": "5d6c54e7-534d-406f-b8e6-fd592efd0ab2", "metadata": {}, "outputs": [], @@ -1226,7 +1118,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 34, "id": "dc1bbbe3-4232-49e5-80f6-99976524b73b", "metadata": {}, "outputs": [], @@ -1237,7 +1129,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 35, "id": "5d10c61c-6102-4d19-8dd6-0c7b5b65343e", "metadata": {}, "outputs": [ @@ -1248,26 +1140,26 @@ "+------------------------------------------------------------------------------------------------------------------------+\n", "| input|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", - "| Translate English to German: |\n", - "|Translate English to German: Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pimp story wi...|\n", - "|Translate English to German: I watched this movie to see the direction one of the most promising young talents in mov...|\n", - "| Translate English to German: This movie makes you wish imdb would let you vote a zero|\n", - "|Translate English to German: I never want to see this movie again!

Not only is it dreadfully bad, but I ca...|\n", - "|Translate English to German: (As a note, I'd like to say that I saw this movie at my annual church camp, where the en...|\n", - "| Translate English to German: Don't get me wrong, I love the TV series of League Of Gentlemen|\n", - "|Translate English to German: Did you ever think, like after watching a horror movie with a group of friends: \"Wow, th...|\n", - "| Translate English to German: Awful, awful, awful|\n", - "|Translate English to German: This movie seems a little clunky around the edges, like not quite enough zaniness was th...|\n", - "|Translate English to German: I rented this movie hoping that it would provide some good entertainment and some cool p...|\n", - "|Translate English to German: Well, where to start describing this celluloid debacle? You already know the big fat NAD...|\n", - "| Translate English to German: I hoped for this show to be somewhat realistic|\n", - "| Translate English to German: All I have to say is one word|\n", - "| Translate English to German: Honestly awful film, bad editing, awful lighting, dire dialog and scrappy screenplay|\n", - "|Translate English to German: This critique tells the story of 4 little friends who went to watch Angels and Demons th...|\n", - "| Translate English to German: This review contains a partial spoiler|\n", - "| Translate English to German: I'm rather surprised that anybody found this film touching or moving|\n", - "| Translate English to German: If you like bad movies (and you must to watch this one) here's a good one|\n", - "|Translate English to German: This is really bad, the characters were bland, the story was boring, and there is no sex...|\n", + "| Translate English to German: This is so overly clichéd you'll want to switch it off after the first 45 minutes|\n", + "| Translate English to German: I am a big fan of The ABC Movies of the Week genre|\n", + "|Translate English to German: In the early 1990's \"Step-by-Step\" came as a tedious combination of the ultra-cheesy \"Fu...|\n", + "|Translate English to German: When The Spirits Within was released, all you heard from Final Fantasy fans was how awfu...|\n", + "| Translate English to German: I like to think of myself as a bad movie connoisseur|\n", + "|Translate English to German: This film did well at the box office, and the producers of this mess thought the stars h...|\n", + "|Translate English to German: Following the pleasingly atmospheric original and the amusingly silly second one, this i...|\n", + "| Translate English to German: I like CKY and Viva La Bam, so I couldn't resist this when I saw it for £1|\n", + "| Translate English to German: I have read all of the reviews for this direct to video movie|\n", + "|Translate English to German: Yes, it was an awful movie, but there was a song near the beginning of the movie, I thin...|\n", + "| Translate English to German: This was the most uninteresting horror flick I have seen to date|\n", + "|Translate English to German: I don't know if this exceptionally dull movie was intended as an unofficial sequel to 'T...|\n", + "|Translate English to German: Heart of Darkness Movie Review Could a book that is well known for its eloquent wording ...|\n", + "| Translate English to German: A bad movie ABOUT a bad movie|\n", + "|Translate English to German: Apart from the fact that this film was made ( I suppose it seemed a good idea at the tim...|\n", + "|Translate English to German: Watching this movie, you just have to ask: What were they thinking? There are so many no...|\n", + "| Translate English to German: OK, lets start with the best|\n", + "|Translate English to German: Anna Christie (Greta Garbo) returns to see her father Chris (George F Marion) after 15 y...|\n", + "| Translate English to German: C|\n", + "| Translate English to German: Tom and Jerry are transporting goods via airplane to Africa|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n" @@ -1280,7 +1172,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 36, "id": "2e0907da-a5d9-4c3b-9db4-ce5e70ca9bb4", "metadata": {}, "outputs": [], @@ -1330,12 +1222,12 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 37, "id": "9308bdd7-6f67-484d-8b51-dd1e1b2960ba", "metadata": {}, "outputs": [], "source": [ - "generate = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"hf_generation\"),\n", + "generate = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"hf_generation_torch\"),\n", " return_type=StringType(),\n", " input_tensor_shapes=[[1]],\n", " batch_size=100)" @@ -1343,7 +1235,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 38, "id": "38484ffd-370d-492b-8ca4-9eff9f242a9f", "metadata": {}, "outputs": [ @@ -1351,15 +1243,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 43:> (0 + 1) / 1]\r" + "[Stage 45:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 22.3 ms, sys: 4.66 ms, total: 27 ms\n", - "Wall time: 4.47 s\n" + "CPU times: user 4.61 ms, sys: 1.26 ms, total: 5.87 ms\n", + "Wall time: 2.04 s\n" ] }, { @@ -1379,7 +1271,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 39, "id": "ebcb6699-3ac2-4529-ab0f-fab0a5e792da", "metadata": {}, "outputs": [ @@ -1387,15 +1279,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 45:> (0 + 1) / 1]\r" + "[Stage 47:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 9.54 ms, sys: 4.29 ms, total: 13.8 ms\n", - "Wall time: 4.31 s\n" + "CPU times: user 3.16 ms, sys: 641 μs, total: 3.8 ms\n", + "Wall time: 1.58 s\n" ] }, { @@ -1414,7 +1306,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 40, "id": "e2ed18ad-d00b-472c-b2c3-047932f2105d", "metadata": {}, "outputs": [ @@ -1422,15 +1314,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 47:> (0 + 1) / 1]\r" + "[Stage 49:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 11.7 ms, sys: 9.72 ms, total: 21.4 ms\n", - "Wall time: 4.22 s\n" + "CPU times: user 1.91 ms, sys: 2.38 ms, total: 4.29 ms\n", + "Wall time: 1.75 s\n" ] }, { @@ -1449,7 +1341,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 41, "id": "0cd64a1c-beb8-47d5-ac6f-e8525bb61176", "metadata": {}, "outputs": [ @@ -1460,26 +1352,26 @@ "+------------------------------------------------------------+------------------------------------------------------------+\n", "| input| preds|\n", "+------------------------------------------------------------+------------------------------------------------------------+\n", - "| Translate English to German: | Übersetzen Sie Englisch.|\n", - "|Translate English to German: Hard up, No proper jobs goin...| Warum nicht die Kinder mieten?|\n", - "|Translate English to German: I watched this movie to see ...|Ich habe diesen Film gesehen, um zu sehen, in welche Rich...|\n", - "|Translate English to German: This movie makes you wish im...|Dieser Film macht Sie sich wünschen, dass imdb Sie es Ihn...|\n", - "|Translate English to German: I never want to see this mov...| Ich möchte diesen Film nie wieder sehen!br />br|\n", - "|Translate English to German: (As a note, I'd like to say ...| (Als eine Bemerkung, möchte ich sagen, dass ich diesen|\n", - "|Translate English to German: Don't get me wrong, I love t...|Verstehen Sie mich nicht falsch, ich liebe die TV-Serie L...|\n", - "|Translate English to German: Did you ever think, like aft...|Haben Sie jemals glaubt, wie nach einem Horrorfilm mit ei...|\n", - "| Translate English to German: Awful, awful, awful| Wüstenlos, schrecklich, schrecklich|\n", - "|Translate English to German: This movie seems a little cl...|Dieser Film scheint etwas schlank um die Ecken zu sein, w...|\n", - "|Translate English to German: I rented this movie hoping t...|Ich miete diesen Film in der Hoffnung, dass er einige gut...|\n", - "|Translate English to German: Well, where to start describ...| Wie kann man dieses Celluloid-Debakel beschreiben?|\n", - "|Translate English to German: I hoped for this show to be ...| Ich hoffe, dass diese Show etwas realistisch sein wird.|\n", - "| Translate English to German: All I have to say is one word| Ich muss nur ein Wort sagen|\n", - "|Translate English to German: Honestly awful film, bad edi...|Honestly awful film, bad editing, awful lighting, dire di...|\n", - "|Translate English to German: This critique tells the stor...|Diese Kritik erzählt die Geschichte von 4 kleinen Freunde...|\n", - "|Translate English to German: This review contains a parti...| Dieses Review enthält einen Teil-Störer|\n", - "|Translate English to German: I'm rather surprised that an...|Ich bin ziemlich überrascht, dass jemand diesen Film berü...|\n", - "|Translate English to German: If you like bad movies (and ...|Wenn Sie schlechte Filme (und Sie müssen diesen schauen) ...|\n", - "|Translate English to German: This is really bad, the char...|Das ist wirklich schlecht, die Charaktere waren schmeiche...|\n", + "|Translate English to German: This is so overly clichéd yo...| Das ist so übertrieben klischeehaft, dass Sie es nach den|\n", + "|Translate English to German: I am a big fan of The ABC Mo...| Ich bin ein großer Fan von The ABC Movies of the Week|\n", + "|Translate English to German: In the early 1990's \"Step-by...| Anfang der 1990er Jahre kam \"Step-by-Step\" als müh|\n", + "|Translate English to German: When The Spirits Within was ...|Als The Spirits Within veröffentlicht wurde, hörten Sie v...|\n", + "|Translate English to German: I like to think of myself as...| Ich halte mich gerne als schlechter Filmliebhaber|\n", + "|Translate English to German: This film did well at the bo...|Dieser Film hat sich gut an der Boxoffice ereignet, und d...|\n", + "|Translate English to German: Following the pleasingly atm...|Nach dem erfreulich stimmungsvollen Original und dem amüsant|\n", + "|Translate English to German: I like CKY and Viva La Bam, ...| Ich mag CKY und Viva La Bam, also konnte ich mich nicht|\n", + "|Translate English to German: I have read all of the revie...| Ich habe alle Rezensionen zu diesem direkten Film gelesen.|\n", + "|Translate English to German: Yes, it was an awful movie, ...| Ja, es war ein schrecklicher Film, aber es gab|\n", + "|Translate English to German: This was the most uninterest...|Dies war der größte Horrorfilm, den ich bisher gesehen habe.|\n", + "|Translate English to German: I don't know if this excepti...|Ich weiß nicht, ob dieser außergewöhnlich langweilige Fil...|\n", + "|Translate English to German: Heart of Darkness Movie Revi...|Herz der Dunkelheit Film Review Kann ein Buch, das für se...|\n", + "| Translate English to German: A bad movie ABOUT a bad movie| Ein schlechter Film ABOUT a bad movie|\n", + "|Translate English to German: Apart from the fact that thi...| Dieser Film wurde zwar fertiggestellt, aber es schien mir|\n", + "|Translate English to German: Watching this movie, you jus...|Wenn man diesen Film anschaut, muss man einfach fragen: W...|\n", + "| Translate English to German: OK, lets start with the best| OK, lets start with the best|\n", + "|Translate English to German: Anna Christie (Greta Garbo) ...| Anna Christie (Greta Garbo) kehrt nach 15 Jahren zurück,|\n", + "| Translate English to German: C| C|\n", + "|Translate English to German: Tom and Jerry are transporti...|Tom und Jerry transportieren Güter über Flugzeug nach Afrika|\n", "+------------------------------------------------------------+------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n" @@ -1492,7 +1384,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 42, "id": "af70fed8-0f2b-4ea7-841c-476afdf9b1c0", "metadata": {}, "outputs": [ @@ -1500,7 +1392,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "23/05/19 19:06:28 WARN CacheManager: Asked to cache already cached data.\n" + "24/10/10 00:12:21 WARN CacheManager: Asked to cache already cached data.\n" ] } ], @@ -1511,7 +1403,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 43, "id": "ef075e10-e22c-4236-9e0b-cb47cf2d3d06", "metadata": {}, "outputs": [ @@ -1522,26 +1414,26 @@ "+------------------------------------------------------------------------------------------------------------------------+\n", "| input|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", - "| Translate English to French: |\n", - "|Translate English to French: Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pimp story wi...|\n", - "|Translate English to French: I watched this movie to see the direction one of the most promising young talents in mov...|\n", - "| Translate English to French: This movie makes you wish imdb would let you vote a zero|\n", - "|Translate English to French: I never want to see this movie again!

Not only is it dreadfully bad, but I ca...|\n", - "|Translate English to French: (As a note, I'd like to say that I saw this movie at my annual church camp, where the en...|\n", - "| Translate English to French: Don't get me wrong, I love the TV series of League Of Gentlemen|\n", - "|Translate English to French: Did you ever think, like after watching a horror movie with a group of friends: \"Wow, th...|\n", - "| Translate English to French: Awful, awful, awful|\n", - "|Translate English to French: This movie seems a little clunky around the edges, like not quite enough zaniness was th...|\n", - "|Translate English to French: I rented this movie hoping that it would provide some good entertainment and some cool p...|\n", - "|Translate English to French: Well, where to start describing this celluloid debacle? You already know the big fat NAD...|\n", - "| Translate English to French: I hoped for this show to be somewhat realistic|\n", - "| Translate English to French: All I have to say is one word|\n", - "| Translate English to French: Honestly awful film, bad editing, awful lighting, dire dialog and scrappy screenplay|\n", - "|Translate English to French: This critique tells the story of 4 little friends who went to watch Angels and Demons th...|\n", - "| Translate English to French: This review contains a partial spoiler|\n", - "| Translate English to French: I'm rather surprised that anybody found this film touching or moving|\n", - "| Translate English to French: If you like bad movies (and you must to watch this one) here's a good one|\n", - "|Translate English to French: This is really bad, the characters were bland, the story was boring, and there is no sex...|\n", + "| Translate English to French: This is so overly clichéd you'll want to switch it off after the first 45 minutes|\n", + "| Translate English to French: I am a big fan of The ABC Movies of the Week genre|\n", + "|Translate English to French: In the early 1990's \"Step-by-Step\" came as a tedious combination of the ultra-cheesy \"Fu...|\n", + "|Translate English to French: When The Spirits Within was released, all you heard from Final Fantasy fans was how awfu...|\n", + "| Translate English to French: I like to think of myself as a bad movie connoisseur|\n", + "|Translate English to French: This film did well at the box office, and the producers of this mess thought the stars h...|\n", + "|Translate English to French: Following the pleasingly atmospheric original and the amusingly silly second one, this i...|\n", + "| Translate English to French: I like CKY and Viva La Bam, so I couldn't resist this when I saw it for £1|\n", + "| Translate English to French: I have read all of the reviews for this direct to video movie|\n", + "|Translate English to French: Yes, it was an awful movie, but there was a song near the beginning of the movie, I thin...|\n", + "| Translate English to French: This was the most uninteresting horror flick I have seen to date|\n", + "|Translate English to French: I don't know if this exceptionally dull movie was intended as an unofficial sequel to 'T...|\n", + "|Translate English to French: Heart of Darkness Movie Review Could a book that is well known for its eloquent wording ...|\n", + "| Translate English to French: A bad movie ABOUT a bad movie|\n", + "|Translate English to French: Apart from the fact that this film was made ( I suppose it seemed a good idea at the tim...|\n", + "|Translate English to French: Watching this movie, you just have to ask: What were they thinking? There are so many no...|\n", + "| Translate English to French: OK, lets start with the best|\n", + "|Translate English to French: Anna Christie (Greta Garbo) returns to see her father Chris (George F Marion) after 15 y...|\n", + "| Translate English to French: C|\n", + "| Translate English to French: Tom and Jerry are transporting goods via airplane to Africa|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n" @@ -1554,7 +1446,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 44, "id": "2e7e4af8-b815-4375-b851-8368309ee8e1", "metadata": {}, "outputs": [ @@ -1562,15 +1454,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 53:> (0 + 1) / 1]\r" + "[Stage 55:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 8.14 ms, sys: 12.6 ms, total: 20.8 ms\n", - "Wall time: 4.75 s\n" + "CPU times: user 3.4 ms, sys: 2.75 ms, total: 6.14 ms\n", + "Wall time: 1.96 s\n" ] }, { @@ -1589,7 +1481,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 45, "id": "7b0aefb0-a96b-4791-a23c-1ce9b24eb20c", "metadata": {}, "outputs": [ @@ -1597,15 +1489,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 55:> (0 + 1) / 1]\r" + "[Stage 57:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 11.6 ms, sys: 3 ms, total: 14.6 ms\n", - "Wall time: 3.87 s\n" + "CPU times: user 3.76 ms, sys: 897 μs, total: 4.66 ms\n", + "Wall time: 1.61 s\n" ] }, { @@ -1624,7 +1516,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 46, "id": "1214b75b-a373-4579-b4c6-0cb8627da776", "metadata": {}, "outputs": [ @@ -1632,15 +1524,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 57:> (0 + 1) / 1]\r" + "[Stage 59:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 13.1 ms, sys: 4.3 ms, total: 17.4 ms\n", - "Wall time: 3.9 s\n" + "CPU times: user 2.61 ms, sys: 2.26 ms, total: 4.87 ms\n", + "Wall time: 1.67 s\n" ] }, { @@ -1659,7 +1551,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 47, "id": "c9dbd21f-9e37-4221-b765-80ba8c80b884", "metadata": {}, "outputs": [ @@ -1670,37 +1562,30 @@ "+------------------------------------------------------------+------------------------------------------------------------+\n", "| input| preds|\n", "+------------------------------------------------------------+------------------------------------------------------------+\n", - "| Translate English to French: | :|\n", - "|Translate English to French: Hard up, No proper jobs goin...| Vous ne pouvez pas louer vos enfants!|\n", - "|Translate English to French: I watched this movie to see ...|J’ai regardé ce film pour voir la direction d’un des jeun...|\n", - "|Translate English to French: This movie makes you wish im...|Ce film vous fait envie de voir imdb vous laisser voter zéro|\n", - "|Translate English to French: I never want to see this mov...| Je ne veux jamais voir ce film à nouveau!br /|\n", - "|Translate English to French: (As a note, I'd like to say ...| ( titre de note, je voudrais dire que j'ai vu ce film|\n", - "|Translate English to French: Don't get me wrong, I love t...|Ne m'oubliez pas, je m'aime la série de télévision de League|\n", - "|Translate English to French: Did you ever think, like aft...|Vous avez jamais pensé, comme après avoir vu un film d'horre|\n", - "| Translate English to French: Awful, awful, awful| Awful, awful, awful|\n", - "|Translate English to French: This movie seems a little cl...| Ce film semble un peu cloné autour des bords, comme il|\n", - "|Translate English to French: I rented this movie hoping t...| J'ai loué ce film en espérant qu'il fournirait|\n", - "|Translate English to French: Well, where to start describ...|Vous savez déjà que la grande graisse NADA passe comme un...|\n", - "|Translate English to French: I hoped for this show to be ...| J'espère que ce spectacle sera quelque peu réaliste|\n", - "| Translate English to French: All I have to say is one word| Je n'ai qu'à dire un mot|\n", - "|Translate English to French: Honestly awful film, bad edi...| l'instar de l'arrière-plan, il|\n", - "|Translate English to French: This critique tells the stor...|Cette critique raconte l'histoire de 4 petits amis qui on...|\n", - "|Translate English to French: This review contains a parti...| Cet examen contient un spoiler partiel|\n", - "|Translate English to French: I'm rather surprised that an...|Je suis plutôt surpris que quelqu'un ait trouvé ce film t...|\n", - "|Translate English to French: If you like bad movies (and ...|Si vous aimez des films mauvais (et vous devez regarder c...|\n", - "|Translate English to French: This is really bad, the char...| C'est vraiment mauvais, les personnages étaient bourds, l|\n", + "|Translate English to French: This is so overly clichéd yo...| Vous ne pouvez pas en tirer d'un tel cliché|\n", + "|Translate English to French: I am a big fan of The ABC Mo...| Je suis un grand fan du genre The ABC Movies of the Week|\n", + "|Translate English to French: In the early 1990's \"Step-by...| Au début des années 1990, «Step-by-Step» a été une|\n", + "|Translate English to French: When The Spirits Within was ...|Lorsque The Spirits Within a été publié, tout ce que vous...|\n", + "|Translate English to French: I like to think of myself as...| Je me considère comme un mauvais réalisateur de films|\n", + "|Translate English to French: This film did well at the bo...| Ce film a bien avancé à la salle de cinéma et|\n", + "|Translate English to French: Following the pleasingly atm...|Après l'original agréablement atmosphérique et la seconde...|\n", + "|Translate English to French: I like CKY and Viva La Bam, ...| Je m'aime CKY et Viva La Bam,|\n", + "|Translate English to French: I have read all of the revie...| J'ai lu tous les commentaires pour ce film direct à vidéo|\n", + "|Translate English to French: Yes, it was an awful movie, ...| Oui, c'était un film terrible, mais il y avait une chanson|\n", + "|Translate English to French: This was the most uninterest...| Ce fut le plus inquiétant et le plus inquiétant d'h|\n", + "|Translate English to French: I don't know if this excepti...|Je ne sais pas si ce film extrêmement tacheté était desti...|\n", + "|Translate English to French: Heart of Darkness Movie Revi...| Un livre connu pour son éloquence et ses concepts complexes|\n", + "| Translate English to French: A bad movie ABOUT a bad movie| Un mauvais film ABOUT a bad movie|\n", + "|Translate English to French: Apart from the fact that thi...|En plus du fait que ce film a été réalisé (je suppose quil s|\n", + "|Translate English to French: Watching this movie, you jus...|Vous devez simplement vous demander : « Que pense-t-il? » Il|\n", + "| Translate English to French: OK, lets start with the best| OK, s'il y a lieu de commencer par le meilleur|\n", + "|Translate English to French: Anna Christie (Greta Garbo) ...|Anna Christie (Greta Garbo) retourne pour voir son père C...|\n", + "| Translate English to French: C| C|\n", + "|Translate English to French: Tom and Jerry are transporti...| Tom et Jerry transportent des marchandises par avion en|\n", "+------------------------------------------------------------+------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n" ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] } ], "source": [ @@ -1719,7 +1604,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 48, "id": "425d3b28-7705-45ba-8a18-ad34fc895219", "metadata": {}, "outputs": [ @@ -1736,7 +1621,7 @@ "[True]" ] }, - "execution_count": 56, + "execution_count": 48, "metadata": {}, "output_type": "execute_result" } @@ -1760,7 +1645,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 49, "id": "2dec80ca-7a7c-46a9-97c0-7afb1572f5b9", "metadata": {}, "outputs": [], @@ -1779,7 +1664,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "spark-dl-torch", "language": "python", "name": "python3" }, @@ -1793,7 +1678,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_tf/1/model.py b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_tf/1/model.py new file mode 100644 index 000000000..b788c8930 --- /dev/null +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_tf/1/model.py @@ -0,0 +1,150 @@ +# Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of NVIDIA CORPORATION nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import numpy as np +import json + +# triton_python_backend_utils is available in every Triton Python model. You +# need to use this module to create inference requests and responses. It also +# contains some utility functions for extracting information from model_config +# and converting Triton input/output types to numpy types. +import triton_python_backend_utils as pb_utils + + +class TritonPythonModel: + """Your Python model must use the same class name. Every Python model + that is created must have "TritonPythonModel" as the class name. + """ + + def initialize(self, args): + """`initialize` is called only once when the model is being loaded. + Implementing `initialize` function is optional. This function allows + the model to intialize any state associated with this model. + + Parameters + ---------- + args : dict + Both keys and values are strings. The dictionary keys and values are: + * model_config: A JSON string containing the model configuration + * model_instance_kind: A string containing model instance kind + * model_instance_device_id: A string containing model instance device ID + * model_repository: Model repository path + * model_version: Model version + * model_name: Model name + """ + import tensorflow as tf + # Enable GPU memory growth + gpus = tf.config.experimental.list_physical_devices('GPU') + if gpus: + try: + for gpu in gpus: + tf.config.experimental.set_memory_growth(gpu, True) + except RuntimeError as e: + print(e) + + print(tf.__version__) + + from transformers import AutoTokenizer, TFT5ForConditionalGeneration + + self.tokenizer = AutoTokenizer.from_pretrained("google-t5/t5-small") + self.model = TFT5ForConditionalGeneration.from_pretrained("google-t5/t5-small") + + # You must parse model_config. JSON string is not parsed here + self.model_config = model_config = json.loads(args['model_config']) + + # Get output configuration + output_config = pb_utils.get_output_config_by_name(model_config, "output") + + # Convert Triton types to numpy types + self.output_dtype = pb_utils.triton_string_to_numpy(output_config['data_type']) + + def execute(self, requests): + """`execute` MUST be implemented in every Python model. `execute` + function receives a list of pb_utils.InferenceRequest as the only + argument. This function is called when an inference request is made + for this model. Depending on the batching configuration (e.g. Dynamic + Batching) used, `requests` may contain multiple requests. Every + Python model, must create one pb_utils.InferenceResponse for every + pb_utils.InferenceRequest in `requests`. If there is an error, you can + set the error argument when creating a pb_utils.InferenceResponse + + Parameters + ---------- + requests : list + A list of pb_utils.InferenceRequest + + Returns + ------- + list + A list of pb_utils.InferenceResponse. The length of this list must + be the same as `requests` + """ + + output_dtype = self.output_dtype + + responses = [] + + # Every Python backend must iterate over everyone of the requests + # and create a pb_utils.InferenceResponse for each of them. + for request in requests: + # Get input numpy + sentence_input = pb_utils.get_input_tensor_by_name(request, "input") + sentences = list(sentence_input.as_numpy()) + sentences = np.squeeze(sentences, -1).tolist() + sentences = [s.decode('utf-8') for s in sentences] + + input_ids = self.tokenizer(sentences, + padding="longest", + max_length=512, + truncation=True, + return_tensors="tf").input_ids + output_ids = self.model.generate(input_ids, max_length=20) + outputs = np.array([self.tokenizer.decode(o, skip_special_tokens=True) for o in output_ids]) + + # Create output tensors. You need pb_utils.Tensor + # objects to create pb_utils.InferenceResponse. + output_tensor = pb_utils.Tensor("output", outputs.astype(output_dtype)) + + # Create InferenceResponse. You can set an error here in case + # there was a problem with handling this inference request. + # Below is an example of how you can set errors in inference + # response: + # + # pb_utils.InferenceResponse( + # output_tensors=..., TritonError("An error occured")) + inference_response = pb_utils.InferenceResponse(output_tensors=[output_tensor]) + responses.append(inference_response) + + # You should return a list of pb_utils.InferenceResponse. Length + # of this list must match the length of `requests` list. + return responses + + def finalize(self): + """`finalize` is called only once when the model is being unloaded. + Implementing `finalize` function is OPTIONAL. This function allows + the model to perform any necessary clean ups before exit. + """ + print('Cleaning up...') diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation/config.pbtxt b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_tf/config.pbtxt similarity index 98% rename from examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation/config.pbtxt rename to examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_tf/config.pbtxt index 380af49c5..88b87130f 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation/config.pbtxt +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_tf/config.pbtxt @@ -24,7 +24,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -name: "hf_generation" +name: "hf_generation_tf" backend: "python" max_batch_size: 8192 @@ -47,6 +47,6 @@ instance_group [{ kind: KIND_GPU }] parameters: { key: "EXECUTION_ENV_PATH", - value: {string_value: "$$TRITON_MODEL_DIRECTORY/../huggingface.tar.gz"} + value: {string_value: "$$TRITON_MODEL_DIRECTORY/../huggingface-tf.tar.gz"} } diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation/1/model.py b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_torch/1/model.py similarity index 98% rename from examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation/1/model.py rename to examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_torch/1/model.py index e7ae472fe..8e9604daa 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation/1/model.py +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_torch/1/model.py @@ -113,8 +113,9 @@ def execute(self, requests): input_ids = self.tokenizer(sentences, padding="longest", max_length=512, + truncation=True, return_tensors="pt").input_ids - output_ids = self.model.generate(input_ids) + output_ids = self.model.generate(input_ids, max_length=20) outputs = np.array([self.tokenizer.decode(o, skip_special_tokens=True) for o in output_ids]) # Create output tensors. You need pb_utils.Tensor diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_torch/config.pbtxt b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_torch/config.pbtxt new file mode 100644 index 000000000..47db54680 --- /dev/null +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_generation_torch/config.pbtxt @@ -0,0 +1,52 @@ +# Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of NVIDIA CORPORATION nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +name: "hf_generation_torch" +backend: "python" +max_batch_size: 8192 + +input [ + { + name: "input" + data_type: TYPE_STRING + dims: [1] + } +] +output [ + { + name: "output" + data_type: TYPE_STRING + dims: [1] + } +] + +instance_group [{ kind: KIND_GPU }] + +parameters: { + key: "EXECUTION_ENV_PATH", + value: {string_value: "$$TRITON_MODEL_DIRECTORY/../huggingface-torch.tar.gz"} +} + diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_tf/1/model.py b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_tf/1/model.py new file mode 100644 index 000000000..2a1bfda61 --- /dev/null +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_tf/1/model.py @@ -0,0 +1,147 @@ +# Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of NVIDIA CORPORATION nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import numpy as np +import json + +# triton_python_backend_utils is available in every Triton Python model. You +# need to use this module to create inference requests and responses. It also +# contains some utility functions for extracting information from model_config +# and converting Triton input/output types to numpy types. +import triton_python_backend_utils as pb_utils + + +class TritonPythonModel: + """Your Python model must use the same class name. Every Python model + that is created must have "TritonPythonModel" as the class name. + """ + + def initialize(self, args): + """`initialize` is called only once when the model is being loaded. + Implementing `initialize` function is optional. This function allows + the model to intialize any state associated with this model. + + Parameters + ---------- + args : dict + Both keys and values are strings. The dictionary keys and values are: + * model_config: A JSON string containing the model configuration + * model_instance_kind: A string containing model instance kind + * model_instance_device_id: A string containing model instance device ID + * model_repository: Model repository path + * model_version: Model version + * model_name: Model name + """ + import tensorflow as tf + print("tf: {}".format(tf.__version__)) + + # Enable GPU memory growth + gpus = tf.config.experimental.list_physical_devices('GPU') + if gpus: + try: + for gpu in gpus: + tf.config.experimental.set_memory_growth(gpu, True) + except RuntimeError as e: + print(e) + + from transformers import pipeline + self.pipe = pipeline("sentiment-analysis", device=0) + + # You must parse model_config. JSON string is not parsed here + self.model_config = model_config = json.loads(args['model_config']) + + # Get output configuration + label_config = pb_utils.get_output_config_by_name(model_config, "label") + score_config = pb_utils.get_output_config_by_name(model_config, "score") + + # Convert Triton types to numpy types + self.label_dtype = pb_utils.triton_string_to_numpy(label_config['data_type']) + self.score_dtype = pb_utils.triton_string_to_numpy(score_config['data_type']) + + def execute(self, requests): + """`execute` MUST be implemented in every Python model. `execute` + function receives a list of pb_utils.InferenceRequest as the only + argument. This function is called when an inference request is made + for this model. Depending on the batching configuration (e.g. Dynamic + Batching) used, `requests` may contain multiple requests. Every + Python model, must create one pb_utils.InferenceResponse for every + pb_utils.InferenceRequest in `requests`. If there is an error, you can + set the error argument when creating a pb_utils.InferenceResponse + + Parameters + ---------- + requests : list + A list of pb_utils.InferenceRequest + + Returns + ------- + list + A list of pb_utils.InferenceResponse. The length of this list must + be the same as `requests` + """ + + label_dtype = self.label_dtype + score_dtype = self.score_dtype + + responses = [] + + # Every Python backend must iterate over everyone of the requests + # and create a pb_utils.InferenceResponse for each of them. + for request in requests: + # Get input numpy + sentence_input = pb_utils.get_input_tensor_by_name(request, "sentence") + sentences = [s.decode('utf-8') for s in sentence_input.as_numpy().flatten()] + + results = self.pipe(sentences) + + label = np.array([res['label'] for res in results]) + score = np.array([res['score'] for res in results]) + + # Create output tensors. You need pb_utils.Tensor + # objects to create pb_utils.InferenceResponse. + label_tensor = pb_utils.Tensor("label", label.astype(label_dtype)) + score_tensor = pb_utils.Tensor("score", score.astype(score_dtype)) + + # Create InferenceResponse. You can set an error here in case + # there was a problem with handling this inference request. + # Below is an example of how you can set errors in inference + # response: + # + # pb_utils.InferenceResponse( + # output_tensors=..., TritonError("An error occured")) + inference_response = pb_utils.InferenceResponse(output_tensors=[label_tensor, score_tensor]) + responses.append(inference_response) + + # You should return a list of pb_utils.InferenceResponse. Length + # of this list must match the length of `requests` list. + return responses + + def finalize(self): + """`finalize` is called only once when the model is being unloaded. + Implementing `finalize` function is OPTIONAL. This function allows + the model to perform any necessary clean ups before exit. + """ + print('Cleaning up...') diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline/config.pbtxt b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_tf/config.pbtxt similarity index 98% rename from examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline/config.pbtxt rename to examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_tf/config.pbtxt index 5caae44f2..df7082ca4 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline/config.pbtxt +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_tf/config.pbtxt @@ -24,7 +24,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -name: "hf_pipeline" +name: "hf_pipeline_tf" backend: "python" max_batch_size: 8192 @@ -52,6 +52,6 @@ instance_group [{ kind: KIND_GPU }] parameters: { key: "EXECUTION_ENV_PATH", - value: {string_value: "$$TRITON_MODEL_DIRECTORY/../huggingface.tar.gz"} + value: {string_value: "$$TRITON_MODEL_DIRECTORY/../huggingface-tf.tar.gz"} } diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline/1/model.py b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_torch/1/model.py similarity index 96% rename from examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline/1/model.py rename to examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_torch/1/model.py index 79faa0306..f01886c91 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline/1/model.py +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_torch/1/model.py @@ -63,7 +63,7 @@ def initialize(self, args): print("transformers: {}".format(transformers.__version__)) from transformers import pipeline - self.pipe = pipeline("text-classification", device=0) + self.pipe = pipeline("sentiment-analysis", device=0) # You must parse model_config. JSON string is not parsed here self.model_config = model_config = json.loads(args['model_config']) @@ -108,9 +108,7 @@ def execute(self, requests): for request in requests: # Get input numpy sentence_input = pb_utils.get_input_tensor_by_name(request, "sentence") - sentences = list(sentence_input.as_numpy()) - sentences = np.squeeze(sentences).tolist() - sentences = [s.decode('utf-8') for s in sentences] + sentences = [s.decode('utf-8') for s in sentence_input.as_numpy().flatten()] results = self.pipe(sentences) diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_torch/config.pbtxt b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_torch/config.pbtxt new file mode 100644 index 000000000..4e54607d2 --- /dev/null +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_pipeline_torch/config.pbtxt @@ -0,0 +1,57 @@ +# Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of NVIDIA CORPORATION nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +name: "hf_pipeline_torch" +backend: "python" +max_batch_size: 8192 + +input [ + { + name: "sentence" + data_type: TYPE_STRING + dims: [1] + } +] +output [ + { + name: "label" + data_type: TYPE_STRING + dims: [1] + }, + { + name: "score" + data_type: TYPE_FP32 + dims: [1] + } +] + +instance_group [{ kind: KIND_GPU }] + +parameters: { + key: "EXECUTION_ENV_PATH", + value: {string_value: "$$TRITON_MODEL_DIRECTORY/../huggingface-torch.tar.gz"} +} + diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_transformer/1/model.py b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_transformer_torch/1/model.py similarity index 100% rename from examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_transformer/1/model.py rename to examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_transformer_torch/1/model.py diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_transformer/config.pbtxt b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_transformer_torch/config.pbtxt similarity index 97% rename from examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_transformer/config.pbtxt rename to examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_transformer_torch/config.pbtxt index ccdee3a50..798cf4fc7 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_transformer/config.pbtxt +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/models_config/hf_transformer_torch/config.pbtxt @@ -24,7 +24,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -name: "hf_transformer" +name: "hf_transformer_torch" backend: "python" max_batch_size: 8192 @@ -47,6 +47,6 @@ instance_group [{ kind: KIND_GPU }] parameters: { key: "EXECUTION_ENV_PATH", - value: {string_value: "$$TRITON_MODEL_DIRECTORY/../huggingface.tar.gz"} + value: {string_value: "$$TRITON_MODEL_DIRECTORY/../huggingface-torch.tar.gz"} } diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_tf.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_tf.ipynb new file mode 100644 index 000000000..115cfffc4 --- /dev/null +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_tf.ipynb @@ -0,0 +1,1056 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "60f7ac5d-4a95-4170-a0ac-a7faac9d9ef4", + "metadata": {}, + "source": [ + "# PySpark Huggingface Inferencing\n", + "### Text Classification using Pipelines with Tensorflow\n", + "\n", + "Based on: https://huggingface.co/docs/transformers/quicktour#pipeline-usage" + ] + }, + { + "cell_type": "markdown", + "id": "1799fd4f", + "metadata": {}, + "source": [ + "### Using TensorFlow\n", + "Note that cuFFT/cuDNN/cuBLAS registration errors are expected with `tf=2.17.0` and will not affect behavior, as noted in [this issue.](https://github.com/tensorflow/tensorflow/issues/62075) \n", + "This notebook does not demonstrate inference with TensorRT, as [TF-TRT](https://docs.nvidia.com/deeplearning/tensorrt/release-notes/index.html#tensorrt-10) does not yet support `tf=2.17.0`. See the `pytorch` notebooks for TensorRT demos." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "0dd0f77b-ee1b-4477-a038-d25a4f1da0ea", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 16:47:48.209366: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2024-10-03 16:47:48.215921: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", + "2024-10-03 16:47:48.223519: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", + "2024-10-03 16:47:48.225906: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", + "2024-10-03 16:47:48.231640: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2024-10-03 16:47:48.625790: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" + ] + } + ], + "source": [ + "import tensorflow as tf\n", + "from transformers import pipeline" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "d80fc3f8", + "metadata": {}, + "outputs": [], + "source": [ + "# set device if tensorflow gpu is available\n", + "device = 0 if tf.config.list_physical_devices('GPU') else -1" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "e60a2877", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.17.0\n" + ] + } + ], + "source": [ + "print(tf.__version__)\n", + "\n", + "# Enable GPU memory growth\n", + "gpus = tf.config.experimental.list_physical_devices('GPU')\n", + "if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "553b28d2-a5d1-4d07-8a49-8f82b808e738", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "No model was supplied, defaulted to distilbert/distilbert-base-uncased-finetuned-sst-2-english and revision 714eb0f (https://huggingface.co/distilbert/distilbert-base-uncased-finetuned-sst-2-english).\n", + "Using a pipeline without specifying a model name and revision in production is not recommended.\n", + "2024-10-03 16:47:49.863791: I tensorflow/core/common_runtime/gpu/gpu_device.cc:2021] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 46447 MB memory: -> device: 0, name: NVIDIA RTX A6000, pci bus id: 0000:01:00.0, compute capability: 8.6\n", + "All PyTorch model weights were used when initializing TFDistilBertForSequenceClassification.\n", + "\n", + "All the weights of TFDistilBertForSequenceClassification were initialized from the PyTorch model.\n", + "If your task is similar to the task the model of the checkpoint was trained on, you can already use TFDistilBertForSequenceClassification for predictions without further training.\n" + ] + } + ], + "source": [ + "classifier = pipeline(\"sentiment-analysis\", device=device)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "3b91fe91-b725-4564-ae93-56e3fb51e47c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'label': 'POSITIVE', 'score': 0.9997794032096863}]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "classifier((\"We are very happy to show you the 🤗 Transformers library.\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "0be39eb3-462c-42ff-b8f4-09f4e4fe3a3c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "label: POSITIVE, with score: 0.9998\n", + "label: NEGATIVE, with score: 0.5282\n" + ] + } + ], + "source": [ + "results = classifier([\"We are very happy to show you the 🤗 Transformers library.\", \"We hope you don't hate it.\"])\n", + "for result in results:\n", + " print(f\"label: {result['label']}, with score: {round(result['score'], 4)}\")" + ] + }, + { + "cell_type": "markdown", + "id": "30c90100", + "metadata": {}, + "source": [ + "#### Use another model and tokenizer in the pipeline" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "cd9d3349", + "metadata": {}, + "outputs": [], + "source": [ + "model_name = \"nlptown/bert-base-multilingual-uncased-sentiment\"" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "99e21b58", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Some layers from the model checkpoint at nlptown/bert-base-multilingual-uncased-sentiment were not used when initializing TFBertForSequenceClassification: ['dropout_37']\n", + "- This IS expected if you are initializing TFBertForSequenceClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n", + "- This IS NOT expected if you are initializing TFBertForSequenceClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n", + "All the layers of TFBertForSequenceClassification were initialized from the model checkpoint at nlptown/bert-base-multilingual-uncased-sentiment.\n", + "If your task is similar to the task the model of the checkpoint was trained on, you can already use TFBertForSequenceClassification for predictions without further training.\n" + ] + } + ], + "source": [ + "from transformers import AutoTokenizer, TFAutoModelForSequenceClassification\n", + "\n", + "model = TFAutoModelForSequenceClassification.from_pretrained(model_name)\n", + "tokenizer = AutoTokenizer.from_pretrained(model_name)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "31079133", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'label': '5 stars', 'score': 0.7272655963897705}]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "classifier = pipeline(\"sentiment-analysis\", model=model, tokenizer=tokenizer)\n", + "classifier(\"Nous sommes très heureux de vous présenter la bibliothèque 🤗 Transformers.\")" + ] + }, + { + "cell_type": "markdown", + "id": "ae92b15e-0da0-46c3-81a3-fabaedbfc42c", + "metadata": {}, + "source": [ + "## Inference using Spark DL API" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "69dd6a1a-f450-47f0-9dbf-ad250585a011", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import pandas as pd\n", + "from pyspark.sql.functions import col, struct, pandas_udf\n", + "from pyspark.ml.functions import predict_batch_udf\n", + "from pyspark.sql.types import FloatType, StringType, StructField, StructType\n", + "from pyspark.sql import SparkSession\n", + "from pyspark import SparkConf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6e0e0dd7", + "metadata": {}, + "outputs": [], + "source": [ + "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", + "\n", + "conf = SparkConf()\n", + "if 'spark' not in globals():\n", + " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", + " import socket\n", + " hostname = socket.gethostname()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", + "conf.set(\"spark.task.maxFailures\", \"1\")\n", + "conf.set(\"spark.driver.memory\", \"8g\")\n", + "conf.set(\"spark.executor.memory\", \"8g\")\n", + "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", + "conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + "conf.set(\"spark.python.worker.reuse\", \"true\")\n", + "# Create Spark Session\n", + "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", + "sc = spark.sparkContext" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "42d70208", + "metadata": {}, + "outputs": [], + "source": [ + "from datasets import load_dataset\n", + "\n", + "# Load the IMDB dataset\n", + "data = load_dataset(\"imdb\", split=\"test\")\n", + "\n", + "lines = []\n", + "for example in data:\n", + " # first sentence only\n", + " lines.append([example[\"text\"]])\n", + "\n", + "len(lines)\n", + "\n", + "df = spark.createDataFrame(lines, ['lines']).repartition(8).cache()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "ac24f3c2", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "24/10/03 16:47:58 WARN TaskSetManager: Stage 0 contains a task of very large size (3860 KiB). The maximum recommended task size is 1000 KiB.\n", + " \r" + ] + } + ], + "source": [ + "df.write.mode(\"overwrite\").parquet(\"imdb_test\")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "9665b7b6-d7e9-4bd4-b29d-7a449ac5b574", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------------------------------------------------------------------+\n", + "| sentence|\n", + "+--------------------------------------------------------------------------------+\n", + "| |\n", + "|Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pi...|\n", + "|I watched this movie to see the direction one of the most promising young tal...|\n", + "| This movie makes you wish imdb would let you vote a zero|\n", + "|I never want to see this movie again!

Not only is it dreadfully ba...|\n", + "|(As a note, I'd like to say that I saw this movie at my annual church camp, w...|\n", + "| Don't get me wrong, I love the TV series of League Of Gentlemen|\n", + "|Did you ever think, like after watching a horror movie with a group of friend...|\n", + "| Awful, awful, awful|\n", + "|This movie seems a little clunky around the edges, like not quite enough zani...|\n", + "|I rented this movie hoping that it would provide some good entertainment and ...|\n", + "|Well, where to start describing this celluloid debacle? You already know the ...|\n", + "| I hoped for this show to be somewhat realistic|\n", + "| All I have to say is one word|\n", + "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy scr...|\n", + "|This critique tells the story of 4 little friends who went to watch Angels an...|\n", + "| This review contains a partial spoiler|\n", + "| I'm rather surprised that anybody found this film touching or moving|\n", + "| If you like bad movies (and you must to watch this one) here's a good one|\n", + "|This is really bad, the characters were bland, the story was boring, and ther...|\n", + "+--------------------------------------------------------------------------------+\n", + "only showing top 20 rows\n", + "\n" + ] + } + ], + "source": [ + "# only use first sentence of IMDB reviews\n", + "@pandas_udf(\"string\")\n", + "def first_sentence(text: pd.Series) -> pd.Series:\n", + " return pd.Series([s.split(\".\")[0] for s in text])\n", + "\n", + "df = spark.read.parquet(\"imdb_test\").withColumn(\"sentence\", first_sentence(col(\"lines\"))).select(\"sentence\").limit(100).cache()\n", + "df.show(truncate=80)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "0da9d25c-5ebe-4503-bb19-154fcc047cbf", + "metadata": {}, + "outputs": [], + "source": [ + "def predict_batch_fn():\n", + " import tensorflow as tf\n", + " from transformers import pipeline\n", + "\n", + " # Enable GPU memory growth\n", + " gpus = tf.config.experimental.list_physical_devices('GPU')\n", + " if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)\n", + " \n", + " device = 0 if tf.config.list_physical_devices('GPU') else -1\n", + " pipe = pipeline(\"sentiment-analysis\", device=device)\n", + " def predict(inputs):\n", + " return pipe(inputs.tolist())\n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "78afef29-ee30-4267-9fb6-be2dcb86cbba", + "metadata": {}, + "outputs": [], + "source": [ + "classify = predict_batch_udf(predict_batch_fn,\n", + " return_type=StructType([\n", + " StructField(\"label\", StringType(), True),\n", + " StructField(\"score\", FloatType(), True)\n", + " ]),\n", + " batch_size=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "a5bc327e-89cf-4731-82e6-e66cb93deef1", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 11:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 9.15 ms, sys: 6.76 ms, total: 15.9 ms\n", + "Wall time: 5 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "# note: expanding the \"struct\" return_type to top-level columns\n", + "preds = df.withColumn(\"preds\", classify(struct(\"sentence\"))).select(\"sentence\", \"preds.*\")\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "ac642895-cfd6-47ee-9b21-02e7835424e4", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 13:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 4.86 ms, sys: 2.19 ms, total: 7.05 ms\n", + "Wall time: 2.81 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "# note: expanding the \"struct\" return_type to top-level columns\n", + "preds = df.withColumn(\"preds\", classify(\"sentence\")).select(\"sentence\", \"preds.*\")\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "76a44d80-d5db-405f-989c-7246379cfb95", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 15:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 3.91 ms, sys: 1.96 ms, total: 5.87 ms\n", + "Wall time: 2.76 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "# note: expanding the \"struct\" return_type to top-level columns\n", + "preds = df.withColumn(\"preds\", classify(col(\"sentence\"))).select(\"sentence\", \"preds.*\")\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "c01761b3-c766-46b0-ae0b-fcf968ffb3a1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------------------------------------------------------------------+--------+----------+\n", + "| sentence| label| score|\n", + "+--------------------------------------------------------------------------------+--------+----------+\n", + "| |POSITIVE|0.74807304|\n", + "|Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pi...|NEGATIVE| 0.9996724|\n", + "|I watched this movie to see the direction one of the most promising young tal...|POSITIVE| 0.9994948|\n", + "| This movie makes you wish imdb would let you vote a zero|NEGATIVE| 0.9981299|\n", + "|I never want to see this movie again!

Not only is it dreadfully ba...|NEGATIVE|0.99883264|\n", + "|(As a note, I'd like to say that I saw this movie at my annual church camp, w...|POSITIVE| 0.9901753|\n", + "| Don't get me wrong, I love the TV series of League Of Gentlemen|POSITIVE|0.99983096|\n", + "|Did you ever think, like after watching a horror movie with a group of friend...|POSITIVE| 0.9992768|\n", + "| Awful, awful, awful|NEGATIVE| 0.9997433|\n", + "|This movie seems a little clunky around the edges, like not quite enough zani...|NEGATIVE| 0.9996525|\n", + "|I rented this movie hoping that it would provide some good entertainment and ...|NEGATIVE|0.99643254|\n", + "|Well, where to start describing this celluloid debacle? You already know the ...|NEGATIVE|0.99973005|\n", + "| I hoped for this show to be somewhat realistic|POSITIVE| 0.8417903|\n", + "| All I have to say is one word|NEGATIVE|0.97844803|\n", + "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy scr...|NEGATIVE| 0.9997701|\n", + "|This critique tells the story of 4 little friends who went to watch Angels an...|POSITIVE| 0.9942386|\n", + "| This review contains a partial spoiler|NEGATIVE|0.99620205|\n", + "| I'm rather surprised that anybody found this film touching or moving|POSITIVE|0.83874947|\n", + "| If you like bad movies (and you must to watch this one) here's a good one|POSITIVE| 0.9936475|\n", + "|This is really bad, the characters were bland, the story was boring, and ther...|NEGATIVE|0.99953806|\n", + "+--------------------------------------------------------------------------------+--------+----------+\n", + "only showing top 20 rows\n", + "\n" + ] + } + ], + "source": [ + "preds.show(truncate=80)" + ] + }, + { + "cell_type": "markdown", + "id": "eb826fde-99d9-43fe-8ddc-f5acbe76b4e9", + "metadata": {}, + "source": [ + "### Using Triton Inference Server\n", + "\n", + "Note: you can restart the kernel and run from this point to simulate running in a different node or environment. " + ] + }, + { + "cell_type": "markdown", + "id": "10368010-f94d-4167-91a1-2cf9ed91a2c9", + "metadata": {}, + "source": [ + "This notebook uses the [Python backend with a custom execution environment](https://github.com/triton-inference-server/python_backend#creating-custom-execution-environments) with the compatible versions of Python/Numpy for Triton 24.08, using a conda-pack environment created as follows:\n", + "```\n", + "conda create -n huggingface-tf -c conda-forge python=3.10.0\n", + "conda activate huggingface-tf\n", + "\n", + "export PYTHONNOUSERSITE=True\n", + "pip install numpy==1.26.4 tensorflow[and-cuda] tf-keras transformers conda-pack\n", + "\n", + "conda-pack # huggingface-tf.tar.gz\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "4d4be844-4b8c-47df-bd09-0c280c7ff16b", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import os\n", + "from pyspark.ml.functions import predict_batch_udf\n", + "from pyspark.sql.functions import col, struct, pandas_udf\n", + "from pyspark.sql.types import FloatType, StringType, StructField, StructType" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "7e53df9f-43cb-4c38-b8ac-dc2cbad99815", + "metadata": {}, + "outputs": [], + "source": [ + "%%bash\n", + "# copy custom model to expected layout for Triton\n", + "rm -rf models\n", + "mkdir -p models\n", + "cp -r models_config/hf_pipeline_tf models\n", + "\n", + "# add custom execution environment\n", + "cp huggingface-tf.tar.gz models" + ] + }, + { + "cell_type": "markdown", + "id": "db4a5b06-126a-4bc4-baae-a45ea30832a7", + "metadata": { + "tags": [] + }, + "source": [ + "#### Start Triton Server on each executor" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "144acb8e-4c08-40fc-a9ed-f721c409ee68", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "[True]" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "num_executors = 1\n", + "triton_models_dir = \"{}/models\".format(os.getcwd())\n", + "huggingface_cache_dir = \"{}/.cache/huggingface\".format(os.path.expanduser('~'))\n", + "nodeRDD = sc.parallelize(list(range(num_executors)), num_executors)\n", + "\n", + "def start_triton(it):\n", + " import docker\n", + " import time\n", + " import tritonclient.grpc as grpcclient\n", + " \n", + " client=docker.from_env()\n", + " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", + " if containers:\n", + " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", + " else:\n", + " container=client.containers.run(\n", + " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", + " detach=True,\n", + " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", + " environment=[\n", + " \"TRANSFORMERS_CACHE=/cache\"\n", + " ],\n", + " name=\"spark-triton\",\n", + " network_mode=\"host\",\n", + " remove=True,\n", + " shm_size=\"256M\",\n", + " volumes={\n", + " triton_models_dir: {\"bind\": \"/models\", \"mode\": \"ro\"},\n", + " huggingface_cache_dir: {\"bind\": \"/cache\", \"mode\": \"rw\"}\n", + " }\n", + " )\n", + " print(\">>>> starting triton: {}\".format(container.short_id))\n", + " # wait for triton to be running\n", + " time.sleep(15)\n", + " \n", + " client = grpcclient.InferenceServerClient(\"localhost:8001\")\n", + " \n", + " elapsed = 0\n", + " timeout = 120\n", + " ready = False\n", + " while not ready and elapsed < timeout:\n", + " try:\n", + " time.sleep(5)\n", + " elapsed += 5\n", + " ready = client.is_server_ready()\n", + " except Exception as e:\n", + " pass\n", + "\n", + " return [True]\n", + "\n", + "nodeRDD.barrier().mapPartitions(start_triton).collect()" + ] + }, + { + "cell_type": "markdown", + "id": "c24d77ab-60d3-45eb-a9c2-dc811eca0af4", + "metadata": {}, + "source": [ + "#### Run inference" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "d53fb283-bf9e-4571-8c68-b75a41f1f067", + "metadata": {}, + "outputs": [], + "source": [ + "# only use first sentence of IMDB reviews\n", + "@pandas_udf(\"string\")\n", + "def first_sentence(text: pd.Series) -> pd.Series:\n", + " return pd.Series([s.split(\".\")[0] for s in text])\n", + "\n", + "df = spark.read.parquet(\"imdb_test\").withColumn(\"sentence\", first_sentence(col(\"lines\"))).select(\"sentence\").limit(1000)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "29b0cc0d-c480-4e4a-bd41-207dc314cba5", + "metadata": {}, + "outputs": [], + "source": [ + "def triton_fn(triton_uri, model_name):\n", + " import numpy as np\n", + " import tritonclient.grpc as grpcclient\n", + " \n", + " np_types = {\n", + " \"BOOL\": np.dtype(np.bool_),\n", + " \"INT8\": np.dtype(np.int8),\n", + " \"INT16\": np.dtype(np.int16),\n", + " \"INT32\": np.dtype(np.int32),\n", + " \"INT64\": np.dtype(np.int64),\n", + " \"FP16\": np.dtype(np.float16),\n", + " \"FP32\": np.dtype(np.float32),\n", + " \"FP64\": np.dtype(np.float64),\n", + " \"FP64\": np.dtype(np.double),\n", + " \"BYTES\": np.dtype(object)\n", + " }\n", + "\n", + " client = grpcclient.InferenceServerClient(triton_uri)\n", + " model_meta = client.get_model_metadata(model_name)\n", + " \n", + " def predict(inputs):\n", + " if isinstance(inputs, np.ndarray):\n", + " # single ndarray input\n", + " request = [grpcclient.InferInput(model_meta.inputs[0].name, inputs.shape, model_meta.inputs[0].datatype)]\n", + " request[0].set_data_from_numpy(inputs.astype(np_types[model_meta.inputs[0].datatype]))\n", + " else:\n", + " # dict of multiple ndarray inputs\n", + " request = [grpcclient.InferInput(i.name, inputs[i.name].shape, i.datatype) for i in model_meta.inputs]\n", + " for i in request:\n", + " i.set_data_from_numpy(inputs[i.name()].astype(np_types[i.datatype()]))\n", + " \n", + " response = client.infer(model_name, inputs=request)\n", + " \n", + " if len(model_meta.outputs) > 1:\n", + " # return dictionary of numpy arrays\n", + " return {o.name: response.as_numpy(o.name) for o in model_meta.outputs}\n", + " else:\n", + " # return single numpy array\n", + " return response.as_numpy(model_meta.outputs[0].name)\n", + " \n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "3930cfcd-3284-4c6a-a9b5-36b8053fe899", + "metadata": {}, + "outputs": [], + "source": [ + "from functools import partial\n", + "\n", + "classify = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"hf_pipeline_tf\"),\n", + " return_type=StructType([\n", + " StructField(\"label\", StringType(), True),\n", + " StructField(\"score\", FloatType(), True)\n", + " ]),\n", + " input_tensor_shapes=[[1]],\n", + " batch_size=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "8eecbf23-4e9e-4d4c-8645-98209b25db2c", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 20:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 22.5 ms, sys: 5.9 ms, total: 28.4 ms\n", + "Wall time: 24.6 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "# first pass caches model/fn\n", + "# note: expanding the \"struct\" return_type to top-level columns\n", + "preds = df.withColumn(\"preds\", classify(struct(\"sentence\"))).select(\"sentence\", \"preds.*\")\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "566ba28c-0ca4-4479-a24a-c8a362228b89", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 21:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 12.2 ms, sys: 10.1 ms, total: 22.3 ms\n", + "Wall time: 23.8 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "# note: expanding the \"struct\" return_type to top-level columns\n", + "preds = df.withColumn(\"preds\", classify(\"sentence\")).select(\"sentence\", \"preds.*\")\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "44c7e776-08da-484a-ba07-9d6add1a0f15", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 22:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 8.74 ms, sys: 8.23 ms, total: 17 ms\n", + "Wall time: 23.8 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "# note: expanding the \"struct\" return_type to top-level columns\n", + "preds = df.withColumn(\"preds\", classify(col(\"sentence\"))).select(\"sentence\", \"preds.*\")\n", + "results = preds.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "f61d79f8-661e-4d9e-a3aa-c0754b854603", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 23:> (0 + 1) / 1]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+----------+\n", + "|sentence |label |score |\n", + "+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+----------+\n", + "| |POSITIVE|0.74807304|\n", + "|Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pimp story without the gratuitous sex scenes, either hard core or soft core, therefore reads like a public information film from the fifties, give this a wide miss, use a barge pole if you can|NEGATIVE|0.9996724 |\n", + "|I watched this movie to see the direction one of the most promising young talents in movies was going |POSITIVE|0.9994948 |\n", + "|This movie makes you wish imdb would let you vote a zero |NEGATIVE|0.9981299 |\n", + "|I never want to see this movie again!

Not only is it dreadfully bad, but I can't stand seeing my hero Stan Laurel looking so old and sick |NEGATIVE|0.99883264|\n", + "|(As a note, I'd like to say that I saw this movie at my annual church camp, where the entire youth group laughed at it |POSITIVE|0.9901753 |\n", + "|Don't get me wrong, I love the TV series of League Of Gentlemen |POSITIVE|0.99983096|\n", + "|Did you ever think, like after watching a horror movie with a group of friends: \"Wow, this is so cool! We have got to make a splatter horror movie ourselves some day soon |POSITIVE|0.9992768 |\n", + "|Awful, awful, awful |NEGATIVE|0.9997433 |\n", + "|This movie seems a little clunky around the edges, like not quite enough zaniness was thrown it when it should have been |NEGATIVE|0.9996525 |\n", + "|I rented this movie hoping that it would provide some good entertainment and some cool poker knowledge or stories |NEGATIVE|0.99643254|\n", + "|Well, where to start describing this celluloid debacle? You already know the big fat NADA passing as a plot, so let's jut point out that this is so PC it's offensive |NEGATIVE|0.99973005|\n", + "|I hoped for this show to be somewhat realistic |POSITIVE|0.8417903 |\n", + "|All I have to say is one word |NEGATIVE|0.97844803|\n", + "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy screenplay |NEGATIVE|0.9997701 |\n", + "|This critique tells the story of 4 little friends who went to watch Angels and Demons the movie on the first night it came out, even though it was a school night, because \"Angels and Demons is worth it |POSITIVE|0.9942386 |\n", + "|This review contains a partial spoiler |NEGATIVE|0.99620205|\n", + "|I'm rather surprised that anybody found this film touching or moving |POSITIVE|0.83874947|\n", + "|If you like bad movies (and you must to watch this one) here's a good one |POSITIVE|0.9936475 |\n", + "|This is really bad, the characters were bland, the story was boring, and there is no sex scene |NEGATIVE|0.99953806|\n", + "+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+----------+\n", + "only showing top 20 rows\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "preds.show(truncate=False)" + ] + }, + { + "cell_type": "markdown", + "id": "e197c146-1794-47f0-bcd9-7e8d8ab8625f", + "metadata": { + "tags": [] + }, + "source": [ + "#### Stop Triton Server on each executor" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "425d3b28-7705-45ba-8a18-ad34fc895219", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "[True]" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def stop_triton(it):\n", + " import docker\n", + " import time\n", + " \n", + " client=docker.from_env()\n", + " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", + " print(\">>>> stopping containers: {}\".format([c.short_id for c in containers]))\n", + " if containers:\n", + " container=containers[0]\n", + " container.stop(timeout=120)\n", + "\n", + " return [True]\n", + "\n", + "nodeRDD.barrier().mapPartitions(stop_triton).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "9f19643c-4ee4-44f2-b762-2078c0c8eba9", + "metadata": {}, + "outputs": [], + "source": [ + "spark.stop()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a538c47-317d-4cac-b9b9-559e88677518", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "spark-dl-tf", + "language": "python", + "name": "python3" + }, + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_torch.ipynb similarity index 65% rename from examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines.ipynb rename to examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_torch.ipynb index 51b8feb8e..47f45b670 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_torch.ipynb @@ -6,37 +6,36 @@ "metadata": {}, "source": [ "# PySpark Huggingface Inferencing\n", - "### Text Classification using Pipelines\n", + "### Text Classification using Pipelines with PyTorch\n", "\n", "Based on: https://huggingface.co/docs/transformers/quicktour#pipeline-usage" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "id": "0dd0f77b-ee1b-4477-a038-d25a4f1da0ea", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/leey/.pyenv/versions/3.9.10/envs/spark_rapids_examples/lib/python3.9/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n" - ] - } - ], + "outputs": [], "source": [ - "import pandas as pd\n", - "\n", - "from inspect import signature\n", - "from pyspark.sql.functions import col, pandas_udf\n", + "import torch\n", "from transformers import pipeline" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, + "id": "e1f756c6", + "metadata": {}, + "outputs": [], + "source": [ + "# set device if gpu is available\n", + "device = 0 if torch.cuda.is_available() else -1" + ] + }, + { + "cell_type": "code", + "execution_count": 4, "id": "553b28d2-a5d1-4d07-8a49-8f82b808e738", "metadata": {}, "outputs": [ @@ -44,57 +43,108 @@ "name": "stderr", "output_type": "stream", "text": [ - "No model was supplied, defaulted to distilbert-base-uncased-finetuned-sst-2-english and revision af0f99b (https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english).\n", - "Using a pipeline without specifying a model name and revision in production is not recommended.\n", - "Xformers is not installed correctly. If you want to use memorry_efficient_attention to accelerate training use the following command to install Xformers\n", - "pip install xformers.\n" + "No model was supplied, defaulted to distilbert/distilbert-base-uncased-finetuned-sst-2-english and revision 714eb0f (https://huggingface.co/distilbert/distilbert-base-uncased-finetuned-sst-2-english).\n", + "Using a pipeline without specifying a model name and revision in production is not recommended.\n" ] } ], "source": [ - "pipe = pipeline(\"text-classification\")" + "classifier = pipeline(\"sentiment-analysis\", device=device)" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "id": "3b91fe91-b725-4564-ae93-56e3fb51e47c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[{'label': 'POSITIVE', 'score': 0.9994712471961975}]" + "[{'label': 'POSITIVE', 'score': 0.9997795224189758}]" ] }, - "execution_count": 3, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "pipe(\"What can I say that hasn't been said already. I think this place is totally worth the hype.\")" + "classifier((\"We are very happy to show you the 🤗 Transformers library.\"))" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "id": "0be39eb3-462c-42ff-b8f4-09f4e4fe3a3c", "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "label: POSITIVE, with score: 0.9998\n", + "label: NEGATIVE, with score: 0.5309\n" + ] + } + ], + "source": [ + "results = classifier([\"We are very happy to show you the 🤗 Transformers library.\", \"We hope you don't hate it.\"])\n", + "for result in results:\n", + " print(f\"label: {result['label']}, with score: {round(result['score'], 4)}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f752f929", + "metadata": {}, + "source": [ + "#### Use another model and tokenizer in the pipeline" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "9861865f", + "metadata": {}, + "outputs": [], + "source": [ + "model_name = \"nlptown/bert-base-multilingual-uncased-sentiment\"" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "506e7834", + "metadata": {}, + "outputs": [], + "source": [ + "from transformers import AutoTokenizer, AutoModelForSequenceClassification\n", + "\n", + "model = AutoModelForSequenceClassification.from_pretrained(model_name)\n", + "tokenizer = AutoTokenizer.from_pretrained(model_name)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "312017fc", + "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[{'label': 'NEGATIVE', 'score': 0.9997401833534241}]" + "[{'label': '5 stars', 'score': 0.7272652983665466}]" ] }, - "execution_count": 4, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "pipe(\"I will not say much about this film, because there is not much to say, because there is not much there to talk about.\")" + "classifier = pipeline(\"sentiment-analysis\", model=model, tokenizer=tokenizer, device=device)\n", + "classifier(\"Nous sommes très heureux de vous présenter la bibliothèque 🤗 Transformers.\")" ] }, { @@ -107,7 +157,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 10, "id": "69dd6a1a-f450-47f0-9dbf-ad250585a011", "metadata": {}, "outputs": [], @@ -115,12 +165,85 @@ "import pandas as pd\n", "from pyspark.sql.functions import col, struct, pandas_udf\n", "from pyspark.ml.functions import predict_batch_udf\n", - "from pyspark.sql.types import FloatType, StringType, StructField, StructType" + "from pyspark.sql.types import FloatType, StringType, StructField, StructType\n", + "from pyspark.sql import SparkSession\n", + "from pyspark import SparkConf\n", + "import os" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, + "id": "6e0e0dd7", + "metadata": {}, + "outputs": [], + "source": [ + "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", + "\n", + "conf = SparkConf()\n", + "if 'spark' not in globals():\n", + " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", + " import socket\n", + " hostname = socket.gethostname()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", + "conf.set(\"spark.task.maxFailures\", \"1\")\n", + "conf.set(\"spark.driver.memory\", \"8g\")\n", + "conf.set(\"spark.executor.memory\", \"8g\")\n", + "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", + "conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + "conf.set(\"spark.python.worker.reuse\", \"true\")\n", + "# Create Spark Session\n", + "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", + "sc = spark.sparkContext" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "42d70208", + "metadata": {}, + "outputs": [], + "source": [ + "from datasets import load_dataset\n", + "\n", + "# Load the IMDB dataset\n", + "data = load_dataset(\"imdb\", split=\"test\")\n", + "\n", + "lines = []\n", + "for example in data:\n", + " # first sentence only\n", + " lines.append([example[\"text\"]])\n", + "\n", + "len(lines)\n", + "\n", + "df = spark.createDataFrame(lines, ['lines']).repartition(8).cache()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "ac24f3c2", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "24/10/03 16:44:02 WARN TaskSetManager: Stage 0 contains a task of very large size (3860 KiB). The maximum recommended task size is 1000 KiB.\n", + " \r" + ] + } + ], + "source": [ + "df.write.mode(\"overwrite\").parquet(\"imdb_test\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, "id": "9665b7b6-d7e9-4bd4-b29d-7a449ac5b574", "metadata": {}, "outputs": [ @@ -128,7 +251,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 1:====================================================> (9 + 1) / 10]\r" + " \r" ] }, { @@ -162,13 +285,6 @@ "only showing top 20 rows\n", "\n" ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] } ], "source": [ @@ -183,14 +299,17 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 15, "id": "0da9d25c-5ebe-4503-bb19-154fcc047cbf", "metadata": {}, "outputs": [], "source": [ "def predict_batch_fn():\n", + " import torch\n", " from transformers import pipeline\n", - " pipe = pipeline(\"text-classification\")\n", + " \n", + " device = 0 if torch.cuda.is_available() else -1\n", + " pipe = pipeline(\"sentiment-analysis\", device=device)\n", " def predict(inputs):\n", " return pipe(inputs.tolist())\n", " return predict" @@ -198,7 +317,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 16, "id": "78afef29-ee30-4267-9fb6-be2dcb86cbba", "metadata": {}, "outputs": [], @@ -213,7 +332,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 17, "id": "a5bc327e-89cf-4731-82e6-e66cb93deef1", "metadata": {}, "outputs": [ @@ -221,15 +340,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 4:> (0 + 1) / 1]\r" + "[Stage 11:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 21.2 ms, sys: 4.33 ms, total: 25.5 ms\n", - "Wall time: 12.3 s\n" + "CPU times: user 12.6 ms, sys: 2.39 ms, total: 15 ms\n", + "Wall time: 2.02 s\n" ] }, { @@ -249,30 +368,16 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 18, "id": "ac642895-cfd6-47ee-9b21-02e7835424e4", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 6:> (0 + 1) / 1]\r" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 8.67 ms, sys: 4.24 ms, total: 12.9 ms\n", - "Wall time: 5.44 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" + "CPU times: user 2.13 ms, sys: 1.06 ms, total: 3.19 ms\n", + "Wall time: 237 ms\n" ] } ], @@ -285,30 +390,16 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 19, "id": "76a44d80-d5db-405f-989c-7246379cfb95", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 8:> (0 + 1) / 1]\r" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 13.8 ms, sys: 1.52 ms, total: 15.4 ms\n", - "Wall time: 5.46 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" + "CPU times: user 2.28 ms, sys: 790 μs, total: 3.07 ms\n", + "Wall time: 230 ms\n" ] } ], @@ -321,17 +412,10 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 20, "id": "c01761b3-c766-46b0-ae0b-fcf968ffb3a1", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 10:> (0 + 1) / 1]\r" - ] - }, { "name": "stdout", "output_type": "stream", @@ -339,7 +423,7 @@ "+--------------------------------------------------------------------------------+--------+----------+\n", "| sentence| label| score|\n", "+--------------------------------------------------------------------------------+--------+----------+\n", - "| |POSITIVE|0.74812096|\n", + "| |POSITIVE| 0.7481212|\n", "|Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pi...|NEGATIVE|0.99967253|\n", "|I watched this movie to see the direction one of the most promising young tal...|POSITIVE| 0.9994943|\n", "| This movie makes you wish imdb would let you vote a zero|NEGATIVE| 0.9981305|\n", @@ -351,25 +435,18 @@ "|This movie seems a little clunky around the edges, like not quite enough zani...|NEGATIVE|0.99965274|\n", "|I rented this movie hoping that it would provide some good entertainment and ...|NEGATIVE|0.99642426|\n", "|Well, where to start describing this celluloid debacle? You already know the ...|NEGATIVE|0.99973005|\n", - "| I hoped for this show to be somewhat realistic|POSITIVE| 0.8426521|\n", + "| I hoped for this show to be somewhat realistic|POSITIVE| 0.8426496|\n", "| All I have to say is one word|NEGATIVE| 0.9784491|\n", "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy scr...|NEGATIVE| 0.99977|\n", "|This critique tells the story of 4 little friends who went to watch Angels an...|POSITIVE| 0.9942334|\n", "| This review contains a partial spoiler|NEGATIVE| 0.996191|\n", - "| I'm rather surprised that anybody found this film touching or moving|POSITIVE| 0.8392786|\n", + "| I'm rather surprised that anybody found this film touching or moving|POSITIVE| 0.8392794|\n", "| If you like bad movies (and you must to watch this one) here's a good one|POSITIVE|0.99366415|\n", "|This is really bad, the characters were bland, the story was boring, and ther...|NEGATIVE|0.99953806|\n", "+--------------------------------------------------------------------------------+--------+----------+\n", "only showing top 20 rows\n", "\n" ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] } ], "source": [ @@ -391,21 +468,21 @@ "id": "10368010-f94d-4167-91a1-2cf9ed91a2c9", "metadata": {}, "source": [ - "This notebook uses the [Python backend with a custom execution environment](https://github.com/triton-inference-server/python_backend#creating-custom-execution-environments), using a conda-pack environment created as follows:\n", + "This notebook uses the [Python backend with a custom execution environment](https://github.com/triton-inference-server/python_backend#creating-custom-execution-environments) with the compatible versions of Python/Numpy for Triton 24.08, using a conda-pack environment created as follows:\n", "```\n", - "conda create -n huggingface -c conda-forge python=3.8\n", - "conda activate huggingface\n", + "conda create -n huggingface-torch -c conda-forge python=3.10.0\n", + "conda activate huggingface-torch\n", "\n", - "export PYTHONUSERSITE=True\n", - "pip install conda-pack sentencepiece sentence_transformers transformers\n", + "export PYTHONNOUSERSITE=True\n", + "pip install numpy==1.26.4 conda-pack sentencepiece sentence_transformers transformers\n", "\n", - "conda-pack # huggingface.tar.gz\n", + "conda-pack # huggingface-torch.tar.gz\n", "```" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 21, "id": "4d4be844-4b8c-47df-bd09-0c280c7ff16b", "metadata": {}, "outputs": [], @@ -420,30 +497,19 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 22, "id": "7e53df9f-43cb-4c38-b8ac-dc2cbad99815", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n", - "To disable this warning, you can either:\n", - "\t- Avoid using `tokenizers` before the fork if possible\n", - "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n" - ] - } - ], + "outputs": [], "source": [ "%%bash\n", "# copy custom model to expected layout for Triton\n", "rm -rf models\n", "mkdir -p models\n", - "cp -r models_config/hf_pipeline models\n", + "cp -r models_config/hf_pipeline_torch models\n", "\n", "# add custom execution environment\n", - "cp huggingface.tar.gz models" + "cp huggingface-torch.tar.gz models" ] }, { @@ -458,7 +524,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 23, "id": "144acb8e-4c08-40fc-a9ed-f721c409ee68", "metadata": {}, "outputs": [ @@ -475,7 +541,7 @@ "[True]" ] }, - "execution_count": 15, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -497,7 +563,7 @@ " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", " else:\n", " container=client.containers.run(\n", - " \"nvcr.io/nvidia/tritonserver:23.04-py3\", \"tritonserver --model-repository=/models\",\n", + " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", " detach=True,\n", " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", " environment=[\n", @@ -544,7 +610,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 24, "id": "d53fb283-bf9e-4571-8c68-b75a41f1f067", "metadata": {}, "outputs": [], @@ -559,7 +625,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 25, "id": "29b0cc0d-c480-4e4a-bd41-207dc314cba5", "metadata": {}, "outputs": [], @@ -569,7 +635,7 @@ " import tritonclient.grpc as grpcclient\n", " \n", " np_types = {\n", - " \"BOOL\": np.dtype(np.bool8),\n", + " \"BOOL\": np.dtype(np.bool_),\n", " \"INT8\": np.dtype(np.int8),\n", " \"INT16\": np.dtype(np.int16),\n", " \"INT32\": np.dtype(np.int32),\n", @@ -609,14 +675,14 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 26, "id": "3930cfcd-3284-4c6a-a9b5-36b8053fe899", "metadata": {}, "outputs": [], "source": [ "from functools import partial\n", "\n", - "classify = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"hf_pipeline\"),\n", + "classify = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"hf_pipeline_torch\"),\n", " return_type=StructType([\n", " StructField(\"label\", StringType(), True),\n", " StructField(\"score\", FloatType(), True)\n", @@ -627,7 +693,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 27, "id": "8eecbf23-4e9e-4d4c-8645-98209b25db2c", "metadata": {}, "outputs": [ @@ -635,15 +701,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 13:> (0 + 1) / 1]\r" + "[Stage 20:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 25.5 ms, sys: 0 ns, total: 25.5 ms\n", - "Wall time: 5.42 s\n" + "CPU times: user 5.89 ms, sys: 5.41 ms, total: 11.3 ms\n", + "Wall time: 1.98 s\n" ] }, { @@ -664,7 +730,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 28, "id": "566ba28c-0ca4-4479-a24a-c8a362228b89", "metadata": {}, "outputs": [ @@ -672,15 +738,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 14:> (0 + 1) / 1]\r" + "[Stage 21:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 11.6 ms, sys: 7.68 ms, total: 19.3 ms\n", - "Wall time: 4.52 s\n" + "CPU times: user 5.87 ms, sys: 2.39 ms, total: 8.26 ms\n", + "Wall time: 1.87 s\n" ] }, { @@ -700,7 +766,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 29, "id": "44c7e776-08da-484a-ba07-9d6add1a0f15", "metadata": {}, "outputs": [ @@ -708,15 +774,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 15:> (0 + 1) / 1]\r" + "[Stage 22:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 13.1 ms, sys: 5.65 ms, total: 18.7 ms\n", - "Wall time: 4.51 s\n" + "CPU times: user 5.24 ms, sys: 1.13 ms, total: 6.37 ms\n", + "Wall time: 1.86 s\n" ] }, { @@ -736,59 +802,45 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 30, "id": "f61d79f8-661e-4d9e-a3aa-c0754b854603", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 16:> (0 + 1) / 1]\r" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "+--------------------------------------------------------------------------------+--------+----------+\n", - "| sentence| label| score|\n", - "+--------------------------------------------------------------------------------+--------+----------+\n", - "| |POSITIVE| 0.7481212|\n", - "|Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pi...|NEGATIVE|0.99967253|\n", - "|I watched this movie to see the direction one of the most promising young tal...|POSITIVE| 0.9994943|\n", - "| This movie makes you wish imdb would let you vote a zero|NEGATIVE| 0.9981305|\n", - "|I never want to see this movie again!

Not only is it dreadfully ba...|NEGATIVE| 0.9988337|\n", - "|(As a note, I'd like to say that I saw this movie at my annual church camp, w...|POSITIVE| 0.9901974|\n", - "| Don't get me wrong, I love the TV series of League Of Gentlemen|POSITIVE| 0.9998311|\n", - "|Did you ever think, like after watching a horror movie with a group of friend...|POSITIVE| 0.9992779|\n", - "| Awful, awful, awful|NEGATIVE| 0.9997433|\n", - "|This movie seems a little clunky around the edges, like not quite enough zani...|NEGATIVE|0.99965274|\n", - "|I rented this movie hoping that it would provide some good entertainment and ...|NEGATIVE|0.99642426|\n", - "|Well, where to start describing this celluloid debacle? You already know the ...|NEGATIVE|0.99973005|\n", - "| I hoped for this show to be somewhat realistic|POSITIVE|0.84265035|\n", - "| All I have to say is one word|NEGATIVE| 0.9784491|\n", - "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy scr...|NEGATIVE| 0.99977|\n", - "|This critique tells the story of 4 little friends who went to watch Angels an...|POSITIVE| 0.9942334|\n", - "| This review contains a partial spoiler|NEGATIVE| 0.996191|\n", - "| I'm rather surprised that anybody found this film touching or moving|POSITIVE|0.83927685|\n", - "| If you like bad movies (and you must to watch this one) here's a good one|POSITIVE|0.99366415|\n", - "|This is really bad, the characters were bland, the story was boring, and ther...|NEGATIVE|0.99953806|\n", - "+--------------------------------------------------------------------------------+--------+----------+\n", + "+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+----------+\n", + "|sentence |label |score |\n", + "+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+----------+\n", + "| |POSITIVE|0.7481212 |\n", + "|Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pimp story without the gratuitous sex scenes, either hard core or soft core, therefore reads like a public information film from the fifties, give this a wide miss, use a barge pole if you can|NEGATIVE|0.99967253|\n", + "|I watched this movie to see the direction one of the most promising young talents in movies was going |POSITIVE|0.9994943 |\n", + "|This movie makes you wish imdb would let you vote a zero |NEGATIVE|0.9981305 |\n", + "|I never want to see this movie again!

Not only is it dreadfully bad, but I can't stand seeing my hero Stan Laurel looking so old and sick |NEGATIVE|0.9988337 |\n", + "|(As a note, I'd like to say that I saw this movie at my annual church camp, where the entire youth group laughed at it |POSITIVE|0.9901974 |\n", + "|Don't get me wrong, I love the TV series of League Of Gentlemen |POSITIVE|0.9998311 |\n", + "|Did you ever think, like after watching a horror movie with a group of friends: \"Wow, this is so cool! We have got to make a splatter horror movie ourselves some day soon |POSITIVE|0.9992779 |\n", + "|Awful, awful, awful |NEGATIVE|0.9997433 |\n", + "|This movie seems a little clunky around the edges, like not quite enough zaniness was thrown it when it should have been |NEGATIVE|0.99965274|\n", + "|I rented this movie hoping that it would provide some good entertainment and some cool poker knowledge or stories |NEGATIVE|0.99642426|\n", + "|Well, where to start describing this celluloid debacle? You already know the big fat NADA passing as a plot, so let's jut point out that this is so PC it's offensive |NEGATIVE|0.99973005|\n", + "|I hoped for this show to be somewhat realistic |POSITIVE|0.8426496 |\n", + "|All I have to say is one word |NEGATIVE|0.9784491 |\n", + "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy screenplay |NEGATIVE|0.99977 |\n", + "|This critique tells the story of 4 little friends who went to watch Angels and Demons the movie on the first night it came out, even though it was a school night, because \"Angels and Demons is worth it |POSITIVE|0.9942334 |\n", + "|This review contains a partial spoiler |NEGATIVE|0.996191 |\n", + "|I'm rather surprised that anybody found this film touching or moving |POSITIVE|0.8392794 |\n", + "|If you like bad movies (and you must to watch this one) here's a good one |POSITIVE|0.99366415|\n", + "|This is really bad, the characters were bland, the story was boring, and there is no sex scene |NEGATIVE|0.99953806|\n", + "+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------+----------+\n", "only showing top 20 rows\n", "\n" ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] } ], "source": [ - "preds.show(truncate=80)" + "preds.show(truncate=False)" ] }, { @@ -803,7 +855,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 31, "id": "425d3b28-7705-45ba-8a18-ad34fc895219", "metadata": {}, "outputs": [ @@ -820,7 +872,7 @@ "[True]" ] }, - "execution_count": 23, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -844,7 +896,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 32, "id": "9f19643c-4ee4-44f2-b762-2078c0c8eba9", "metadata": {}, "outputs": [], @@ -863,7 +915,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "spark-dl-torch", "language": "python", "name": "python3" }, @@ -877,7 +929,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/sentence_transformers.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/sentence_transformers_torch.ipynb similarity index 50% rename from examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/sentence_transformers.ipynb rename to examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/sentence_transformers_torch.ipynb index cb4b5d867..4a8a04078 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/sentence_transformers.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/sentence_transformers_torch.ipynb @@ -6,7 +6,7 @@ "metadata": {}, "source": [ "# PySpark Huggingface Inferencing\n", - "### Sentence Transformers\n", + "## Sentence Transformers with PyTorch\n", "\n", "From: https://huggingface.co/sentence-transformers" ] @@ -21,8 +21,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/leey/.pyenv/versions/3.9.10/envs/spark_rapids_examples/lib/python3.9/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n" + "/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/sentence_transformers/cross_encoder/CrossEncoder.py:13: TqdmExperimentalWarning: Using `tqdm.autonotebook.tqdm` in notebook mode. Use `tqdm.tqdm` instead to force console mode (e.g. in jupyter console)\n", + " from tqdm.autonotebook import tqdm, trange\n", + "/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/transformers/tokenization_utils_base.py:1617: FutureWarning: `clean_up_tokenization_spaces` was not set. It will be set to `True` by default. This behavior will be deprecated in transformers v4.45, and will be then set to `False` by default. For more details check this issue: https://github.com/huggingface/transformers/issues/31884\n", + " warnings.warn(\n" ] } ], @@ -45,145 +47,18 @@ "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "array([[-1.76214516e-01, 1.20601304e-01, -2.93624043e-01,\n", - " -2.29858175e-01, -8.22924003e-02, 2.37709180e-01,\n", - " 3.39985013e-01, -7.80964136e-01, 1.18127793e-01,\n", - " 1.63374111e-01, -1.37715325e-01, 2.40282863e-01,\n", - " 4.25125599e-01, 1.72417879e-01, 1.05279416e-01,\n", - " 5.18164098e-01, 6.22219592e-02, 3.99285942e-01,\n", - " -1.81652382e-01, -5.85578799e-01, 4.49718162e-02,\n", - " -1.72750458e-01, -2.68443376e-01, -1.47386298e-01,\n", - " -1.89217895e-01, 1.92150623e-01, -3.83842528e-01,\n", - " -3.96006793e-01, 4.30648834e-01, -3.15320045e-01,\n", - " 3.65949810e-01, 6.05160184e-02, 3.57326001e-01,\n", - " 1.59736484e-01, -3.00984085e-01, 2.63250291e-01,\n", - " -3.94310981e-01, 1.84855387e-01, -3.99549156e-01,\n", - " -2.67889678e-01, -5.45117497e-01, -3.13403830e-02,\n", - " -4.30644304e-01, 1.33278236e-01, -1.74793929e-01,\n", - " -4.35465544e-01, -4.77378905e-01, 7.12556019e-02,\n", - " -7.37000927e-02, 5.69136977e-01, -2.82579631e-01,\n", - " 5.24974912e-02, -8.20008039e-01, 1.98296875e-01,\n", - " 1.69511944e-01, 2.71780223e-01, 2.64610887e-01,\n", - " -2.55740248e-02, -1.74096078e-01, 1.63314238e-01,\n", - " -3.95261019e-01, -3.17557529e-02, -2.62556016e-01,\n", - " 3.52754653e-01, 3.01434726e-01, -1.47197261e-01,\n", - " 2.10075721e-01, -1.84010327e-01, -4.12896097e-01,\n", - " 4.14775908e-01, -1.89769432e-01, -1.35482103e-01,\n", - " -3.79272342e-01, -4.68020253e-02, -3.33600566e-02,\n", - " 9.00392979e-02, -3.30133080e-01, -3.87317017e-02,\n", - " 3.75082225e-01, -1.46996513e-01, 4.34959859e-01,\n", - " 5.38325727e-01, -2.65445322e-01, 1.64445966e-01,\n", - " 4.17078137e-01, -4.72507551e-02, -7.48731717e-02,\n", - " -4.26260680e-01, -1.96994469e-01, 6.10315353e-02,\n", - " -4.74262595e-01, -6.48334563e-01, 3.71462375e-01,\n", - " 2.50956744e-01, 1.22529656e-01, 8.88765603e-02,\n", - " -1.06724449e-01, 5.33984527e-02, 9.74504799e-02,\n", - " -3.46659198e-02, -1.02882944e-01, 2.32289046e-01,\n", - " -2.53739715e-01, -5.13112009e-01, 1.85215965e-01,\n", - " -3.04357857e-01, -3.55209708e-02, -1.26975283e-01,\n", - " -7.71633461e-02, -5.15329778e-01, -2.28072166e-01,\n", - " 2.03343891e-02, 7.38176629e-02, -1.52558297e-01,\n", - " -4.00837600e-01, -2.47749388e-01, 3.97470415e-01,\n", - " -2.60260761e-01, 2.50905871e-01, 1.68229103e-01,\n", - " 1.33900389e-01, -2.10832264e-02, -4.70035672e-01,\n", - " 4.78850305e-01, 2.80345857e-01, -4.64546710e-01,\n", - " 3.21746945e-01, 2.34207466e-01, 2.45772362e-01,\n", - " -4.71482247e-01, 5.00401437e-01, 4.10190284e-01,\n", - " 5.15217066e-01, 2.62549222e-01, 2.11592801e-02,\n", - " -3.89687479e-01, -2.41742760e-01, -2.14834422e-01,\n", - " -8.62650797e-02, -1.65323481e-01, -5.21896258e-02,\n", - " 3.41875046e-01, 4.50314254e-01, -3.06973517e-01,\n", - " -2.02294275e-01, 6.85521781e-01, -5.33892572e-01,\n", - " 3.58471453e-01, 1.45286813e-01, -7.07055628e-02,\n", - " -1.50529206e-01, -8.56279060e-02, -7.67850205e-02,\n", - " 1.89544708e-01, -1.04067393e-01, 5.33544004e-01,\n", - " -5.27887166e-01, 2.42331959e-02, -2.64348119e-01,\n", - " -2.23186791e-01, -3.81208628e-01, 7.59914368e-02,\n", - " -4.64485019e-01, -3.36549103e-01, 4.21229810e-01,\n", - " 1.07479259e-01, 1.90457568e-01, 2.89495080e-03,\n", - " -1.08513527e-01, 1.53545514e-01, 3.16023558e-01,\n", - " -2.70837210e-02, -5.40594459e-01, 8.97289440e-02,\n", - " -1.15549557e-01, 3.97803813e-01, -4.97683465e-01,\n", - " -2.84893245e-01, 4.99861389e-02, 3.61279517e-01,\n", - " 6.90535426e-01, 1.46821350e-01, 1.73396409e-01,\n", - " -1.74582213e-01, -3.15702498e-01, 6.72999024e-02,\n", - " 2.17250124e-01, 9.78534073e-02, -1.29472524e-01,\n", - " -1.86929733e-01, 1.34877980e-01, -1.53885141e-01,\n", - " 7.44716451e-02, -1.85536250e-01, -2.80628234e-01,\n", - " -1.14144124e-01, 4.12249714e-01, 6.39493242e-02,\n", - " -1.45715356e-01, -9.82063636e-02, -1.33081853e-01,\n", - " -1.88410729e-01, -2.84840688e-02, -3.49510685e-02,\n", - " 3.34260389e-02, 6.98895752e-02, 1.90354556e-01,\n", - " -2.96724111e-01, 2.64700665e-03, 1.09140664e-01,\n", - " 1.70893949e-02, 2.60589182e-01, 3.29038322e-01,\n", - " -6.61561564e-02, 2.39665493e-01, -2.26194724e-01,\n", - " -3.36869434e-02, 1.49400219e-01, -3.21265519e-01,\n", - " -2.68578082e-01, 5.72631419e-01, -4.92308617e-01,\n", - " 2.00666517e-01, -3.49261880e-01, -2.89886966e-02,\n", - " 6.09010518e-01, -5.72333217e-01, 2.35000581e-01,\n", - " 6.47170283e-03, -3.14947553e-02, 2.78106760e-02,\n", - " -3.90340686e-01, -2.08949789e-01, -3.04452747e-01,\n", - " -7.20199049e-02, -8.29839855e-02, 3.73792797e-01,\n", - " 7.38939270e-02, -2.21075043e-02, 9.88139212e-02,\n", - " -1.51426777e-01, -1.40430599e-01, 2.26017937e-01,\n", - " 2.76090086e-01, -8.87750760e-02, -1.12816244e-01,\n", - " -2.66285956e-01, 2.77834475e-01, -4.75612208e-02,\n", - " 6.71006441e-02, -2.78584342e-02, -2.39992719e-02,\n", - " 2.51708895e-01, 4.68793869e-01, -5.39325416e-01,\n", - " 1.10598333e-01, -3.44947278e-01, 4.15990025e-01,\n", - " 7.28482902e-02, -3.19647491e-01, 4.90374297e-01,\n", - " -7.30326539e-03, -2.64258590e-03, 9.63711143e-01,\n", - " 3.23884934e-01, -7.79617876e-02, -2.37589255e-01,\n", - " 2.34038249e-01, -3.16054285e-01, -1.65644684e-03,\n", - " -1.09070671e+00, 3.38409394e-01, 4.70604822e-02,\n", - " 1.07435532e-01, -2.06672445e-01, 4.26434958e-03,\n", - " -1.38471671e-03, -5.31455398e-01, -2.75648385e-01,\n", - " -1.64648548e-01, -3.42916548e-01, -4.26118731e-01,\n", - " 6.01812005e-01, 4.55971926e-01, -2.72701979e-01,\n", - " -3.45803909e-02, 2.62752384e-01, -6.34182245e-03,\n", - " 2.79631168e-01, -2.53559083e-01, -1.68626398e-01,\n", - " 3.82935070e-02, 2.07763270e-01, -4.31525737e-01,\n", - " -7.24000186e-02, -1.26854718e-01, 2.07032599e-02,\n", - " 5.74441671e-01, 3.54672760e-01, 9.28299800e-02,\n", - " 6.70504868e-02, 1.11520380e-01, -1.86511762e-02,\n", - " 4.62352008e-01, 2.72504658e-01, -3.60473931e-01,\n", - " 5.29415190e-01, -1.00307481e-03, -8.81362036e-02,\n", - " 1.49975210e-01, 5.25863320e-02, 4.63517606e-01,\n", - " -3.96831453e-01, 2.42640764e-01, -2.08912343e-01,\n", - " 3.65672171e-01, -4.73377790e-04, 5.33963263e-01,\n", - " -1.97879702e-01, 3.11582834e-01, -6.96714938e-01,\n", - " -4.29500610e-01, -4.49359357e-01, -2.71370225e-02,\n", - " -6.98709935e-02, 2.06174642e-01, -1.57107607e-01,\n", - " 4.43521231e-01, -6.74267113e-02, -3.00924242e-01,\n", - " 5.14859617e-01, 3.36029500e-01, 6.63374960e-02,\n", - " -1.15235247e-01, -2.95980442e-02, 2.79471934e-01,\n", - " -3.48198377e-02, -7.29323775e-02, -4.58472818e-02,\n", - " 1.54262766e-01, 8.09356093e-01, 5.20328283e-01,\n", - " -4.02114809e-01, -3.23153809e-02, -1.10363849e-01,\n", - " 7.50504881e-02, -1.51098818e-01, 8.45739901e-01,\n", - " -1.80844069e-01, 3.22573632e-01, 1.04708232e-01,\n", - " 3.19663674e-01, -1.55085340e-01, 1.69236794e-01,\n", - " -2.56996810e-01, 2.01208934e-01, 1.77392989e-01,\n", - " -2.74333209e-01, -3.36944401e-01, 5.02356768e-01,\n", - " -1.18357144e-01, -2.01166883e-01, -5.36485732e-01,\n", - " -7.69810155e-02, 1.15381051e-02, -2.36464351e-01,\n", - " -2.98769865e-02, 1.31366819e-01, 2.94184357e-01,\n", - " 9.90916416e-02, -5.43897390e-01, 1.40812859e-01,\n", - " 3.66998732e-01, 5.04862480e-02, 1.99122518e-01,\n", - " -2.80674607e-01, 4.34192210e-01, -1.40274912e-01,\n", - " 5.78049004e-01, 1.77715704e-01, 8.98363292e-02,\n", - " 3.29651982e-01, 6.13008998e-02, -3.24933499e-01]], dtype=float32)" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "[-0.17621444 0.1206013 -0.29362372 -0.22985819 -0.08229247 0.2377093\n", + " 0.33998525 -0.7809643 0.11812777 0.16337365 -0.13771524 0.24028276\n", + " 0.4251256 0.17241786 0.10527937 0.5181643 0.062222 0.39928585\n", + " -0.18165241 -0.58557856]\n" + ] } ], "source": [ - "embedding" + "print(embedding[0][:20])" ] }, { @@ -212,41 +87,105 @@ "source": [ "from pyspark.ml.functions import predict_batch_udf\n", "from pyspark.sql.functions import col, struct\n", - "from pyspark.sql.types import ArrayType, FloatType" + "from pyspark.sql.types import ArrayType, FloatType\n", + "from pyspark.sql import SparkSession\n", + "from pyspark import SparkConf\n", + "from datasets import load_dataset" ] }, { "cell_type": "code", "execution_count": 4, - "id": "836e5f84-12c6-4c95-838e-53de7e46a20b", + "id": "23ec67ba", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - " \r" + "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n", + "To disable this warning, you can either:\n", + "\t- Avoid using `tokenizers` before the fork if possible\n", + "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n", + "24/10/08 00:19:28 WARN Utils: Your hostname, cb4ae00-lcedt resolves to a loopback address: 127.0.1.1; using 10.110.47.100 instead (on interface eno1)\n", + "24/10/08 00:19:28 WARN Utils: Set SPARK_LOCAL_IP if you need to bind to another address\n", + "Setting default log level to \"WARN\".\n", + "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", + "24/10/08 00:19:28 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n" ] } ], "source": [ - "# only use first N examples, since this is slow\n", - "df = spark.read.parquet(\"imdb_test\").limit(100).cache()" + "import os\n", + "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", + "\n", + "conf = SparkConf()\n", + "if 'spark' not in globals():\n", + " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", + " import socket\n", + " hostname = socket.gethostname()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", + "conf.set(\"spark.task.maxFailures\", \"1\")\n", + "conf.set(\"spark.driver.memory\", \"8g\")\n", + "conf.set(\"spark.executor.memory\", \"8g\")\n", + "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", + "conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + "conf.set(\"spark.python.worker.reuse\", \"true\")\n", + "# Create Spark Session\n", + "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", + "sc = spark.sparkContext" ] }, { "cell_type": "code", "execution_count": 5, - "id": "36703d23-37a3-40df-b09a-c68206d285b6", + "id": "9bc1edb5", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "[Stage 1:==============================================> (8 + 2) / 10]\r" + " \r" ] - }, + } + ], + "source": [ + "# load IMDB reviews (test) dataset and write to parquet\n", + "data = load_dataset(\"imdb\", split=\"test\")\n", + "\n", + "lines = []\n", + "for example in data:\n", + " lines.append([example[\"text\"].split(\".\")[0]])\n", + "\n", + "len(lines)\n", + "\n", + "df = spark.createDataFrame(lines, ['lines']).repartition(10)\n", + "df.schema\n", + "\n", + "df.write.mode(\"overwrite\").parquet(\"imdb_test\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "836e5f84-12c6-4c95-838e-53de7e46a20b", + "metadata": {}, + "outputs": [], + "source": [ + "# only use first N examples, since this is slow\n", + "df = spark.read.parquet(\"imdb_test\").limit(100).cache()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "36703d23-37a3-40df-b09a-c68206d285b6", + "metadata": {}, + "outputs": [ { "name": "stdout", "output_type": "stream", @@ -254,37 +193,30 @@ "+------------------------------------------------------------------------------------------------------------------------+\n", "| lines|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", - "|...But not this one! I always wanted to know \"what happened\" next. We will never know for sure what happened because ...|\n", - "|Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pimp story without the gratuitous sex scen...|\n", - "|I watched this movie to see the direction one of the most promising young talents in movies was going. Unfortunately,...|\n", - "|This movie makes you wish imdb would let you vote a zero. One of the two movies I've ever walked out of. It's very ha...|\n", - "|I never want to see this movie again!

Not only is it dreadfully bad, but I can't stand seeing my hero Stan...|\n", - "|(As a note, I'd like to say that I saw this movie at my annual church camp, where the entire youth group laughed at i...|\n", - "|Don't get me wrong, I love the TV series of League Of Gentlemen. It was funny, twisted and completely inspired. I was...|\n", - "|Did you ever think, like after watching a horror movie with a group of friends: \"Wow, this is so cool! We have got to...|\n", - "|Awful, awful, awful...

I loved the original film. It was funny, charming, and had heart... this piece of j...|\n", - "|This movie seems a little clunky around the edges, like not quite enough zaniness was thrown it when it should have b...|\n", - "|I rented this movie hoping that it would provide some good entertainment and some cool poker knowledge or stories. Wh...|\n", - "|Well, where to start describing this celluloid debacle? You already know the big fat NADA passing as a plot, so let's...|\n", - "|I hoped for this show to be somewhat realistic. It stroke me as just another mainstream show after I watched it. I di...|\n", - "|All I have to say is one word...SUCKS!!!!. The only reason I gave this a 2 is because Josh Hartnett was in it and he'...|\n", - "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy screenplay.

The lighting at is s...|\n", - "|This critique tells the story of 4 little friends who went to watch Angels and Demons the movie on the first night it...|\n", - "|This review contains a partial spoiler.

Shallow from the outset, 'D.O.A.' at least starts as if it might b...|\n", - "|I'm rather surprised that anybody found this film touching or moving.

The basic premise of the film sounde...|\n", - "|If you like bad movies (and you must to watch this one) here's a good one. Not quite as funny as the first, but much ...|\n", - "|This is really bad, the characters were bland, the story was boring, and there is no sex scene. Furthermore, it lacks...|\n", + "| This is so overly clichéd you'll want to switch it off after the first 45 minutes|\n", + "| I was very disappointed by this movie|\n", + "| I think vampire movies (usually) are wicked|\n", + "| Though not a complete waste of time, 'Eighteen' really wasn't all sweet as it pretended to be|\n", + "|This film did well at the box office, and the producers of this mess thought the stars had such good chemistry in thi...|\n", + "| Peter Crawford discovers a comet on a collision course with the moon|\n", + "|This tale of the upper-classes getting their come-uppance and wallowing in their high-class misery is like a contempo...|\n", + "|Words almost fail me to describe how terrible this Irish vanity project (funded by Canadian taxpayers - both federal ...|\n", + "| This was the most uninteresting horror flick I have seen to date|\n", + "| Heart of Darkness was terrible|\n", + "| I saw this movie when it was first released in Pittsburgh Pa|\n", + "|It was funny because the whole thing was so unrealistic, I mean, come on, like a pop star would just show up at a pub...|\n", + "|Watching this movie, you just have to ask: What were they thinking? There are so many noticeably bad parts of this mo...|\n", + "| In a sense, this movie did not even compare to the novel|\n", + "| Poor Jane Austen ought to be glad she's not around to see this dreadful wreck of an adaptation|\n", + "| I gave this movie a four-star rating for a few reasons|\n", + "| It seems that Dee Snyder ran out of ideas halfway through the script|\n", + "| Now, let me see if I have this correct, a lunatic serial killer is going around murdering estate agents|\n", + "| Tommy Lee Jones was the best Woodroe and no one can play Woodroe F|\n", + "|First of all, I would like to say that I am a fan of all of the actors that appear in this film and at the time that ...|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n" ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] } ], "source": [ @@ -293,7 +225,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 8, "id": "f780c026-0f3f-4aea-8b61-5b3dbae83fb7", "metadata": {}, "outputs": [], @@ -308,7 +240,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "id": "f5c88ddc-ca19-4430-8b0e-b9fae143b237", "metadata": {}, "outputs": [], @@ -320,7 +252,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "id": "85344c22-4a4d-4cb0-8771-5836ae2794db", "metadata": {}, "outputs": [ @@ -328,15 +260,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 4:> (0 + 1) / 1]\r" + "[Stage 9:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 17.8 ms, sys: 9.35 ms, total: 27.2 ms\n", - "Wall time: 8.36 s\n" + "CPU times: user 4.34 ms, sys: 4.15 ms, total: 8.48 ms\n", + "Wall time: 2.58 s\n" ] }, { @@ -356,7 +288,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, "id": "c23bb885-6ab0-4471-943d-4c10414100fa", "metadata": {}, "outputs": [ @@ -364,15 +296,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 6:> (0 + 1) / 1]\r" + "[Stage 11:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 17.7 ms, sys: 1.13 ms, total: 18.8 ms\n", - "Wall time: 3.25 s\n" + "CPU times: user 1.76 ms, sys: 4.89 ms, total: 6.65 ms\n", + "Wall time: 2.47 s\n" ] }, { @@ -391,7 +323,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 12, "id": "93bc6da3-d853-4233-b805-cb4a46f4f9b9", "metadata": {}, "outputs": [ @@ -399,15 +331,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 8:> (0 + 1) / 1]\r" + "[Stage 13:> (0 + 1) / 1]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 16.9 ms, sys: 0 ns, total: 16.9 ms\n", - "Wall time: 2.91 s\n" + "CPU times: user 1.55 ms, sys: 6.05 ms, total: 7.6 ms\n", + "Wall time: 2.46 s\n" ] }, { @@ -426,10 +358,17 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 13, "id": "2073616f-7151-4760-92f2-441dd0bfe9fe", "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 15:> (0 + 1) / 1]\r" + ] + }, { "name": "stdout", "output_type": "stream", @@ -437,30 +376,37 @@ "+------------------------------------------------------------+------------------------------------------------------------+\n", "| lines| encoding|\n", "+------------------------------------------------------------+------------------------------------------------------------+\n", - "|...But not this one! I always wanted to know \"what happen...|[0.050629966, -0.19899231, 2.686046E-4, 0.13270327, -0.16...|\n", - "|Hard up, No proper jobs going down at the pit, why not re...|[0.08634103, -0.002254839, 0.10213216, -0.03454912, -0.23...|\n", - "|I watched this movie to see the direction one of the most...|[0.008758117, -0.0083419345, -0.119090386, 0.025434377, -...|\n", - "|This movie makes you wish imdb would let you vote a zero....|[0.24080081, -0.14614257, 0.18119521, 0.118741795, 0.1022...|\n", - "|I never want to see this movie again!

Not only...|[0.32271573, -0.14145091, 0.09245593, 0.04562203, 0.07219...|\n", - "|(As a note, I'd like to say that I saw this movie at my a...|[0.1308969, 0.14792246, -0.021109976, -0.16882573, -0.055...|\n", - "|Don't get me wrong, I love the TV series of League Of Gen...|[-0.19420472, 0.116419405, 0.01985946, -0.37481546, 0.052...|\n", - "|Did you ever think, like after watching a horror movie wi...|[0.050077364, -0.34728476, -0.47222477, 0.09191189, -0.16...|\n", - "|Awful, awful, awful...

I loved the original fi...|[-0.23921771, -0.22389278, -0.0042956644, 0.058358684, 0....|\n", - "|This movie seems a little clunky around the edges, like n...|[-0.12948105, -0.16344212, -0.28761974, -0.10628598, -0.0...|\n", - "|I rented this movie hoping that it would provide some goo...|[-0.030982, -0.13821997, 0.14594209, -0.20565805, -0.0225...|\n", - "|Well, where to start describing this celluloid debacle? Y...|[-0.29094818, 0.026240889, -0.21248402, 0.028826537, -0.1...|\n", - "|I hoped for this show to be somewhat realistic. It stroke...|[0.14481407, -0.13123356, -0.47293735, -0.21168816, 0.001...|\n", - "|All I have to say is one word...SUCKS!!!!. The only reaso...|[0.018178312, 0.11847291, -0.33938172, -0.15572134, 0.051...|\n", - "|Honestly awful film, bad editing, awful lighting, dire di...|[-0.10033801, -0.28231186, 0.18979141, 0.042497832, 0.125...|\n", - "|This critique tells the story of 4 little friends who wen...|[0.1318425, -0.1671868, -0.013854267, 0.14505053, -0.2534...|\n", - "|This review contains a partial spoiler.

Shallo...|[-0.08296674, -0.08548329, -0.13219479, -0.20946309, 0.01...|\n", - "|I'm rather surprised that anybody found this film touchin...|[-0.21176083, -0.12755248, -0.28217235, 0.02004116, 0.074...|\n", - "|If you like bad movies (and you must to watch this one) h...|[-0.38088003, -0.1916466, 0.16510564, -0.11013024, -0.233...|\n", - "|This is really bad, the characters were bland, the story ...|[0.09919267, 0.042636175, -0.17805319, -0.1818586, -0.123...|\n", + "|This is so overly clichéd you'll want to switch it off af...|[-0.06755405, -0.13365394, 0.36675274, -0.2772311, -0.085...|\n", + "| I was very disappointed by this movie|[-0.05903806, 0.16684641, 0.16768408, 0.10940918, 0.18100...|\n", + "| I think vampire movies (usually) are wicked|[0.025601083, -0.5308639, -0.319133, -0.013351389, -0.338...|\n", + "|Though not a complete waste of time, 'Eighteen' really wa...|[0.20991832, 0.5228605, 0.44517252, -0.031682555, -0.4117...|\n", + "|This film did well at the box office, and the producers o...|[0.18097948, -0.03622232, -0.34149718, 0.061557338, -0.06...|\n", + "|Peter Crawford discovers a comet on a collision course wi...|[-0.27548054, 0.196654, -0.24626413, -0.39380816, -0.5501...|\n", + "|This tale of the upper-classes getting their come-uppance...|[0.24201547, 0.011018356, -0.080340266, 0.31388673, -0.28...|\n", + "|Words almost fail me to describe how terrible this Irish ...|[0.055901285, -0.14539501, -0.14005454, -0.038912475, 0.4...|\n", + "|This was the most uninteresting horror flick I have seen ...|[0.27159664, -0.012541974, -0.31898177, 0.058205508, 0.56...|\n", + "| Heart of Darkness was terrible|[0.1593065, 0.36501122, 0.10715093, 0.76344764, 0.2555183...|\n", + "|I saw this movie when it was first released in Pittsburgh Pa|[-0.34647614, 0.115615666, -0.18874267, 0.36590436, -0.06...|\n", + "|It was funny because the whole thing was so unrealistic, ...|[0.09473594, -0.43785918, 0.14436111, 0.0045353747, -0.08...|\n", + "|Watching this movie, you just have to ask: What were they...|[0.43020695, -0.09714467, 0.1356213, 0.23126744, -0.03908...|\n", + "| In a sense, this movie did not even compare to the novel|[0.2838324, -0.018966805, -0.37275136, 0.27034461, 0.2017...|\n", + "|Poor Jane Austen ought to be glad she's not around to see...|[0.27462235, -0.32494685, 0.48243234, 0.07208571, 0.22470...|\n", + "| I gave this movie a four-star rating for a few reasons|[0.31143323, -0.09470663, -0.10863629, 0.077851094, -0.15...|\n", + "|It seems that Dee Snyder ran out of ideas halfway through...|[0.44354546, -0.08122106, -0.15206784, -0.29244298, 0.559...|\n", + "|Now, let me see if I have this correct, a lunatic serial ...|[0.39831734, 0.15871558, -0.35366735, -0.11643518, -0.137...|\n", + "|Tommy Lee Jones was the best Woodroe and no one can play ...|[-0.20960264, -0.15760101, -0.30596393, -0.51817703, -0.0...|\n", + "|First of all, I would like to say that I am a fan of all ...|[0.25831866, -0.26871824, 0.026099348, -0.3459879, -0.180...|\n", "+------------------------------------------------------------+------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n" ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] } ], "source": [ @@ -479,24 +425,24 @@ }, { "cell_type": "markdown", - "id": "a8211920-234e-480f-bf87-6d719090e292", + "id": "5f502a20", "metadata": {}, "source": [ - "This notebook uses the [Python backend with a custom execution environment](https://github.com/triton-inference-server/python_backend#creating-custom-execution-environments), using a conda-pack environment created as follows:\n", + "This notebook uses the [Python backend with a custom execution environment](https://github.com/triton-inference-server/python_backend#creating-custom-execution-environments) with the compatible versions of Python/Numpy for Triton 24.08, using a conda-pack environment created as follows:\n", "```\n", - "conda create -n huggingface -c conda-forge python=3.8\n", - "conda activate huggingface\n", + "conda create -n huggingface-torch -c conda-forge python=3.10.0\n", + "conda activate huggingface-torch\n", "\n", - "export PYTHONUSERSITE=True\n", - "pip install conda-pack sentencepiece sentence_transformers transformers\n", + "export PYTHONNOUSERSITE=True\n", + "pip install numpy==1.26.4 conda-pack sentencepiece sentence_transformers transformers\n", "\n", - "conda-pack # huggingface.tar.gz\n", + "conda-pack # huggingface-torch.tar.gz\n", "```" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 14, "id": "772e337e-1098-4c7b-ba81-8cb221a518e2", "metadata": {}, "outputs": [], @@ -510,30 +456,19 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 15, "id": "69d0c93a-bb0b-46c5-9d28-7b08a2e70964", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "huggingface/tokenizers: The current process just got forked, after parallelism has already been used. Disabling parallelism to avoid deadlocks...\n", - "To disable this warning, you can either:\n", - "\t- Avoid using `tokenizers` before the fork if possible\n", - "\t- Explicitly set the environment variable TOKENIZERS_PARALLELISM=(true | false)\n" - ] - } - ], + "outputs": [], "source": [ "%%bash\n", "# copy custom model to expected layout for Triton\n", "rm -rf models\n", "mkdir -p models\n", - "cp -r models_config/hf_transformer models\n", + "cp -r models_config/hf_transformer_torch models\n", "\n", "# add custom execution environment\n", - "cp huggingface.tar.gz models" + "cp huggingface-torch.tar.gz models" ] }, { @@ -548,7 +483,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 16, "id": "1654cdc1-4f9a-4fd5-b7ac-6ca4215bde5d", "metadata": {}, "outputs": [ @@ -565,7 +500,7 @@ "[True]" ] }, - "execution_count": 14, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -587,7 +522,7 @@ " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", " else:\n", " container=client.containers.run(\n", - " \"nvcr.io/nvidia/tritonserver:23.04-py3\", \"tritonserver --model-repository=/models\",\n", + " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", " detach=True,\n", " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", " environment=[\n", @@ -629,7 +564,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 17, "id": "2969d502-e97b-49d6-bf80-7d177ae867cf", "metadata": {}, "outputs": [], @@ -642,7 +577,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 18, "id": "c8f1e6d6-6519-49e7-8465-4419547633b8", "metadata": {}, "outputs": [ @@ -650,7 +585,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "23/05/19 19:15:37 WARN CacheManager: Asked to cache already cached data.\n" + "24/10/08 00:20:24 WARN CacheManager: Asked to cache already cached data.\n" ] } ], @@ -661,7 +596,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 19, "id": "29b0cc0d-c480-4e4a-bd41-207dc314cba5", "metadata": {}, "outputs": [], @@ -671,7 +606,7 @@ " import tritonclient.grpc as grpcclient\n", " \n", " np_types = {\n", - " \"BOOL\": np.dtype(np.bool8),\n", + " \"BOOL\": np.dtype(np.bool_),\n", " \"INT8\": np.dtype(np.int8),\n", " \"INT16\": np.dtype(np.int16),\n", " \"INT32\": np.dtype(np.int32),\n", @@ -711,12 +646,12 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 20, "id": "9c712b8f-6eb4-4fb8-9f0a-04feef847fea", "metadata": {}, "outputs": [], "source": [ - "encode = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"hf_transformer\"),\n", + "encode = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"hf_transformer_torch\"),\n", " return_type=ArrayType(FloatType()),\n", " input_tensor_shapes=[[1]],\n", " batch_size=100)" @@ -724,30 +659,16 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 21, "id": "934c1a1f-b126-45b0-9c15-265236820ad3", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 14:> (0 + 1) / 1]\r" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 19.7 ms, sys: 3.95 ms, total: 23.6 ms\n", - "Wall time: 2.67 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" + "CPU times: user 4.65 ms, sys: 2.85 ms, total: 7.49 ms\n", + "Wall time: 480 ms\n" ] } ], @@ -760,7 +681,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 22, "id": "f84cd3f6-b6a8-4142-859a-91f3c183457b", "metadata": {}, "outputs": [ @@ -768,8 +689,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 7.66 ms, sys: 3.04 ms, total: 10.7 ms\n", - "Wall time: 265 ms\n" + "CPU times: user 1.45 ms, sys: 1.1 ms, total: 2.56 ms\n", + "Wall time: 384 ms\n" ] } ], @@ -781,7 +702,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 23, "id": "921a4c01-e296-4406-be90-86f20c8c582d", "metadata": {}, "outputs": [ @@ -789,8 +710,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 12.6 ms, sys: 570 µs, total: 13.2 ms\n", - "Wall time: 261 ms\n" + "CPU times: user 1.63 ms, sys: 1.28 ms, total: 2.91 ms\n", + "Wall time: 416 ms\n" ] } ], @@ -802,7 +723,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 24, "id": "9f67584e-9c4e-474f-b6ea-7811b14d116e", "metadata": {}, "outputs": [ @@ -813,26 +734,26 @@ "+------------------------------------------------------------+------------------------------------------------------------+\n", "| lines| encoding|\n", "+------------------------------------------------------------+------------------------------------------------------------+\n", - "|...But not this one! I always wanted to know \"what happen...|[0.050629944, -0.19899224, 2.68735E-4, 0.13270333, -0.160...|\n", - "|Hard up, No proper jobs going down at the pit, why not re...|[0.08634147, -0.002254737, 0.10213226, -0.034549147, -0.2...|\n", - "|I watched this movie to see the direction one of the most...|[0.008757966, -0.008341991, -0.11909033, 0.02543464, -0.2...|\n", - "|This movie makes you wish imdb would let you vote a zero....|[0.24080098, -0.14614293, 0.1811954, 0.11874188, 0.102292...|\n", - "|I never want to see this movie again!

Not only...|[0.3227157, -0.14145078, 0.0924558, 0.045622032, 0.072197...|\n", - "|(As a note, I'd like to say that I saw this movie at my a...|[0.13089702, 0.1479226, -0.021110116, -0.16882578, -0.055...|\n", - "|Don't get me wrong, I love the TV series of League Of Gen...|[-0.19420475, 0.11641937, 0.019859463, -0.37481567, 0.052...|\n", - "|Did you ever think, like after watching a horror movie wi...|[0.050077528, -0.34728497, -0.4722248, 0.091912046, -0.16...|\n", - "|Awful, awful, awful...

I loved the original fi...|[-0.2392176, -0.22389287, -0.004295718, 0.05835876, 0.082...|\n", - "|This movie seems a little clunky around the edges, like n...|[-0.12948103, -0.16344213, -0.2876199, -0.106286034, -0.0...|\n", - "|I rented this movie hoping that it would provide some goo...|[-0.03098194, -0.13821997, 0.1459418, -0.20565815, -0.022...|\n", - "|Well, where to start describing this celluloid debacle? Y...|[-0.29094803, 0.026240645, -0.21248397, 0.028826557, -0.1...|\n", - "|I hoped for this show to be somewhat realistic. It stroke...|[0.14481404, -0.13123384, -0.47293738, -0.21168788, 0.001...|\n", - "|All I have to say is one word...SUCKS!!!!. The only reaso...|[0.018178271, 0.11847262, -0.3393819, -0.15572123, 0.0515...|\n", - "|Honestly awful film, bad editing, awful lighting, dire di...|[-0.10033788, -0.28231215, 0.18979158, 0.042498272, 0.125...|\n", - "|This critique tells the story of 4 little friends who wen...|[0.13184246, -0.16718695, -0.013854082, 0.14505032, -0.25...|\n", - "|This review contains a partial spoiler.

Shallo...|[-0.08296674, -0.08548302, -0.1321949, -0.20946284, 0.010...|\n", - "|I'm rather surprised that anybody found this film touchin...|[-0.21176091, -0.1275524, -0.28217238, 0.020041106, 0.074...|\n", - "|If you like bad movies (and you must to watch this one) h...|[-0.38088012, -0.19164667, 0.16510546, -0.11012972, -0.23...|\n", - "|This is really bad, the characters were bland, the story ...|[0.099192545, 0.04263605, -0.17805345, -0.18185869, -0.12...|\n", + "|This is so overly clichéd you'll want to switch it off af...|[-0.06755393, -0.1336537, 0.366753, -0.2772312, -0.085145...|\n", + "| I was very disappointed by this movie|[-0.059038587, 0.1668467, 0.16768396, 0.10940957, 0.18100...|\n", + "| I think vampire movies (usually) are wicked|[0.025601566, -0.5308643, -0.31913283, -0.013350786, -0.3...|\n", + "|Though not a complete waste of time, 'Eighteen' really wa...|[0.2099183, 0.5228606, 0.4451728, -0.031682458, -0.411756...|\n", + "|This film did well at the box office, and the producers o...|[0.1809797, -0.036222238, -0.34149715, 0.06155738, -0.066...|\n", + "|Peter Crawford discovers a comet on a collision course wi...|[-0.27548066, 0.196654, -0.24626443, -0.3938084, -0.55015...|\n", + "|This tale of the upper-classes getting their come-uppance...|[0.24201535, 0.011018419, -0.080340445, 0.31388694, -0.28...|\n", + "|Words almost fail me to describe how terrible this Irish ...|[0.05590127, -0.14539507, -0.14005487, -0.03891221, 0.444...|\n", + "|This was the most uninteresting horror flick I have seen ...|[0.2715968, -0.012542339, -0.3189819, 0.05820581, 0.56001...|\n", + "| Heart of Darkness was terrible|[0.15930629, 0.36501077, 0.10715161, 0.7634482, 0.2555183...|\n", + "|I saw this movie when it was first released in Pittsburgh Pa|[-0.34647676, 0.11561544, -0.18874292, 0.36590466, -0.068...|\n", + "|It was funny because the whole thing was so unrealistic, ...|[0.09473588, -0.4378593, 0.14436121, 0.0045354995, -0.085...|\n", + "|Watching this movie, you just have to ask: What were they...|[0.43020678, -0.09714476, 0.13562134, 0.23126753, -0.0390...|\n", + "| In a sense, this movie did not even compare to the novel|[0.28383228, -0.01896684, -0.37275153, 0.27034503, 0.2017...|\n", + "|Poor Jane Austen ought to be glad she's not around to see...|[0.27462238, -0.32494652, 0.48243237, 0.07208576, 0.22470...|\n", + "| I gave this movie a four-star rating for a few reasons|[0.311433, -0.09470633, -0.10863638, 0.07785072, -0.15611...|\n", + "|It seems that Dee Snyder ran out of ideas halfway through...|[0.44354525, -0.08122053, -0.15206799, -0.29244322, 0.559...|\n", + "|Now, let me see if I have this correct, a lunatic serial ...|[0.39831725, 0.15871589, -0.35366756, -0.11643555, -0.137...|\n", + "|Tommy Lee Jones was the best Woodroe and no one can play ...|[-0.20960276, -0.157601, -0.30596414, -0.5181772, -0.0852...|\n", + "|First of all, I would like to say that I am a fan of all ...|[0.25831848, -0.26871827, 0.026099432, -0.34598774, -0.18...|\n", "+------------------------------------------------------------+------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n" @@ -855,7 +776,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 25, "id": "d8e5466b-b5dc-4fe1-9012-0c87cdd72962", "metadata": {}, "outputs": [ @@ -872,7 +793,7 @@ "[True]" ] }, - "execution_count": 23, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } @@ -896,7 +817,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 26, "id": "e82b9518-da7b-4ebc-8990-c8ab909bec18", "metadata": {}, "outputs": [], @@ -915,7 +836,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "spark-dl-torch", "language": "python", "name": "python3" }, @@ -929,7 +850,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification.ipynb deleted file mode 100644 index 8d685eff5..000000000 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification.ipynb +++ /dev/null @@ -1,2180 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "9e87c927", - "metadata": {}, - "source": [ - "# PySpark PyTorch Inference\n", - "\n", - "### Image Classification\n", - "Based on: https://pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "91d7ec98", - "metadata": {}, - "outputs": [], - "source": [ - "import torch\n", - "\n", - "from torch import nn\n", - "from torch.utils.data import DataLoader\n", - "from torchvision import datasets\n", - "from torchvision.transforms import ToTensor" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "d714f40d", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'2.0.1+cpu'" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "torch.__version__" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "1c942a46", - "metadata": {}, - "outputs": [], - "source": [ - "# Download training data from open datasets.\n", - "training_data = datasets.FashionMNIST(\n", - " root=\"data\",\n", - " train=True,\n", - " download=True,\n", - " transform=ToTensor(),\n", - ")\n", - "\n", - "# Download test data from open datasets.\n", - "test_data = datasets.FashionMNIST(\n", - " root=\"data\",\n", - " train=False,\n", - " download=True,\n", - " transform=ToTensor(),\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "4a89aa8e-ef62-4aac-8260-4b004f2c1b55", - "metadata": {}, - "outputs": [], - "source": [ - "classes = [\n", - " \"T-shirt/top\",\n", - " \"Trouser\",\n", - " \"Pullover\",\n", - " \"Dress\",\n", - " \"Coat\",\n", - " \"Sandal\",\n", - " \"Shirt\",\n", - " \"Sneaker\",\n", - " \"Bag\",\n", - " \"Ankle boot\",\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "10a97111", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Shape of X [N, C, H, W]: torch.Size([64, 1, 28, 28]) torch.float32\n", - "Shape of y: torch.Size([64]) torch.int64\n" - ] - } - ], - "source": [ - "batch_size = 64\n", - "\n", - "# Create data loaders.\n", - "train_dataloader = DataLoader(training_data, batch_size=batch_size)\n", - "test_dataloader = DataLoader(test_data, batch_size=batch_size)\n", - "\n", - "for X, y in test_dataloader:\n", - " print(f\"Shape of X [N, C, H, W]: {X.shape} {X.dtype}\")\n", - " print(f\"Shape of y: {y.shape} {y.dtype}\")\n", - " break" - ] - }, - { - "cell_type": "markdown", - "id": "ca7af350", - "metadata": {}, - "source": [ - "### Create model" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "512d0bc7", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Using cpu device\n", - "NeuralNetwork(\n", - " (flatten): Flatten(start_dim=1, end_dim=-1)\n", - " (linear_relu_stack): Sequential(\n", - " (0): Linear(in_features=784, out_features=512, bias=True)\n", - " (1): ReLU()\n", - " (2): Linear(in_features=512, out_features=512, bias=True)\n", - " (3): ReLU()\n", - " (4): Linear(in_features=512, out_features=10, bias=True)\n", - " )\n", - ")\n" - ] - } - ], - "source": [ - "# Get cpu or gpu device for training.\n", - "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", - "print(f\"Using {device} device\")\n", - "\n", - "# Define model\n", - "class NeuralNetwork(nn.Module):\n", - " def __init__(self):\n", - " super(NeuralNetwork, self).__init__()\n", - " self.flatten = nn.Flatten()\n", - " self.linear_relu_stack = nn.Sequential(\n", - " nn.Linear(28*28, 512),\n", - " nn.ReLU(),\n", - " nn.Linear(512, 512),\n", - " nn.ReLU(),\n", - " nn.Linear(512, 10)\n", - " )\n", - "\n", - " def forward(self, x):\n", - " x = self.flatten(x)\n", - " logits = self.linear_relu_stack(x)\n", - " return logits\n", - "\n", - "model = NeuralNetwork().to(device)\n", - "print(model)" - ] - }, - { - "cell_type": "markdown", - "id": "4573c1b7", - "metadata": {}, - "source": [ - "### Train Model" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "4d4f5538", - "metadata": {}, - "outputs": [], - "source": [ - "loss_fn = nn.CrossEntropyLoss()\n", - "optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "92d9076a", - "metadata": {}, - "outputs": [], - "source": [ - "def train(dataloader, model, loss_fn, optimizer):\n", - " size = len(dataloader.dataset)\n", - " model.train()\n", - " for batch, (X, y) in enumerate(dataloader):\n", - " X, y = X.to(device), y.to(device)\n", - "\n", - " # Compute prediction error\n", - " pred = model(X)\n", - " loss = loss_fn(pred, y)\n", - "\n", - " # Backpropagation\n", - " optimizer.zero_grad()\n", - " loss.backward()\n", - " optimizer.step()\n", - "\n", - " if batch % 100 == 0:\n", - " loss, current = loss.item(), batch * len(X)\n", - " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "11c5650d", - "metadata": {}, - "outputs": [], - "source": [ - "def test(dataloader, model, loss_fn):\n", - " size = len(dataloader.dataset)\n", - " num_batches = len(dataloader)\n", - " model.eval()\n", - " test_loss, correct = 0, 0\n", - " with torch.no_grad():\n", - " for X, y in dataloader:\n", - " X, y = X.to(device), y.to(device)\n", - " pred = model(X)\n", - " test_loss += loss_fn(pred, y).item()\n", - " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", - " test_loss /= num_batches\n", - " correct /= size\n", - " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "854608e6", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 1\n", - "-------------------------------\n", - "loss: 2.305429 [ 0/60000]\n", - "loss: 2.297022 [ 6400/60000]\n", - "loss: 2.266470 [12800/60000]\n", - "loss: 2.265714 [19200/60000]\n", - "loss: 2.253563 [25600/60000]\n", - "loss: 2.203140 [32000/60000]\n", - "loss: 2.224580 [38400/60000]\n", - "loss: 2.182435 [44800/60000]\n", - "loss: 2.177402 [51200/60000]\n", - "loss: 2.141706 [57600/60000]\n", - "Test Error: \n", - " Accuracy: 20.4%, Avg loss: 2.142049 \n", - "\n", - "Epoch 2\n", - "-------------------------------\n", - "loss: 2.150640 [ 0/60000]\n", - "loss: 2.147359 [ 6400/60000]\n", - "loss: 2.082054 [12800/60000]\n", - "loss: 2.101886 [19200/60000]\n", - "loss: 2.044116 [25600/60000]\n", - "loss: 1.972289 [32000/60000]\n", - "loss: 2.005282 [38400/60000]\n", - "loss: 1.923009 [44800/60000]\n", - "loss: 1.926389 [51200/60000]\n", - "loss: 1.847295 [57600/60000]\n", - "Test Error: \n", - " Accuracy: 54.4%, Avg loss: 1.854991 \n", - "\n", - "Epoch 3\n", - "-------------------------------\n", - "loss: 1.888080 [ 0/60000]\n", - "loss: 1.862951 [ 6400/60000]\n", - "loss: 1.743250 [12800/60000]\n", - "loss: 1.784036 [19200/60000]\n", - "loss: 1.660822 [25600/60000]\n", - "loss: 1.621519 [32000/60000]\n", - "loss: 1.635365 [38400/60000]\n", - "loss: 1.545240 [44800/60000]\n", - "loss: 1.565089 [51200/60000]\n", - "loss: 1.461044 [57600/60000]\n", - "Test Error: \n", - " Accuracy: 60.3%, Avg loss: 1.486240 \n", - "\n", - "Epoch 4\n", - "-------------------------------\n", - "loss: 1.551637 [ 0/60000]\n", - "loss: 1.524140 [ 6400/60000]\n", - "loss: 1.374491 [12800/60000]\n", - "loss: 1.446650 [19200/60000]\n", - "loss: 1.322406 [25600/60000]\n", - "loss: 1.325748 [32000/60000]\n", - "loss: 1.331345 [38400/60000]\n", - "loss: 1.261354 [44800/60000]\n", - "loss: 1.292640 [51200/60000]\n", - "loss: 1.200176 [57600/60000]\n", - "Test Error: \n", - " Accuracy: 63.3%, Avg loss: 1.229079 \n", - "\n", - "Epoch 5\n", - "-------------------------------\n", - "loss: 1.302291 [ 0/60000]\n", - "loss: 1.292532 [ 6400/60000]\n", - "loss: 1.125565 [12800/60000]\n", - "loss: 1.234343 [19200/60000]\n", - "loss: 1.108794 [25600/60000]\n", - "loss: 1.134641 [32000/60000]\n", - "loss: 1.149444 [38400/60000]\n", - "loss: 1.086560 [44800/60000]\n", - "loss: 1.125073 [51200/60000]\n", - "loss: 1.049052 [57600/60000]\n", - "Test Error: \n", - " Accuracy: 64.7%, Avg loss: 1.072207 \n", - "\n", - "Done!\n" - ] - } - ], - "source": [ - "epochs = 5\n", - "for t in range(epochs):\n", - " print(f\"Epoch {t+1}\\n-------------------------------\")\n", - " train(train_dataloader, model, loss_fn, optimizer)\n", - " test(test_dataloader, model, loss_fn)\n", - "print(\"Done!\")" - ] - }, - { - "cell_type": "markdown", - "id": "85d97839", - "metadata": {}, - "source": [ - "### Save Model State Dict\n", - "This is the [currently recommended save format](https://pytorch.org/tutorials/beginner/saving_loading_models.html#saving-loading-model-for-inference)." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "5d5d24de", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Saved PyTorch Model State to model_weights.pt\n" - ] - } - ], - "source": [ - "torch.save(model.state_dict(), \"model_weights.pt\")\n", - "print(\"Saved PyTorch Model State to model_weights.pt\")" - ] - }, - { - "cell_type": "markdown", - "id": "7416bbef", - "metadata": {}, - "source": [ - "### Save Entire Model\n", - "This saves the entire model using python pickle, but has the [following disadvantage](https://pytorch.org/tutorials/beginner/saving_loading_models.html#save-load-entire-model):\n", - "> The serialized data is bound to the specific classes and the exact directory structure used when the model is saved... Because of this, your code can break in various ways when used in other projects or after refactors." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "e87098c0", - "metadata": {}, - "outputs": [], - "source": [ - "torch.save(model, \"model.pt\")" - ] - }, - { - "cell_type": "markdown", - "id": "ac221ca7-e227-4c8c-8577-1eeda4a61fc7", - "metadata": {}, - "source": [ - "### Save Model as TorchScript\n", - "This saves an [intermediate representation of the compute graph](https://pytorch.org/tutorials/beginner/saving_loading_models.html#export-load-model-in-torchscript-format), which does not require pickle (or even python). However, this currently doesn't work with spark, which uses pickle serialization." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "6d9b3a45-7618-43e4-8bd3-8bb317a484d3", - "metadata": {}, - "outputs": [], - "source": [ - "scripted = torch.jit.script(model)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "0cd01550-c72e-47f2-abe6-e14f26b06fc7", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "scripted.save(\"model.ts\")" - ] - }, - { - "cell_type": "markdown", - "id": "12ee8916-f437-4a2a-9bf4-14ff5376d305", - "metadata": {}, - "source": [ - "### Load Model State" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "8fe3b5d1", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model_from_state = NeuralNetwork()\n", - "model_from_state.load_state_dict(torch.load(\"model_weights.pt\"))" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "0c405bd0", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Predicted: \"Ankle boot\", Actual: \"Ankle boot\"\n" - ] - } - ], - "source": [ - "model_from_state.eval()\n", - "x, y = test_data[0][0], test_data[0][1]\n", - "with torch.no_grad():\n", - " pred = model_from_state(x)\n", - " predicted, actual = classes[pred[0].argmax(0)], classes[y]\n", - " print(f'Predicted: \"{predicted}\", Actual: \"{actual}\"')" - ] - }, - { - "cell_type": "markdown", - "id": "1708f5e0", - "metadata": {}, - "source": [ - "### Load Model" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "dc5bce69", - "metadata": {}, - "outputs": [], - "source": [ - "new_model = torch.load(\"model.pt\")" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "cc219a56-4abd-4b61-9f9a-686dae7c9614", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Predicted: \"Ankle boot\", Actual: \"Ankle boot\"\n" - ] - } - ], - "source": [ - "x, y = test_data[0][0], test_data[0][1]\n", - "with torch.no_grad():\n", - " pred = new_model(x)\n", - " predicted, actual = classes[pred[0].argmax(0)], classes[y]\n", - " print(f'Predicted: \"{predicted}\", Actual: \"{actual}\"')" - ] - }, - { - "cell_type": "markdown", - "id": "290c482a-1c5d-4bf2-bc3f-8a4e53d442b5", - "metadata": {}, - "source": [ - "### Load Torchscript Model" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "ef3c419e-d384-446c-b07b-1af93e07d6c0", - "metadata": {}, - "outputs": [], - "source": [ - "ts_model = torch.jit.load(\"model.ts\")" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "038af830-a360-45eb-ab4e-b1adab0af164", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Predicted: \"Ankle boot\", Actual: \"Ankle boot\"\n" - ] - } - ], - "source": [ - "x, y = test_data[0][0], test_data[0][1]\n", - "with torch.no_grad():\n", - " pred = ts_model(x)\n", - " predicted, actual = classes[pred[0].argmax(0)], classes[y]\n", - " print(f'Predicted: \"{predicted}\", Actual: \"{actual}\"')" - ] - }, - { - "cell_type": "markdown", - "id": "ad918393", - "metadata": {}, - "source": [ - "## PySpark" - ] - }, - { - "cell_type": "markdown", - "id": "fd1daec3", - "metadata": {}, - "source": [ - "### Convert numpy dataset to Pandas DataFrame" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "42c5feba", - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "from pyspark.sql.types import StructType, StructField, ArrayType, FloatType" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "f063cbe7", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "((10000, 28, 28), dtype('uint8'))" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "data = test_data.data.numpy()\n", - "data.shape, data.dtype" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "8c828393", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "((10000, 784), dtype('float64'))" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "data = data.reshape(10000, 784) / 255.0\n", - "data.shape, data.dtype" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "7760bdbe", - "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", - " \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", - " \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", - "
0123456789...774775776777778779780781782783
00.00.00.00.0000000.00.0000000.0000000.00.0000000.000000...0.0000000.0000000.00.0000000.0000000.0000000.0000000.00.00.0
10.00.00.00.0000000.00.0000000.0000000.00.0000000.000000...0.0078430.0117650.00.0117650.6823530.7411760.2627450.00.00.0
20.00.00.00.0000000.00.0000000.0000000.00.0039220.000000...0.6431370.2274510.00.0000000.0000000.0000000.0000000.00.00.0
30.00.00.00.0000000.00.0000000.0000000.00.0000000.082353...0.0039220.0000000.00.0000000.0000000.0000000.0000000.00.00.0
40.00.00.00.0078430.00.0039220.0039220.00.0000000.000000...0.2784310.0470590.00.0000000.0000000.0000000.0000000.00.00.0
..................................................................
99950.00.00.00.0000000.00.0000000.0000000.00.0000000.000000...0.0000000.0000000.00.0000000.0000000.0000000.0000000.00.00.0
99960.00.00.00.0000000.00.0000000.0000000.00.0000000.121569...0.0000000.0000000.00.0000000.0000000.0000000.0000000.00.00.0
99970.00.00.00.0000000.00.0000000.0000000.00.0000000.000000...0.1058820.0000000.00.0000000.0000000.0000000.0000000.00.00.0
99980.00.00.00.0000000.00.0000000.0000000.00.0000000.000000...0.0000000.0000000.00.0000000.0000000.0000000.0000000.00.00.0
99990.00.00.00.0000000.00.0000000.0000000.00.0000000.000000...0.0000000.0000000.00.0000000.0000000.0000000.0000000.00.00.0
\n", - "

10000 rows × 784 columns

\n", - "
" - ], - "text/plain": [ - " 0 1 2 3 4 5 6 7 8 \n", - "0 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \\\n", - "1 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", - "2 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.003922 \n", - "3 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", - "4 0.0 0.0 0.0 0.007843 0.0 0.003922 0.003922 0.0 0.000000 \n", - "... ... ... ... ... ... ... ... ... ... \n", - "9995 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", - "9996 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", - "9997 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", - "9998 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", - "9999 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", - "\n", - " 9 ... 774 775 776 777 778 779 \n", - "0 0.000000 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.000000 \\\n", - "1 0.000000 ... 0.007843 0.011765 0.0 0.011765 0.682353 0.741176 \n", - "2 0.000000 ... 0.643137 0.227451 0.0 0.000000 0.000000 0.000000 \n", - "3 0.082353 ... 0.003922 0.000000 0.0 0.000000 0.000000 0.000000 \n", - "4 0.000000 ... 0.278431 0.047059 0.0 0.000000 0.000000 0.000000 \n", - "... ... ... ... ... ... ... ... ... \n", - "9995 0.000000 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.000000 \n", - "9996 0.121569 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.000000 \n", - "9997 0.000000 ... 0.105882 0.000000 0.0 0.000000 0.000000 0.000000 \n", - "9998 0.000000 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.000000 \n", - "9999 0.000000 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.000000 \n", - "\n", - " 780 781 782 783 \n", - "0 0.000000 0.0 0.0 0.0 \n", - "1 0.262745 0.0 0.0 0.0 \n", - "2 0.000000 0.0 0.0 0.0 \n", - "3 0.000000 0.0 0.0 0.0 \n", - "4 0.000000 0.0 0.0 0.0 \n", - "... ... ... ... ... \n", - "9995 0.000000 0.0 0.0 0.0 \n", - "9996 0.000000 0.0 0.0 0.0 \n", - "9997 0.000000 0.0 0.0 0.0 \n", - "9998 0.000000 0.0 0.0 0.0 \n", - "9999 0.000000 0.0 0.0 0.0 \n", - "\n", - "[10000 rows x 784 columns]" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pdf784 = pd.DataFrame(data)\n", - "pdf784" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "f7d2bc0d", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 178 ms, sys: 52.5 ms, total: 231 ms\n", - "Wall time: 227 ms\n" - ] - }, - { - "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", - "
data
0[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
1[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
2[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.003...
3[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
4[0.0, 0.0, 0.0, 0.00784313725490196, 0.0, 0.00...
......
9995[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
9996[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
9997[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
9998[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
9999[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
\n", - "

10000 rows × 1 columns

\n", - "
" - ], - "text/plain": [ - " data\n", - "0 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - "1 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - "2 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.003...\n", - "3 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - "4 [0.0, 0.0, 0.0, 0.00784313725490196, 0.0, 0.00...\n", - "... ...\n", - "9995 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - "9996 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - "9997 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - "9998 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - "9999 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - "\n", - "[10000 rows x 1 columns]" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "# 1 column of array\n", - "pdf1 = pd.DataFrame()\n", - "pdf1['data'] = pdf784.values.tolist()\n", - "pdf1" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "20c3b86a-8b61-4128-ab61-0199fd3437cc", - "metadata": {}, - "outputs": [], - "source": [ - "### Create Spark DataFrame from Pandas DataFrame" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "4863d5ff", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 3.33 s, sys: 68.3 ms, total: 3.4 s\n", - "Wall time: 5.51 s\n" - ] - } - ], - "source": [ - "%%time\n", - "# force FloatType since Spark defaults to DoubleType\n", - "schema = StructType([StructField(\"data\",ArrayType(FloatType()), True)])\n", - "df = spark.createDataFrame(pdf1, schema)" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "406edba5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "StructType([StructField('data', ArrayType(FloatType(), True), True)])" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.schema" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "831f4a01-3a49-4114-b9a0-2ae54526d72d", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 4.35 s, sys: 141 ms, total: 4.5 s\n", - "Wall time: 4.75 s\n" - ] - } - ], - "source": [ - "%%time\n", - "# force FloatType since Spark defaults to DoubleType\n", - "schema = StructType([StructField(str(x), FloatType(), True) for x in range(784)])\n", - "df784 = spark.createDataFrame(pdf784, schema)" - ] - }, - { - "cell_type": "markdown", - "id": "ac4c7448", - "metadata": {}, - "source": [ - "### Save the test dataset as parquet files" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "e8ebae46", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/05/19 17:55:11 WARN TaskSetManager: Stage 0 contains a task of very large size (7070 KiB). The maximum recommended task size is 1000 KiB.\n", - "[Stage 0:> (0 + 8) / 8]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 5.9 ms, sys: 4.12 ms, total: 10 ms\n", - "Wall time: 4.31 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "%%time\n", - "df.write.mode(\"overwrite\").parquet(\"fashion_mnist_1\")" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "922314ce-2996-4666-9fc9-bcd98d16bb56", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/05/19 17:55:14 WARN package: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.sql.debug.maxToStringFields'.\n", - "23/05/19 17:55:14 WARN TaskSetManager: Stage 1 contains a task of very large size (7067 KiB). The maximum recommended task size is 1000 KiB.\n", - "[Stage 1:> (0 + 8) / 8]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 11.9 ms, sys: 54 µs, total: 12 ms\n", - "Wall time: 2.93 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "%%time\n", - "df784.write.mode(\"overwrite\").parquet(\"fashion_mnist_784\")" - ] - }, - { - "cell_type": "markdown", - "id": "8688429e", - "metadata": {}, - "source": [ - "### Check arrow memory configuration" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "088cb37f", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/05/19 17:55:17 WARN TaskSetManager: Stage 2 contains a task of very large size (7070 KiB). The maximum recommended task size is 1000 KiB.\n" - ] - } - ], - "source": [ - "spark.conf.set(\"spark.sql.execution.arrow.maxRecordsPerBatch\", \"128\")\n", - "# This line will fail if the vectorized reader runs out of memory\n", - "assert len(df.head()) > 0, \"`df` should not be empty\"" - ] - }, - { - "cell_type": "markdown", - "id": "d7c77eb4-7bd6-40c7-9a35-ee899a66ece3", - "metadata": {}, - "source": [ - "## Inference using Spark DL API" - ] - }, - { - "cell_type": "markdown", - "id": "59395856-a588-43c6-93c8-c83100716ac1", - "metadata": { - "tags": [] - }, - "source": [ - "### 1 columns of 784 float" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "133cc9a5-64c6-4820-807e-b87cf7e0b75a", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "from pyspark.ml.functions import predict_batch_udf\n", - "from pyspark.sql.functions import struct, col, array\n", - "from pyspark.sql.types import ArrayType, FloatType, Union, Dict" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "79b151d9-d112-43b6-a479-887e2fd0e2b1", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = spark.read.parquet(\"fashion_mnist_1\")\n", - "len(df.columns)" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "cabcd546-2e8e-40d0-8b79-7598a7a83aae", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "StructType([StructField('data', ArrayType(FloatType(), True), True)])" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.schema" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "5db4b957-57fc-4bc5-b8bb-db0657a186c8", - "metadata": {}, - "outputs": [], - "source": [ - "# get absolute path to model\n", - "model_dir = \"{}/model.ts\".format(os.getcwd())" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "73dc73cb-25e3-4798-a019-e1abd684eaa1", - "metadata": {}, - "outputs": [], - "source": [ - "def predict_batch_fn():\n", - " import torch\n", - " device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", - " print(\"Using {} device\".format(device))\n", - " model = torch.jit.load(model_dir)\n", - " model.to(device)\n", - " \n", - " def predict(inputs: np.ndarray):\n", - " torch_inputs = torch.from_numpy(inputs).to(device)\n", - " outputs = model(torch_inputs)\n", - " return outputs.detach().numpy()\n", - " \n", - " return predict" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "df68cca1-2d47-4e88-8aad-9899402aee97", - "metadata": {}, - "outputs": [], - "source": [ - "mnist = predict_batch_udf(predict_batch_fn,\n", - " input_tensor_shapes=[[784]],\n", - " return_type=ArrayType(FloatType()),\n", - " batch_size=50)" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "id": "63555b3b-3673-4712-97aa-fd728c6c4979", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 465 ms, sys: 117 ms, total: 582 ms\n", - "Wall time: 4.31 s\n" - ] - } - ], - "source": [ - "%%time\n", - "# first pass caches model/fn\n", - "preds = df.withColumn(\"preds\", mnist(struct(df.columns))).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "id": "5dbf058a-70d6-4199-af9d-13843d078950", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 449 ms, sys: 125 ms, total: 574 ms\n", - "Wall time: 1.48 s\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", mnist(*df.columns)).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "id": "3f5ed801-6ca5-43a0-bf9c-2535a0dfe2e8", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 698 ms, sys: 117 ms, total: 815 ms\n", - "Wall time: 1.52 s\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", mnist(*[col(c) for c in df.columns])).collect()" - ] - }, - { - "cell_type": "markdown", - "id": "c6dbec03-9b64-46c4-a748-f889be571384", - "metadata": { - "tags": [] - }, - "source": [ - "### Check predictions" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "id": "f1f1e5fd-5866-4b78-b9d3-709e6b383a0c", - "metadata": {}, - "outputs": [], - "source": [ - "predictions = preds[0].preds\n", - "img = preds[0].data" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "id": "76b76502-adb7-45ec-a365-2e61cdd576fc", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "id": "c163953a-1504-444f-b39f-86b61d34e440", - "metadata": {}, - "outputs": [], - "source": [ - "img = np.array(img).reshape(28,28)" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "id": "bc0fad05-50ab-4ae5-b9fd-e50133c4c92a", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGdCAYAAABU0qcqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAfwElEQVR4nO3df3DU9b3v8dfm10Iw2RBCfkmgARGsSGyppFSlWHKBOMcB5d7xV88FjwevNDhFtHrpqGjbmbR4xzp6qN6Z24KeEbXeERi9LR0EE8YasKAcSrUpSVOBkgTFZjck5ud+7h8c064Q4LNueCfh+ZjZGbL7feX75ptv8so3u/kk4JxzAgDgPEuyHgAAcGGigAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGAixXqAz4tGozp69KgyMjIUCASsxwEAeHLOqbW1VYWFhUpK6v86Z9AV0NGjR1VUVGQ9BgDgCzp8+LDGjRvX7+ODroAyMjIkSdfoeqUo1XgaAICvHnXrLf2q7+t5fwasgNatW6fHH39cTU1NKikp0dNPP62ZM2eeNffZj91SlKqUAAUEAEPOf64weranUQbkRQgvv/yyVq1apTVr1ujdd99VSUmJ5s+fr2PHjg3E7gAAQ9CAFNATTzyhZcuW6Y477tCXv/xlPfvss0pPT9cvfvGLgdgdAGAISngBdXV1ae/evSorK/v7TpKSVFZWppqamlO27+zsVCQSibkBAIa/hBfQxx9/rN7eXuXl5cXcn5eXp6amplO2r6ysVCgU6rvxCjgAuDCY/yLq6tWrFQ6H+26HDx+2HgkAcB4k/FVwOTk5Sk5OVnNzc8z9zc3Nys/PP2X7YDCoYDCY6DEAAINcwq+A0tLSNGPGDG3fvr3vvmg0qu3bt2vWrFmJ3h0AYIgakN8DWrVqlZYsWaKvfe1rmjlzpp588km1tbXpjjvuGIjdAQCGoAEpoJtvvlkfffSRHnnkETU1NenKK6/U1q1bT3lhAgDgwhVwzjnrIf5RJBJRKBTSHC1kJQQAGIJ6XLeqtEXhcFiZmZn9bmf+KjgAwIWJAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJhJeQI8++qgCgUDMberUqYneDQBgiEsZiHd6+eWX64033vj7TlIGZDcAgCFsQJohJSVF+fn5A/GuAQDDxIA8B3Tw4EEVFhZq4sSJuv3223Xo0KF+t+3s7FQkEom5AQCGv4QXUGlpqTZs2KCtW7fqmWeeUUNDg6699lq1traedvvKykqFQqG+W1FRUaJHAgAMQgHnnBvIHbS0tGjChAl64okndOedd57yeGdnpzo7O/vejkQiKioq0hwtVEogdSBHAwAMgB7XrSptUTgcVmZmZr/bDfirA7KysnTppZeqrq7utI8Hg0EFg8GBHgMAMMgM+O8BnThxQvX19SooKBjoXQEAhpCEF9D999+v6upq/eUvf9Hbb7+tG2+8UcnJybr11lsTvSsAwBCW8B/BHTlyRLfeequOHz+usWPH6pprrtGuXbs0duzYRO8KADCEJbyAXnrppUS/SwDAMMRacAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAEwM+B+kw38KBPwzcfyx2kCK/4fU9fR4Z07u7Pz8n4aj5NGjvTN/fHSKd2bStL96ZyQp/Pw478zo52ri2tdwkzRqlHcmns9B9w9/SXqo4goIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCC1bDPl/O0CnQ8q+rGs4J23JKTvSOuq8s7E4hjP9IXWBncU+OGPO9MoN5/P+V5f/APSZr28FbvzL/9y1zvTPP/KfbOZBzxXwU6+c13vTOSlDx5onemc7z/SueH56Z5Zyav+9A7I0k9fz3qH/Je+T4gncOXPK6AAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmGAx0uHGe9HA87cApyTpPO3rfP6fjj7wDe/MXZf8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3btX3d3dMefD1KlTNX78+GF9Pnz+OHzmhRdeUE5OjqZNm6bVq1ervb3dYrx+DbrFSD/v448/Vm9vr/Ly8mLuz8vL0x//+EejqWyUlpZqw4YNmjJlihobG/XYY4/p2muv1YEDB5SRkWE9nommpiZJOu358dljF4oFCxbopptuUnFxserr6/X9739f5eXlqqmpUXJysvV4CReNRrVy5UpdffXVmjZtmqST50NaWpqysrJith3O58PpjoMk3XbbbZowYYIKCwu1f/9+Pfjgg6qtrdWrr75qOG2sQV9A+Lvy8vK+f0+fPl2lpaWaMGGCfvnLX+rOO+80nAyDwS233NL37yuuuELTp0/XpEmTVFVVpblz5xpONjAqKip04MCBC+J50DPp7zjcddddff++4oorVFBQoLlz56q+vl6TJk0632Oe1qD/EVxOTo6Sk5NPeRVLc3Oz8vPzjaYaHLKysnTppZeqrq7OehQzn50DnB+nmjhxonJycobl+bFixQq9/vrrevPNN2P+fEt+fr66urrU0tISs/1wPR/6Ow6nU1paKkmD6nwY9AWUlpamGTNmaPv27X33RaNRbd++XbNmzTKczN6JEydUX1+vgoIC61HMFBcXKz8/P+b8iEQi2r179wV/fhw5ckTHjx8fVueHc04rVqzQpk2btGPHDhUXF8c8PmPGDKWmpsacD7W1tTp06NCwOh/OdhxOZ9++fZI0uM4H61dBnIuXXnrJBYNBt2HDBvf++++7u+66y2VlZbmmpibr0c6r++67z1VVVbmGhgb329/+1pWVlbmcnBx37Ngx69EGVGtrq3vvvffce++95yS5J554wr333nvuww8/dM459+Mf/9hlZWW5LVu2uP3797uFCxe64uJi9+mnnxpPnlhnOg6tra3u/vvvdzU1Na6hocG98cYb7qtf/aqbPHmy6+josB49YZYvX+5CoZCrqqpyjY2Nfbf29va+be6++243fvx4t2PHDrdnzx43a9YsN2vWLMOpE+9sx6Gurs794Ac/cHv27HENDQ1uy5YtbuLEiW727NnGk8caEgXknHNPP/20Gz9+vEtLS3MzZ850u3btsh7pvLv55ptdQUGBS0tLcxdffLG7+eabXV1dnfVYA+7NN990kk65LVmyxDl38qXYDz/8sMvLy3PBYNDNnTvX1dbW2g49AM50HNrb2928efPc2LFjXWpqqpswYYJbtmzZsPsm7XT/f0lu/fr1fdt8+umn7jvf+Y4bPXq0S09PdzfeeKNrbGy0G3oAnO04HDp0yM2ePdtlZ2e7YDDoLrnkEve9733PhcNh28E/hz/HAAAwMeifAwIADE8UEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMEEBAQBM/H+wVOxLQwVbkwAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure()\n", - "plt.imshow(img)\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "id": "56f36efb-e3a2-49f9-b9fb-1657bc25e5c5", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[-1.7200822830200195,\n", - " -2.013300895690918,\n", - " -0.3198302984237671,\n", - " -1.4132847785949707,\n", - " -0.25933510065078735,\n", - " 1.7492953538894653,\n", - " -0.45816969871520996,\n", - " 2.1313018798828125,\n", - " 1.6222647428512573,\n", - " 1.3297781944274902]" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "predictions" - ] - }, - { - "cell_type": "markdown", - "id": "56ca1195-ea0f-405f-87fe-857e5c0c76a5", - "metadata": {}, - "source": [ - "### 784 columns of float" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "id": "e0ab0af6-b5c9-4b74-9dd6-baa7737cc986", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "784" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = spark.read.parquet(\"fashion_mnist_784\")\n", - "len(df.columns)" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "id": "13ae45dc-85a0-4864-8a58-9dc29ae4efd7", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 1.08 s, sys: 142 ms, total: 1.23 s\n", - "Wall time: 6 s\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", mnist(struct(df.columns))).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "id": "0b3fb48b-f871-41f2-ac57-346899a6fe48", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 1.07 s, sys: 137 ms, total: 1.21 s\n", - "Wall time: 3.01 s\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", mnist(array(*df.columns))).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "id": "a43f3a7e-c6ef-4eaa-bfa8-8ca09cab7070", - "metadata": {}, - "outputs": [], - "source": [ - "# should raise ValueError\n", - "# preds = df.withColumn(\"preds\", mnist(*df.columns)).collect()" - ] - }, - { - "cell_type": "markdown", - "id": "dc48ec42-0df6-4e6a-b019-1270ab71d2cf", - "metadata": { - "tags": [] - }, - "source": [ - "### Check predictions" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "id": "d815c701-9f5b-422c-b3f9-fbc30456953c", - "metadata": {}, - "outputs": [], - "source": [ - "preds = df.withColumn(\"preds\", mnist(array(*df.columns))).limit(10).toPandas()" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "id": "b571b742-5079-42b2-8524-9181a0dec2c7", - "metadata": {}, - "outputs": [], - "source": [ - "sample = preds.iloc[0]\n", - "predictions = sample.preds\n", - "img = sample.drop('preds').to_numpy(dtype=float)" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "id": "d33d6a4e-e6b9-489d-ac21-c4eddc801784", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "id": "6d10061e-aca6-4f81-bdfe-72e327ed7349", - "metadata": {}, - "outputs": [], - "source": [ - "img = np.array(img).reshape(28,28)" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "id": "01f70e08-2c1d-419f-8676-3f6f4aba760f", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGdCAYAAABU0qcqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAfwElEQVR4nO3df3DU9b3v8dfm10Iw2RBCfkmgARGsSGyppFSlWHKBOMcB5d7xV88FjwevNDhFtHrpqGjbmbR4xzp6qN6Z24KeEbXeERi9LR0EE8YasKAcSrUpSVOBkgTFZjck5ud+7h8c064Q4LNueCfh+ZjZGbL7feX75ptv8so3u/kk4JxzAgDgPEuyHgAAcGGigAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGAixXqAz4tGozp69KgyMjIUCASsxwEAeHLOqbW1VYWFhUpK6v86Z9AV0NGjR1VUVGQ9BgDgCzp8+LDGjRvX7+ODroAyMjIkSdfoeqUo1XgaAICvHnXrLf2q7+t5fwasgNatW6fHH39cTU1NKikp0dNPP62ZM2eeNffZj91SlKqUAAUEAEPOf64weranUQbkRQgvv/yyVq1apTVr1ujdd99VSUmJ5s+fr2PHjg3E7gAAQ9CAFNATTzyhZcuW6Y477tCXv/xlPfvss0pPT9cvfvGLgdgdAGAISngBdXV1ae/evSorK/v7TpKSVFZWppqamlO27+zsVCQSibkBAIa/hBfQxx9/rN7eXuXl5cXcn5eXp6amplO2r6ysVCgU6rvxCjgAuDCY/yLq6tWrFQ6H+26HDx+2HgkAcB4k/FVwOTk5Sk5OVnNzc8z9zc3Nys/PP2X7YDCoYDCY6DEAAINcwq+A0tLSNGPGDG3fvr3vvmg0qu3bt2vWrFmJ3h0AYIgakN8DWrVqlZYsWaKvfe1rmjlzpp588km1tbXpjjvuGIjdAQCGoAEpoJtvvlkfffSRHnnkETU1NenKK6/U1q1bT3lhAgDgwhVwzjnrIf5RJBJRKBTSHC1kJQQAGIJ6XLeqtEXhcFiZmZn9bmf+KjgAwIWJAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJhJeQI8++qgCgUDMberUqYneDQBgiEsZiHd6+eWX64033vj7TlIGZDcAgCFsQJohJSVF+fn5A/GuAQDDxIA8B3Tw4EEVFhZq4sSJuv3223Xo0KF+t+3s7FQkEom5AQCGv4QXUGlpqTZs2KCtW7fqmWeeUUNDg6699lq1traedvvKykqFQqG+W1FRUaJHAgAMQgHnnBvIHbS0tGjChAl64okndOedd57yeGdnpzo7O/vejkQiKioq0hwtVEogdSBHAwAMgB7XrSptUTgcVmZmZr/bDfirA7KysnTppZeqrq7utI8Hg0EFg8GBHgMAMMgM+O8BnThxQvX19SooKBjoXQEAhpCEF9D999+v6upq/eUvf9Hbb7+tG2+8UcnJybr11lsTvSsAwBCW8B/BHTlyRLfeequOHz+usWPH6pprrtGuXbs0duzYRO8KADCEJbyAXnrppUS/SwDAMMRacAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAEwM+B+kw38KBPwzcfyx2kCK/4fU9fR4Z07u7Pz8n4aj5NGjvTN/fHSKd2bStL96ZyQp/Pw478zo52ri2tdwkzRqlHcmns9B9w9/SXqo4goIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCC1bDPl/O0CnQ8q+rGs4J23JKTvSOuq8s7E4hjP9IXWBncU+OGPO9MoN5/P+V5f/APSZr28FbvzL/9y1zvTPP/KfbOZBzxXwU6+c13vTOSlDx5onemc7z/SueH56Z5Zyav+9A7I0k9fz3qH/Je+T4gncOXPK6AAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmGAx0uHGe9HA87cApyTpPO3rfP6fjj7wDe/MXZf8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3btX3d3dMefD1KlTNX78+GF9Pnz+OHzmhRdeUE5OjqZNm6bVq1ervb3dYrx+DbrFSD/v448/Vm9vr/Ly8mLuz8vL0x//+EejqWyUlpZqw4YNmjJlihobG/XYY4/p2muv1YEDB5SRkWE9nommpiZJOu358dljF4oFCxbopptuUnFxserr6/X9739f5eXlqqmpUXJysvV4CReNRrVy5UpdffXVmjZtmqST50NaWpqysrJith3O58PpjoMk3XbbbZowYYIKCwu1f/9+Pfjgg6qtrdWrr75qOG2sQV9A+Lvy8vK+f0+fPl2lpaWaMGGCfvnLX+rOO+80nAyDwS233NL37yuuuELTp0/XpEmTVFVVpblz5xpONjAqKip04MCBC+J50DPp7zjcddddff++4oorVFBQoLlz56q+vl6TJk0632Oe1qD/EVxOTo6Sk5NPeRVLc3Oz8vPzjaYaHLKysnTppZeqrq7OehQzn50DnB+nmjhxonJycobl+bFixQq9/vrrevPNN2P+fEt+fr66urrU0tISs/1wPR/6Ow6nU1paKkmD6nwY9AWUlpamGTNmaPv27X33RaNRbd++XbNmzTKczN6JEydUX1+vgoIC61HMFBcXKz8/P+b8iEQi2r179wV/fhw5ckTHjx8fVueHc04rVqzQpk2btGPHDhUXF8c8PmPGDKWmpsacD7W1tTp06NCwOh/OdhxOZ9++fZI0uM4H61dBnIuXXnrJBYNBt2HDBvf++++7u+66y2VlZbmmpibr0c6r++67z1VVVbmGhgb329/+1pWVlbmcnBx37Ngx69EGVGtrq3vvvffce++95yS5J554wr333nvuww8/dM459+Mf/9hlZWW5LVu2uP3797uFCxe64uJi9+mnnxpPnlhnOg6tra3u/vvvdzU1Na6hocG98cYb7qtf/aqbPHmy6+josB49YZYvX+5CoZCrqqpyjY2Nfbf29va+be6++243fvx4t2PHDrdnzx43a9YsN2vWLMOpE+9sx6Gurs794Ac/cHv27HENDQ1uy5YtbuLEiW727NnGk8caEgXknHNPP/20Gz9+vEtLS3MzZ850u3btsh7pvLv55ptdQUGBS0tLcxdffLG7+eabXV1dnfVYA+7NN990kk65LVmyxDl38qXYDz/8sMvLy3PBYNDNnTvX1dbW2g49AM50HNrb2928efPc2LFjXWpqqpswYYJbtmzZsPsm7XT/f0lu/fr1fdt8+umn7jvf+Y4bPXq0S09PdzfeeKNrbGy0G3oAnO04HDp0yM2ePdtlZ2e7YDDoLrnkEve9733PhcNh28E/hz/HAAAwMeifAwIADE8UEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMEEBAQBM/H+wVOxLQwVbkwAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure()\n", - "plt.imshow(img)\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "id": "8e1c07cc-b2bc-4902-a9a6-4ac7f02c5fe4", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[-1.720082402229309,\n", - " -2.013301134109497,\n", - " -0.3198302984237671,\n", - " -1.4132847785949707,\n", - " -0.25933507084846497,\n", - " 1.7492954730987549,\n", - " -0.4581696689128876,\n", - " 2.1313018798828125,\n", - " 1.6222645044326782,\n", - " 1.3297783136367798]" - ] - }, - "execution_count": 56, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "predictions" - ] - }, - { - "cell_type": "markdown", - "id": "a937adc9-508d-4ccd-b92d-8ecaa27ee4e4", - "metadata": {}, - "source": [ - "### Using Triton Inference Server\n", - "\n", - "Note: you can restart the kernel and run from this point to simulate running in a different node or environment." - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "id": "53ca290a-ccc3-4923-a292-944921bab36d", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "from functools import partial\n", - "from pyspark.ml.functions import predict_batch_udf\n", - "from pyspark.sql.functions import struct, col, array\n", - "from pyspark.sql.types import ArrayType, FloatType, Union, Dict" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "id": "8fa92fe4-2e04-4d82-a357-bfdfca38bd8c", - "metadata": {}, - "outputs": [], - "source": [ - "%%bash\n", - "# copy model to expected layout for Triton\n", - "rm -rf models\n", - "mkdir -p models/fashion_mnist/1\n", - "cp model.ts models/fashion_mnist/1/model.pt\n", - "\n", - "# add config.pbtxt\n", - "cp models_config/fashion_mnist/config.pbtxt models/fashion_mnist/config.pbtxt" - ] - }, - { - "cell_type": "markdown", - "id": "d42b329c-5921-436f-bfca-a382a6762da4", - "metadata": {}, - "source": [ - "#### Start Triton Server on each executor" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "id": "5e869730-3597-4074-bab0-f87768f8996a", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/plain": [ - "[True]" - ] - }, - "execution_count": 59, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "num_executors = 1\n", - "triton_models_dir = \"{}/models\".format(os.getcwd())\n", - "nodeRDD = sc.parallelize(list(range(num_executors)), num_executors)\n", - "\n", - "def start_triton(it):\n", - " import docker\n", - " import time\n", - " import tritonclient.grpc as grpcclient\n", - " \n", - " client=docker.from_env()\n", - " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", - " if containers:\n", - " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", - " else:\n", - " container=client.containers.run(\n", - " \"nvcr.io/nvidia/tritonserver:22.07-py3\", \"tritonserver --model-repository=/models\",\n", - " detach=True,\n", - " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", - " name=\"spark-triton\",\n", - " network_mode=\"host\",\n", - " remove=True,\n", - " shm_size=\"64M\",\n", - " volumes={triton_models_dir: {\"bind\": \"/models\", \"mode\": \"ro\"}}\n", - " )\n", - " print(\">>>> starting triton: {}\".format(container.short_id))\n", - "\n", - " # wait for triton to be running\n", - " time.sleep(15)\n", - " client = grpcclient.InferenceServerClient(\"localhost:8001\")\n", - " ready = False\n", - " while not ready:\n", - " try:\n", - " ready = client.is_server_ready()\n", - " except Exception as e:\n", - " time.sleep(5)\n", - " \n", - " return [True]\n", - "\n", - "nodeRDD.barrier().mapPartitions(start_triton).collect()" - ] - }, - { - "cell_type": "markdown", - "id": "30a4362d-7514-4b84-b238-f704a97e1e72", - "metadata": {}, - "source": [ - "#### Run inference" - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "id": "ab94d4d1-dac6-4474-9eb0-59478aa98f7d", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 60, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = spark.read.parquet(\"fashion_mnist_1\")\n", - "len(df.columns)" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "id": "12b5f2fc-52e9-428a-b683-6ab1b639aa24", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/plain": [ - "StructType([StructField('data', ArrayType(FloatType(), True), True)])" - ] - }, - "execution_count": 61, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.schema" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "id": "960657d0-31c9-4df6-8eb8-ac3d23137f7a", - "metadata": {}, - "outputs": [], - "source": [ - "def triton_fn(triton_uri, model_name):\n", - " import numpy as np\n", - " import tritonclient.grpc as grpcclient\n", - " \n", - " np_types = {\n", - " \"BOOL\": np.dtype(np.bool8),\n", - " \"INT8\": np.dtype(np.int8),\n", - " \"INT16\": np.dtype(np.int16),\n", - " \"INT32\": np.dtype(np.int32),\n", - " \"INT64\": np.dtype(np.int64),\n", - " \"FP16\": np.dtype(np.float16),\n", - " \"FP32\": np.dtype(np.float32),\n", - " \"FP64\": np.dtype(np.float64),\n", - " \"FP64\": np.dtype(np.double),\n", - " \"BYTES\": np.dtype(object)\n", - " }\n", - "\n", - " client = grpcclient.InferenceServerClient(triton_uri)\n", - " model_meta = client.get_model_metadata(model_name)\n", - " \n", - " def predict(inputs):\n", - " if isinstance(inputs, np.ndarray):\n", - " # single ndarray input\n", - " request = [grpcclient.InferInput(model_meta.inputs[0].name, inputs.shape, model_meta.inputs[0].datatype)]\n", - " request[0].set_data_from_numpy(inputs.astype(np_types[model_meta.inputs[0].datatype]))\n", - " else:\n", - " # dict of multiple ndarray inputs\n", - " request = [grpcclient.InferInput(i.name, inputs[i.name].shape, i.datatype) for i in model_meta.inputs]\n", - " for i in request:\n", - " i.set_data_from_numpy(inputs[i.name()].astype(np_types[i.datatype()]))\n", - " \n", - " response = client.infer(model_name, inputs=request)\n", - " \n", - " if len(model_meta.outputs) > 1:\n", - " # return dictionary of numpy arrays\n", - " return {o.name: response.as_numpy(o.name) for o in model_meta.outputs}\n", - " else:\n", - " # return single numpy array\n", - " return response.as_numpy(model_meta.outputs[0].name)\n", - " \n", - " return predict" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "id": "0262fd4a-9845-44b9-8c75-1c105e7deeca", - "metadata": {}, - "outputs": [], - "source": [ - "mnist = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"fashion_mnist\"),\n", - " input_tensor_shapes=[[784]],\n", - " return_type=ArrayType(FloatType()),\n", - " batch_size=1024)" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "id": "fc5f6baa-052e-4b89-94b6-4821cf01952a", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 491 ms, sys: 60.7 ms, total: 551 ms\n", - "Wall time: 1.98 s\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", mnist(struct(df.columns))).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "id": "a85dea35-e41d-482d-8a8f-52d3c108f038", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 817 ms, sys: 89 ms, total: 906 ms\n", - "Wall time: 1.44 s\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", mnist(*df.columns)).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "id": "bc3f0dbe-c52b-41d6-8097-8cebaa5ee5a8", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 460 ms, sys: 105 ms, total: 565 ms\n", - "Wall time: 1.11 s\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", mnist(*[col(c) for c in df.columns])).collect()" - ] - }, - { - "cell_type": "markdown", - "id": "7a26690a-9dc4-4c36-9904-568d73e2be3c", - "metadata": { - "tags": [] - }, - "source": [ - "#### Stop Triton Server on each executor" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "id": "ab2fe42f-a072-4370-bac2-52fd95363530", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/plain": [ - "[True]" - ] - }, - "execution_count": 67, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def stop_triton(it):\n", - " import docker\n", - " import time\n", - " \n", - " client=docker.from_env()\n", - " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", - " print(\">>>> stopping containers: {}\".format([c.short_id for c in containers]))\n", - " if containers:\n", - " container=containers[0]\n", - " container.stop(timeout=120)\n", - "\n", - " return [True]\n", - "\n", - "nodeRDD.barrier().mapPartitions(stop_triton).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "id": "a0608fff-7cfb-489e-96c9-8e1d92e57562", - "metadata": {}, - "outputs": [], - "source": [ - "spark.stop()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08de2664-3d60-487b-90da-6d0f3b8b9203", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "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.9.10" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification_torch.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification_torch.ipynb new file mode 100644 index 000000000..47489dccb --- /dev/null +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification_torch.ipynb @@ -0,0 +1,2367 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9e87c927", + "metadata": {}, + "source": [ + "# PySpark PyTorch Inference\n", + "\n", + "### Image Classification\n", + "Based on: https://pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html \n", + "\n", + "Also demonstrates accelerated inference on GPU with Torch-TensorRT. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "91d7ec98", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "\n", + "from torch import nn\n", + "from torch.utils.data import DataLoader\n", + "from torchvision import datasets\n", + "from torchvision.transforms import ToTensor" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "d714f40d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'2.4.1+cu121'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.__version__" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "1c942a46", + "metadata": {}, + "outputs": [], + "source": [ + "# Download training data from open datasets.\n", + "training_data = datasets.FashionMNIST(\n", + " root=\"data\",\n", + " train=True,\n", + " download=True,\n", + " transform=ToTensor(),\n", + ")\n", + "\n", + "# Download test data from open datasets.\n", + "test_data = datasets.FashionMNIST(\n", + " root=\"data\",\n", + " train=False,\n", + " download=True,\n", + " transform=ToTensor(),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "4a89aa8e-ef62-4aac-8260-4b004f2c1b55", + "metadata": {}, + "outputs": [], + "source": [ + "classes = [\n", + " \"T-shirt/top\",\n", + " \"Trouser\",\n", + " \"Pullover\",\n", + " \"Dress\",\n", + " \"Coat\",\n", + " \"Sandal\",\n", + " \"Shirt\",\n", + " \"Sneaker\",\n", + " \"Bag\",\n", + " \"Ankle boot\",\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "10a97111", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Shape of X [N, C, H, W]: torch.Size([64, 1, 28, 28]) torch.float32\n", + "Shape of y: torch.Size([64]) torch.int64\n" + ] + } + ], + "source": [ + "batch_size = 64\n", + "\n", + "# Create data loaders.\n", + "train_dataloader = DataLoader(training_data, batch_size=batch_size)\n", + "test_dataloader = DataLoader(test_data, batch_size=batch_size)\n", + "\n", + "for X, y in test_dataloader:\n", + " print(f\"Shape of X [N, C, H, W]: {X.shape} {X.dtype}\")\n", + " print(f\"Shape of y: {y.shape} {y.dtype}\")\n", + " break" + ] + }, + { + "cell_type": "markdown", + "id": "ca7af350", + "metadata": {}, + "source": [ + "### Create model" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "512d0bc7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Using cuda device\n", + "NeuralNetwork(\n", + " (linear_relu_stack): Sequential(\n", + " (0): Linear(in_features=784, out_features=512, bias=True)\n", + " (1): ReLU()\n", + " (2): Linear(in_features=512, out_features=512, bias=True)\n", + " (3): ReLU()\n", + " (4): Linear(in_features=512, out_features=10, bias=True)\n", + " )\n", + ")\n" + ] + } + ], + "source": [ + "# Get cpu or gpu device for training.\n", + "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", + "print(f\"Using {device} device\")\n", + "\n", + "# Define model\n", + "class NeuralNetwork(nn.Module):\n", + " def __init__(self):\n", + " super(NeuralNetwork, self).__init__()\n", + " self.linear_relu_stack = nn.Sequential(\n", + " nn.Linear(28*28, 512),\n", + " nn.ReLU(),\n", + " nn.Linear(512, 512),\n", + " nn.ReLU(),\n", + " nn.Linear(512, 10)\n", + " )\n", + "\n", + " def forward(self, x):\n", + " logits = self.linear_relu_stack(x)\n", + " return logits\n", + "\n", + "model = NeuralNetwork().to(device)\n", + "print(model)" + ] + }, + { + "cell_type": "markdown", + "id": "4573c1b7", + "metadata": {}, + "source": [ + "### Train Model" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "4d4f5538", + "metadata": {}, + "outputs": [], + "source": [ + "loss_fn = nn.CrossEntropyLoss()\n", + "optimizer = torch.optim.SGD(model.parameters(), lr=1e-3)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "92d9076a", + "metadata": {}, + "outputs": [], + "source": [ + "def train(dataloader, model, loss_fn, optimizer):\n", + " size = len(dataloader.dataset)\n", + " model.train()\n", + " for batch, (X, y) in enumerate(dataloader):\n", + " X, y = X.to(device), y.to(device)\n", + " X = torch.flatten(X, start_dim=1, end_dim=-1)\n", + "\n", + " # Zero gradients\n", + " optimizer.zero_grad()\n", + "\n", + " # Compute prediction error\n", + " pred = model(X)\n", + " loss = loss_fn(pred, y)\n", + "\n", + " # Backpropagation\n", + " loss.backward()\n", + " optimizer.step()\n", + "\n", + " if batch % 100 == 0:\n", + " loss, current = loss.item(), (batch + 1) * len(X)\n", + " print(f\"loss: {loss:>7f} [{current:>5d}/{size:>5d}]\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "11c5650d", + "metadata": {}, + "outputs": [], + "source": [ + "def test(dataloader, model, loss_fn):\n", + " size = len(dataloader.dataset)\n", + " num_batches = len(dataloader)\n", + " model.eval()\n", + " test_loss, correct = 0, 0\n", + " with torch.no_grad():\n", + " for X, y in dataloader:\n", + " X, y = X.to(device), y.to(device)\n", + " X = torch.flatten(X, start_dim=1, end_dim=-1)\n", + " pred = model(X)\n", + " test_loss += loss_fn(pred, y).item()\n", + " correct += (pred.argmax(1) == y).type(torch.float).sum().item()\n", + " test_loss /= num_batches\n", + " correct /= size\n", + " print(f\"Test Error: \\n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "854608e6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1\n", + "-------------------------------\n", + "loss: 2.299719 [ 64/60000]\n", + "loss: 2.293332 [ 6464/60000]\n", + "loss: 2.269917 [12864/60000]\n", + "loss: 2.260744 [19264/60000]\n", + "loss: 2.247810 [25664/60000]\n", + "loss: 2.222256 [32064/60000]\n", + "loss: 2.225422 [38464/60000]\n", + "loss: 2.195026 [44864/60000]\n", + "loss: 2.194622 [51264/60000]\n", + "loss: 2.158175 [57664/60000]\n", + "Test Error: \n", + " Accuracy: 47.1%, Avg loss: 2.153042 \n", + "\n", + "Epoch 2\n", + "-------------------------------\n", + "loss: 2.162534 [ 64/60000]\n", + "loss: 2.154336 [ 6464/60000]\n", + "loss: 2.091042 [12864/60000]\n", + "loss: 2.104471 [19264/60000]\n", + "loss: 2.054451 [25664/60000]\n", + "loss: 2.001035 [32064/60000]\n", + "loss: 2.025180 [38464/60000]\n", + "loss: 1.949615 [44864/60000]\n", + "loss: 1.957106 [51264/60000]\n", + "loss: 1.876436 [57664/60000]\n", + "Test Error: \n", + " Accuracy: 54.6%, Avg loss: 1.876885 \n", + "\n", + "Epoch 3\n", + "-------------------------------\n", + "loss: 1.906243 [ 64/60000]\n", + "loss: 1.879715 [ 6464/60000]\n", + "loss: 1.758657 [12864/60000]\n", + "loss: 1.795318 [19264/60000]\n", + "loss: 1.692177 [25664/60000]\n", + "loss: 1.652430 [32064/60000]\n", + "loss: 1.669603 [38464/60000]\n", + "loss: 1.583420 [44864/60000]\n", + "loss: 1.603508 [51264/60000]\n", + "loss: 1.493881 [57664/60000]\n", + "Test Error: \n", + " Accuracy: 61.9%, Avg loss: 1.514976 \n", + "\n", + "Epoch 4\n", + "-------------------------------\n", + "loss: 1.573342 [ 64/60000]\n", + "loss: 1.548722 [ 6464/60000]\n", + "loss: 1.402007 [12864/60000]\n", + "loss: 1.461628 [19264/60000]\n", + "loss: 1.353920 [25664/60000]\n", + "loss: 1.358175 [32064/60000]\n", + "loss: 1.361608 [38464/60000]\n", + "loss: 1.302804 [44864/60000]\n", + "loss: 1.330850 [51264/60000]\n", + "loss: 1.224925 [57664/60000]\n", + "Test Error: \n", + " Accuracy: 63.8%, Avg loss: 1.254037 \n", + "\n", + "Epoch 5\n", + "-------------------------------\n", + "loss: 1.321162 [ 64/60000]\n", + "loss: 1.315946 [ 6464/60000]\n", + "loss: 1.152864 [12864/60000]\n", + "loss: 1.244943 [19264/60000]\n", + "loss: 1.130193 [25664/60000]\n", + "loss: 1.160290 [32064/60000]\n", + "loss: 1.168214 [38464/60000]\n", + "loss: 1.123758 [44864/60000]\n", + "loss: 1.158085 [51264/60000]\n", + "loss: 1.063427 [57664/60000]\n", + "Test Error: \n", + " Accuracy: 65.1%, Avg loss: 1.089330 \n", + "\n", + "Done!\n" + ] + } + ], + "source": [ + "epochs = 5\n", + "for t in range(epochs):\n", + " print(f\"Epoch {t+1}\\n-------------------------------\")\n", + " train(train_dataloader, model, loss_fn, optimizer)\n", + " test(test_dataloader, model, loss_fn)\n", + "print(\"Done!\")" + ] + }, + { + "cell_type": "markdown", + "id": "85d97839", + "metadata": {}, + "source": [ + "### Save Model State Dict\n", + "This saves the serialized object to disk using pickle." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "5d5d24de", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved PyTorch Model State to model.pt\n" + ] + } + ], + "source": [ + "torch.save(model.state_dict(), \"model.pt\")\n", + "print(\"Saved PyTorch Model State to model.pt\")" + ] + }, + { + "cell_type": "markdown", + "id": "ac221ca7-e227-4c8c-8577-1eeda4a61fc7", + "metadata": {}, + "source": [ + "### Save Model as TorchScript\n", + "This saves an [intermediate representation of the compute graph](https://pytorch.org/tutorials/beginner/saving_loading_models.html#export-load-model-in-torchscript-format), which does not require pickle (or even python). " + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "6d9b3a45-7618-43e4-8bd3-8bb317a484d3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved TorchScript Model to ts_model.pt\n" + ] + } + ], + "source": [ + "scripted = torch.jit.script(model)\n", + "scripted.save(\"ts_model.pt\")\n", + "print(\"Saved TorchScript Model to ts_model.pt\")" + ] + }, + { + "cell_type": "markdown", + "id": "12ee8916-f437-4a2a-9bf4-14ff5376d305", + "metadata": {}, + "source": [ + "### Load Model State" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "8fe3b5d1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model_from_state = NeuralNetwork().to(device)\n", + "model_from_state.load_state_dict(torch.load(\"model.pt\", weights_only=True))" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "0c405bd0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Predicted: \"Ankle boot\", Actual: \"Ankle boot\"\n" + ] + } + ], + "source": [ + "model_from_state.eval()\n", + "x, y = test_data[0][0], test_data[0][1]\n", + "with torch.no_grad():\n", + " x = torch.flatten(x.to(device), start_dim=1, end_dim=-1)\n", + " pred = model_from_state(x)\n", + " predicted, actual = classes[pred[0].argmax(0)], classes[y]\n", + " print(f'Predicted: \"{predicted}\", Actual: \"{actual}\"')" + ] + }, + { + "cell_type": "markdown", + "id": "290c482a-1c5d-4bf2-bc3f-8a4e53d442b5", + "metadata": {}, + "source": [ + "### Load Torchscript Model" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "ef3c419e-d384-446c-b07b-1af93e07d6c0", + "metadata": {}, + "outputs": [], + "source": [ + "# Load model to original device (GPU) and move to CPU. \n", + "ts_model = torch.jit.load(\"ts_model.pt\")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "c92d6cdb", + "metadata": {}, + "outputs": [], + "source": [ + "x, y = test_data[0][0], test_data[0][1]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "038af830-a360-45eb-ab4e-b1adab0af164", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Predicted: \"Ankle boot\", Actual: \"Ankle boot\"\n" + ] + } + ], + "source": [ + "with torch.no_grad():\n", + " pred = ts_model(torch.flatten(x.to(device), start_dim=1, end_dim=-1))\n", + " predicted, actual = classes[pred[0].argmax(0)], classes[y]\n", + " print(f'Predicted: \"{predicted}\", Actual: \"{actual}\"')" + ] + }, + { + "cell_type": "markdown", + "id": "76980495", + "metadata": {}, + "source": [ + "### Compile using the Torch JIT Compiler\n", + "This leverages the [Torch-TensorRT inference compiler](https://pytorch.org/TensorRT/) for accelerated inference on GPUs using the `torch.compile` JIT interface under the hood. The compiler stack returns a [boxed-function](http://blog.ezyang.com/2020/09/lets-talk-about-the-pytorch-dispatcher/) that triggers compilation on the first call. \n", + "\n", + "Modules compiled in this fashion are [not serializable with pickle](https://github.com/pytorch/pytorch/issues/101107#issuecomment-1542688089), so we cannot send the compiled model directly to Spark. Instead, we will recompile and cache the model on the executor. " + ] + }, + { + "cell_type": "markdown", + "id": "414bc856", + "metadata": {}, + "source": [ + "(You may see a warning about modelopt quantization. This is safe to ignore, as [implicit quantization](https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#intro-quantization) is deprecated in the latest TensorRT. See [this link](https://pytorch.org/TensorRT/tutorials/_rendered_examples/dynamo/vgg16_fp8_ptq.html) for a guide to explicit quantization.)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "f3e3bdc4", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:torch_tensorrt.dynamo.conversion.aten_ops_converters:Unable to import quantization op. Please install modelopt library (https://github.com/NVIDIA/TensorRT-Model-Optimizer?tab=readme-ov-file#installation) to add support for compiling quantized models\n", + "INFO:torch_tensorrt.dynamo.utils:Using Default Torch-TRT Runtime (as requested by user)\n", + "INFO:torch_tensorrt.dynamo.utils:Device not specified, using Torch default current device - cuda:0. If this is incorrect, please specify an input device, via the device keyword.\n", + "INFO:torch_tensorrt.dynamo.utils:Compilation Settings: CompilationSettings(enabled_precisions={}, debug=False, workspace_size=0, min_block_size=5, torch_executed_ops=set(), pass_through_build_failures=False, max_aux_streams=None, version_compatible=False, optimization_level=None, use_python_runtime=False, truncate_double=False, use_fast_partitioner=True, enable_experimental_decompositions=False, device=Device(type=DeviceType.GPU, gpu_id=0), require_full_compilation=False, disable_tf32=False, assume_dynamic_shape_support=False, sparse_weights=False, refit=False, engine_capability=, num_avg_timing_iters=1, dla_sram_size=1048576, dla_local_dram_size=1073741824, dla_global_dram_size=536870912, dryrun=False, hardware_compatible=False, timing_cache_path='/tmp/timing_cache.bin')\n", + "\n", + "WARNING:torch_tensorrt.dynamo._compiler:Node _param_constant1 of op type get_attr does not have metadata. This could sometimes lead to undefined behavior.\n", + "WARNING:torch_tensorrt.dynamo._compiler:Some nodes do not have metadata (shape and dtype information). This could lead to problems sometimes if the graph has PyTorch and TensorRT segments.\n", + "INFO:torch_tensorrt.dynamo._compiler:Partitioning the graph via the fast partitioner\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init CUDA: CPU +2, GPU +0, now: CPU 457, GPU 713 (MiB)\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init builder kernel library: CPU +1634, GPU +288, now: CPU 2238, GPU 1001 (MiB)\n", + "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch_tensorrt/dynamo/conversion/impl/activation/base.py:40: DeprecationWarning: Use Deprecated in TensorRT 10.1. Superseded by explicit quantization. instead.\n", + " if input_val.dynamic_range is not None and dyn_range_fn is not None:\n", + "\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT INetwork construction elapsed time: 0:00:00.005708\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Global timing cache in use. Profiling results in this builder pass will be stored.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Detected 1 inputs and 1 output network tensors.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Host Persistent Memory: 21984\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Device Persistent Memory: 0\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Scratch Memory: 0\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Started assigning block shifts. This will take 4 steps to complete.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Algorithm ShiftNTopDown took 0.257559ms to assign 2 blocks to 4 nodes requiring 4096 bytes.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Activation Memory: 4096\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Weights Memory: 2678824\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Engine generation completed in 0.023755 seconds.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage of TRT CPU/GPU memory allocators: CPU 1 MiB, GPU 5 MiB\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage during Engine building and serialization: CPU: 3800 MiB\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:Build TRT engine elapsed time: 0:00:00.027501\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT Engine uses: 2832188 bytes of Memory\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 26 bytes of code generator cache.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 176 timing cache entries\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Predicted: \"Ankle boot\", Actual: \"Ankle boot\"\n" + ] + } + ], + "source": [ + "import torch_tensorrt as trt\n", + "\n", + "inputs_bs1 = torch.randn((1, 784), dtype=torch.float).to(\"cuda\")\n", + "# This indicates dimension 0 of inputs_bs1 is dynamic whose range of values is [1, 50]. No recompilation will happen when the batch size changes.\n", + "torch._dynamo.mark_dynamic(inputs_bs1, 0, min=1, max=64)\n", + "trt_model = trt.compile(\n", + " model,\n", + " ir=\"torch_compile\",\n", + " inputs=inputs_bs1,\n", + " enabled_precisions={torch.float},\n", + ")\n", + "\n", + "stream = torch.cuda.Stream()\n", + "with torch.no_grad(), torch.cuda.stream(stream):\n", + " pred = trt_model(torch.flatten(x.to(device), start_dim=1, end_dim=-1))\n", + " predicted, actual = classes[pred[0].argmax(0)], classes[y]\n", + " print(f'Predicted: \"{predicted}\", Actual: \"{actual}\"')" + ] + }, + { + "cell_type": "markdown", + "id": "9ec04be8", + "metadata": {}, + "source": [ + "### Compile using the Torch-TensorRT AOT Compiler\n", + "Alternatively, use the Torch-TensorRT Dynamo backend for Ahead-of-Time (AOT) compilation to eagerly optimize the model in an explicit compilation phase. We first export the model to produce a traced graph representing the Tensor computation in an AOT fashion, which produces a `ExportedProgram` object which can be [serialized and reloaded](https://pytorch.org/TensorRT/user_guide/saving_models.html). We can then compile this IR using the Torch-TensorRT AOT compiler for inference. \n", + "\n", + "[Read the docs](https://pytorch.org/TensorRT/user_guide/torch_tensorrt_explained.html) for more information on JIT vs AOT compilation." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "6b8f1b45", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:torch_tensorrt.dynamo._compiler:Compilation Settings: CompilationSettings(enabled_precisions={}, debug=False, workspace_size=0, min_block_size=5, torch_executed_ops=set(), pass_through_build_failures=False, max_aux_streams=None, version_compatible=False, optimization_level=None, use_python_runtime=False, truncate_double=False, use_fast_partitioner=True, enable_experimental_decompositions=False, device=Device(type=DeviceType.GPU, gpu_id=0), require_full_compilation=True, disable_tf32=False, assume_dynamic_shape_support=False, sparse_weights=False, refit=False, engine_capability=, num_avg_timing_iters=1, dla_sram_size=1048576, dla_local_dram_size=1073741824, dla_global_dram_size=536870912, dryrun=False, hardware_compatible=False, timing_cache_path='/tmp/timing_cache.bin')\n", + "\n", + "INFO:torch_tensorrt.dynamo._compiler:Partitioning the graph via the fast partitioner\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init CUDA: CPU +0, GPU +0, now: CPU 624, GPU 715 (MiB)\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init builder kernel library: CPU +1632, GPU +286, now: CPU 2256, GPU 1001 (MiB)\n", + "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch_tensorrt/dynamo/conversion/impl/activation/base.py:40: DeprecationWarning: Use Deprecated in TensorRT 10.1. Superseded by explicit quantization. instead.\n", + " if input_val.dynamic_range is not None and dyn_range_fn is not None:\n", + "\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT INetwork construction elapsed time: 0:00:00.004551\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Global timing cache in use. Profiling results in this builder pass will be stored.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Detected 1 inputs and 1 output network tensors.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Host Persistent Memory: 21984\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Device Persistent Memory: 0\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Scratch Memory: 0\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Started assigning block shifts. This will take 4 steps to complete.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Algorithm ShiftNTopDown took 0.133258ms to assign 2 blocks to 4 nodes requiring 4096 bytes.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Activation Memory: 4096\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Weights Memory: 2678824\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Engine generation completed in 0.0190609 seconds.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage of TRT CPU/GPU memory allocators: CPU 1 MiB, GPU 5 MiB\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage during Engine building and serialization: CPU: 3818 MiB\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:Build TRT engine elapsed time: 0:00:00.021306\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT Engine uses: 2833124 bytes of Memory\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 26 bytes of code generator cache.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 176 timing cache entries\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Predicted: \"Ankle boot\", Actual: \"Ankle boot\"\n" + ] + } + ], + "source": [ + "# Preparing the inputs for batch_size = 1. \n", + "inputs = (torch.randn((1, 784), dtype=torch.float).cuda(),)\n", + "\n", + "# Produce traced graph in the ExportedProgram format\n", + "exp_program = trt.dynamo.trace(model_from_state, inputs)\n", + "# Compile the traced graph to produce an optimized module\n", + "trt_gm = trt.dynamo.compile(exp_program, inputs=inputs, require_full_compilation=True)\n", + "\n", + "stream = torch.cuda.Stream()\n", + "with torch.no_grad(), torch.cuda.stream(stream):\n", + " trt_gm(torch.flatten(x.to(device), start_dim=1, end_dim=-1))\n", + " predicted, actual = classes[pred[0].argmax(0)], classes[y]\n", + " print(f'Predicted: \"{predicted}\", Actual: \"{actual}\"')" + ] + }, + { + "cell_type": "markdown", + "id": "6f2bbfe1", + "metadata": {}, + "source": [ + "We can save the compiled model using `torch_tensorrt.save`. Unfortunately, serializing the model to be reloaded at a later date currently only supports *static inputs*." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "d87e4b20", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch_tensorrt/dynamo/_exporter.py:364: UserWarning: Attempted to insert a get_attr Node with no underlying reference in the owning GraphModule! Call GraphModule.add_submodule to add the necessary submodule, GraphModule.add_parameter to add the necessary Parameter, or nn.Module.register_buffer to add the necessary buffer\n", + " engine_node = gm.graph.get_attr(engine_name)\n", + "\n", + "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch/fx/graph.py:1545: UserWarning: Node _run_on_acc_0_engine target _run_on_acc_0_engine _run_on_acc_0_engine of does not reference an nn.Module, nn.Parameter, or buffer, which is what 'get_attr' Nodes typically target\n", + " warnings.warn(f'Node {node} target {node.target} {atom} of {seen_qualname} does '\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved AOT compiled TensorRT model to trt_model_aot.ep\n" + ] + } + ], + "source": [ + "with torch.cuda.stream(stream):\n", + " trt.save(trt_gm, \"trt_model_aot.ep\", inputs=[torch.randn((1, 784), dtype=torch.float).to(\"cuda\")])\n", + " print(\"Saved AOT compiled TensorRT model to trt_model_aot.ep\")" + ] + }, + { + "cell_type": "markdown", + "id": "ad918393", + "metadata": {}, + "source": [ + "## PySpark" + ] + }, + { + "cell_type": "markdown", + "id": "fd1daec3", + "metadata": {}, + "source": [ + "### Convert numpy dataset to Pandas DataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "42c5feba", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "from pyspark import SparkConf\n", + "from pyspark.sql import SparkSession\n", + "from pyspark.sql.types import StructType, StructField, ArrayType, FloatType" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "f063cbe7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "((10000, 28, 28), dtype('uint8'))" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = test_data.data.numpy()\n", + "data.shape, data.dtype" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "8c828393", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "((10000, 784), dtype('float64'))" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data = data.reshape(10000, 784) / 255.0\n", + "data.shape, data.dtype" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "7760bdbe", + "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", + " \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", + " \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", + "
0123456789...774775776777778779780781782783
00.00.00.00.0000000.00.0000000.0000000.00.0000000.000000...0.0000000.0000000.00.0000000.0000000.0000000.0000000.00.00.0
10.00.00.00.0000000.00.0000000.0000000.00.0000000.000000...0.0078430.0117650.00.0117650.6823530.7411760.2627450.00.00.0
20.00.00.00.0000000.00.0000000.0000000.00.0039220.000000...0.6431370.2274510.00.0000000.0000000.0000000.0000000.00.00.0
30.00.00.00.0000000.00.0000000.0000000.00.0000000.082353...0.0039220.0000000.00.0000000.0000000.0000000.0000000.00.00.0
40.00.00.00.0078430.00.0039220.0039220.00.0000000.000000...0.2784310.0470590.00.0000000.0000000.0000000.0000000.00.00.0
..................................................................
99950.00.00.00.0000000.00.0000000.0000000.00.0000000.000000...0.0000000.0000000.00.0000000.0000000.0000000.0000000.00.00.0
99960.00.00.00.0000000.00.0000000.0000000.00.0000000.121569...0.0000000.0000000.00.0000000.0000000.0000000.0000000.00.00.0
99970.00.00.00.0000000.00.0000000.0000000.00.0000000.000000...0.1058820.0000000.00.0000000.0000000.0000000.0000000.00.00.0
99980.00.00.00.0000000.00.0000000.0000000.00.0000000.000000...0.0000000.0000000.00.0000000.0000000.0000000.0000000.00.00.0
99990.00.00.00.0000000.00.0000000.0000000.00.0000000.000000...0.0000000.0000000.00.0000000.0000000.0000000.0000000.00.00.0
\n", + "

10000 rows × 784 columns

\n", + "
" + ], + "text/plain": [ + " 0 1 2 3 4 5 6 7 8 \\\n", + "0 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", + "1 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", + "2 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.003922 \n", + "3 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", + "4 0.0 0.0 0.0 0.007843 0.0 0.003922 0.003922 0.0 0.000000 \n", + "... ... ... ... ... ... ... ... ... ... \n", + "9995 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", + "9996 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", + "9997 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", + "9998 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", + "9999 0.0 0.0 0.0 0.000000 0.0 0.000000 0.000000 0.0 0.000000 \n", + "\n", + " 9 ... 774 775 776 777 778 779 \\\n", + "0 0.000000 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.000000 \n", + "1 0.000000 ... 0.007843 0.011765 0.0 0.011765 0.682353 0.741176 \n", + "2 0.000000 ... 0.643137 0.227451 0.0 0.000000 0.000000 0.000000 \n", + "3 0.082353 ... 0.003922 0.000000 0.0 0.000000 0.000000 0.000000 \n", + "4 0.000000 ... 0.278431 0.047059 0.0 0.000000 0.000000 0.000000 \n", + "... ... ... ... ... ... ... ... ... \n", + "9995 0.000000 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.000000 \n", + "9996 0.121569 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.000000 \n", + "9997 0.000000 ... 0.105882 0.000000 0.0 0.000000 0.000000 0.000000 \n", + "9998 0.000000 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.000000 \n", + "9999 0.000000 ... 0.000000 0.000000 0.0 0.000000 0.000000 0.000000 \n", + "\n", + " 780 781 782 783 \n", + "0 0.000000 0.0 0.0 0.0 \n", + "1 0.262745 0.0 0.0 0.0 \n", + "2 0.000000 0.0 0.0 0.0 \n", + "3 0.000000 0.0 0.0 0.0 \n", + "4 0.000000 0.0 0.0 0.0 \n", + "... ... ... ... ... \n", + "9995 0.000000 0.0 0.0 0.0 \n", + "9996 0.000000 0.0 0.0 0.0 \n", + "9997 0.000000 0.0 0.0 0.0 \n", + "9998 0.000000 0.0 0.0 0.0 \n", + "9999 0.000000 0.0 0.0 0.0 \n", + "\n", + "[10000 rows x 784 columns]" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pdf784 = pd.DataFrame(data)\n", + "pdf784" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "f7d2bc0d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 87.6 ms, sys: 56.2 ms, total: 144 ms\n", + "Wall time: 143 ms\n" + ] + }, + { + "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", + "
data
0[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
1[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
2[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.003...
3[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
4[0.0, 0.0, 0.0, 0.00784313725490196, 0.0, 0.00...
......
9995[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
9996[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
9997[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
9998[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
9999[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...
\n", + "

10000 rows × 1 columns

\n", + "
" + ], + "text/plain": [ + " data\n", + "0 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", + "1 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", + "2 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.003...\n", + "3 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", + "4 [0.0, 0.0, 0.0, 0.00784313725490196, 0.0, 0.00...\n", + "... ...\n", + "9995 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", + "9996 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", + "9997 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", + "9998 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", + "9999 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", + "\n", + "[10000 rows x 1 columns]" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "# 1 column of array\n", + "pdf1 = pd.DataFrame()\n", + "pdf1['data'] = pdf784.values.tolist()\n", + "pdf1" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "a5d7ccf1", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "24/10/08 00:30:18 WARN Utils: Your hostname, cb4ae00-lcedt resolves to a loopback address: 127.0.1.1; using 10.110.47.100 instead (on interface eno1)\n", + "24/10/08 00:30:18 WARN Utils: Set SPARK_LOCAL_IP if you need to bind to another address\n", + "Setting default log level to \"WARN\".\n", + "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", + "24/10/08 00:30:18 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n" + ] + } + ], + "source": [ + "import os\n", + "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", + "\n", + "conf = SparkConf()\n", + "if 'spark' not in globals():\n", + " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", + " import socket\n", + " hostname = socket.gethostname()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", + "conf.set(\"spark.task.maxFailures\", \"1\")\n", + "conf.set(\"spark.driver.memory\", \"8g\")\n", + "conf.set(\"spark.executor.memory\", \"8g\")\n", + "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", + "conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + "conf.set(\"spark.python.worker.reuse\", \"true\")\n", + "# Create Spark Session\n", + "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", + "sc = spark.sparkContext" + ] + }, + { + "cell_type": "markdown", + "id": "320760db", + "metadata": {}, + "source": [ + "#### Create Spark DataFrame from Pandas DataFrame" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "4863d5ff", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/pyspark/sql/pandas/serializers.py:224: DeprecationWarning: is_categorical_dtype is deprecated and will be removed in a future version. Use isinstance(dtype, pd.CategoricalDtype) instead\n", + " if is_categorical_dtype(series.dtype):\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 389 ms, sys: 63.2 ms, total: 452 ms\n", + "Wall time: 1.44 s\n" + ] + } + ], + "source": [ + "%%time\n", + "# force FloatType since Spark defaults to DoubleType\n", + "schema = StructType([StructField(\"data\",ArrayType(FloatType()), True)])\n", + "df = spark.createDataFrame(pdf1, schema).repartition(8)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "406edba5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "StructType([StructField('data', ArrayType(FloatType(), True), True)])" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.schema" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "831f4a01-3a49-4114-b9a0-2ae54526d72d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 61 ms, sys: 21.6 ms, total: 82.6 ms\n", + "Wall time: 854 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "# force FloatType since Spark defaults to DoubleType\n", + "schema = StructType([StructField(str(x), FloatType(), True) for x in range(784)])\n", + "df784 = spark.createDataFrame(pdf784, schema).repartition(8)" + ] + }, + { + "cell_type": "markdown", + "id": "ac4c7448", + "metadata": {}, + "source": [ + "### Save the test dataset as parquet files" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "e8ebae46", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "24/10/08 00:30:21 WARN TaskSetManager: Stage 0 contains a task of very large size (4032 KiB). The maximum recommended task size is 1000 KiB.\n", + "[Stage 0:> (0 + 8) / 8]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.09 ms, sys: 2.57 ms, total: 4.66 ms\n", + "Wall time: 1.78 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "df.write.mode(\"overwrite\").parquet(\"fashion_mnist_1\")" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "922314ce-2996-4666-9fc9-bcd98d16bb56", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "24/10/08 00:30:23 WARN SparkStringUtils: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.sql.debug.maxToStringFields'.\n", + "24/10/08 00:30:23 WARN TaskSetManager: Stage 3 contains a task of very large size (7849 KiB). The maximum recommended task size is 1000 KiB.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 3.01 ms, sys: 22 μs, total: 3.03 ms\n", + "Wall time: 734 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "df784.write.mode(\"overwrite\").parquet(\"fashion_mnist_784\")" + ] + }, + { + "cell_type": "markdown", + "id": "8688429e", + "metadata": {}, + "source": [ + "### Check arrow memory configuration" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "088cb37f", + "metadata": {}, + "outputs": [], + "source": [ + "spark.conf.set(\"spark.sql.execution.arrow.maxRecordsPerBatch\", \"128\")\n", + "# This line will fail if the vectorized reader runs out of memory\n", + "assert len(df.head()) > 0, \"`df` should not be empty\"" + ] + }, + { + "cell_type": "markdown", + "id": "d7c77eb4-7bd6-40c7-9a35-ee899a66ece3", + "metadata": {}, + "source": [ + "## Inference using Spark DL API" + ] + }, + { + "cell_type": "markdown", + "id": "59395856-a588-43c6-93c8-c83100716ac1", + "metadata": { + "tags": [] + }, + "source": [ + "### 1 columns of 784 float" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "133cc9a5-64c6-4820-807e-b87cf7e0b75a", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import numpy as np\n", + "\n", + "from pyspark.ml.functions import predict_batch_udf\n", + "from pyspark.sql.functions import struct, col, array\n", + "from pyspark.sql.types import ArrayType, FloatType, Union, Dict" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "79b151d9-d112-43b6-a479-887e2fd0e2b1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = spark.read.parquet(\"fashion_mnist_1\")\n", + "len(df.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "cabcd546-2e8e-40d0-8b79-7598a7a83aae", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "StructType([StructField('data', ArrayType(FloatType(), True), True)])" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.schema" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "823c3825", + "metadata": {}, + "outputs": [], + "source": [ + "# Get absolute path to model\n", + "model_path = \"{}/model.pt\".format(os.getcwd())" + ] + }, + { + "cell_type": "markdown", + "id": "2d7c2bac", + "metadata": {}, + "source": [ + "For inference on Spark, we'll compile the model with the Torch-TensorRT AOT compiler and cache on the executor. We can specify dynamic batch sizes before compilation to [optimize across multiple input shapes](https://pytorch.org/TensorRT/user_guide/dynamic_shapes.html)." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "73dc73cb-25e3-4798-a019-e1abd684eaa1", + "metadata": {}, + "outputs": [], + "source": [ + "def predict_batch_fn():\n", + " import torch\n", + " import torch_tensorrt as trt\n", + " \n", + " device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", + " if device != \"cuda\":\n", + " raise ValueError(\"This function uses the TensorRT model which requires a GPU device\")\n", + "\n", + " # Define model\n", + " class NeuralNetwork(nn.Module):\n", + " def __init__(self):\n", + " super(NeuralNetwork, self).__init__()\n", + " self.linear_relu_stack = nn.Sequential(\n", + " nn.Linear(28*28, 512),\n", + " nn.ReLU(),\n", + " nn.Linear(512, 512),\n", + " nn.ReLU(),\n", + " nn.Linear(512, 10)\n", + " )\n", + "\n", + " def forward(self, x):\n", + " logits = self.linear_relu_stack(x)\n", + " return logits\n", + "\n", + " model = NeuralNetwork().to(device)\n", + " model.load_state_dict(torch.load(model_path, weights_only=True))\n", + "\n", + " # Preparing the inputs for dynamic batch sizing.\n", + " inputs = [trt.Input(min_shape=(1, 784), \n", + " opt_shape=(50, 784), \n", + " max_shape=(64, 784), \n", + " dtype=torch.float32)]\n", + "\n", + " # Trace the computation graph and compile to produce an optimized module\n", + " trt_gm = trt.compile(model, ir=\"dynamo\", inputs=inputs, require_full_compilation=True)\n", + "\n", + " def predict(inputs: np.ndarray):\n", + " print(\"Predicting on process PID: {}\".format(os.getpid()))\n", + " stream = torch.cuda.Stream()\n", + " with torch.no_grad(), torch.cuda.stream(stream):\n", + " # use array to combine columns into tensors\n", + " torch_inputs = torch.from_numpy(inputs).to(device)\n", + " outputs = trt_gm(torch_inputs)\n", + " return outputs.detach().cpu().numpy()\n", + " \n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "df68cca1-2d47-4e88-8aad-9899402aee97", + "metadata": {}, + "outputs": [], + "source": [ + "mnist = predict_batch_udf(predict_batch_fn,\n", + " input_tensor_shapes=[[784]],\n", + " return_type=ArrayType(FloatType()),\n", + " batch_size=50)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "63555b3b-3673-4712-97aa-fd728c6c4979", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 189 ms, sys: 53.6 ms, total: 242 ms\n", + "Wall time: 9.73 s\n" + ] + } + ], + "source": [ + "%%time\n", + "# first pass caches model/fn\n", + "preds = df.withColumn(\"preds\", mnist(struct(df.columns))).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "5dbf058a-70d6-4199-af9d-13843d078950", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 195 ms, sys: 75 ms, total: 270 ms\n", + "Wall time: 1.26 s\n" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", mnist(*df.columns)).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "3f5ed801-6ca5-43a0-bf9c-2535a0dfe2e8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 199 ms, sys: 54.9 ms, total: 254 ms\n", + "Wall time: 1.27 s\n" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", mnist(*[col(c) for c in df.columns])).collect()" + ] + }, + { + "cell_type": "markdown", + "id": "c6dbec03-9b64-46c4-a748-f889be571384", + "metadata": { + "tags": [] + }, + "source": [ + "### Check predictions" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "f1f1e5fd-5866-4b78-b9d3-709e6b383a0c", + "metadata": {}, + "outputs": [], + "source": [ + "predictions = preds[0].preds\n", + "img = preds[0].data" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "76b76502-adb7-45ec-a365-2e61cdd576fc", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "c163953a-1504-444f-b39f-86b61d34e440", + "metadata": {}, + "outputs": [], + "source": [ + "img = np.array(img).reshape(28,28)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "bc0fad05-50ab-4ae5-b9fd-e50133c4c92a", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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37qlS5e6rKwsV1dXF3ppveob3/iG27Ztm6upqXFvvPGGKy0tdTk5Oe748eOhl9ajTp065fbu3ev27t3rJLlHHnnE7d2717333nvOOed+8IMfuKysLLdp0ya3f/9+N3/+fFdcXOzOnDkTeOXd6+OOw6lTp9y9997rduzY4WpqatyWLVvc5z73OXfFFVe4lpaW0EvvNsuWLXOxWMxt27bNHTt2rPPW3Nzcuc2dd97pRo8e7V599VW3e/duN2PGDDdjxoyAq+5+FzoOBw8edN/97nfd7t27XU1Njdu0aZMbO3asmzlzZuCVd9UvCsg55x577DE3evRol56e7qZPn+527twZekm97uabb3YFBQUuPT3dXX755e7mm292Bw8eDL2sHvfaa685SR+5LVq0yDl39qXY3/72t11eXp6LRqNu9uzZrrq6Ouyie8DHHYfm5mY3Z84cN3LkSJeWlubGjBnjlixZMuC+STvX+y/JrV27tnObM2fOuK997Wvusssuc0OHDnU33nijO3bsWLhF94ALHYfDhw+7mTNnuuzsbBeNRt348ePdN7/5TdfY2Bh24R/Cn2MAAATR558DAgAMTBQQACAICggAEAQFBAAIggICAARBAQEAgqCAAABBUEAAgCAoIABAEBQQACAICggAEAQFBAAI4v8DIE1CeiobCX8AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure()\n", + "plt.imshow(img)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "56f36efb-e3a2-49f9-b9fb-1657bc25e5c5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[-1.309907078742981, -3.8460376262664795, 0.845407247543335, -2.5534284114837646, 0.7116107940673828, 0.9341840147972107, 0.4921048879623413, 0.22850888967514038, 2.951157331466675, 1.0042279958724976]\n", + "predicted label: Bag\n" + ] + } + ], + "source": [ + "print(predictions)\n", + "print(\"predicted label:\", classes[np.argmax(predictions)])" + ] + }, + { + "cell_type": "markdown", + "id": "56ca1195-ea0f-405f-87fe-857e5c0c76a5", + "metadata": {}, + "source": [ + "### 784 columns of float" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "e0ab0af6-b5c9-4b74-9dd6-baa7737cc986", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "784" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = spark.read.parquet(\"fashion_mnist_784\")\n", + "len(df.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "13ae45dc-85a0-4864-8a58-9dc29ae4efd7", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 266 ms, sys: 69.9 ms, total: 336 ms\n", + "Wall time: 4.05 s\n" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", mnist(struct(df.columns))).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "0b3fb48b-f871-41f2-ac57-346899a6fe48", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 271 ms, sys: 66.2 ms, total: 337 ms\n", + "Wall time: 1.96 s\n" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", mnist(array(*df.columns))).collect()" + ] + }, + { + "cell_type": "markdown", + "id": "dc48ec42-0df6-4e6a-b019-1270ab71d2cf", + "metadata": { + "tags": [] + }, + "source": [ + "### Check predictions" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "d815c701-9f5b-422c-b3f9-fbc30456953c", + "metadata": {}, + "outputs": [], + "source": [ + "preds = df.withColumn(\"preds\", mnist(array(*df.columns))).limit(10).toPandas()" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "b571b742-5079-42b2-8524-9181a0dec2c7", + "metadata": {}, + "outputs": [], + "source": [ + "sample = preds.iloc[0]\n", + "predictions = sample.preds\n", + "img = sample.drop('preds').to_numpy(dtype=float)" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "d33d6a4e-e6b9-489d-ac21-c4eddc801784", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "6d10061e-aca6-4f81-bdfe-72e327ed7349", + "metadata": {}, + "outputs": [], + "source": [ + "img = np.array(img).reshape(28,28)" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "01f70e08-2c1d-419f-8676-3f6f4aba760f", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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Ki4u1qJFi9TY2Khp06YNd5uDSvlfweXn5yscDp93FUtra6uKioqMukoNubm5uvbaa3XkyBHrVsx8cQxwfJxv6tSpys/PH5XHx5o1a/T222/r/fffT/jzLUVFRerr61NbW1vC+qP1eLjQfhhMeXm5JKXU8ZDyAZSZmam5c+dq165d8ftisZh27dql+fPnG3Zm79SpU2psbFRxcbF1K2bKyspUVFSUcHx0dHRo7969V/zx8emnn+rkyZOj6vhwzmnNmjXatm2b3nvvPZWVlSU8PnfuXGVkZCQcDw0NDTp69OioOh4utR8Gc+DAAUlKrePB+iqIf8Srr77qIpGI27Jli/vjH//oVq9e7XJzc11LS4t1a8PqBz/4gautrXVNTU3ud7/7nauoqHD5+fnuxIkT1q0Nqc7OTvfRRx+5jz76yElyzz77rPvoo4/cX/7yF+eccz/96U9dbm6u27Fjhzt48KC79dZbXVlZmTt9+rRx58l1sf3Q2dnpHn74YVdfX++amprcu+++677+9a+7a665xvX09Fi3njQPPPCAi0ajrra21h0/fjy+dHd3x9e5//773eTJk917773n9u3b5+bPn+/mz59v2HXyXWo/HDlyxD399NNu3759rqmpye3YscNNnTrVLViwwLjzRCMigJxz7oUXXnCTJ092mZmZbt68eW7Pnj3WLQ27O+64wxUXF7vMzEz3pS99yd1xxx3uyJEj1m0Nuffff99JOm9ZsWKFc+7spdiPP/64KywsdJFIxC1atMg1NDTYNj0ELrYfuru73eLFi93EiRNdRkaGmzJlilu1atWoe5E22L9fktu8eXN8ndOnT7vvfe977qqrrnJjxoxxt912mzt+/Lhd00PgUvvh6NGjbsGCBS4vL89FIhF39dVXux/+8Ieuvb3dtvFz8OcYAAAmUv49IADA6EQAAQBMEEAAABMEEADABAEEADBBAAEATBBAAAATBBAAwAQBBAAwQQABAEwQQAAAEwQQAMDEfwNH5VgkZZXaeQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure()\n", + "plt.imshow(img)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "8e1c07cc-b2bc-4902-a9a6-4ac7f02c5fe4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[ 2.5953586 3.9101725 0.65233815 3.2538052 1.270339 -3.0440047\n", + " 1.1500907 -3.7935097 -1.8807431 -3.321768 ]\n", + "predicted label: Trouser\n" + ] + } + ], + "source": [ + "print(predictions)\n", + "print(\"predicted label:\", classes[np.argmax(predictions)])" + ] + }, + { + "cell_type": "markdown", + "id": "a937adc9-508d-4ccd-b92d-8ecaa27ee4e4", + "metadata": {}, + "source": [ + "### Using Triton Inference Server\n", + "\n", + "Note: you can restart the kernel and run from this point to simulate running in a different node or environment." + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "53ca290a-ccc3-4923-a292-944921bab36d", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "from functools import partial\n", + "from pyspark.ml.functions import predict_batch_udf\n", + "from pyspark.sql.functions import struct, col, array\n", + "from pyspark.sql.types import ArrayType, FloatType, Union, Dict" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "8fa92fe4-2e04-4d82-a357-bfdfca38bd8c", + "metadata": {}, + "outputs": [], + "source": [ + "%%bash\n", + "# copy model to expected layout for Triton\n", + "rm -rf models\n", + "mkdir -p models/fashion_mnist/1\n", + "cp ts_model.pt models/fashion_mnist/1/model.pt\n", + "\n", + "# add config.pbtxt\n", + "cp models_config/fashion_mnist/config.pbtxt models/fashion_mnist/config.pbtxt" + ] + }, + { + "cell_type": "markdown", + "id": "d42b329c-5921-436f-bfca-a382a6762da4", + "metadata": {}, + "source": [ + "#### Start Triton Server on each executor" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e869730-3597-4074-bab0-f87768f8996a", + "metadata": {}, + "outputs": [], + "source": [ + "num_executors = 1\n", + "triton_models_dir = \"{}/models\".format(os.getcwd())\n", + "nodeRDD = sc.parallelize(list(range(num_executors)), num_executors)\n", + "\n", + "def start_triton(it):\n", + " import docker\n", + " import time\n", + " import tritonclient.grpc as grpcclient\n", + " \n", + " client=docker.from_env()\n", + " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", + " if containers:\n", + " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", + " else:\n", + " container=client.containers.run(\n", + " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", + " detach=True,\n", + " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", + " name=\"spark-triton\",\n", + " network_mode=\"host\",\n", + " remove=True,\n", + " shm_size=\"64M\",\n", + " volumes={triton_models_dir: {\"bind\": \"/models\", \"mode\": \"ro\"}}\n", + " )\n", + " print(\">>>> starting triton: {}\".format(container.short_id))\n", + "\n", + " # wait for triton to be running\n", + " time.sleep(15)\n", + " client = grpcclient.InferenceServerClient(\"localhost:8001\")\n", + " ready = False\n", + " while not ready:\n", + " try:\n", + " ready = client.is_server_ready()\n", + " except Exception as e:\n", + " time.sleep(5)\n", + " \n", + " return [True]\n", + "\n", + "nodeRDD.barrier().mapPartitions(start_triton).collect()" + ] + }, + { + "cell_type": "markdown", + "id": "30a4362d-7514-4b84-b238-f704a97e1e72", + "metadata": {}, + "source": [ + "#### Run inference" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "id": "ab94d4d1-dac6-4474-9eb0-59478aa98f7d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = spark.read.parquet(\"fashion_mnist_1\")\n", + "len(df.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "id": "12b5f2fc-52e9-428a-b683-6ab1b639aa24", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "StructType([StructField('data', ArrayType(FloatType(), True), True)])" + ] + }, + "execution_count": 61, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.schema" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "id": "960657d0-31c9-4df6-8eb8-ac3d23137f7a", + "metadata": {}, + "outputs": [], + "source": [ + "def triton_fn(triton_uri, model_name):\n", + " import numpy as np\n", + " import tritonclient.grpc as grpcclient\n", + " \n", + " np_types = {\n", + " \"BOOL\": np.dtype(np.bool_),\n", + " \"INT8\": np.dtype(np.int8),\n", + " \"INT16\": np.dtype(np.int16),\n", + " \"INT32\": np.dtype(np.int32),\n", + " \"INT64\": np.dtype(np.int64),\n", + " \"FP16\": np.dtype(np.float16),\n", + " \"FP32\": np.dtype(np.float32),\n", + " \"FP64\": np.dtype(np.float64),\n", + " \"FP64\": np.dtype(np.double),\n", + " \"BYTES\": np.dtype(object)\n", + " }\n", + "\n", + " client = grpcclient.InferenceServerClient(triton_uri)\n", + " model_meta = client.get_model_metadata(model_name)\n", + " \n", + " def predict(inputs):\n", + " if isinstance(inputs, np.ndarray):\n", + " # single ndarray input\n", + " request = [grpcclient.InferInput(model_meta.inputs[0].name, inputs.shape, model_meta.inputs[0].datatype)]\n", + " request[0].set_data_from_numpy(inputs.astype(np_types[model_meta.inputs[0].datatype]))\n", + " else:\n", + " # dict of multiple ndarray inputs\n", + " request = [grpcclient.InferInput(i.name, inputs[i.name].shape, i.datatype) for i in model_meta.inputs]\n", + " for i in request:\n", + " i.set_data_from_numpy(inputs[i.name()].astype(np_types[i.datatype()]))\n", + " \n", + " response = client.infer(model_name, inputs=request)\n", + " \n", + " if len(model_meta.outputs) > 1:\n", + " # return dictionary of numpy arrays\n", + " return {o.name: response.as_numpy(o.name) for o in model_meta.outputs}\n", + " else:\n", + " # return single numpy array\n", + " return response.as_numpy(model_meta.outputs[0].name)\n", + " \n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "0262fd4a-9845-44b9-8c75-1c105e7deeca", + "metadata": {}, + "outputs": [], + "source": [ + "mnist = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"fashion_mnist\"),\n", + " input_tensor_shapes=[[784]],\n", + " return_type=ArrayType(FloatType()),\n", + " batch_size=1024)" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "id": "fc5f6baa-052e-4b89-94b6-4821cf01952a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 326 ms, sys: 39.6 ms, total: 365 ms\n", + "Wall time: 1.77 s\n" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", mnist(struct(df.columns))).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "a85dea35-e41d-482d-8a8f-52d3c108f038", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 199 ms, sys: 63.2 ms, total: 262 ms\n", + "Wall time: 1.21 s\n" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", mnist(*df.columns)).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "id": "bc3f0dbe-c52b-41d6-8097-8cebaa5ee5a8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 195 ms, sys: 25.4 ms, total: 220 ms\n", + "Wall time: 1.21 s\n" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", mnist(*[col(c) for c in df.columns])).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "id": "99fb5e8d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Predicted label: Bag\n" + ] + }, + { + "data": { + "image/png": "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37qlS5e6rKwsV1dXF3ppveob3/iG27Ztm6upqXFvvPGGKy0tdTk5Oe748eOhl9ajTp065fbu3ev27t3rJLlHHnnE7d2717333nvOOed+8IMfuKysLLdp0ya3f/9+N3/+fFdcXOzOnDkTeOXd6+OOw6lTp9y9997rduzY4WpqatyWLVvc5z73OXfFFVe4lpaW0EvvNsuWLXOxWMxt27bNHTt2rPPW3Nzcuc2dd97pRo8e7V599VW3e/duN2PGDDdjxoyAq+5+FzoOBw8edN/97nfd7t27XU1Njdu0aZMbO3asmzlzZuCVd9UvCsg55x577DE3evRol56e7qZPn+527twZekm97uabb3YFBQUuPT3dXX755e7mm292Bw8eDL2sHvfaa685SR+5LVq0yDl39qXY3/72t11eXp6LRqNu9uzZrrq6Ouyie8DHHYfm5mY3Z84cN3LkSJeWlubGjBnjlixZMuC+STvX+y/JrV27tnObM2fOuK997Wvusssuc0OHDnU33nijO3bsWLhF94ALHYfDhw+7mTNnuuzsbBeNRt348ePdN7/5TdfY2Bh24R/Cn2MAAATR558DAgAMTBQQACAICggAEAQFBAAIggICAARBAQEAgqCAAABBUEAAgCAoIABAEBQQACAICggAEAQFBAAI4v8DIE1CeiobCX8AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Sample prediction\n", + "sample = preds[0]\n", + "predictions = sample.preds\n", + "img = sample.data\n", + "\n", + "img = np.array(img).reshape(28,28)\n", + "plt.figure()\n", + "plt.imshow(img)\n", + "\n", + "print(\"Predicted label:\", classes[np.argmax(predictions)])" + ] + }, + { + "cell_type": "markdown", + "id": "7a26690a-9dc4-4c36-9904-568d73e2be3c", + "metadata": { + "tags": [] + }, + "source": [ + "#### Stop Triton Server on each executor" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ab2fe42f-a072-4370-bac2-52fd95363530", + "metadata": {}, + "outputs": [], + "source": [ + "def stop_triton(it):\n", + " import docker\n", + " import time\n", + " \n", + " client=docker.from_env()\n", + " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", + " print(\">>>> stopping containers: {}\".format([c.short_id for c in containers]))\n", + " if containers:\n", + " container=containers[0]\n", + " container.stop(timeout=120)\n", + "\n", + " return [True]\n", + "\n", + "nodeRDD.barrier().mapPartitions(stop_triton).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "a0608fff-7cfb-489e-96c9-8e1d92e57562", + "metadata": {}, + "outputs": [], + "source": [ + "spark.stop()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08de2664-3d60-487b-90da-6d0f3b8b9203", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "spark-dl-torch", + "language": "python", + "name": "python3" + }, + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression_torch.ipynb similarity index 55% rename from examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression.ipynb rename to examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression_torch.ipynb index 3e537d42f..d2fd9157d 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression_torch.ipynb @@ -2,12 +2,15 @@ "cells": [ { "cell_type": "markdown", - "id": "f04d288a-f4bf-4256-8ef8-fbc3ab92f24e", - "metadata": { - "tags": [] - }, + "id": "792d95f9", + "metadata": {}, "source": [ - "Based on: https://github.com/christianversloot/machine-learning-articles/blob/main/how-to-create-a-neural-network-for-regression-with-pytorch.md" + "# PySpark PyTorch Inference\n", + "\n", + "### Regression\n", + "Based on: https://github.com/christianversloot/machine-learning-articles/blob/main/how-to-create-a-neural-network-for-regression-with-pytorch.md \n", + "\n", + "For the first MLP (array inputs) we'll also demonstrate accelerated inference on GPU with Torch-TensorRT. " ] }, { @@ -29,13 +32,13 @@ { "cell_type": "code", "execution_count": 2, - "id": "cf02ba0a-8384-42b5-917c-53889b4a6471", + "id": "6d5bc0c7", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "'2.4.1+cu121'" ] }, "execution_count": 2, @@ -44,12 +47,53 @@ } ], "source": [ - "torch.manual_seed(42)" + "torch.__version__" ] }, { "cell_type": "code", "execution_count": 3, + "id": "cf02ba0a-8384-42b5-917c-53889b4a6471", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.manual_seed(42)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "bb5c10ab", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Using cuda device\n" + ] + } + ], + "source": [ + "# Get cpu or gpu device for training.\n", + "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", + "print(f\"Using {device} device\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, "id": "2bee64cf-a44a-4aff-82db-c64ee3a8b0e8", "metadata": {}, "outputs": [], @@ -59,7 +103,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "id": "8644e508-5e4c-4cdd-9ed1-9235887d9659", "metadata": {}, "outputs": [], @@ -82,7 +126,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "id": "cc6b55c3-dc7b-4831-9943-83efd48091bf", "metadata": {}, "outputs": [], @@ -94,7 +138,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 8, "id": "d868f39d-4695-4110-91d2-6f7a09d73b93", "metadata": {}, "outputs": [ @@ -115,7 +159,7 @@ " 2.0530])]" ] }, - "execution_count": 6, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -126,7 +170,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "id": "9a441b60-dca4-44d2-bc1c-aa7336d704bb", "metadata": {}, "outputs": [], @@ -148,7 +192,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "id": "15cff2b4-9d23-4d2b-808a-a5edb8eda135", "metadata": { "scrolled": true, @@ -157,7 +201,7 @@ "outputs": [], "source": [ "# Initialize the MLP\n", - "mlp = MLP()\n", + "mlp = MLP().to(device)\n", "\n", "# Define the loss function and optimizer\n", "loss_function = nn.L1Loss()\n", @@ -166,7 +210,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, "id": "5e2db3f9-5db8-4b42-89ad-e77f23c4c1fe", "metadata": { "scrolled": true, @@ -256,6 +300,7 @@ "\n", " # Get and prepare inputs\n", " inputs, targets = data\n", + " inputs, targets = inputs.to(device), targets.to(device)\n", " targets = targets.reshape((targets.shape[0], 1))\n", "\n", " # Zero the gradients\n", @@ -286,31 +331,59 @@ }, { "cell_type": "markdown", - "id": "ace480ba-9316-49a4-9763-dc0f61f66989", + "id": "352539f5", "metadata": {}, "source": [ - "### Save Model" + "### Save Model State Dict\n", + "This saves the serialized object to disk using pickle." ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 12, "id": "b950a3ed-ffe1-477f-a84f-f71c85dbf9ce", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved PyTorch Model State to housing_model.pt\n" + ] + } + ], "source": [ - "torch.save(mlp, \"housing_model.pt\")" + "torch.save(mlp.state_dict(), \"housing_model.pt\")\n", + "print(\"Saved PyTorch Model State to housing_model.pt\")" + ] + }, + { + "cell_type": "markdown", + "id": "0060fcca", + "metadata": {}, + "source": [ + "### Save Model as TorchScript\n", + "This saves an [intermediate representation of the compute graph](https://pytorch.org/tutorials/beginner/saving_loading_models.html#export-load-model-in-torchscript-format), which does not require pickle (or even python). " ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 13, "id": "20fedb5d-c59e-4b0b-ba91-3dd15df1f09e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved TorchScript Model to ts_housing_model.pt\n" + ] + } + ], "source": [ "scripted = torch.jit.script(mlp)\n", - "scripted.save(\"housing_model.ts\")" + "scripted.save(\"ts_housing_model.pt\")\n", + "print(\"Saved TorchScript Model to ts_housing_model.pt\")" ] }, { @@ -318,22 +391,34 @@ "id": "3101c0fe-65f1-411e-9192-e8a6b585ba0d", "metadata": {}, "source": [ - "### Load and Test Model" + "### Load and Test from Model State" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 14, "id": "7411b00f-88d2-40f5-b716-a26733c968ff", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "loaded_mlp = torch.load(\"housing_model.pt\")" + "loaded_mlp = MLP().to(device)\n", + "loaded_mlp.load_state_dict(torch.load(\"housing_model.pt\", weights_only=True))" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 15, "id": "e226f449-2931-4492-9003-503cdc61f061", "metadata": {}, "outputs": [], @@ -343,48 +428,48 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 16, "id": "d46af47e-db7e-42ee-9bd3-6e7d93850be3", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "tensor([[2.8778],\n", - " [0.6233],\n", - " [3.9021],\n", - " [2.4543],\n", - " [1.0209],\n", - " [1.8093],\n", - " [1.4593],\n", - " [3.2933],\n", - " [2.9263],\n", - " [1.4790]], grad_fn=)" + "tensor([[1.7498],\n", + " [3.0116],\n", + " [1.1925],\n", + " [4.0598],\n", + " [2.0545],\n", + " [2.9072],\n", + " [2.0551],\n", + " [4.6094],\n", + " [1.0068],\n", + " [1.1174]], device='cuda:0', grad_fn=)" ] }, - "execution_count": 14, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "loaded_mlp(testX)" + "loaded_mlp(testX.to(device))" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 17, "id": "13ae2c0f-1da5-45a4-bf32-ed8b562d7907", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "tensor([2.8380, 0.5740, 5.0000, 2.0430, 1.2680, 1.8380, 1.4340, 2.6830, 1.6100,\n", - " 1.3050])" + "tensor([3.5000, 2.9130, 0.7020, 5.0000, 1.7970, 2.7080, 2.1470, 5.0000, 0.6000,\n", + " 0.8480])" ] }, - "execution_count": 15, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } @@ -393,19 +478,27 @@ "testY" ] }, + { + "cell_type": "markdown", + "id": "3bcd329d", + "metadata": {}, + "source": [ + "### Load and Test from TorchScript" + ] + }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 18, "id": "422e317f-c9bd-4f76-9463-7af2935d401d", "metadata": {}, "outputs": [], "source": [ - "scripted_mlp = torch.jit.load(\"housing_model.ts\")" + "scripted_mlp = torch.jit.load(\"ts_housing_model.pt\")" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 19, "id": "0cda8ec8-644e-4888-bfa0-b79425ece7c3", "metadata": { "tags": [] @@ -414,17 +507,264 @@ { "data": { "text/plain": [ - "tensor([2.8778, 0.6233, 3.9021, 2.4543, 1.0209, 1.8093, 1.4593, 3.2933, 2.9263,\n", - " 1.4790], grad_fn=)" + "tensor([1.7498, 3.0116, 1.1925, 4.0598, 2.0545, 2.9072, 2.0551, 4.6094, 1.0068,\n", + " 1.1174], device='cuda:0', grad_fn=)" ] }, - "execution_count": 17, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "scripted_mlp(testX).flatten()" + "scripted_mlp(testX.to(device)).flatten()" + ] + }, + { + "cell_type": "markdown", + "id": "2a3b64e4", + "metadata": {}, + "source": [ + "### Compile using the Torch JIT Compiler\n", + "This leverages the [Torch-TensorRT inference compiler](https://pytorch.org/TensorRT/) for accelerated inference on GPUs using the `torch.compile` JIT interface under the hood. The compiler stack returns a [boxed-function](http://blog.ezyang.com/2020/09/lets-talk-about-the-pytorch-dispatcher/) that triggers compilation on the first call. \n", + "\n", + "Modules compiled in this fashion are [not serializable with pickle](https://github.com/pytorch/pytorch/issues/101107#issuecomment-1542688089), so we cannot send the compiled model directly to Spark. Instead, we will recompile and cache the model on the executor. " + ] + }, + { + "cell_type": "markdown", + "id": "c613f24e", + "metadata": {}, + "source": [ + "(You may see a warning about modelopt quantization. This is safe to ignore, as [implicit quantization](https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#intro-quantization) is deprecated in the latest TensorRT. See [this link](https://pytorch.org/TensorRT/tutorials/_rendered_examples/dynamo/vgg16_fp8_ptq.html) for a guide to explicit quantization.)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "b4aa2523", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:torch_tensorrt.dynamo.conversion.aten_ops_converters:Unable to import quantization op. Please install modelopt library (https://github.com/NVIDIA/TensorRT-Model-Optimizer?tab=readme-ov-file#installation) to add support for compiling quantized models\n", + "INFO:torch_tensorrt.dynamo.utils:Using Default Torch-TRT Runtime (as requested by user)\n", + "INFO:torch_tensorrt.dynamo.utils:Device not specified, using Torch default current device - cuda:0. If this is incorrect, please specify an input device, via the device keyword.\n", + "INFO:torch_tensorrt.dynamo.utils:Compilation Settings: CompilationSettings(enabled_precisions={}, debug=False, workspace_size=0, min_block_size=5, torch_executed_ops=set(), pass_through_build_failures=False, max_aux_streams=None, version_compatible=False, optimization_level=None, use_python_runtime=False, truncate_double=False, use_fast_partitioner=True, enable_experimental_decompositions=False, device=Device(type=DeviceType.GPU, gpu_id=0), require_full_compilation=False, disable_tf32=False, assume_dynamic_shape_support=False, sparse_weights=False, refit=False, engine_capability=, num_avg_timing_iters=1, dla_sram_size=1048576, dla_local_dram_size=1073741824, dla_global_dram_size=536870912, dryrun=False, hardware_compatible=False, timing_cache_path='/tmp/timing_cache.bin')\n", + "\n", + "WARNING:torch_tensorrt.dynamo._compiler:Node _param_constant1 of op type get_attr does not have metadata. This could sometimes lead to undefined behavior.\n", + "WARNING:torch_tensorrt.dynamo._compiler:Some nodes do not have metadata (shape and dtype information). This could lead to problems sometimes if the graph has PyTorch and TensorRT segments.\n", + "INFO:torch_tensorrt.dynamo._compiler:Partitioning the graph via the fast partitioner\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init CUDA: CPU +1, GPU +0, now: CPU 586, GPU 1112 (MiB)\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init builder kernel library: CPU +1635, GPU +288, now: CPU 2368, GPU 1400 (MiB)\n", + "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch_tensorrt/dynamo/conversion/impl/activation/base.py:40: DeprecationWarning: Use Deprecated in TensorRT 10.1. Superseded by explicit quantization. instead.\n", + " if input_val.dynamic_range is not None and dyn_range_fn is not None:\n", + "\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT INetwork construction elapsed time: 0:00:00.003844\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Global timing cache in use. Profiling results in this builder pass will be stored.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Detected 1 inputs and 1 output network tensors.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Host Persistent Memory: 22240\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Device Persistent Memory: 0\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Scratch Memory: 0\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Started assigning block shifts. This will take 10 steps to complete.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Algorithm ShiftNTopDown took 0.156445ms to assign 4 blocks to 10 nodes requiring 7168 bytes.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Activation Memory: 6656\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Weights Memory: 11648\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Engine generation completed in 0.0225783 seconds.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage of TRT CPU/GPU memory allocators: CPU 0 MiB, GPU 1 MiB\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage during Engine building and serialization: CPU: 3966 MiB\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:Build TRT engine elapsed time: 0:00:00.026248\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT Engine uses: 665972 bytes of Memory\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 26 bytes of code generator cache.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 176 timing cache entries\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[1.7498],\n", + " [3.0116],\n", + " [1.1925],\n", + " [4.0598],\n", + " [2.0545],\n", + " [2.9072],\n", + " [2.0551],\n", + " [4.6094],\n", + " [1.0068],\n", + " [1.1174]], device='cuda:0')\n" + ] + } + ], + "source": [ + "import torch_tensorrt as trt\n", + "\n", + "inputs_bs1 = torch.randn((10, 8), dtype=torch.float).to(\"cuda\")\n", + "# This indicates dimension 0 of inputs_bs1 is dynamic whose range of values is [1, 50]. No recompilation will happen when the batch size changes.\n", + "torch._dynamo.mark_dynamic(inputs_bs1, 0, min=1, max=50)\n", + "trt_model = trt.compile(\n", + " loaded_mlp,\n", + " ir=\"torch_compile\",\n", + " inputs=inputs_bs1,\n", + " enabled_precisions={torch.float},\n", + ")\n", + "\n", + "stream = torch.cuda.Stream()\n", + "with torch.no_grad(), torch.cuda.stream(stream):\n", + " testX = testX.to(device)\n", + " print(trt_model(testX))" + ] + }, + { + "cell_type": "markdown", + "id": "d2c55e07", + "metadata": {}, + "source": [ + "### Compile using the Torch-TensorRT AOT Compiler\n", + "Alternatively, use the Torch-TensorRT Dynamo backend for Ahead-of-Time (AOT) compilation to eagerly optimize the model in an explicit compilation phase. We first export the model to produce a traced graph representing the Tensor computation in an AOT fashion, which produces a `ExportedProgram` object which can be [serialized and reloaded](https://pytorch.org/TensorRT/user_guide/saving_models.html). We can then compile this IR using the Torch-TensorRT AOT compiler for inference. \n", + "\n", + "[Read the docs](https://pytorch.org/TensorRT/user_guide/torch_tensorrt_explained.html) for more information on JIT vs AOT compilation." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "b6b5c112", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:torch_tensorrt.dynamo._compiler:Compilation Settings: CompilationSettings(enabled_precisions={}, debug=False, workspace_size=0, min_block_size=5, torch_executed_ops=set(), pass_through_build_failures=False, max_aux_streams=None, version_compatible=False, optimization_level=None, use_python_runtime=False, truncate_double=False, use_fast_partitioner=True, enable_experimental_decompositions=False, device=Device(type=DeviceType.GPU, gpu_id=0), require_full_compilation=False, disable_tf32=False, assume_dynamic_shape_support=False, sparse_weights=False, refit=False, engine_capability=, num_avg_timing_iters=1, dla_sram_size=1048576, dla_local_dram_size=1073741824, dla_global_dram_size=536870912, dryrun=False, hardware_compatible=False, timing_cache_path='/tmp/timing_cache.bin')\n", + "\n", + "INFO:torch_tensorrt.dynamo._compiler:Partitioning the graph via the fast partitioner\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init CUDA: CPU +0, GPU +0, now: CPU 762, GPU 1114 (MiB)\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init builder kernel library: CPU +1633, GPU +286, now: CPU 2395, GPU 1400 (MiB)\n", + "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch_tensorrt/dynamo/conversion/impl/activation/base.py:40: DeprecationWarning: Use Deprecated in TensorRT 10.1. Superseded by explicit quantization. instead.\n", + " if input_val.dynamic_range is not None and dyn_range_fn is not None:\n", + "\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT INetwork construction elapsed time: 0:00:00.002832\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Global timing cache in use. Profiling results in this builder pass will be stored.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Detected 1 inputs and 1 output network tensors.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Host Persistent Memory: 22240\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Device Persistent Memory: 0\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Scratch Memory: 0\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Started assigning block shifts. This will take 10 steps to complete.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Algorithm ShiftNTopDown took 0.120805ms to assign 4 blocks to 10 nodes requiring 7168 bytes.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Activation Memory: 6656\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Weights Memory: 11648\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Engine generation completed in 0.014855 seconds.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage of TRT CPU/GPU memory allocators: CPU 0 MiB, GPU 1 MiB\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage during Engine building and serialization: CPU: 3989 MiB\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:Build TRT engine elapsed time: 0:00:00.016879\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT Engine uses: 666804 bytes of Memory\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 26 bytes of code generator cache.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 176 timing cache entries\n", + "INFO:torch_tensorrt.dynamo.utils:Using Default Torch-TRT Runtime (as requested by user)\n", + "INFO:torch_tensorrt.dynamo.utils:Device not specified, using Torch default current device - cuda:0. If this is incorrect, please specify an input device, via the device keyword.\n", + "INFO:torch_tensorrt.dynamo.utils:Compilation Settings: CompilationSettings(enabled_precisions={}, debug=False, workspace_size=0, min_block_size=5, torch_executed_ops=set(), pass_through_build_failures=False, max_aux_streams=None, version_compatible=False, optimization_level=None, use_python_runtime=False, truncate_double=False, use_fast_partitioner=True, enable_experimental_decompositions=False, device=Device(type=DeviceType.GPU, gpu_id=0), require_full_compilation=False, disable_tf32=False, assume_dynamic_shape_support=False, sparse_weights=False, refit=False, engine_capability=, num_avg_timing_iters=1, dla_sram_size=1048576, dla_local_dram_size=1073741824, dla_global_dram_size=536870912, dryrun=False, hardware_compatible=False, timing_cache_path='/tmp/timing_cache.bin')\n", + "\n", + "WARNING:torch_tensorrt.dynamo._compiler:Node _param_constant1 of op type get_attr does not have metadata. This could sometimes lead to undefined behavior.\n", + "WARNING:torch_tensorrt.dynamo._compiler:Some nodes do not have metadata (shape and dtype information). This could lead to problems sometimes if the graph has PyTorch and TensorRT segments.\n", + "INFO:torch_tensorrt.dynamo._compiler:Partitioning the graph via the fast partitioner\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:The logger passed into createInferBuilder differs from one already provided for an existing builder, runtime, or refitter. Uses of the global logger, returned by nvinfer1::getLogger(), will return the existing value.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init CUDA: CPU +0, GPU +0, now: CPU 764, GPU 1136 (MiB)\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init builder kernel library: CPU +1632, GPU +286, now: CPU 2396, GPU 1422 (MiB)\n", + "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch_tensorrt/dynamo/conversion/impl/activation/base.py:40: DeprecationWarning: Use Deprecated in TensorRT 10.1. Superseded by explicit quantization. instead.\n", + " if input_val.dynamic_range is not None and dyn_range_fn is not None:\n", + "\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT INetwork construction elapsed time: 0:00:00.002990\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Global timing cache in use. Profiling results in this builder pass will be stored.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Detected 1 inputs and 1 output network tensors.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Host Persistent Memory: 22240\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Device Persistent Memory: 0\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Scratch Memory: 0\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Started assigning block shifts. This will take 10 steps to complete.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Algorithm ShiftNTopDown took 0.243798ms to assign 4 blocks to 10 nodes requiring 7168 bytes.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Activation Memory: 6656\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Weights Memory: 11648\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Engine generation completed in 0.0158591 seconds.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage of TRT CPU/GPU memory allocators: CPU 0 MiB, GPU 1 MiB\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage during Engine building and serialization: CPU: 3991 MiB\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:Build TRT engine elapsed time: 0:00:00.017873\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT Engine uses: 665972 bytes of Memory\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 26 bytes of code generator cache.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 176 timing cache entries\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[1.7498],\n", + " [3.0116],\n", + " [1.1925],\n", + " [4.0598],\n", + " [2.0545],\n", + " [2.9072],\n", + " [2.0551],\n", + " [4.6094],\n", + " [1.0068],\n", + " [1.1174]], device='cuda:0')\n" + ] + } + ], + "source": [ + "# Preparing the inputs for batch_size = 50. \n", + "inputs = (torch.randn((10, 8), dtype=torch.float).cuda(),)\n", + "\n", + "# Produce traced graph in the ExportedProgram format\n", + "exp_program = trt.dynamo.trace(loaded_mlp, inputs)\n", + "# Compile the traced graph to produce an optimized module\n", + "trt_gm = trt.dynamo.compile(exp_program, inputs=inputs, device='cuda:0')\n", + "\n", + "stream = torch.cuda.Stream()\n", + "with torch.no_grad(), torch.cuda.stream(stream):\n", + " testX = testX.to(device)\n", + " print(trt_model(testX))" + ] + }, + { + "cell_type": "markdown", + "id": "b4fef57d", + "metadata": {}, + "source": [ + "We can save the compiled model using `torch_tensorrt.save`. Unfortunately, serializing the model to be reloaded at a later date currently only supports *static inputs*." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "dabc91a4", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch_tensorrt/dynamo/_exporter.py:364: UserWarning: Attempted to insert a get_attr Node with no underlying reference in the owning GraphModule! Call GraphModule.add_submodule to add the necessary submodule, GraphModule.add_parameter to add the necessary Parameter, or nn.Module.register_buffer to add the necessary buffer\n", + " engine_node = gm.graph.get_attr(engine_name)\n", + "\n", + "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch/fx/graph.py:1545: UserWarning: Node _run_on_acc_0_engine target _run_on_acc_0_engine _run_on_acc_0_engine of does not reference an nn.Module, nn.Parameter, or buffer, which is what 'get_attr' Nodes typically target\n", + " warnings.warn(f'Node {node} target {node.target} {atom} of {seen_qualname} does '\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved AOT compiled TensorRT model to trt_model_aot.ep\n" + ] + } + ], + "source": [ + "with torch.cuda.stream(stream):\n", + " trt.save(trt_gm, \"trt_model_aot.ep\", inputs=[torch.randn((10, 8), dtype=torch.float).to(\"cuda\")])\n", + " print(\"Saved AOT compiled TensorRT model to trt_model_aot.ep\")" ] }, { @@ -437,7 +777,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 23, "id": "32e11813-cf75-448e-a46e-f210cc7f52ba", "metadata": {}, "outputs": [], @@ -455,17 +795,17 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 24, "id": "dc7da567-65df-4895-a867-0be05de27ee0", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 19, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } @@ -476,7 +816,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 25, "id": "e3340e01-b3bc-4cce-bb21-890517e1bcd5", "metadata": {}, "outputs": [], @@ -486,7 +826,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 26, "id": "dea2ecd8-34e2-4ed5-8bd6-c9d56c951eeb", "metadata": {}, "outputs": [], @@ -520,7 +860,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 27, "id": "f52f4640-e190-413e-8e01-d67492408f97", "metadata": {}, "outputs": [], @@ -531,7 +871,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 28, "id": "e2179934-6ae0-4d58-ae2c-d82f90d48074", "metadata": {}, "outputs": [ @@ -558,7 +898,7 @@ " 2.0530])]" ] }, - "execution_count": 23, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } @@ -569,7 +909,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 29, "id": "7fc3383b-fb1c-4daf-9844-88df7abf799d", "metadata": {}, "outputs": [], @@ -592,18 +932,18 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 30, "id": "25e9de54-a8da-46da-ba89-177a75227420", "metadata": {}, "outputs": [], "source": [ "# Initialize the MLP\n", - "mlp2 = MLP2()" + "mlp2 = MLP2().to(device)" ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 31, "id": "631116aa-e496-4125-9970-14aeb816c106", "metadata": {}, "outputs": [], @@ -615,7 +955,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 32, "id": "509d0581-5911-4f21-b0c8-b94523f66dd2", "metadata": { "scrolled": true, @@ -705,6 +1045,7 @@ "\n", " # Get and prepare inputs\n", " a,b,c,d,e,f,g,h,targets = data\n", + " a,b,c,d,e,f,g,h,targets = a.to(device),b.to(device),c.to(device),d.to(device),e.to(device),f.to(device),g.to(device),h.to(device),targets.to(device)\n", " targets = targets.reshape((targets.shape[0], 1))\n", "\n", " # Zero the gradients\n", @@ -738,28 +1079,54 @@ "id": "5029a35d-8fbd-4a11-b3b0-55bcc0a072dd", "metadata": {}, "source": [ - "### Save Model" + "### Save Model State Dict" ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 33, "id": "ca720ac4-8b4e-489b-844f-d54dd0659755", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved PyTorch Model State to housing_model2.pt\n" + ] + } + ], + "source": [ + "torch.save(mlp2.state_dict(), \"housing_model2.pt\")\n", + "print(\"Saved PyTorch Model State to housing_model2.pt\")" + ] + }, + { + "cell_type": "markdown", + "id": "7f677429", + "metadata": {}, "source": [ - "torch.save(mlp2, \"housing_model2.pt\")" + "### Save Model as TorchScript" ] }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 34, "id": "cdcced78-62ee-45fa-b334-6f73a2b21d32", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved TorchScript Model to ts_housing_model2.pt\n" + ] + } + ], "source": [ "scripted = torch.jit.script(mlp2)\n", - "scripted.save(\"housing_model2.ts\")" + "scripted.save(\"ts_housing_model2.pt\")\n", + "print(\"Saved TorchScript Model to ts_housing_model2.pt\")" ] }, { @@ -767,32 +1134,45 @@ "id": "8ecb33c2-2e3f-487c-8b12-c4e8f13a67a2", "metadata": {}, "source": [ - "### Load and Test Model" + "### Load and Test from Model State" ] }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 35, "id": "c54b12f2-9981-477b-8c21-a652a1736fc9", "metadata": {}, "outputs": [], "source": [ - "a,b,c,d,e,f,g,h,targets = next(iter(trainloader2))" + "a,b,c,d,e,f,g,h,targets = next(iter(trainloader2))\n", + "a,b,c,d,e,f,g,h,targets = a.to(device), b.to(device), c.to(device), d.to(device), e.to(device), f.to(device), g.to(device), h.to(device), targets.to(device)" ] }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 36, "id": "31b2fa69-9a8a-4409-8652-23c547536e50", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "loaded_mlp2 = torch.load(\"housing_model2.pt\")" + "loaded_mlp2 = MLP2().to(device)\n", + "loaded_mlp2.load_state_dict(torch.load(\"housing_model2.pt\", weights_only=True))" ] }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 37, "id": "80a21d52-ea98-4c74-98e8-1e088cdfa742", "metadata": {}, "outputs": [ @@ -808,10 +1188,10 @@ " [1.4593],\n", " [3.2933],\n", " [2.9263],\n", - " [1.4790]], grad_fn=)" + " [1.4790]], device='cuda:0', grad_fn=)" ] }, - "execution_count": 32, + "execution_count": 37, "metadata": {}, "output_type": "execute_result" } @@ -822,7 +1202,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 38, "id": "90d29fb0-5923-4684-8aa6-62618e8f1ef6", "metadata": {}, "outputs": [ @@ -838,19 +1218,27 @@ "print(signature(loaded_mlp2.forward))" ] }, + { + "cell_type": "markdown", + "id": "de84bc12", + "metadata": {}, + "source": [ + "### Load and Test from TorchScript" + ] + }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 39, "id": "165772b2-8277-4b6e-a178-c99ea2a031fa", "metadata": {}, "outputs": [], "source": [ - "scripted_mlp2 = torch.jit.load(\"housing_model2.ts\")" + "scripted_mlp2 = torch.jit.load(\"ts_housing_model2.pt\")" ] }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 40, "id": "e53d927e-fa6d-419d-b570-8ca9b0756812", "metadata": {}, "outputs": [ @@ -866,10 +1254,10 @@ " [1.4593],\n", " [3.2933],\n", " [2.9263],\n", - " [1.4790]], grad_fn=)" + " [1.4790]], device='cuda:0', grad_fn=)" ] }, - "execution_count": 35, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" } @@ -896,7 +1284,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 41, "id": "cf35da14-61a3-4e7b-9d4f-086bf5e931b3", "metadata": {}, "outputs": [], @@ -906,7 +1294,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 42, "id": "95148019-ea95-40e5-a529-fcdb9a06f928", "metadata": {}, "outputs": [], @@ -916,7 +1304,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 43, "id": "f82d957c-6747-4408-aac8-45305afbfe5e", "metadata": {}, "outputs": [ @@ -1079,8 +1467,8 @@ "" ], "text/plain": [ - " MedInc HouseAge AveRooms AveBedrms Population AveOccup \n", - "0 2.344766 0.982143 0.628559 -0.153758 -0.974429 -0.049597 \\\n", + " MedInc HouseAge AveRooms AveBedrms Population AveOccup \\\n", + "0 2.344766 0.982143 0.628559 -0.153758 -0.974429 -0.049597 \n", "1 2.332238 -0.607019 0.327041 -0.263336 0.861439 -0.092512 \n", "2 1.782699 1.856182 1.155620 -0.049016 -0.820777 -0.025843 \n", "3 0.932967 1.856182 0.156966 -0.049833 -0.766028 -0.050329 \n", @@ -1108,7 +1496,7 @@ "[20640 rows x 8 columns]" ] }, - "execution_count": 38, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } @@ -1120,7 +1508,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 44, "id": "5ba338cd-76d2-46bd-baf5-7d18a339a449", "metadata": {}, "outputs": [], @@ -1130,7 +1518,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 45, "id": "224b5036-d2ed-4edf-975f-66127862343d", "metadata": {}, "outputs": [ @@ -1140,7 +1528,7 @@ "dict_keys(['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup', 'Latitude', 'Longitude'])" ] }, - "execution_count": 40, + "execution_count": 45, "metadata": {}, "output_type": "execute_result" } @@ -1151,7 +1539,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 46, "id": "0b32ea98-a7f1-4011-a067-700377f1717f", "metadata": {}, "outputs": [ @@ -1169,7 +1557,7 @@ "dtype: object" ] }, - "execution_count": 41, + "execution_count": 46, "metadata": {}, "output_type": "execute_result" } @@ -1180,7 +1568,19 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 47, + "id": "e630236c", + "metadata": {}, + "outputs": [], + "source": [ + "from pyspark.sql.types import *\n", + "from pyspark.sql import SparkSession\n", + "from pyspark import SparkConf" + ] + }, + { + "cell_type": "code", + "execution_count": 48, "id": "6388cce9-6469-4f5a-898a-1a0b74eec438", "metadata": {}, "outputs": [ @@ -1188,52 +1588,86 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 0:> (0 + 1) / 1]\r" + "24/10/08 00:36:22 WARN Utils: Your hostname, cb4ae00-lcedt resolves to a loopback address: 127.0.1.1; using 10.110.47.100 instead (on interface eno1)\n", + "24/10/08 00:36:22 WARN Utils: Set SPARK_LOCAL_IP if you need to bind to another address\n", + "Setting default log level to \"WARN\".\n", + "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", + "24/10/08 00:36:22 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n" ] - }, + } + ], + "source": [ + "import os\n", + "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", + "\n", + "conf = SparkConf()\n", + "if 'spark' not in globals():\n", + " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", + " import socket\n", + " hostname = socket.gethostname()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", + "conf.set(\"spark.task.maxFailures\", \"1\")\n", + "conf.set(\"spark.driver.memory\", \"8g\")\n", + "conf.set(\"spark.executor.memory\", \"8g\")\n", + "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + "conf.set(\"spark.python.worker.reuse\", \"true\")\n", + "# Create Spark Session\n", + "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", + "sc = spark.sparkContext" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "881afee9", + "metadata": {}, + "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "+------------+----------+------------+------------+-----------+------------+---------+----------+\n", - "| MedInc| HouseAge| AveRooms| AveBedrms| Population| AveOccup| Latitude| Longitude|\n", - "+------------+----------+------------+------------+-----------+------------+---------+----------+\n", - "| 2.344766| 0.9821427| 0.62855947| -0.15375753|-0.97442853|-0.049596533|1.0525488|-1.3278369|\n", - "| 2.3322382|-0.6070189| 0.32704142| -0.26333576| 0.8614389| -0.09251223|1.0431849|-1.3228445|\n", - "| 1.7826993| 1.8561815| 1.1556205|-0.049016476|-0.82077736|-0.025842525| 1.038502|-1.3328254|\n", - "| 0.93296736| 1.8561815| 0.15696616|-0.049833003|-0.76602805|-0.050329294| 1.038502|-1.3378178|\n", - "|-0.012881001| 1.8561815| 0.34471077|-0.032905966| -0.7598467| -0.08561575| 1.038502|-1.3378178|\n", - "| 0.087446585| 1.8561815| -0.26972958| 0.014669393|-0.89407074|-0.089618415| 1.038502|-1.3378178|\n", - "| -0.11136628| 1.8561815| -0.20091766| -0.30663314| -0.2927116| -0.09072491|1.0338209|-1.3378178|\n", - "| -0.39513668| 1.8561815| -0.255232|-0.073541574|-0.23707923| -0.12347647|1.0338209|-1.3378178|\n", - "| -0.94235915| 1.0616008| -0.45870265| 0.04425391|-0.19380963| -0.10049919|1.0338209|-1.3428102|\n", - "| -0.09446957| 1.8561815| -0.18528317| -0.22468716| 0.1108437| -0.08650142|1.0338209|-1.3378178|\n", - "| -0.35139465| 1.8561815| 0.019648364|-0.036026947|-0.45519334| -0.07769971| 1.038502|-1.3428102|\n", - "| -0.31591678| 1.8561815| -0.26535577| -0.15225175| 0.06934021| -0.09836594| 1.038502|-1.3428102|\n", - "| -0.41882363| 1.8561815|-0.042985205| -0.17694615|-0.28917935| -0.06975886| 1.038502|-1.3428102|\n", - "| -0.6301118| 1.8561815| -0.5775806| 0.002165105| -0.9541183| -0.10474847|1.0338209|-1.3428102|\n", - "| -1.0285273| 1.8561815| -0.471319| -0.1835785|-0.18851131| -0.10743675| 1.038502|-1.3428102|\n", - "| -0.9188827| 1.6972654| -0.4795964| -0.05213217|-0.64328367|-0.041451186| 1.038502|-1.3428102|\n", - "| -0.576737| 1.8561815| 0.20636784| -0.10199789| -0.5585106| -0.06498151| 1.038502|-1.3477987|\n", - "| -0.92140937| 1.8561815| -0.5562374| -0.27364123| -0.6865533| -0.08974189| 1.038502|-1.3477987|\n", - "| -0.98936474| 1.6972654|-0.034486752|-0.022697322| -0.3845491| -0.06815911|1.0338209|-1.3428102|\n", - "| -0.6671161| 1.8561815| 0.014734507|-0.027513746| -0.649465|-0.054070402|1.0338209|-1.3477987|\n", - "+------------+----------+------------+------------+-----------+------------+---------+----------+\n", - "only showing top 20 rows\n", - "\n" + "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/pyspark/sql/pandas/serializers.py:224: DeprecationWarning: is_categorical_dtype is deprecated and will be removed in a future version. Use isinstance(dtype, pd.CategoricalDtype) instead\n", + " if is_categorical_dtype(series.dtype):\n", + "\n", + " \r" ] }, { - "name": "stderr", + "name": "stdout", "output_type": "stream", "text": [ - " \r" + "+------------+------------+-----------+------------+-----------+------------+----------+------------+\n", + "| MedInc| HouseAge| AveRooms| AveBedrms| Population| AveOccup| Latitude| Longitude|\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+\n", + "| 0.20909257| -1.1632254| 0.38946992| 0.04609274| -0.9806099| -0.07099328|0.61245227|-0.020113053|\n", + "|-0.098627955| 0.34647804| 0.27216315| -0.0129226| -0.6953838| -0.05380849| 1.0665938| -1.2479742|\n", + "| -0.66006273| 1.0616008|-0.55292207| -0.48945764|-0.13641118| 0.028952759| 1.1040496| -1.3827378|\n", + "| 0.08218294| 0.5848523|-0.13912922| -0.14707813|-0.19116047| -0.07136432|0.96827507| -1.3028787|\n", + "| 0.0784456| -1.4810578| 0.57265776| 0.32067496| 1.0345173|-0.024157424| 1.4411427| -0.52423614|\n", + "| -0.82318723| -0.36864465| 0.07829511| -0.1808107|-0.67242444|-0.061470542| 1.9374212| -1.0083897|\n", + "| 0.59671736| 0.5848523| 0.19346413| -0.1371872|-0.19645879| 0.009964322|0.96827507| -1.2928978|\n", + "| -0.9612035| -1.5605159|-0.56329846| 0.027148023|-0.71127874| -0.08471591| 0.5328614| -0.13990337|\n", + "| -0.74344087| -1.2426835| 0.27282518| 0.4037246| -0.9841421| -0.05610115| 1.2257773| -0.42940006|\n", + "| 0.9784464| -0.2891866| 0.24374022| -0.24670053| 0.28922042| -0.01102468| 1.1087307| -1.2280084|\n", + "| -0.5070446| -1.0043093|-0.78254056|0.0122275995| 2.8465424|-0.060435444| 0.8980464| -1.2080427|\n", + "| -0.18690155| 1.2205169|0.015323491| 0.12183313|-0.41015765| 0.04452552| 1.010412| -1.3228445|\n", + "| -1.2551856| 1.6178073| -0.3341509|-0.060125165| -0.7554314| -0.08777025| 1.0291398| -1.3477987|\n", + "| 4.9607058| -1.9578062| 1.4854684| -0.03948475| 2.1833694|0.0029250523| 1.024457| -1.1581304|\n", + "| 0.73652315| -1.6399739| 0.7913185| -0.05238397| 1.67738| 0.01944797| 1.0993668| -1.1331724|\n", + "| -0.505834| 0.18756187|-0.47093546| -0.24297306|-0.60619545| -0.10791535| 0.977639| -1.2879055|\n", + "| -0.88477343|-0.050812364| -0.6318951| -0.15244243| -0.5258376| -0.15618815| 0.9823201| -1.2879055|\n", + "| -0.42840376| 0.9821427| -0.2266495| -0.36083496| -0.6883194| -0.08552282| 0.5328614| -0.12493005|\n", + "| 0.9369153| -1.4810578| 0.6722208|-0.121177554| 0.3996021| 0.01291408| 1.1040496| -1.1082181|\n", + "| -0.80702734| -0.92485124|-0.26602685| -0.1560743| 1.4398388| -0.09314839|0.55627036| -0.09498342|\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+\n", + "only showing top 20 rows\n", + "\n" ] } ], "source": [ - "from pyspark.sql.types import *\n", - "\n", "# Spark is somehow auto-converting Pandas float32 to DoubleType(), so forcing FloatType()\n", "schema = StructType([\n", "StructField(\"MedInc\",FloatType(),True),\n", @@ -1246,13 +1680,13 @@ "StructField(\"Longitude\",FloatType(),True)\n", "])\n", "\n", - "df = spark.createDataFrame(pdf, schema=schema)\n", + "df = spark.createDataFrame(pdf, schema=schema).repartition(8)\n", "df.show(truncate=12)" ] }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 50, "id": "7b33d367-fbf9-4918-b755-5447125547c4", "metadata": {}, "outputs": [ @@ -1262,7 +1696,7 @@ "StructType([StructField('MedInc', FloatType(), True), StructField('HouseAge', FloatType(), True), StructField('AveRooms', FloatType(), True), StructField('AveBedrms', FloatType(), True), StructField('Population', FloatType(), True), StructField('AveOccup', FloatType(), True), StructField('Latitude', FloatType(), True), StructField('Longitude', FloatType(), True)])" ] }, - "execution_count": 43, + "execution_count": 50, "metadata": {}, "output_type": "execute_result" } @@ -1281,18 +1715,10 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 51, "id": "751bff7a-b687-4184-b3fa-b5f5b46ef5d1", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], + "outputs": [], "source": [ "df.write.mode(\"overwrite\").parquet(\"california_housing\")" ] @@ -1308,11 +1734,12 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 52, "id": "986d1a97-ea84-4707-b94a-78498780c47c", "metadata": {}, "outputs": [], "source": [ + "import os\n", "from pyspark.ml.functions import predict_batch_udf\n", "from pyspark.sql.functions import array, struct, col\n", "from pyspark.sql.types import ArrayType, FloatType" @@ -1320,7 +1747,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 53, "id": "1e40c266-24de-454d-a776-f3716ba50e90", "metadata": {}, "outputs": [], @@ -1330,7 +1757,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 54, "id": "ac802fb6-f159-4776-b55d-b9c421e8c57e", "metadata": {}, "outputs": [ @@ -1347,7 +1774,7 @@ " 'Longitude']" ] }, - "execution_count": 47, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } @@ -1359,7 +1786,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 55, "id": "4b8de001-e791-4a91-bd6f-c80bdf1c4472", "metadata": {}, "outputs": [ @@ -1367,30 +1794,30 @@ "name": "stdout", "output_type": "stream", "text": [ - "+-----------+-----------+------------+-------------+------------+-------------+----------+------------+\n", - "| MedInc| HouseAge| AveRooms| AveBedrms| Population| AveOccup| Latitude| Longitude|\n", - "+-----------+-----------+------------+-------------+------------+-------------+----------+------------+\n", - "| -1.669445|-0.20972852| -1.1155425| -0.17418891| 0.2070965| -0.13437383| 0.5094524| -0.08001011|\n", - "| -0.8564016| -1.5605159| -0.53141737| -0.02190494| -0.66006166| -0.12997007| 0.5141335| -0.08001011|\n", - "| 0.73173314|-0.76593506| 0.67250663| -0.10979619| 0.14175056| -0.02296524| 0.5141335| -0.07002536|\n", - "|-0.44887984| -1.719432| 0.14690235| -0.009905009| -0.06664997| 0.01090982|0.50476956|-0.075017735|\n", - "|-0.96920437| -1.0837674| 0.058284093| 0.07351444| -0.20793848| -0.011342554| 0.5094524| -0.08001011|\n", - "| -1.0906925| 0.26701993| -0.72011936| -0.2243873| -0.6574125| 0.021105729|0.49072453| -0.08001011|\n", - "|-0.90240705| 0.5848523| 0.24784403| 0.08091579| -0.5205393| 0.043980353| 0.4954056|-0.060044423|\n", - "| -1.0712692|0.028645715| -0.38059494| 0.062626354| -0.5205393| -0.005065064|0.49072453| -0.09498342|\n", - "|0.026544658| -0.686477| 0.06193017| -0.20868859| 0.03401808| 0.017589226| 0.4766795|-0.050059676|\n", - "|-0.24211854| 0.34647804| 0.2122066| -0.11910806| -0.71127874| 0.047426607|0.47199664|-0.030093992|\n", - "| -1.1632799| -1.7988901| -0.3091| -0.16322336| -0.0719483| 0.01691941|0.46263272|-0.040078737|\n", - "| -0.4509853| 0.8232265| -0.10236703| -0.053904843| -0.6953838| -0.03862959|0.46731555| -0.05505205|\n", - "| -0.5102555|-0.76593506| 0.26753396| 0.023170268| -0.14877392|-0.0061120046| 0.4766795|-0.084998675|\n", - "| -1.1635431| 0.18756187| -0.59673625| -0.023986263| -0.71481097| -0.014560648|0.46263272| -0.05505205|\n", - "|-0.15400293| 0.5053942| 0.33031902|-0.0012220128| -0.35275918| 0.0010038698|0.46263272| -0.08001011|\n", - "|-0.27733323| 0.18756187|-0.010031368| -0.13782738| -0.32450148| 0.059288267| 0.4485877| -0.08001011|\n", - "| -0.8956694| 0.18756187|-0.043201063| -0.12283955|-0.087843254| 0.011250444|0.49072453| -0.11494911|\n", - "|-0.57936895|-0.13027044| 0.15416715| 0.08602174| -0.6353362| 0.026508931| 0.4766795| -0.10496436|\n", - "| -0.8548752| 0.1081038|-0.061331607| -0.26316243| -0.36865416| 0.0066948985|0.47199664| -0.12493005|\n", - "| -1.1061679| 0.42593613| 0.053027753| -0.12104499| -0.2132368| -0.015556259| 0.4766795| -0.11494911|\n", - "+-----------+-----------+------------+-------------+------------+-------------+----------+------------+\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+\n", + "| MedInc| HouseAge| AveRooms| AveBedrms| Population| AveOccup| Latitude| Longitude|\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+\n", + "| 0.20909257| -1.1632254| 0.38946992| 0.04609274| -0.9806099| -0.07099328|0.61245227|-0.020113053|\n", + "|-0.098627955| 0.34647804| 0.27216315| -0.0129226| -0.6953838| -0.05380849| 1.0665938| -1.2479742|\n", + "| -0.66006273| 1.0616008|-0.55292207| -0.48945764|-0.13641118| 0.028952759| 1.1040496| -1.3827378|\n", + "| 0.08218294| 0.5848523|-0.13912922| -0.14707813|-0.19116047| -0.07136432|0.96827507| -1.3028787|\n", + "| 0.0784456| -1.4810578| 0.57265776| 0.32067496| 1.0345173|-0.024157424| 1.4411427| -0.52423614|\n", + "| -0.82318723| -0.36864465| 0.07829511| -0.1808107|-0.67242444|-0.061470542| 1.9374212| -1.0083897|\n", + "| 0.59671736| 0.5848523| 0.19346413| -0.1371872|-0.19645879| 0.009964322|0.96827507| -1.2928978|\n", + "| -0.9612035| -1.5605159|-0.56329846| 0.027148023|-0.71127874| -0.08471591| 0.5328614| -0.13990337|\n", + "| -0.74344087| -1.2426835| 0.27282518| 0.4037246| -0.9841421| -0.05610115| 1.2257773| -0.42940006|\n", + "| 0.9784464| -0.2891866| 0.24374022| -0.24670053| 0.28922042| -0.01102468| 1.1087307| -1.2280084|\n", + "| -0.5070446| -1.0043093|-0.78254056|0.0122275995| 2.8465424|-0.060435444| 0.8980464| -1.2080427|\n", + "| -0.18690155| 1.2205169|0.015323491| 0.12183313|-0.41015765| 0.04452552| 1.010412| -1.3228445|\n", + "| -1.2551856| 1.6178073| -0.3341509|-0.060125165| -0.7554314| -0.08777025| 1.0291398| -1.3477987|\n", + "| 4.9607058| -1.9578062| 1.4854684| -0.03948475| 2.1833694|0.0029250523| 1.024457| -1.1581304|\n", + "| 0.73652315| -1.6399739| 0.7913185| -0.05238397| 1.67738| 0.01944797| 1.0993668| -1.1331724|\n", + "| -0.505834| 0.18756187|-0.47093546| -0.24297306|-0.60619545| -0.10791535| 0.977639| -1.2879055|\n", + "| -0.88477343|-0.050812364| -0.6318951| -0.15244243| -0.5258376| -0.15618815| 0.9823201| -1.2879055|\n", + "| -0.42840376| 0.9821427| -0.2266495| -0.36083496| -0.6883194| -0.08552282| 0.5328614| -0.12493005|\n", + "| 0.9369153| -1.4810578| 0.6722208|-0.121177554| 0.3996021| 0.01291408| 1.1040496| -1.1082181|\n", + "| -0.80702734| -0.92485124|-0.26602685| -0.1560743| 1.4398388| -0.09314839|0.55627036| -0.09498342|\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+\n", "only showing top 20 rows\n", "\n" ] @@ -1405,46 +1832,75 @@ "id": "650dda22-31b7-419b-96d4-387a036f3b07", "metadata": {}, "source": [ - "### Using TorchScript Model (single input)" + "### Using TensorRT Model (single input)" ] }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 56, "id": "3d608e2f-66a8-44b5-9cde-5f7837bf4247", "metadata": {}, "outputs": [], "source": [ "# get absolute path to model\n", - "model_dir = \"{}/housing_model.ts\".format(os.getcwd())" + "model_dir = \"{}/housing_model.pt\".format(os.getcwd())" ] }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 57, "id": "a2f45f5d-c941-4197-a274-1eec2af3fca4", "metadata": {}, "outputs": [], "source": [ "def predict_batch_fn():\n", " import torch\n", + " import torch_tensorrt as trt\n", + "\n", " device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", - " print(\"Using {} device\".format(device))\n", - " \n", - " scripted_mlp = torch.jit.load(model_dir)\n", - " scripted_mlp.to(device)\n", + " if device != \"cuda\":\n", + " raise ValueError(\"This function uses the TensorRT model which requires a GPU device\")\n", + "\n", + " # Define model\n", + " class MLP(nn.Module):\n", + " def __init__(self):\n", + " super().__init__()\n", + " self.layers = nn.Sequential(\n", + " nn.Linear(8, 64),\n", + " nn.ReLU(),\n", + " nn.Linear(64, 32),\n", + " nn.ReLU(),\n", + " nn.Linear(32, 1)\n", + " )\n", + "\n", + " def forward(self, x):\n", + " return self.layers(x)\n", + "\n", + " model = MLP().to(device)\n", + " model.load_state_dict(torch.load(model_dir, weights_only=True))\n", + "\n", + " # Preparing the inputs for dynamic batch sizing.\n", + " inputs = [trt.Input(min_shape=(20, 8), \n", + " opt_shape=(50, 8), \n", + " max_shape=(64, 8), \n", + " dtype=torch.float32)]\n", + "\n", + " # Trace the computation graph and compile to produce an optimized module\n", + " trt_gm = trt.compile(model, ir=\"dynamo\", inputs=inputs)\n", " \n", " def predict(inputs):\n", - " torch_inputs = torch.from_numpy(inputs).to(device)\n", - " outputs = scripted_mlp(torch_inputs) # .flatten()\n", - " return outputs.detach().numpy()\n", + " stream = torch.cuda.Stream()\n", + " with torch.no_grad(), torch.cuda.stream(stream), trt.logging.errors():\n", + " torch_inputs = torch.from_numpy(inputs).to(device)\n", + " outputs = trt_gm(torch_inputs) # .flatten()\n", + " return outputs.detach().cpu().numpy()\n", "\n", " return predict" ] }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 59, "id": "220a00a4-e842-4f5d-a4b3-7693d09e2d31", "metadata": {}, "outputs": [], @@ -1457,7 +1913,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 60, "id": "0f3bf287-8ffc-4456-8772-e97c418d6aee", "metadata": {}, "outputs": [ @@ -1472,8 +1928,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 200 ms, sys: 6.02 ms, total: 206 ms\n", - "Wall time: 3.24 s\n" + "CPU times: user 148 ms, sys: 17.9 ms, total: 166 ms\n", + "Wall time: 8.28 s\n" ] } ], @@ -1485,7 +1941,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 61, "id": "6cd23b71-296d-4ce7-b56c-567cc2eec79c", "metadata": { "tags": [] @@ -1495,8 +1951,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 48.7 ms, sys: 2.68 ms, total: 51.4 ms\n", - "Wall time: 540 ms\n" + "CPU times: user 31.2 ms, sys: 5.84 ms, total: 37.1 ms\n", + "Wall time: 257 ms\n" ] } ], @@ -1508,7 +1964,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 62, "id": "13c52980-fc55-4e81-ae54-b476b98f11b1", "metadata": {}, "outputs": [], @@ -1520,7 +1976,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 63, "id": "764a40d8-25f7-425c-ba03-fe8c45f4b063", "metadata": {}, "outputs": [ @@ -1528,30 +1984,30 @@ "name": "stdout", "output_type": "stream", "text": [ - "+-----------+-----------+------------+-------------+------------+-------------+----------+------------+----------+\n", - "| MedInc| HouseAge| AveRooms| AveBedrms| Population| AveOccup| Latitude| Longitude| preds|\n", - "+-----------+-----------+------------+-------------+------------+-------------+----------+------------+----------+\n", - "| -1.669445|-0.20972852| -1.1155425| -0.17418891| 0.2070965| -0.13437383| 0.5094524| -0.08001011| 0.8521974|\n", - "| -0.8564016| -1.5605159| -0.53141737| -0.02190494| -0.66006166| -0.12997007| 0.5141335| -0.08001011| 1.1964239|\n", - "| 0.73173314|-0.76593506| 0.67250663| -0.10979619| 0.14175056| -0.02296524| 0.5141335| -0.07002536| 1.7371099|\n", - "|-0.44887984| -1.719432| 0.14690235| -0.009905009| -0.06664997| 0.01090982|0.50476956|-0.075017735| 1.0491724|\n", - "|-0.96920437| -1.0837674| 0.058284093| 0.07351444| -0.20793848| -0.011342554| 0.5094524| -0.08001011| 0.8659589|\n", - "| -1.0906925| 0.26701993| -0.72011936| -0.2243873| -0.6574125| 0.021105729|0.49072453| -0.08001011|0.70745003|\n", - "|-0.90240705| 0.5848523| 0.24784403| 0.08091579| -0.5205393| 0.043980353| 0.4954056|-0.060044423| 0.5371985|\n", - "| -1.0712692|0.028645715| -0.38059494| 0.062626354| -0.5205393| -0.005065064|0.49072453| -0.09498342| 0.8064569|\n", - "|0.026544658| -0.686477| 0.06193017| -0.20868859| 0.03401808| 0.017589226| 0.4766795|-0.050059676| 1.1329681|\n", - "|-0.24211854| 0.34647804| 0.2122066| -0.11910806| -0.71127874| 0.047426607|0.47199664|-0.030093992|0.87097365|\n", - "| -1.1632799| -1.7988901| -0.3091| -0.16322336| -0.0719483| 0.01691941|0.46263272|-0.040078737| 0.6880104|\n", - "| -0.4509853| 0.8232265| -0.10236703| -0.053904843| -0.6953838| -0.03862959|0.46731555| -0.05505205| 0.9974648|\n", - "| -0.5102555|-0.76593506| 0.26753396| 0.023170268| -0.14877392|-0.0061120046| 0.4766795|-0.084998675| 1.0234879|\n", - "| -1.1635431| 0.18756187| -0.59673625| -0.023986263| -0.71481097| -0.014560648|0.46263272| -0.05505205|0.82353294|\n", - "|-0.15400293| 0.5053942| 0.33031902|-0.0012220128| -0.35275918| 0.0010038698|0.46263272| -0.08001011| 1.1798486|\n", - "|-0.27733323| 0.18756187|-0.010031368| -0.13782738| -0.32450148| 0.059288267| 0.4485877| -0.08001011| 0.8976056|\n", - "| -0.8956694| 0.18756187|-0.043201063| -0.12283955|-0.087843254| 0.011250444|0.49072453| -0.11494911|0.61913794|\n", - "|-0.57936895|-0.13027044| 0.15416715| 0.08602174| -0.6353362| 0.026508931| 0.4766795| -0.10496436| 0.8908371|\n", - "| -0.8548752| 0.1081038|-0.061331607| -0.26316243| -0.36865416| 0.0066948985|0.47199664| -0.12493005| 0.6539954|\n", - "| -1.1061679| 0.42593613| 0.053027753| -0.12104499| -0.2132368| -0.015556259| 0.4766795| -0.11494911|0.54294837|\n", - "+-----------+-----------+------------+-------------+------------+-------------+----------+------------+----------+\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+----------+\n", + "| MedInc| HouseAge| AveRooms| AveBedrms| Population| AveOccup| Latitude| Longitude| preds|\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+----------+\n", + "| 0.20909257| -1.1632254| 0.38946992| 0.04609274| -0.9806099| -0.07099328|0.61245227|-0.020113053| 1.3980268|\n", + "|-0.098627955| 0.34647804| 0.27216315| -0.0129226| -0.6953838| -0.05380849| 1.0665938| -1.2479742| 1.7447104|\n", + "| -0.66006273| 1.0616008|-0.55292207| -0.48945764|-0.13641118| 0.028952759| 1.1040496| -1.3827378| 1.439564|\n", + "| 0.08218294| 0.5848523|-0.13912922| -0.14707813|-0.19116047| -0.07136432|0.96827507| -1.3028787| 2.4199378|\n", + "| 0.0784456| -1.4810578| 0.57265776| 0.32067496| 1.0345173|-0.024157424| 1.4411427| -0.52423614| 1.2448893|\n", + "| -0.82318723| -0.36864465| 0.07829511| -0.1808107|-0.67242444|-0.061470542| 1.9374212| -1.0083897|0.68910843|\n", + "| 0.59671736| 0.5848523| 0.19346413| -0.1371872|-0.19645879| 0.009964322|0.96827507| -1.2928978| 2.656445|\n", + "| -0.9612035| -1.5605159|-0.56329846| 0.027148023|-0.71127874| -0.08471591| 0.5328614| -0.13990337| 1.13419|\n", + "| -0.74344087| -1.2426835| 0.27282518| 0.4037246| -0.9841421| -0.05610115| 1.2257773| -0.42940006| 1.1380601|\n", + "| 0.9784464| -0.2891866| 0.24374022| -0.24670053| 0.28922042| -0.01102468| 1.1087307| -1.2280084| 2.5711632|\n", + "| -0.5070446| -1.0043093|-0.78254056|0.0122275995| 2.8465424|-0.060435444| 0.8980464| -1.2080427| 1.8561494|\n", + "| -0.18690155| 1.2205169|0.015323491| 0.12183313|-0.41015765| 0.04452552| 1.010412| -1.3228445| 1.8643656|\n", + "| -1.2551856| 1.6178073| -0.3341509|-0.060125165| -0.7554314| -0.08777025| 1.0291398| -1.3477987| 1.2487215|\n", + "| 4.9607058| -1.9578062| 1.4854684| -0.03948475| 2.1833694|0.0029250523| 1.024457| -1.1581304| 5.595224|\n", + "| 0.73652315| -1.6399739| 0.7913185| -0.05238397| 1.67738| 0.01944797| 1.0993668| -1.1331724| 2.069084|\n", + "| -0.505834| 0.18756187|-0.47093546| -0.24297306|-0.60619545| -0.10791535| 0.977639| -1.2879055| 1.7858529|\n", + "| -0.88477343|-0.050812364| -0.6318951| -0.15244243| -0.5258376| -0.15618815| 0.9823201| -1.2879055| 1.6675146|\n", + "| -0.42840376| 0.9821427| -0.2266495| -0.36083496| -0.6883194| -0.08552282| 0.5328614| -0.12493005| 1.01702|\n", + "| 0.9369153| -1.4810578| 0.6722208|-0.121177554| 0.3996021| 0.01291408| 1.1040496| -1.1082181| 2.1314554|\n", + "| -0.80702734| -0.92485124|-0.26602685| -0.1560743| 1.4398388| -0.09314839|0.55627036| -0.09498342| 0.8631196|\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+----------+\n", "only showing top 20 rows\n", "\n" ] @@ -1571,7 +2027,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 64, "id": "1a69a9d2-5c7f-4e71-bb65-ae51927ccacf", "metadata": {}, "outputs": [], @@ -1583,7 +2039,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 65, "id": "7214e2ac-fd2c-473e-a9c7-a65488570b5c", "metadata": {}, "outputs": [], @@ -1593,7 +2049,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 66, "id": "5ee170b9-8ba6-4681-a10c-4cea71c1be15", "metadata": {}, "outputs": [ @@ -1610,7 +2066,7 @@ " 'Longitude']" ] }, - "execution_count": 58, + "execution_count": 66, "metadata": {}, "output_type": "execute_result" } @@ -1622,30 +2078,31 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 67, "id": "0b7af043-5f20-49c7-bed6-39a9d13988e4", "metadata": {}, "outputs": [], "source": [ "# get absolute path to model\n", - "model2_dir = \"{}/housing_model2.ts\".format(os.getcwd())" + "model2_dir = \"{}/ts_housing_model2.pt\".format(os.getcwd())" ] }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 68, "id": "104b2378-e191-4560-9a2e-276b8dcf0f2b", "metadata": {}, "outputs": [], "source": [ "def predict_batch_fn():\n", " import torch\n", + "\n", " device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", - " print(\"Using {} device\".format(device))\n", " scripted_mlp = torch.jit.load(model2_dir)\n", " scripted_mlp.to(device)\n", " \n", " def predict(inc, age, rms, bdrms, pop, occ, lat, lon):\n", + " # print input shape\n", " outputs = scripted_mlp(\n", " torch.from_numpy(inc).to(device),\n", " torch.from_numpy(age).to(device),\n", @@ -1656,14 +2113,14 @@ " torch.from_numpy(lat).to(device),\n", " torch.from_numpy(lon).to(device),\n", " )\n", - " return outputs.detach().numpy()\n", + " return outputs.detach().cpu().numpy()\n", "\n", " return predict" ] }, { "cell_type": "code", - "execution_count": 61, + "execution_count": 69, "id": "020056dc-f8b0-483a-88eb-7e1ff2a0fdcf", "metadata": {}, "outputs": [], @@ -1675,7 +2132,7 @@ }, { "cell_type": "code", - "execution_count": 62, + "execution_count": 70, "id": "1b73518e-04ec-49c7-bf1e-93520d94028e", "metadata": {}, "outputs": [ @@ -1683,15 +2140,22 @@ "name": "stderr", "output_type": "stream", "text": [ - " \r" + "[Stage 12:==================================================> (7 + 1) / 8]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 192 ms, sys: 4.28 ms, total: 196 ms\n", - "Wall time: 1.89 s\n" + "CPU times: user 16.7 ms, sys: 5.44 ms, total: 22.1 ms\n", + "Wall time: 1.13 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" ] } ], @@ -1704,21 +2168,7 @@ }, { "cell_type": "code", - "execution_count": 63, - "id": "2d3559d3-644f-432e-92fc-21e6339a19f2", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "# should fail with ValueError\n", - "# preds = df.withColumn(\"preds\", classify(array(*columns)))\n", - "# results = preds.collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 64, + "execution_count": 71, "id": "86b56805-a211-43cb-878d-78957b08f865", "metadata": {}, "outputs": [ @@ -1726,8 +2176,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 64.7 ms, sys: 584 µs, total: 65.3 ms\n", - "Wall time: 363 ms\n" + "CPU times: user 19.6 ms, sys: 8.68 ms, total: 28.3 ms\n", + "Wall time: 451 ms\n" ] } ], @@ -1739,7 +2189,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 72, "id": "5032b474-db92-4f04-b732-8b9d418cf211", "metadata": { "scrolled": true, @@ -1750,30 +2200,30 @@ "name": "stdout", "output_type": "stream", "text": [ - "+-----------+-----------+------------+-------------+------------+-------------+----------+------------+----------+\n", - "| MedInc| HouseAge| AveRooms| AveBedrms| Population| AveOccup| Latitude| Longitude| preds|\n", - "+-----------+-----------+------------+-------------+------------+-------------+----------+------------+----------+\n", - "| -1.669445|-0.20972852| -1.1155425| -0.17418891| 0.2070965| -0.13437383| 0.5094524| -0.08001011| 0.8521974|\n", - "| -0.8564016| -1.5605159| -0.53141737| -0.02190494| -0.66006166| -0.12997007| 0.5141335| -0.08001011| 1.1964239|\n", - "| 0.73173314|-0.76593506| 0.67250663| -0.10979619| 0.14175056| -0.02296524| 0.5141335| -0.07002536| 1.7371099|\n", - "|-0.44887984| -1.719432| 0.14690235| -0.009905009| -0.06664997| 0.01090982|0.50476956|-0.075017735| 1.0491724|\n", - "|-0.96920437| -1.0837674| 0.058284093| 0.07351444| -0.20793848| -0.011342554| 0.5094524| -0.08001011| 0.8659589|\n", - "| -1.0906925| 0.26701993| -0.72011936| -0.2243873| -0.6574125| 0.021105729|0.49072453| -0.08001011|0.70745003|\n", - "|-0.90240705| 0.5848523| 0.24784403| 0.08091579| -0.5205393| 0.043980353| 0.4954056|-0.060044423| 0.5371985|\n", - "| -1.0712692|0.028645715| -0.38059494| 0.062626354| -0.5205393| -0.005065064|0.49072453| -0.09498342| 0.8064569|\n", - "|0.026544658| -0.686477| 0.06193017| -0.20868859| 0.03401808| 0.017589226| 0.4766795|-0.050059676| 1.1329681|\n", - "|-0.24211854| 0.34647804| 0.2122066| -0.11910806| -0.71127874| 0.047426607|0.47199664|-0.030093992|0.87097365|\n", - "| -1.1632799| -1.7988901| -0.3091| -0.16322336| -0.0719483| 0.01691941|0.46263272|-0.040078737| 0.6880104|\n", - "| -0.4509853| 0.8232265| -0.10236703| -0.053904843| -0.6953838| -0.03862959|0.46731555| -0.05505205| 0.9974648|\n", - "| -0.5102555|-0.76593506| 0.26753396| 0.023170268| -0.14877392|-0.0061120046| 0.4766795|-0.084998675| 1.0234879|\n", - "| -1.1635431| 0.18756187| -0.59673625| -0.023986263| -0.71481097| -0.014560648|0.46263272| -0.05505205|0.82353294|\n", - "|-0.15400293| 0.5053942| 0.33031902|-0.0012220128| -0.35275918| 0.0010038698|0.46263272| -0.08001011| 1.1798486|\n", - "|-0.27733323| 0.18756187|-0.010031368| -0.13782738| -0.32450148| 0.059288267| 0.4485877| -0.08001011| 0.8976056|\n", - "| -0.8956694| 0.18756187|-0.043201063| -0.12283955|-0.087843254| 0.011250444|0.49072453| -0.11494911|0.61913794|\n", - "|-0.57936895|-0.13027044| 0.15416715| 0.08602174| -0.6353362| 0.026508931| 0.4766795| -0.10496436| 0.8908371|\n", - "| -0.8548752| 0.1081038|-0.061331607| -0.26316243| -0.36865416| 0.0066948985|0.47199664| -0.12493005| 0.6539954|\n", - "| -1.1061679| 0.42593613| 0.053027753| -0.12104499| -0.2132368| -0.015556259| 0.4766795| -0.11494911|0.54294837|\n", - "+-----------+-----------+------------+-------------+------------+-------------+----------+------------+----------+\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+----------+\n", + "| MedInc| HouseAge| AveRooms| AveBedrms| Population| AveOccup| Latitude| Longitude| preds|\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+----------+\n", + "| 0.20909257| -1.1632254| 0.38946992| 0.04609274| -0.9806099| -0.07099328|0.61245227|-0.020113053| 1.3979516|\n", + "|-0.098627955| 0.34647804| 0.27216315| -0.0129226| -0.6953838| -0.05380849| 1.0665938| -1.2479742| 1.7442212|\n", + "| -0.66006273| 1.0616008|-0.55292207| -0.48945764|-0.13641118| 0.028952759| 1.1040496| -1.3827378| 1.4398992|\n", + "| 0.08218294| 0.5848523|-0.13912922| -0.14707813|-0.19116047| -0.07136432|0.96827507| -1.3028787| 2.4199052|\n", + "| 0.0784456| -1.4810578| 0.57265776| 0.32067496| 1.0345173|-0.024157424| 1.4411427| -0.52423614| 1.2446644|\n", + "| -0.82318723| -0.36864465| 0.07829511| -0.1808107|-0.67242444|-0.061470542| 1.9374212| -1.0083897| 0.6888372|\n", + "| 0.59671736| 0.5848523| 0.19346413| -0.1371872|-0.19645879| 0.009964322|0.96827507| -1.2928978| 2.6563153|\n", + "| -0.9612035| -1.5605159|-0.56329846| 0.027148023|-0.71127874| -0.08471591| 0.5328614| -0.13990337| 1.1341839|\n", + "| -0.74344087| -1.2426835| 0.27282518| 0.4037246| -0.9841421| -0.05610115| 1.2257773| -0.42940006| 1.1378745|\n", + "| 0.9784464| -0.2891866| 0.24374022| -0.24670053| 0.28922042| -0.01102468| 1.1087307| -1.2280084| 2.5710382|\n", + "| -0.5070446| -1.0043093|-0.78254056|0.0122275995| 2.8465424|-0.060435444| 0.8980464| -1.2080427| 1.8561647|\n", + "| -0.18690155| 1.2205169|0.015323491| 0.12183313|-0.41015765| 0.04452552| 1.010412| -1.3228445| 1.8639375|\n", + "| -1.2551856| 1.6178073| -0.3341509|-0.060125165| -0.7554314| -0.08777025| 1.0291398| -1.3477987| 1.24879|\n", + "| 4.9607058| -1.9578062| 1.4854684| -0.03948475| 2.1833694|0.0029250523| 1.024457| -1.1581304| 5.5946765|\n", + "| 0.73652315| -1.6399739| 0.7913185| -0.05238397| 1.67738| 0.01944797| 1.0993668| -1.1331724| 2.0694952|\n", + "| -0.505834| 0.18756187|-0.47093546| -0.24297306|-0.60619545| -0.10791535| 0.977639| -1.2879055| 1.7852836|\n", + "| -0.88477343|-0.050812364| -0.6318951| -0.15244243| -0.5258376| -0.15618815| 0.9823201| -1.2879055| 1.6675682|\n", + "| -0.42840376| 0.9821427| -0.2266495| -0.36083496| -0.6883194| -0.08552282| 0.5328614| -0.12493005| 1.0169572|\n", + "| 0.9369153| -1.4810578| 0.6722208|-0.121177554| 0.3996021| 0.01291408| 1.1040496| -1.1082181| 2.1317377|\n", + "| -0.80702734| -0.92485124|-0.26602685| -0.1560743| 1.4398388| -0.09314839|0.55627036| -0.09498342|0.86303747|\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+----------+\n", "only showing top 20 rows\n", "\n" ] @@ -1795,7 +2245,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": 73, "id": "a9ab4cdf-8103-447e-9ac8-944e2e527239", "metadata": {}, "outputs": [], @@ -1810,7 +2260,7 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 74, "id": "6632636e-67a3-406c-832c-758aac4245fd", "metadata": {}, "outputs": [], @@ -1821,7 +2271,7 @@ "mkdir models\n", "cp -r models_config/housing_model models\n", "mkdir -p models/housing_model/1\n", - "cp housing_model.ts models/housing_model/1/model.pt" + "cp ts_housing_model.pt models/housing_model/1/model.pt" ] }, { @@ -1834,7 +2284,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 75, "id": "c6fd1612-de6a-461c-a2ad-1a3fcd277d66", "metadata": { "scrolled": true @@ -1853,7 +2303,7 @@ "[True]" ] }, - "execution_count": 68, + "execution_count": 75, "metadata": {}, "output_type": "execute_result" } @@ -1874,7 +2324,7 @@ " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", " else:\n", " container=client.containers.run(\n", - " \"nvcr.io/nvidia/tritonserver:22.07-py3\", \"tritonserver --model-repository=/models\",\n", + " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", " detach=True,\n", " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", " name=\"spark-triton\",\n", @@ -1910,7 +2360,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 76, "id": "5eae04bc-75ca-421a-87c8-ac507ce1f2f5", "metadata": {}, "outputs": [], @@ -1920,7 +2370,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 77, "id": "b350bd8e-9b8f-4511-9ddf-76d917b21b5f", "metadata": { "tags": [] @@ -1939,7 +2389,7 @@ " 'Longitude']" ] }, - "execution_count": 70, + "execution_count": 77, "metadata": {}, "output_type": "execute_result" } @@ -1951,7 +2401,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 78, "id": "69b343ec-688d-4e4d-985e-db72beaaf00c", "metadata": {}, "outputs": [], @@ -1961,7 +2411,7 @@ " import tritonclient.grpc as grpcclient\n", " \n", " np_types = {\n", - " \"BOOL\": np.dtype(np.bool8),\n", + " \"BOOL\": np.dtype(np.bool_),\n", " \"INT8\": np.dtype(np.int8),\n", " \"INT16\": np.dtype(np.int16),\n", " \"INT32\": np.dtype(np.int32),\n", @@ -2001,7 +2451,7 @@ }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 79, "id": "d3e64fda-117b-4810-a9a2-dd498239496f", "metadata": {}, "outputs": [], @@ -2014,30 +2464,16 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 80, "id": "a24149a5-3adc-4089-8769-13cf1e44547a", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 13:> (0 + 8) / 8]\r" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 74.3 ms, sys: 9.28 ms, total: 83.6 ms\n", - "Wall time: 1.07 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" + "CPU times: user 15.3 ms, sys: 4.33 ms, total: 19.6 ms\n", + "Wall time: 461 ms\n" ] } ], @@ -2050,7 +2486,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 81, "id": "df2ce39f-30af-491a-8472-800fb1ce8458", "metadata": {}, "outputs": [ @@ -2058,8 +2494,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 197 ms, sys: 24.2 ms, total: 221 ms\n", - "Wall time: 400 ms\n" + "CPU times: user 30.2 ms, sys: 5.78 ms, total: 36 ms\n", + "Wall time: 200 ms\n" ] } ], @@ -2071,7 +2507,7 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": 82, "id": "ca6f3eaa-9569-45d0-88bf-9aa0757e1ecb", "metadata": {}, "outputs": [], @@ -2083,7 +2519,7 @@ }, { "cell_type": "code", - "execution_count": 76, + "execution_count": 83, "id": "b79c62c8-e1e8-4467-8aef-8939c31833b8", "metadata": { "tags": [] @@ -2093,30 +2529,30 @@ "name": "stdout", "output_type": "stream", "text": [ - "+-----------+-----------+------------+-------------+------------+-------------+----------+------------+----------+\n", - "| MedInc| HouseAge| AveRooms| AveBedrms| Population| AveOccup| Latitude| Longitude| preds|\n", - "+-----------+-----------+------------+-------------+------------+-------------+----------+------------+----------+\n", - "| -1.669445|-0.20972852| -1.1155425| -0.17418891| 0.2070965| -0.13437383| 0.5094524| -0.08001011|0.85219747|\n", - "| -0.8564016| -1.5605159| -0.53141737| -0.02190494| -0.66006166| -0.12997007| 0.5141335| -0.08001011| 1.1964238|\n", - "| 0.73173314|-0.76593506| 0.67250663| -0.10979619| 0.14175056| -0.02296524| 0.5141335| -0.07002536| 1.7371097|\n", - "|-0.44887984| -1.719432| 0.14690235| -0.009905009| -0.06664997| 0.01090982|0.50476956|-0.075017735| 1.0491724|\n", - "|-0.96920437| -1.0837674| 0.058284093| 0.07351444| -0.20793848| -0.011342554| 0.5094524| -0.08001011| 0.8659591|\n", - "| -1.0906925| 0.26701993| -0.72011936| -0.2243873| -0.6574125| 0.021105729|0.49072453| -0.08001011| 0.7074499|\n", - "|-0.90240705| 0.5848523| 0.24784403| 0.08091579| -0.5205393| 0.043980353| 0.4954056|-0.060044423|0.53719854|\n", - "| -1.0712692|0.028645715| -0.38059494| 0.062626354| -0.5205393| -0.005065064|0.49072453| -0.09498342|0.80645704|\n", - "|0.026544658| -0.686477| 0.06193017| -0.20868859| 0.03401808| 0.017589226| 0.4766795|-0.050059676| 1.1329681|\n", - "|-0.24211854| 0.34647804| 0.2122066| -0.11910806| -0.71127874| 0.047426607|0.47199664|-0.030093992| 0.8709737|\n", - "| -1.1632799| -1.7988901| -0.3091| -0.16322336| -0.0719483| 0.01691941|0.46263272|-0.040078737| 0.6880103|\n", - "| -0.4509853| 0.8232265| -0.10236703| -0.053904843| -0.6953838| -0.03862959|0.46731555| -0.05505205| 0.9974648|\n", - "| -0.5102555|-0.76593506| 0.26753396| 0.023170268| -0.14877392|-0.0061120046| 0.4766795|-0.084998675| 1.0234879|\n", - "| -1.1635431| 0.18756187| -0.59673625| -0.023986263| -0.71481097| -0.014560648|0.46263272| -0.05505205| 0.823533|\n", - "|-0.15400293| 0.5053942| 0.33031902|-0.0012220128| -0.35275918| 0.0010038698|0.46263272| -0.08001011| 1.1798486|\n", - "|-0.27733323| 0.18756187|-0.010031368| -0.13782738| -0.32450148| 0.059288267| 0.4485877| -0.08001011| 0.8976056|\n", - "| -0.8956694| 0.18756187|-0.043201063| -0.12283955|-0.087843254| 0.011250444|0.49072453| -0.11494911|0.61913794|\n", - "|-0.57936895|-0.13027044| 0.15416715| 0.08602174| -0.6353362| 0.026508931| 0.4766795| -0.10496436| 0.890837|\n", - "| -0.8548752| 0.1081038|-0.061331607| -0.26316243| -0.36865416| 0.0066948985|0.47199664| -0.12493005| 0.6539954|\n", - "| -1.1061679| 0.42593613| 0.053027753| -0.12104499| -0.2132368| -0.015556259| 0.4766795| -0.11494911| 0.5429483|\n", - "+-----------+-----------+------------+-------------+------------+-------------+----------+------------+----------+\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+----------+\n", + "| MedInc| HouseAge| AveRooms| AveBedrms| Population| AveOccup| Latitude| Longitude| preds|\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+----------+\n", + "| 0.20909257| -1.1632254| 0.38946992| 0.04609274| -0.9806099| -0.07099328|0.61245227|-0.020113053| 1.3979516|\n", + "|-0.098627955| 0.34647804| 0.27216315| -0.0129226| -0.6953838| -0.05380849| 1.0665938| -1.2479742| 1.7442212|\n", + "| -0.66006273| 1.0616008|-0.55292207| -0.48945764|-0.13641118| 0.028952759| 1.1040496| -1.3827378| 1.4398992|\n", + "| 0.08218294| 0.5848523|-0.13912922| -0.14707813|-0.19116047| -0.07136432|0.96827507| -1.3028787| 2.4199052|\n", + "| 0.0784456| -1.4810578| 0.57265776| 0.32067496| 1.0345173|-0.024157424| 1.4411427| -0.52423614| 1.2446644|\n", + "| -0.82318723| -0.36864465| 0.07829511| -0.1808107|-0.67242444|-0.061470542| 1.9374212| -1.0083897| 0.6888372|\n", + "| 0.59671736| 0.5848523| 0.19346413| -0.1371872|-0.19645879| 0.009964322|0.96827507| -1.2928978| 2.6563153|\n", + "| -0.9612035| -1.5605159|-0.56329846| 0.027148023|-0.71127874| -0.08471591| 0.5328614| -0.13990337| 1.1341839|\n", + "| -0.74344087| -1.2426835| 0.27282518| 0.4037246| -0.9841421| -0.05610115| 1.2257773| -0.42940006| 1.1378745|\n", + "| 0.9784464| -0.2891866| 0.24374022| -0.24670053| 0.28922042| -0.01102468| 1.1087307| -1.2280084| 2.5710382|\n", + "| -0.5070446| -1.0043093|-0.78254056|0.0122275995| 2.8465424|-0.060435444| 0.8980464| -1.2080427| 1.8561647|\n", + "| -0.18690155| 1.2205169|0.015323491| 0.12183313|-0.41015765| 0.04452552| 1.010412| -1.3228445| 1.8639375|\n", + "| -1.2551856| 1.6178073| -0.3341509|-0.060125165| -0.7554314| -0.08777025| 1.0291398| -1.3477987| 1.24879|\n", + "| 4.9607058| -1.9578062| 1.4854684| -0.03948475| 2.1833694|0.0029250523| 1.024457| -1.1581304| 5.5946765|\n", + "| 0.73652315| -1.6399739| 0.7913185| -0.05238397| 1.67738| 0.01944797| 1.0993668| -1.1331724| 2.0694952|\n", + "| -0.505834| 0.18756187|-0.47093546| -0.24297306|-0.60619545| -0.10791535| 0.977639| -1.2879055| 1.7852836|\n", + "| -0.88477343|-0.050812364| -0.6318951| -0.15244243| -0.5258376| -0.15618815| 0.9823201| -1.2879055| 1.6675682|\n", + "| -0.42840376| 0.9821427| -0.2266495| -0.36083496| -0.6883194| -0.08552282| 0.5328614| -0.12493005| 1.0169572|\n", + "| 0.9369153| -1.4810578| 0.6722208|-0.121177554| 0.3996021| 0.01291408| 1.1040496| -1.1082181| 2.1317377|\n", + "| -0.80702734| -0.92485124|-0.26602685| -0.1560743| 1.4398388| -0.09314839|0.55627036| -0.09498342|0.86303747|\n", + "+------------+------------+-----------+------------+-----------+------------+----------+------------+----------+\n", "only showing top 20 rows\n", "\n" ] @@ -2138,7 +2574,7 @@ }, { "cell_type": "code", - "execution_count": 77, + "execution_count": 84, "id": "15e9b3df-f3c9-46bb-bbeb-42496f7663de", "metadata": {}, "outputs": [ @@ -2155,7 +2591,7 @@ "[True]" ] }, - "execution_count": 77, + "execution_count": 84, "metadata": {}, "output_type": "execute_result" } @@ -2179,7 +2615,7 @@ }, { "cell_type": "code", - "execution_count": 78, + "execution_count": 85, "id": "0138a029-87c5-497f-ac5c-3eed0e11b0f6", "metadata": {}, "outputs": [], @@ -2198,7 +2634,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "spark-dl-torch", "language": "python", "name": "python3" }, @@ -2212,7 +2648,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/requirements.txt b/examples/ML+DL-Examples/Spark-DL/dl_inference/requirements.txt index 87c8dcfbe..abd6ad089 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/requirements.txt +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/requirements.txt @@ -1,19 +1,16 @@ -docker -huggingface -jupyterlab -matplotlib numpy pandas +matplotlib portalocker pyarrow -pyspark>=3.4.0 -sentencepiece -sentence_transformers +h5py +pydot scikit-learn -tensorflow-cpu +jupyterlab +pyspark>=3.4.0 +huggingface +datasets +docker +tritonclient[grpc] transformers -tritonclient ---extra-index-url https://download.pytorch.org/whl/cpu -torch -torchtext -torchvision +ipywidgets \ No newline at end of file diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/feature_columns.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/feature_columns_tf.ipynb similarity index 63% rename from examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/feature_columns.ipynb rename to examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/feature_columns_tf.ipynb index 2a338d4d8..17af1c934 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/feature_columns.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/feature_columns_tf.ipynb @@ -2,18 +2,45 @@ "cells": [ { "cell_type": "markdown", - "id": "66834048-5285-44a9-a031-e2e6e3347442", + "id": "7fcc021a", "metadata": {}, "source": [ + "# Pyspark TensorFlow Inference\n", + "\n", + "## Feature Columns\n", "From: https://www.tensorflow.org/tutorials/structured_data/preprocessing_layers" ] }, + { + "cell_type": "markdown", + "id": "35203476", + "metadata": {}, + "source": [ + "### Using TensorFlow\n", + "Note that cuFFT/cuDNN/cuBLAS registration errors are expected with `tf=2.17.0` and will not affect behavior, as noted in [this issue.](https://github.com/tensorflow/tensorflow/issues/62075) \n", + "This notebook does not demonstrate inference with TensorRT, as [TF-TRT](https://docs.nvidia.com/deeplearning/tensorrt/release-notes/index.html#tensorrt-10) does not yet support `tf=2.17.0`. See the `pytorch` notebooks for TensorRT demos." + ] + }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "id": "01162f42-0637-4dfe-8d7d-b577e4ffd017", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:38:52.548855: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2024-10-03 17:38:52.555529: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", + "2024-10-03 17:38:52.563119: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", + "2024-10-03 17:38:52.565499: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", + "2024-10-03 17:38:52.571252: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2024-10-03 17:38:52.894224: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" + ] + } + ], "source": [ "import numpy as np\n", "import pandas as pd\n", @@ -24,28 +51,34 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "id": "9fa3e1b7-58cd-45f9-9fee-85f25a31c3c6", "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "'2.12.0'" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "2.17.0\n" + ] } ], "source": [ - "tf.__version__" + "print(tf.__version__)\n", + "\n", + "# Enable GPU memory growth\n", + "gpus = tf.config.experimental.list_physical_devices('GPU')\n", + "if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "9326b072-a53c-40c4-a6cb-bd4d3d644d03", "metadata": {}, "outputs": [], @@ -60,7 +93,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "e98480ef-d13d-44c0-a227-e9a22f9bf2b0", "metadata": {}, "outputs": [ @@ -198,15 +231,15 @@ "" ], "text/plain": [ - " Type Age Breed1 Gender Color1 Color2 MaturitySize \n", - "0 Cat 3 Tabby Male Black White Small \\\n", + " Type Age Breed1 Gender Color1 Color2 MaturitySize \\\n", + "0 Cat 3 Tabby Male Black White Small \n", "1 Cat 1 Domestic Medium Hair Male Black Brown Medium \n", "2 Dog 1 Mixed Breed Male Brown White Medium \n", "3 Dog 4 Mixed Breed Female Black Brown Medium \n", "4 Dog 1 Mixed Breed Male Black No Color Medium \n", "\n", - " FurLength Vaccinated Sterilized Health Fee \n", - "0 Short No No Healthy 100 \\\n", + " FurLength Vaccinated Sterilized Health Fee \\\n", + "0 Short No No Healthy 100 \n", "1 Medium Not Sure Not Sure Healthy 0 \n", "2 Medium Yes No Healthy 0 \n", "3 Short Yes No Healthy 150 \n", @@ -220,7 +253,7 @@ "4 This handsome yet cute boy is up for adoption.... 3 2 " ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -231,7 +264,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "e8efce25-a835-4cbd-b8a2-1418ba2c1d31", "metadata": {}, "outputs": [], @@ -246,17 +279,26 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "id": "00d403cf-9ae7-4780-9fac-13d920d8b395", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/rishic/anaconda3/envs/spark-dl-tf/lib/python3.11/site-packages/numpy/core/fromnumeric.py:59: FutureWarning: 'DataFrame.swapaxes' is deprecated and will be removed in a future version. Please use 'DataFrame.transpose' instead.\n", + " return bound(*args, **kwds)\n" + ] + } + ], "source": [ - "train, val, test = np.split(dataframe.sample(frac=1), [int(0.8*len(dataframe)), int(0.9*len(dataframe))])\n" + "train, val, test = np.split(dataframe.sample(frac=1), [int(0.8*len(dataframe)), int(0.9*len(dataframe))])" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "id": "4206a56e-5403-42a9-805e-e037044e7995", "metadata": {}, "outputs": [ @@ -278,7 +320,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "id": "499ade5f-ac8a-47ca-a021-071239dfe97d", "metadata": {}, "outputs": [], @@ -286,7 +328,7 @@ "def df_to_dataset(dataframe, shuffle=True, batch_size=32):\n", " df = dataframe.copy()\n", " labels = df.pop('target')\n", - " df = {key: np.array(value)[:, tf.newaxis] for key, value in dataframe.items()}\n", + " df = {key: value.to_numpy()[:,tf.newaxis] for key, value in dataframe.items()}\n", " ds = tf.data.Dataset.from_tensor_slices((dict(df), labels))\n", " if shuffle:\n", " ds = ds.shuffle(buffer_size=len(dataframe))\n", @@ -297,10 +339,18 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "id": "b9ec57c9-080e-4626-9e03-acf309cf3736", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:38:53.526119: I tensorflow/core/common_runtime/gpu/gpu_device.cc:2021] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 46022 MB memory: -> device: 0, name: NVIDIA RTX A6000, pci bus id: 0000:01:00.0, compute capability: 8.6\n" + ] + } + ], "source": [ "batch_size = 5\n", "train_ds = df_to_dataset(train, batch_size=batch_size)" @@ -308,7 +358,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "id": "dfcbf268-4508-4eb8-abe1-acf1dbb97bd5", "metadata": {}, "outputs": [ @@ -318,12 +368,19 @@ "text": [ "Every feature: ['Type', 'Age', 'Breed1', 'Gender', 'Color1', 'Color2', 'MaturitySize', 'FurLength', 'Vaccinated', 'Sterilized', 'Health', 'Fee', 'PhotoAmt', 'target']\n", "A batch of ages: tf.Tensor(\n", - "[[ 2]\n", - " [15]\n", - " [ 3]\n", - " [11]\n", - " [ 8]], shape=(5, 1), dtype=int64)\n", - "A batch of targets: tf.Tensor([1 1 1 1 1], shape=(5,), dtype=int64)\n" + "[[18]\n", + " [ 5]\n", + " [ 2]\n", + " [ 5]\n", + " [ 1]], shape=(5, 1), dtype=int64)\n", + "A batch of targets: tf.Tensor([1 0 1 1 1], shape=(5,), dtype=int64)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:38:53.588272: I tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence\n" ] } ], @@ -336,7 +393,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 12, "id": "6c09dc4b-3a2a-44f5-b41c-821ec30b87b1", "metadata": {}, "outputs": [], @@ -356,22 +413,29 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 13, "id": "59bb91dc-360a-4a89-a9ea-bebc1ddbf1b7", "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:38:55.015073: I tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence\n" + ] + }, { "data": { "text/plain": [ "" + "array([[-0.19597158],\n", + " [-0.19597158],\n", + " [-0.8320273 ],\n", + " [-0.19597158],\n", + " [-0.8320273 ]], dtype=float32)>" ] }, - "execution_count": 12, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -384,7 +448,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 14, "id": "4623b612-e924-472b-9ef4-c7f14f9f53c5", "metadata": {}, "outputs": [], @@ -413,7 +477,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "id": "0a40e9ee-20a5-4a42-8543-c267f99af55e", "metadata": {}, "outputs": [ @@ -421,14 +485,14 @@ "data": { "text/plain": [ "" ] }, - "execution_count": 14, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -443,22 +507,29 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "id": "ff63a5cc-71f4-428e-9299-a8018edc7648", "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:38:56.454126: I tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence\n" + ] + }, { "data": { "text/plain": [ "" + " [0., 0., 0., 1., 0.]], dtype=float32)>" ] }, - "execution_count": 15, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } @@ -474,7 +545,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "id": "2b040b0e-d8ca-4cf0-917c-dd9a272e1f0a", "metadata": {}, "outputs": [], @@ -487,12 +558,12 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "id": "19df498e-4dd1-467a-8741-e1f5e15932a5", "metadata": {}, "outputs": [], "source": [ - "all_inputs = []\n", + "all_inputs = {}\n", "encoded_features = []\n", "\n", "# Numerical features.\n", @@ -500,13 +571,13 @@ " numeric_col = tf.keras.Input(shape=(1,), name=header)\n", " normalization_layer = get_normalization_layer(header, train_ds)\n", " encoded_numeric_col = normalization_layer(numeric_col)\n", - " all_inputs.append(numeric_col)\n", + " all_inputs[header] = numeric_col\n", " encoded_features.append(encoded_numeric_col)" ] }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 19, "id": "1d12579f-34fb-40b0-a16a-3e13cfea8178", "metadata": {}, "outputs": [], @@ -518,16 +589,25 @@ " dtype='int64',\n", " max_tokens=5)\n", "encoded_age_col = encoding_layer(age_col)\n", - "all_inputs.append(age_col)\n", + "all_inputs['Age'] = age_col\n", "encoded_features.append(encoded_age_col)" ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 20, "id": "bff286eb-7ad7-4d3a-8fa4-c729692d1425", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:38:56.758056: I tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence\n", + "2024-10-03 17:38:57.171981: I tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence\n" + ] + } + ], "source": [ "categorical_cols = ['Type', 'Color1', 'Color2', 'Gender', 'MaturitySize',\n", " 'FurLength', 'Vaccinated', 'Sterilized', 'Health', 'Breed1']\n", @@ -535,18 +615,17 @@ "for header in categorical_cols:\n", " categorical_col = tf.keras.Input(shape=(1,), name=header, dtype='string')\n", " encoding_layer = get_category_encoding_layer(name=header,\n", - " dataset=train_ds,\n", - " dtype='string',\n", - " max_tokens=5)\n", - "\n", + " dataset=train_ds,\n", + " dtype='string',\n", + " max_tokens=5)\n", " encoded_categorical_col = encoding_layer(categorical_col)\n", - " all_inputs.append(categorical_col)\n", + " all_inputs[header] = categorical_col\n", " encoded_features.append(encoded_categorical_col)" ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 21, "id": "79247436-32d8-4738-a656-3f288c77001c", "metadata": {}, "outputs": [], @@ -561,33 +640,15 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 22, "id": "dbc85d3e-6d1e-4167-9516-b1182e880542", "metadata": {}, "outputs": [], "source": [ "model.compile(optimizer='adam',\n", " loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n", - " metrics=[\"accuracy\"])" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "03b54d91-26f3-4232-ac33-895599bd6126", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "You must install pydot (`pip install pydot`) and install graphviz (see instructions at https://graphviz.gitlab.io/download/) for plot_model to work.\n" - ] - } - ], - "source": [ - "# Use `rankdir='LR'` to make the graph horizontal.\n", - "tf.keras.utils.plot_model(model, show_shapes=True, rankdir=\"LR\")" + " metrics=[\"accuracy\"],\n", + " run_eagerly=True)" ] }, { @@ -603,43 +664,35 @@ "Epoch 1/10\n" ] }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/leey/.pyenv/versions/3.9.10/envs/spark_rapids_examples/lib/python3.9/site-packages/keras/engine/functional.py:639: UserWarning: Input dict contained keys ['target'] which did not match any model input. They will be ignored by the model.\n", - " inputs = self._flatten_to_reference_inputs(inputs)\n" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "37/37 [==============================] - 1s 14ms/step - loss: 0.6070 - accuracy: 0.6274 - val_loss: 0.5371 - val_accuracy: 0.7374\n", + "\u001b[1m37/37\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 15ms/step - accuracy: 0.4109 - loss: 0.7333 - val_accuracy: 0.6898 - val_loss: 0.5666\n", "Epoch 2/10\n", - "37/37 [==============================] - 0s 4ms/step - loss: 0.5733 - accuracy: 0.6728 - val_loss: 0.5245 - val_accuracy: 0.7366\n", + "\u001b[1m37/37\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 15ms/step - accuracy: 0.6423 - loss: 0.5994 - val_accuracy: 0.7210 - val_loss: 0.5484\n", "Epoch 3/10\n", - "37/37 [==============================] - 0s 5ms/step - loss: 0.5552 - accuracy: 0.6964 - val_loss: 0.5158 - val_accuracy: 0.7409\n", + "\u001b[1m37/37\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 17ms/step - accuracy: 0.6825 - loss: 0.5728 - val_accuracy: 0.7253 - val_loss: 0.5383\n", "Epoch 4/10\n", - "37/37 [==============================] - 0s 6ms/step - loss: 0.5469 - accuracy: 0.7025 - val_loss: 0.5116 - val_accuracy: 0.7470\n", + "\u001b[1m37/37\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 17ms/step - accuracy: 0.6796 - loss: 0.5653 - val_accuracy: 0.7331 - val_loss: 0.5314\n", "Epoch 5/10\n", - "37/37 [==============================] - 0s 6ms/step - loss: 0.5419 - accuracy: 0.7097 - val_loss: 0.5090 - val_accuracy: 0.7409\n", + "\u001b[1m37/37\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 16ms/step - accuracy: 0.6853 - loss: 0.5584 - val_accuracy: 0.7348 - val_loss: 0.5259\n", "Epoch 6/10\n", - "37/37 [==============================] - 0s 5ms/step - loss: 0.5356 - accuracy: 0.7142 - val_loss: 0.5089 - val_accuracy: 0.7461\n", + "\u001b[1m37/37\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 14ms/step - accuracy: 0.7120 - loss: 0.5447 - val_accuracy: 0.7418 - val_loss: 0.5218\n", "Epoch 7/10\n", - "37/37 [==============================] - 0s 6ms/step - loss: 0.5327 - accuracy: 0.7073 - val_loss: 0.5056 - val_accuracy: 0.7530\n", + "\u001b[1m37/37\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 14ms/step - accuracy: 0.7068 - loss: 0.5422 - val_accuracy: 0.7435 - val_loss: 0.5189\n", "Epoch 8/10\n", - "37/37 [==============================] - 0s 5ms/step - loss: 0.5319 - accuracy: 0.7148 - val_loss: 0.5039 - val_accuracy: 0.7574\n", + "\u001b[1m37/37\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 14ms/step - accuracy: 0.7043 - loss: 0.5397 - val_accuracy: 0.7435 - val_loss: 0.5162\n", "Epoch 9/10\n", - "37/37 [==============================] - 0s 6ms/step - loss: 0.5229 - accuracy: 0.7223 - val_loss: 0.5042 - val_accuracy: 0.7565\n", + "\u001b[1m37/37\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 14ms/step - accuracy: 0.7172 - loss: 0.5372 - val_accuracy: 0.7496 - val_loss: 0.5146\n", "Epoch 10/10\n", - "37/37 [==============================] - 0s 6ms/step - loss: 0.5242 - accuracy: 0.7200 - val_loss: 0.5023 - val_accuracy: 0.7582\n" + "\u001b[1m37/37\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 14ms/step - accuracy: 0.7337 - loss: 0.5232 - val_accuracy: 0.7409 - val_loss: 0.5131\n" ] }, { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 23, @@ -661,8 +714,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "5/5 [==============================] - 0s 5ms/step - loss: 0.4920 - accuracy: 0.7504\n", - "Accuracy 0.7504332661628723\n" + "\u001b[1m5/5\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 7ms/step - accuracy: 0.7480 - loss: 0.5028 \n", + "Accuracy 0.753032922744751\n" ] } ], @@ -692,82 +745,26 @@ { "cell_type": "code", "execution_count": 26, - "id": "d1724a4e-fdaa-4169-8740-05bf18cb3153", + "id": "6bf0d024", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING:absl:Function `_wrapped_model` contains input name(s) PhotoAmt, Fee, Age, Type, Color1, Color2, Gender, MaturitySize, FurLength, Vaccinated, Sterilized, Health, Breed1 with unsupported characters which will be renamed to photoamt, fee, age, type, color1, color2, gender, maturitysize, furlength, vaccinated, sterilized, health, breed1 in the SavedModel.\n", - "WARNING:absl:Found untraced functions such as _update_step_xla while saving (showing 1 of 1). These functions will not be directly callable after loading.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "INFO:tensorflow:Assets written to: my_pet_classifier/assets\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:tensorflow:Assets written to: my_pet_classifier/assets\n" - ] - } - ], + "outputs": [], "source": [ - "model.save('my_pet_classifier')" + "model.save('my_pet_classifier.keras')" ] }, { "cell_type": "code", "execution_count": 27, - "id": "d604ca70-e0af-4cdb-8046-53e37f4b6afe", + "id": "d1a7be62", "metadata": {}, "outputs": [], "source": [ - "reloaded_model = tf.keras.models.load_model('my_pet_classifier')" + "reloaded_model = tf.keras.models.load_model('my_pet_classifier.keras')" ] }, { "cell_type": "code", "execution_count": 28, - "id": "7b8be0a1-e16b-4509-8cbc-357def8bb282", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ]" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "reloaded_model.inputs" - ] - }, - { - "cell_type": "code", - "execution_count": 29, "id": "f3d2a2d5-fd4d-4320-bacc-fd4571cec709", "metadata": {}, "outputs": [ @@ -775,8 +772,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "1/1 [==============================] - 0s 264ms/step\n", - "This particular pet had a 76.8 percent probability of getting adopted.\n" + "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 26ms/step\n", + "This particular pet had a 81.1 percent probability of getting adopted.\n" ] } ], @@ -817,17 +814,58 @@ }, { "cell_type": "code", - "execution_count": 30, - "id": "3c64fd7b-3d1e-40f8-ab64-b5c13f8bbe77", + "execution_count": 29, + "id": "fc8a0536", "metadata": {}, "outputs": [], "source": [ - "df = spark.createDataFrame(dataframe)" + "from pyspark import SparkConf\n", + "from pyspark.sql import SparkSession" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60dff1da", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", + "\n", + "conf = SparkConf()\n", + "if 'spark' not in globals():\n", + " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", + " import socket\n", + " hostname = socket.gethostname()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", + "conf.set(\"spark.task.maxFailures\", \"1\")\n", + "conf.set(\"spark.driver.memory\", \"8g\")\n", + "conf.set(\"spark.executor.memory\", \"8g\")\n", + "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", + "conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + "conf.set(\"spark.python.worker.reuse\", \"true\")\n", + "# Create Spark Session\n", + "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", + "sc = spark.sparkContext" ] }, { "cell_type": "code", "execution_count": 31, + "id": "3c64fd7b-3d1e-40f8-ab64-b5c13f8bbe77", + "metadata": {}, + "outputs": [], + "source": [ + "df = spark.createDataFrame(dataframe).repartition(8)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, "id": "1be8215b-5068-41b4-849c-1c3ea7bb108a", "metadata": {}, "outputs": [ @@ -845,7 +883,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 33, "id": "d4dbde99-cf65-4c15-a163-754a0201a48d", "metadata": {}, "outputs": [ @@ -896,7 +934,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 34, "id": "4c21296c-20ed-43f8-921a-c85a820d1819", "metadata": {}, "outputs": [], @@ -911,7 +949,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 35, "id": "04b38f3a-70ea-4746-9f52-c50087401508", "metadata": {}, "outputs": [ @@ -919,28 +957,28 @@ "name": "stdout", "output_type": "stream", "text": [ - "+----+---+-------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+\n", - "|Type|Age| Breed1|Gender|Color1| Color2|MaturitySize|FurLength|Vaccinated|Sterilized| Health|Fee|PhotoAmt|target|\n", - "+----+---+-------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+\n", - "| Dog| 7| Spitz| Male| Brown| Golden| Medium| Medium| Not Sure| No|Healthy| 0| 2| 0|\n", - "| Cat| 4|Domestic Short Hair|Female| White|No Color| Medium| Short| No| No|Healthy| 0| 2| 1|\n", - "| Cat| 3|Domestic Short Hair| Male| Brown|No Color| Small| Short| No| No|Healthy| 0| 2| 1|\n", - "| Cat| 11|Domestic Short Hair|Female| Brown| Yellow| Medium| Short| Yes| Yes|Healthy|100| 1| 0|\n", - "| Dog| 1| Mixed Breed| Male| Black| Brown| Medium| Medium| No| No|Healthy| 0| 1| 1|\n", - "+----+---+-------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+\n", + "+----+---+--------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+\n", + "|Type|Age| Breed1|Gender|Color1| Color2|MaturitySize|FurLength|Vaccinated|Sterilized| Health|Fee|PhotoAmt|target|\n", + "+----+---+--------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+\n", + "| Cat| 1|Domestic Medium Hair|Female| White|No Color| Small| Medium| No| No|Healthy| 0| 2| 1|\n", + "| Dog| 2| Mixed Breed|Female| Black| Brown| Medium| Medium| No| No|Healthy| 0| 3| 1|\n", + "| Dog| 18| Dalmatian|Female| Black| White| Medium| Medium| Yes| No|Healthy|350| 5| 1|\n", + "| Dog| 3| Mixed Breed|Female| Black|No Color| Medium| Short| No| No|Healthy| 0| 1| 0|\n", + "| Dog| 2| Mixed Breed| Male| Black| Brown| Medium| Short| No| No|Healthy| 0| 1| 1|\n", + "+----+---+--------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+\n", "only showing top 5 rows\n", "\n" ] } ], "source": [ - "df = spark.read.parquet(\"datasets/petfinder-mini\")\n", + "df = spark.read.parquet(\"datasets/petfinder-mini\").cache()\n", "df.show(5)" ] }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 36, "id": "29c27243-7c74-4045-aaf1-f75a322c0530", "metadata": {}, "outputs": [ @@ -959,7 +997,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 37, "id": "47508b14-97fa-42ee-a7d0-6175e6408283", "metadata": { "tags": [] @@ -981,18 +1019,18 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 38, "id": "d62eb95a-54c6-44d2-9279-38fb65e0e160", "metadata": {}, "outputs": [], "source": [ "# get absolute path to model\n", - "model_dir = \"{}/my_pet_classifier\".format(os.getcwd())" + "model_dir = \"{}/my_pet_classifier.keras\".format(os.getcwd())" ] }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 39, "id": "45665acf-50c8-445b-a985-b3dabd734709", "metadata": {}, "outputs": [], @@ -1000,6 +1038,16 @@ "def predict_batch_fn():\n", " import tensorflow as tf\n", " import pandas as pd\n", + " \n", + " # Enable GPU memory growth to avoid CUDA OOM\n", + " gpus = tf.config.experimental.list_physical_devices('GPU')\n", + " if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)\n", + "\n", " model = tf.keras.models.load_model(model_dir)\n", "\n", " def predict(t, a, b, g, c1, c2, m, f, v, s, h, fee, p):\n", @@ -1026,7 +1074,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 40, "id": "815e3b5f-7914-4235-85fa-50153dcd3d30", "metadata": {}, "outputs": [], @@ -1039,7 +1087,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 41, "id": "da03a0c6-2d39-425e-a9fa-57c139cca1ed", "metadata": {}, "outputs": [ @@ -1047,16 +1095,23 @@ "name": "stderr", "output_type": "stream", "text": [ - "23/05/19 17:53:03 WARN package: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.sql.debug.maxToStringFields'.\n", - " \r" + "24/10/03 17:39:09 WARN SparkStringUtils: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.sql.debug.maxToStringFields'.\n", + "[Stage 4:> (0 + 8) / 8]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 271 ms, sys: 16.3 ms, total: 288 ms\n", - "Wall time: 7.58 s\n" + "CPU times: user 24.1 ms, sys: 6.37 ms, total: 30.4 ms\n", + "Wall time: 4.58 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" ] } ], @@ -1068,7 +1123,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 42, "id": "03990c76-7198-49a7-bb5d-6870be915fb3", "metadata": {}, "outputs": [ @@ -1076,15 +1131,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 5:====================================> (5 + 3) / 8]\r" + "[Stage 5:> (0 + 8) / 8]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 71.2 ms, sys: 801 µs, total: 72 ms\n", - "Wall time: 2.41 s\n" + "CPU times: user 98.2 ms, sys: 8.34 ms, total: 107 ms\n", + "Wall time: 1.57 s\n" ] }, { @@ -1103,7 +1158,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 43, "id": "edb93cf3-c248-40c9-b8dc-acc8f51786a9", "metadata": {}, "outputs": [ @@ -1111,15 +1166,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 6:====================================> (5 + 3) / 8]\r" + "[Stage 6:> (0 + 8) / 8]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 84.9 ms, sys: 0 ns, total: 84.9 ms\n", - "Wall time: 2.41 s\n" + "CPU times: user 17.6 ms, sys: 2.19 ms, total: 19.8 ms\n", + "Wall time: 1.51 s\n" ] }, { @@ -1138,7 +1193,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 44, "id": "a91f19cb-f7f1-4669-aff1-be594bea5378", "metadata": { "scrolled": true @@ -1148,30 +1203,30 @@ "name": "stdout", "output_type": "stream", "text": [ - "+----+---+-------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+----------+\n", - "|Type|Age| Breed1|Gender|Color1| Color2|MaturitySize|FurLength|Vaccinated|Sterilized| Health|Fee|PhotoAmt|target| preds|\n", - "+----+---+-------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+----------+\n", - "| Dog| 7| Spitz| Male| Brown| Golden| Medium| Medium| Not Sure| No|Healthy| 0| 2| 0| 1.2876476|\n", - "| Cat| 4|Domestic Short Hair|Female| White|No Color| Medium| Short| No| No|Healthy| 0| 2| 1| 0.8216562|\n", - "| Cat| 3|Domestic Short Hair| Male| Brown|No Color| Small| Short| No| No|Healthy| 0| 2| 1| 1.1362813|\n", - "| Cat| 11|Domestic Short Hair|Female| Brown| Yellow| Medium| Short| Yes| Yes|Healthy|100| 1| 0|-0.5538333|\n", - "| Dog| 1| Mixed Breed| Male| Black| Brown| Medium| Medium| No| No|Healthy| 0| 1| 1| 1.8639014|\n", - "| Dog| 12|German Shepherd Dog|Female| Black| Brown| Large| Medium| Not Sure| Not Sure|Healthy| 0| 4| 1| 0.646166|\n", - "| Cat| 3|Oriental Short Hair|Female| White|No Color| Medium| Short| Not Sure| Not Sure|Healthy| 0| 3| 1| 1.2250762|\n", - "| Cat| 6| Russian Blue| Male| Gray|No Color| Medium| Short| Not Sure| No|Healthy| 0| 3| 1| 1.2427491|\n", - "| Dog| 13| Miniature Pinscher|Female|Golden|No Color| Small| Short| Yes| Yes|Healthy| 0| 6| 1| 1.2280617|\n", - "| Dog| 5| Mixed Breed| Male| Black| White| Large| Medium| Yes| Yes|Healthy| 0| 6| 1| 0.3791974|\n", - "| Dog| 62| Golden Retriever|Female|Golden| Cream| Medium| Medium| Yes| Yes|Healthy| 0| 3| 1| 0.9814444|\n", - "| Cat| 2| Domestic Long Hair|Female| Cream|No Color| Medium| Medium| No| No|Healthy| 80| 5| 1| 2.7954462|\n", - "| Cat| 12|Domestic Short Hair|Female| White|No Color| Medium| Short| Yes| Yes|Healthy| 0| 1| 1|-0.2367835|\n", - "| Dog| 1| Mixed Breed|Female| Brown|No Color| Medium| Medium| No| No|Healthy| 0| 3| 1| 1.8235079|\n", - "| Dog| 5| Mixed Breed|Female| Brown|No Color| Medium| Medium| Yes| No|Healthy| 0| 1| 1|0.16853562|\n", - "| Dog| 2| Mixed Breed|Female| Black| Brown| Medium| Medium| Yes| No|Healthy| 0| 1| 0| 1.3014978|\n", - "| Cat| 4|Domestic Short Hair| Male| Black|No Color| Medium| Short| No| No|Healthy| 0| 3| 0| 1.0102129|\n", - "| Dog| 2| Mixed Breed| Male| Cream|No Color| Medium| Medium| No| No|Healthy| 0| 3| 1| 2.032087|\n", - "| Dog| 24| Pomeranian| Male|Yellow| White| Small| Medium| Not Sure| Not Sure|Healthy| 0| 9| 1| 1.7647744|\n", - "| Cat| 36|Domestic Short Hair|Female| Gray| White| Small| Short| Not Sure| Not Sure|Healthy| 0| 2| 1|0.16341272|\n", - "+----+---+-------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+----------+\n", + "+----+---+--------------------+------+------+--------+------------+---------+----------+----------+------------+---+--------+------+-----------+\n", + "|Type|Age| Breed1|Gender|Color1| Color2|MaturitySize|FurLength|Vaccinated|Sterilized| Health|Fee|PhotoAmt|target| preds|\n", + "+----+---+--------------------+------+------+--------+------------+---------+----------+----------+------------+---+--------+------+-----------+\n", + "| Cat| 1|Domestic Medium Hair|Female| White|No Color| Small| Medium| No| No| Healthy| 0| 2| 1| 1.9543833|\n", + "| Dog| 2| Mixed Breed|Female| Black| Brown| Medium| Medium| No| No| Healthy| 0| 3| 1| 1.7454995|\n", + "| Dog| 18| Dalmatian|Female| Black| White| Medium| Medium| Yes| No| Healthy|350| 5| 1| 1.5183508|\n", + "| Dog| 3| Mixed Breed|Female| Black|No Color| Medium| Short| No| No| Healthy| 0| 1| 0| 0.67013955|\n", + "| Dog| 2| Mixed Breed| Male| Black| Brown| Medium| Short| No| No| Healthy| 0| 1| 1| 1.5492269|\n", + "| Dog| 36| Mixed Breed| Male| Brown|No Color| Medium| Medium| Not Sure| Yes|Minor Injury| 0| 1| 0|-0.27595556|\n", + "| Cat| 6| Domestic Short Hair|Female| Black| White| Medium| Short| Yes| No| Healthy| 0| 5| 0| 0.7229555|\n", + "| Dog| 72| Golden Retriever|Female| Cream|No Color| Large| Medium| Yes| Not Sure| Healthy| 0| 1| 1| 0.7397226|\n", + "| Cat| 2| Domestic Short Hair| Male| Black| White| Small| Short| No| Yes| Healthy| 0| 4| 1| 1.4016482|\n", + "| Dog| 3| Irish Terrier| Male| Brown| Cream| Medium| Medium| Yes| No|Minor Injury|200| 3| 0| 1.3436754|\n", + "| Dog| 2| Mixed Breed|Female| White|No Color| Medium| Medium| Yes| No| Healthy| 0| 1| 1| 1.156439|\n", + "| Dog| 2| Mixed Breed| Male| Brown|No Color| Medium| Medium| Yes| No| Healthy| 0| 4| 1| 1.7760799|\n", + "| Cat| 2| Domestic Short Hair| Male| Black| Gray| Medium| Short| No| No| Healthy| 0| 2| 1| 1.8319463|\n", + "| Dog| 1| German Shepherd Dog| Male| Gray|No Color| Medium| Medium| No| No| Healthy| 0| 6| 1| 2.5471144|\n", + "| Dog| 24| Golden Retriever| Male|Yellow| Cream| Medium| Long| Yes| Yes| Healthy| 0| 7| 1| 1.4675076|\n", + "| Dog| 1| Mixed Breed|Female| Black| Brown| Small| Medium| No| Yes| Healthy| 0| 1| 0| 0.8451028|\n", + "| Cat| 12| Tuxedo| Male| Black|No Color| Small| Medium| Yes| Yes| Healthy| 50| 1| 1| 0.6487097|\n", + "| Cat| 3| Domestic Short Hair|Female| Black|No Color| Small| Short| No| No| Healthy| 0| 1| 1| 1.0688435|\n", + "| Dog| 2| Mixed Breed|Female| Brown| White| Medium| Short| No| No| Healthy| 0| 1| 1| 1.4086031|\n", + "| Dog| 11| Mixed Breed|Female|Golden|No Color| Medium| Short| Yes| Yes| Healthy| 0| 9| 1| 0.28429908|\n", + "+----+---+--------------------+------+------+--------+------------+---------+----------+----------+------------+---+--------+------+-----------+\n", "only showing top 20 rows\n", "\n" ] @@ -1196,19 +1251,21 @@ "id": "22d1805b-7cac-4b27-9359-7a25b4ef3f71", "metadata": {}, "source": [ - "This notebook uses the [Python backend with a custom execution environment](https://github.com/triton-inference-server/python_backend#creating-custom-execution-environments), using a conda-pack environment created as follows:\n", + "This notebook uses the [Python backend with a custom execution environment](https://github.com/triton-inference-server/python_backend#creating-custom-execution-environments) for Triton 24.08, using a conda-pack environment created as follows:\n", "```\n", - "conda create -n tf-gpu -c conda-forge python=3.8\n", + "conda create -n tf-gpu -c conda-forge python=3.10.0\n", "conda activate tf-gpu\n", - "pip install tensorflow\n", - "pip install conda-pack\n", - "conda pack # tf-gpu.tar.gz\n", + "\n", + "export PYTHONNOUSERSITE=True\n", + "pip install numpy==1.26.4 tensorflow[and-cuda] conda-pack\n", + "\n", + "conda-pack # tf-gpu.tar.gz\n", "```" ] }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 45, "id": "2605d134-ef75-4d94-9b16-2c6d85f29bef", "metadata": {}, "outputs": [], @@ -1222,14 +1279,23 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 46, "id": "4666e618-8038-4dc5-9be7-793aedbf4500", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper\n", + "sudo: a password is required\n" + ] + } + ], "source": [ "%%bash\n", "# copy custom model to expected layout for Triton\n", - "rm -rf models\n", + "sudo rm -rf models\n", "mkdir -p models\n", "cp -r models_config/feature_columns models\n", "\n", @@ -1247,7 +1313,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 47, "id": "a7fb146c-5319-4831-85f7-f2f3c084b042", "metadata": { "scrolled": true @@ -1266,7 +1332,7 @@ "[True]" ] }, - "execution_count": 46, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -1274,7 +1340,7 @@ "source": [ "num_executors = 1\n", "triton_models_dir = \"{}/models\".format(os.getcwd())\n", - "my_pet_classifier_dir = \"{}/my_pet_classifier\".format(os.getcwd())\n", + "my_pet_classifier_dir = \"{}/my_pet_classifier.keras\".format(os.getcwd())\n", "nodeRDD = sc.parallelize(list(range(num_executors)), num_executors)\n", "\n", "def start_triton(it):\n", @@ -1288,7 +1354,7 @@ " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", " else:\n", " container=client.containers.run(\n", - " \"nvcr.io/nvidia/tritonserver:23.04-py3\", \"tritonserver --model-repository=/models\",\n", + " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", " detach=True,\n", " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", " name=\"spark-triton\",\n", @@ -1297,7 +1363,7 @@ " shm_size=\"128M\",\n", " volumes={\n", " triton_models_dir: {\"bind\": \"/models\", \"mode\": \"ro\"},\n", - " my_pet_classifier_dir: {\"bind\": \"/my_pet_classifier\", \"mode\": \"ro\"}\n", + " my_pet_classifier_dir: {\"bind\": \"/my_pet_classifier.keras\", \"mode\": \"ro\"}\n", " }\n", " )\n", " print(\">>>> starting triton: {}\".format(container.short_id))\n", @@ -1327,7 +1393,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 48, "id": "fe8dc3e6-f1b1-4a24-85f4-0a5ecabef4c5", "metadata": {}, "outputs": [], @@ -1337,7 +1403,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 49, "id": "ce92f041-930f-48ed-9a03-19f6c249ca27", "metadata": {}, "outputs": [ @@ -1345,15 +1411,15 @@ "name": "stdout", "output_type": "stream", "text": [ - "+----+---+-------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+\n", - "|Type|Age| Breed1|Gender|Color1| Color2|MaturitySize|FurLength|Vaccinated|Sterilized| Health|Fee|PhotoAmt|target|\n", - "+----+---+-------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+\n", - "| Dog| 7| Spitz| Male| Brown| Golden| Medium| Medium| Not Sure| No|Healthy| 0| 2| 0|\n", - "| Cat| 4|Domestic Short Hair|Female| White|No Color| Medium| Short| No| No|Healthy| 0| 2| 1|\n", - "| Cat| 3|Domestic Short Hair| Male| Brown|No Color| Small| Short| No| No|Healthy| 0| 2| 1|\n", - "| Cat| 11|Domestic Short Hair|Female| Brown| Yellow| Medium| Short| Yes| Yes|Healthy|100| 1| 0|\n", - "| Dog| 1| Mixed Breed| Male| Black| Brown| Medium| Medium| No| No|Healthy| 0| 1| 1|\n", - "+----+---+-------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+\n", + "+----+---+--------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+\n", + "|Type|Age| Breed1|Gender|Color1| Color2|MaturitySize|FurLength|Vaccinated|Sterilized| Health|Fee|PhotoAmt|target|\n", + "+----+---+--------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+\n", + "| Cat| 1|Domestic Medium Hair|Female| White|No Color| Small| Medium| No| No|Healthy| 0| 2| 1|\n", + "| Dog| 2| Mixed Breed|Female| Black| Brown| Medium| Medium| No| No|Healthy| 0| 3| 1|\n", + "| Dog| 18| Dalmatian|Female| Black| White| Medium| Medium| Yes| No|Healthy|350| 5| 1|\n", + "| Dog| 3| Mixed Breed|Female| Black|No Color| Medium| Short| No| No|Healthy| 0| 1| 0|\n", + "| Dog| 2| Mixed Breed| Male| Black| Brown| Medium| Short| No| No|Healthy| 0| 1| 1|\n", + "+----+---+--------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+\n", "only showing top 5 rows\n", "\n" ] @@ -1365,7 +1431,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 50, "id": "4cfb3f34-a215-4781-91bf-2bec85e15633", "metadata": {}, "outputs": [ @@ -1384,7 +1450,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 51, "id": "b315ee72-62af-476b-a994-0dba72d5f96e", "metadata": { "scrolled": true, @@ -1407,7 +1473,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 52, "id": "da004eca-f7ad-4ee3-aa88-a6a20c1b72e5", "metadata": {}, "outputs": [], @@ -1417,7 +1483,7 @@ " import tritonclient.grpc as grpcclient\n", " \n", " np_types = {\n", - " \"BOOL\": np.dtype(np.bool8),\n", + " \"BOOL\": np.dtype(np.bool_),\n", " \"INT8\": np.dtype(np.int8),\n", " \"INT16\": np.dtype(np.int16),\n", " \"INT32\": np.dtype(np.int32),\n", @@ -1477,7 +1543,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 53, "id": "2ffb020e-dc93-456b-bee6-405611eee1e1", "metadata": {}, "outputs": [], @@ -1493,7 +1559,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 54, "id": "7657f820-5ec2-4ac8-a107-4b58773d204a", "metadata": {}, "outputs": [ @@ -1501,30 +1567,30 @@ "name": "stdout", "output_type": "stream", "text": [ - "+----+---+----------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+----------+\n", - "|Type|Age| Breed1|Gender|Color1| Color2|MaturitySize|FurLength|Vaccinated|Sterilized| Health|Fee|PhotoAmt|target| preds|\n", - "+----+---+----------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+----------+\n", - "| Dog| 7| Spitz| Male| Brown| Golden| Medium| Medium| Not Sure| No|Healthy| 0| 2| 0| 1.2876476|\n", - "| Cat| 4|Domesti...|Female| White|No Color| Medium| Short| No| No|Healthy| 0| 2| 1| 0.8216562|\n", - "| Cat| 3|Domesti...| Male| Brown|No Color| Small| Short| No| No|Healthy| 0| 2| 1| 1.1362813|\n", - "| Cat| 11|Domesti...|Female| Brown| Yellow| Medium| Short| Yes| Yes|Healthy|100| 1| 0|-0.5538333|\n", - "| Dog| 1|Mixed B...| Male| Black| Brown| Medium| Medium| No| No|Healthy| 0| 1| 1| 1.8639014|\n", - "| Dog| 12|German ...|Female| Black| Brown| Large| Medium| Not Sure| Not Sure|Healthy| 0| 4| 1| 0.646166|\n", - "| Cat| 3|Orienta...|Female| White|No Color| Medium| Short| Not Sure| Not Sure|Healthy| 0| 3| 1| 1.2250762|\n", - "| Cat| 6|Russian...| Male| Gray|No Color| Medium| Short| Not Sure| No|Healthy| 0| 3| 1| 1.2427491|\n", - "| Dog| 13|Miniatu...|Female|Golden|No Color| Small| Short| Yes| Yes|Healthy| 0| 6| 1| 1.2280617|\n", - "| Dog| 5|Mixed B...| Male| Black| White| Large| Medium| Yes| Yes|Healthy| 0| 6| 1| 0.3791974|\n", - "| Dog| 62|Golden ...|Female|Golden| Cream| Medium| Medium| Yes| Yes|Healthy| 0| 3| 1| 0.9814444|\n", - "| Cat| 2|Domesti...|Female| Cream|No Color| Medium| Medium| No| No|Healthy| 80| 5| 1| 2.7954462|\n", - "| Cat| 12|Domesti...|Female| White|No Color| Medium| Short| Yes| Yes|Healthy| 0| 1| 1|-0.2367835|\n", - "| Dog| 1|Mixed B...|Female| Brown|No Color| Medium| Medium| No| No|Healthy| 0| 3| 1| 1.8235079|\n", - "| Dog| 5|Mixed B...|Female| Brown|No Color| Medium| Medium| Yes| No|Healthy| 0| 1| 1|0.16853562|\n", - "| Dog| 2|Mixed B...|Female| Black| Brown| Medium| Medium| Yes| No|Healthy| 0| 1| 0| 1.3014978|\n", - "| Cat| 4|Domesti...| Male| Black|No Color| Medium| Short| No| No|Healthy| 0| 3| 0| 1.0102129|\n", - "| Dog| 2|Mixed B...| Male| Cream|No Color| Medium| Medium| No| No|Healthy| 0| 3| 1| 2.032087|\n", - "| Dog| 24|Pomeranian| Male|Yellow| White| Small| Medium| Not Sure| Not Sure|Healthy| 0| 9| 1| 1.7647744|\n", - "| Cat| 36|Domesti...|Female| Gray| White| Small| Short| Not Sure| Not Sure|Healthy| 0| 2| 1|0.16341272|\n", - "+----+---+----------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+----------+\n", + "+----+---+----------+------+------+--------+------------+---------+----------+----------+----------+---+--------+------+----------+\n", + "|Type|Age| Breed1|Gender|Color1| Color2|MaturitySize|FurLength|Vaccinated|Sterilized| Health|Fee|PhotoAmt|target| preds|\n", + "+----+---+----------+------+------+--------+------------+---------+----------+----------+----------+---+--------+------+----------+\n", + "| Cat| 1|Domesti...|Female| White|No Color| Small| Medium| No| No| Healthy| 0| 2| 1| 1.9543833|\n", + "| Dog| 2|Mixed B...|Female| Black| Brown| Medium| Medium| No| No| Healthy| 0| 3| 1| 1.7454995|\n", + "| Dog| 18| Dalmatian|Female| Black| White| Medium| Medium| Yes| No| Healthy|350| 5| 1| 1.5183508|\n", + "| Dog| 3|Mixed B...|Female| Black|No Color| Medium| Short| No| No| Healthy| 0| 1| 0|0.67013955|\n", + "| Dog| 2|Mixed B...| Male| Black| Brown| Medium| Short| No| No| Healthy| 0| 1| 1| 1.5492269|\n", + "| Dog| 36|Mixed B...| Male| Brown|No Color| Medium| Medium| Not Sure| Yes|Minor I...| 0| 1| 0|-0.2759...|\n", + "| Cat| 6|Domesti...|Female| Black| White| Medium| Short| Yes| No| Healthy| 0| 5| 0| 0.7229555|\n", + "| Dog| 72|Golden ...|Female| Cream|No Color| Large| Medium| Yes| Not Sure| Healthy| 0| 1| 1| 0.7397226|\n", + "| Cat| 2|Domesti...| Male| Black| White| Small| Short| No| Yes| Healthy| 0| 4| 1| 1.4016482|\n", + "| Dog| 3|Irish T...| Male| Brown| Cream| Medium| Medium| Yes| No|Minor I...|200| 3| 0| 1.3436754|\n", + "| Dog| 2|Mixed B...|Female| White|No Color| Medium| Medium| Yes| No| Healthy| 0| 1| 1| 1.156439|\n", + "| Dog| 2|Mixed B...| Male| Brown|No Color| Medium| Medium| Yes| No| Healthy| 0| 4| 1| 1.7760799|\n", + "| Cat| 2|Domesti...| Male| Black| Gray| Medium| Short| No| No| Healthy| 0| 2| 1| 1.8319463|\n", + "| Dog| 1|German ...| Male| Gray|No Color| Medium| Medium| No| No| Healthy| 0| 6| 1| 2.5471144|\n", + "| Dog| 24|Golden ...| Male|Yellow| Cream| Medium| Long| Yes| Yes| Healthy| 0| 7| 1| 1.4675076|\n", + "| Dog| 1|Mixed B...|Female| Black| Brown| Small| Medium| No| Yes| Healthy| 0| 1| 0| 0.8451028|\n", + "| Cat| 12| Tuxedo| Male| Black|No Color| Small| Medium| Yes| Yes| Healthy| 50| 1| 1| 0.6487097|\n", + "| Cat| 3|Domesti...|Female| Black|No Color| Small| Short| No| No| Healthy| 0| 1| 1| 1.0688435|\n", + "| Dog| 2|Mixed B...|Female| Brown| White| Medium| Short| No| No| Healthy| 0| 1| 1| 1.4086031|\n", + "| Dog| 11|Mixed B...|Female|Golden|No Color| Medium| Short| Yes| Yes| Healthy| 0| 9| 1|0.28429908|\n", + "+----+---+----------+------+------+--------+------------+---------+----------+----------+----------+---+--------+------+----------+\n", "only showing top 20 rows\n", "\n" ] @@ -1537,7 +1603,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 55, "id": "e6ff0356-becd-421f-aebb-272497d5ad6a", "metadata": {}, "outputs": [ @@ -1552,8 +1618,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 62.9 ms, sys: 15.5 ms, total: 78.4 ms\n", - "Wall time: 2.62 s\n" + "CPU times: user 17.2 ms, sys: 2.85 ms, total: 20 ms\n", + "Wall time: 2.5 s\n" ] } ], @@ -1565,7 +1631,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 56, "id": "ce18ee7c-5958-4986-b200-6d986fcc6243", "metadata": {}, "outputs": [ @@ -1580,8 +1646,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 70 ms, sys: 6.89 ms, total: 76.9 ms\n", - "Wall time: 2.51 s\n" + "CPU times: user 23.4 ms, sys: 984 μs, total: 24.4 ms\n", + "Wall time: 2.5 s\n" ] }, { @@ -1600,7 +1666,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 57, "id": "0888ce40-b2c4-4aed-8ccb-6a8bcd00abc8", "metadata": { "tags": [] @@ -1610,22 +1676,15 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 14:===========================================> (6 + 2) / 8]\r" + " \r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 85.5 ms, sys: 6.85 ms, total: 92.4 ms\n", - "Wall time: 2.3 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" + "CPU times: user 14.7 ms, sys: 4.61 ms, total: 19.3 ms\n", + "Wall time: 2.47 s\n" ] } ], @@ -1637,7 +1696,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 58, "id": "d45812b5-f584-41a4-a821-2b59e065671c", "metadata": {}, "outputs": [ @@ -1645,30 +1704,30 @@ "name": "stdout", "output_type": "stream", "text": [ - "+----+---+-------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+----------+\n", - "|Type|Age| Breed1|Gender|Color1| Color2|MaturitySize|FurLength|Vaccinated|Sterilized| Health|Fee|PhotoAmt|target| preds|\n", - "+----+---+-------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+----------+\n", - "| Dog| 7| Spitz| Male| Brown| Golden| Medium| Medium| Not Sure| No|Healthy| 0| 2| 0| 1.2876476|\n", - "| Cat| 4|Domestic Short Hair|Female| White|No Color| Medium| Short| No| No|Healthy| 0| 2| 1| 0.8216562|\n", - "| Cat| 3|Domestic Short Hair| Male| Brown|No Color| Small| Short| No| No|Healthy| 0| 2| 1| 1.1362813|\n", - "| Cat| 11|Domestic Short Hair|Female| Brown| Yellow| Medium| Short| Yes| Yes|Healthy|100| 1| 0|-0.5538333|\n", - "| Dog| 1| Mixed Breed| Male| Black| Brown| Medium| Medium| No| No|Healthy| 0| 1| 1| 1.8639014|\n", - "| Dog| 12|German Shepherd Dog|Female| Black| Brown| Large| Medium| Not Sure| Not Sure|Healthy| 0| 4| 1| 0.646166|\n", - "| Cat| 3|Oriental Short Hair|Female| White|No Color| Medium| Short| Not Sure| Not Sure|Healthy| 0| 3| 1| 1.2250762|\n", - "| Cat| 6| Russian Blue| Male| Gray|No Color| Medium| Short| Not Sure| No|Healthy| 0| 3| 1| 1.2427491|\n", - "| Dog| 13| Miniature Pinscher|Female|Golden|No Color| Small| Short| Yes| Yes|Healthy| 0| 6| 1| 1.2280617|\n", - "| Dog| 5| Mixed Breed| Male| Black| White| Large| Medium| Yes| Yes|Healthy| 0| 6| 1| 0.3791974|\n", - "| Dog| 62| Golden Retriever|Female|Golden| Cream| Medium| Medium| Yes| Yes|Healthy| 0| 3| 1| 0.9814444|\n", - "| Cat| 2| Domestic Long Hair|Female| Cream|No Color| Medium| Medium| No| No|Healthy| 80| 5| 1| 2.7954462|\n", - "| Cat| 12|Domestic Short Hair|Female| White|No Color| Medium| Short| Yes| Yes|Healthy| 0| 1| 1|-0.2367835|\n", - "| Dog| 1| Mixed Breed|Female| Brown|No Color| Medium| Medium| No| No|Healthy| 0| 3| 1| 1.8235079|\n", - "| Dog| 5| Mixed Breed|Female| Brown|No Color| Medium| Medium| Yes| No|Healthy| 0| 1| 1|0.16853562|\n", - "| Dog| 2| Mixed Breed|Female| Black| Brown| Medium| Medium| Yes| No|Healthy| 0| 1| 0| 1.3014978|\n", - "| Cat| 4|Domestic Short Hair| Male| Black|No Color| Medium| Short| No| No|Healthy| 0| 3| 0| 1.0102129|\n", - "| Dog| 2| Mixed Breed| Male| Cream|No Color| Medium| Medium| No| No|Healthy| 0| 3| 1| 2.032087|\n", - "| Dog| 24| Pomeranian| Male|Yellow| White| Small| Medium| Not Sure| Not Sure|Healthy| 0| 9| 1| 1.7647744|\n", - "| Cat| 36|Domestic Short Hair|Female| Gray| White| Small| Short| Not Sure| Not Sure|Healthy| 0| 2| 1|0.16341272|\n", - "+----+---+-------------------+------+------+--------+------------+---------+----------+----------+-------+---+--------+------+----------+\n", + "+----+---+--------------------+------+------+--------+------------+---------+----------+----------+------------+---+--------+------+-----------+\n", + "|Type|Age| Breed1|Gender|Color1| Color2|MaturitySize|FurLength|Vaccinated|Sterilized| Health|Fee|PhotoAmt|target| preds|\n", + "+----+---+--------------------+------+------+--------+------------+---------+----------+----------+------------+---+--------+------+-----------+\n", + "| Cat| 1|Domestic Medium Hair|Female| White|No Color| Small| Medium| No| No| Healthy| 0| 2| 1| 1.9543833|\n", + "| Dog| 2| Mixed Breed|Female| Black| Brown| Medium| Medium| No| No| Healthy| 0| 3| 1| 1.7454995|\n", + "| Dog| 18| Dalmatian|Female| Black| White| Medium| Medium| Yes| No| Healthy|350| 5| 1| 1.5183508|\n", + "| Dog| 3| Mixed Breed|Female| Black|No Color| Medium| Short| No| No| Healthy| 0| 1| 0| 0.67013955|\n", + "| Dog| 2| Mixed Breed| Male| Black| Brown| Medium| Short| No| No| Healthy| 0| 1| 1| 1.5492269|\n", + "| Dog| 36| Mixed Breed| Male| Brown|No Color| Medium| Medium| Not Sure| Yes|Minor Injury| 0| 1| 0|-0.27595556|\n", + "| Cat| 6| Domestic Short Hair|Female| Black| White| Medium| Short| Yes| No| Healthy| 0| 5| 0| 0.7229555|\n", + "| Dog| 72| Golden Retriever|Female| Cream|No Color| Large| Medium| Yes| Not Sure| Healthy| 0| 1| 1| 0.7397226|\n", + "| Cat| 2| Domestic Short Hair| Male| Black| White| Small| Short| No| Yes| Healthy| 0| 4| 1| 1.4016482|\n", + "| Dog| 3| Irish Terrier| Male| Brown| Cream| Medium| Medium| Yes| No|Minor Injury|200| 3| 0| 1.3436754|\n", + "| Dog| 2| Mixed Breed|Female| White|No Color| Medium| Medium| Yes| No| Healthy| 0| 1| 1| 1.156439|\n", + "| Dog| 2| Mixed Breed| Male| Brown|No Color| Medium| Medium| Yes| No| Healthy| 0| 4| 1| 1.7760799|\n", + "| Cat| 2| Domestic Short Hair| Male| Black| Gray| Medium| Short| No| No| Healthy| 0| 2| 1| 1.8319463|\n", + "| Dog| 1| German Shepherd Dog| Male| Gray|No Color| Medium| Medium| No| No| Healthy| 0| 6| 1| 2.5471144|\n", + "| Dog| 24| Golden Retriever| Male|Yellow| Cream| Medium| Long| Yes| Yes| Healthy| 0| 7| 1| 1.4675076|\n", + "| Dog| 1| Mixed Breed|Female| Black| Brown| Small| Medium| No| Yes| Healthy| 0| 1| 0| 0.8451028|\n", + "| Cat| 12| Tuxedo| Male| Black|No Color| Small| Medium| Yes| Yes| Healthy| 50| 1| 1| 0.6487097|\n", + "| Cat| 3| Domestic Short Hair|Female| Black|No Color| Small| Short| No| No| Healthy| 0| 1| 1| 1.0688435|\n", + "| Dog| 2| Mixed Breed|Female| Brown| White| Medium| Short| No| No| Healthy| 0| 1| 1| 1.4086031|\n", + "| Dog| 11| Mixed Breed|Female|Golden|No Color| Medium| Short| Yes| Yes| Healthy| 0| 9| 1| 0.28429908|\n", + "+----+---+--------------------+------+------+--------+------------+---------+----------+----------+------------+---+--------+------+-----------+\n", "only showing top 20 rows\n", "\n" ] @@ -1690,7 +1749,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 59, "id": "6914f44f-677f-4db3-be09-783df8d11b8a", "metadata": {}, "outputs": [ @@ -1707,7 +1766,7 @@ "[True]" ] }, - "execution_count": 58, + "execution_count": 59, "metadata": {}, "output_type": "execute_result" } @@ -1731,7 +1790,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 60, "id": "f8c6ee43-8891-4446-986e-1447c5d48bac", "metadata": {}, "outputs": [], @@ -1750,7 +1809,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "spark-dl-tf", "language": "python", "name": "python3" }, @@ -1764,7 +1823,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification.ipynb index 25e809387..5add2686b 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification.ipynb @@ -11,17 +11,40 @@ "Based on: https://www.tensorflow.org/tutorials/keras/save_and_load" ] }, + { + "cell_type": "markdown", + "id": "5233632d", + "metadata": {}, + "source": [ + "### Using TensorFlow\n", + "Note that cuFFT/cuDNN/cuBLAS registration errors are expected with `tf=2.17.0` and will not affect behavior, as noted in [this issue.](https://github.com/tensorflow/tensorflow/issues/62075) \n", + "This notebook does not demonstrate inference with TensorRT, as [TF-TRT](https://docs.nvidia.com/deeplearning/tensorrt/release-notes/index.html#tensorrt-10) does not yet support `tf=2.17.0`. See the `pytorch` notebooks for TensorRT demos." + ] + }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "id": "c8b28f02", "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:40:20.324462: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2024-10-03 17:40:20.331437: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", + "2024-10-03 17:40:20.339109: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", + "2024-10-03 17:40:20.341362: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", + "2024-10-03 17:40:20.347337: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2024-10-03 17:40:20.672391: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" + ] + }, { "name": "stdout", "output_type": "stream", "text": [ - "2.12.0\n" + "2.17.0\n" ] } ], @@ -30,12 +53,30 @@ "import numpy as np\n", "import subprocess\n", "import tensorflow as tf\n", + "import os\n", "\n", "from tensorflow import keras\n", "\n", "print(tf.version.VERSION)" ] }, + { + "cell_type": "code", + "execution_count": 3, + "id": "e2e67086", + "metadata": {}, + "outputs": [], + "source": [ + "# Enable GPU memory growth\n", + "gpus = tf.config.experimental.list_physical_devices('GPU')\n", + "if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)" + ] + }, { "cell_type": "markdown", "id": "7e0c7ad6", @@ -46,17 +87,31 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "id": "5b007f7c", "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m11490434/11490434\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n" + ] + }, { "data": { "text/plain": [ "((60000, 28, 28), (10000, 28, 28))" ] }, - "execution_count": 2, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -69,34 +124,28 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "id": "7b7cedd1", "metadata": {}, - "outputs": [], - "source": [ - "# flatten and normalize\n", - "train_images = train_images.reshape(-1, 784) / 255.0\n", - "test_images = test_images.reshape(-1, 784) / 255.0" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "e77bfbd7", - "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "((60000, 784), (10000, 784))" + "((1000, 784), (1000, 784))" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ + "train_labels = train_labels[:1000]\n", + "test_labels = test_labels[:1000]\n", + "\n", + "train_images = train_images[:1000].reshape(-1, 28 * 28) / 255.0\n", + "test_images = test_images[:1000].reshape(-1, 28 * 28) / 255.0\n", + "\n", "train_images.shape, test_images.shape" ] }, @@ -110,44 +159,113 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "id": "746d94db", "metadata": {}, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "Model: \"sequential\"\n", - "_________________________________________________________________\n", - " Layer (type) Output Shape Param # \n", - "=================================================================\n", - " dense (Dense) (None, 512) 401920 \n", - " \n", - " dropout (Dropout) (None, 512) 0 \n", - " \n", - " dense_1 (Dense) (None, 10) 5130 \n", - " \n", - "=================================================================\n", - "Total params: 407,050\n", - "Trainable params: 407,050\n", - "Non-trainable params: 0\n", - "_________________________________________________________________\n" + "/home/rishic/anaconda3/envs/spark-dl-tf/lib/python3.11/site-packages/keras/src/layers/core/dense.py:87: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.\n", + " super().__init__(activity_regularizer=activity_regularizer, **kwargs)\n", + "2024-10-03 17:40:21.624052: I tensorflow/core/common_runtime/gpu/gpu_device.cc:2021] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 45743 MB memory: -> device: 0, name: NVIDIA RTX A6000, pci bus id: 0000:01:00.0, compute capability: 8.6\n" ] + }, + { + "data": { + "text/html": [ + "
Model: \"sequential\"\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1mModel: \"sequential\"\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
+       "┃ Layer (type)                     Output Shape                  Param # ┃\n",
+       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
+       "│ dense (Dense)                   │ (None, 512)            │       401,920 │\n",
+       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+       "│ dropout (Dropout)               │ (None, 512)            │             0 │\n",
+       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+       "│ dense_1 (Dense)                 │ (None, 10)             │         5,130 │\n",
+       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
+       "
\n" + ], + "text/plain": [ + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", + "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", + "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", + "│ dense (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m512\u001b[0m) │ \u001b[38;5;34m401,920\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ dropout (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m512\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ dense_1 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m10\u001b[0m) │ \u001b[38;5;34m5,130\u001b[0m │\n", + "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Total params: 407,050 (1.55 MB)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m407,050\u001b[0m (1.55 MB)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Trainable params: 407,050 (1.55 MB)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m407,050\u001b[0m (1.55 MB)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" } ], "source": [ "# Define a simple sequential model\n", "def create_model():\n", - " model = tf.keras.models.Sequential([\n", - " keras.layers.Dense(512, activation='relu', input_shape=(784,)),\n", - " keras.layers.Dropout(0.2),\n", - " keras.layers.Dense(10)\n", + " model = tf.keras.Sequential([\n", + " keras.layers.Dense(512, activation='relu', input_shape=(784,)),\n", + " keras.layers.Dropout(0.2),\n", + " keras.layers.Dense(10)\n", " ])\n", "\n", " model.compile(optimizer='adam',\n", - " loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),\n", - " metrics=[tf.metrics.SparseCategoricalAccuracy()])\n", + " loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n", + " metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])\n", "\n", " return model\n", "\n", @@ -163,12 +281,12 @@ "id": "605d082a", "metadata": {}, "source": [ - "### Train model" + "### Save checkpoints during training" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "id": "244746be", "metadata": {}, "outputs": [ @@ -176,55 +294,98 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 1/5\n", - "1875/1875 [==============================] - 10s 5ms/step - loss: 0.2183 - sparse_categorical_accuracy: 0.9349 - val_loss: 0.1183 - val_sparse_categorical_accuracy: 0.9624\n", - "Epoch 2/5\n", - "1875/1875 [==============================] - 10s 5ms/step - loss: 0.0978 - sparse_categorical_accuracy: 0.9698 - val_loss: 0.0826 - val_sparse_categorical_accuracy: 0.9744\n", - "Epoch 3/5\n", - "1875/1875 [==============================] - 10s 5ms/step - loss: 0.0686 - sparse_categorical_accuracy: 0.9785 - val_loss: 0.0761 - val_sparse_categorical_accuracy: 0.9762\n", - "Epoch 4/5\n", - "1875/1875 [==============================] - 10s 5ms/step - loss: 0.0522 - sparse_categorical_accuracy: 0.9831 - val_loss: 0.0670 - val_sparse_categorical_accuracy: 0.9809\n", - "Epoch 5/5\n", - "1875/1875 [==============================] - 10s 5ms/step - loss: 0.0424 - sparse_categorical_accuracy: 0.9861 - val_loss: 0.0676 - val_sparse_categorical_accuracy: 0.9796\n" + "Epoch 1/10\n" ] }, { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.fit(train_images, \n", - " train_labels, \n", - " epochs=5,\n", - " validation_data=(test_images, test_labels))" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "6d3bba9e", - "metadata": {}, - "outputs": [ + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n", + "I0000 00:00:1727977222.161202 1835280 service.cc:146] XLA service 0x7ec778008e00 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:\n", + "I0000 00:00:1727977222.161216 1835280 service.cc:154] StreamExecutor device (0): NVIDIA RTX A6000, Compute Capability 8.6\n", + "2024-10-03 17:40:22.168848: I tensorflow/compiler/mlir/tensorflow/utils/dump_mlir_util.cc:268] disabling MLIR crash reproducer, set env var `MLIR_CRASH_REPRODUCER_DIRECTORY` to enable.\n", + "2024-10-03 17:40:22.206298: I external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:531] Loaded cuDNN version 8907\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m24s\u001b[0m 778ms/step - loss: 2.3278 - sparse_categorical_accuracy: 0.1250" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "I0000 00:00:1727977222.715572 1835280 device_compiler.h:188] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 17ms/step - loss: 1.5867 - sparse_categorical_accuracy: 0.5096 " + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:40:23.780912: I external/local_xla/xla/stream_executor/cuda/cuda_asm_compiler.cc:393] ptxas warning : Registers are spilled to local memory in function 'gemm_fusion_dot_33', 4 bytes spill stores, 4 bytes spill loads\n", + "\n" + ] + }, { "name": "stdout", "output_type": "stream", "text": [ - "1/1 [==============================] - 0s 55ms/step\n" + "\n", + "Epoch 1: val_sparse_categorical_accuracy improved from -inf to 0.78700, saving model to training_1/checkpoint.model.keras\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 44ms/step - loss: 1.5733 - sparse_categorical_accuracy: 0.5144 - val_loss: 0.7061 - val_sparse_categorical_accuracy: 0.7870\n", + "Epoch 2/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - loss: 0.5514 - sparse_categorical_accuracy: 0.8438\n", + "Epoch 2: val_sparse_categorical_accuracy improved from 0.78700 to 0.83700, saving model to training_1/checkpoint.model.keras\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 2ms/step - loss: 0.4276 - sparse_categorical_accuracy: 0.8935 - val_loss: 0.5268 - val_sparse_categorical_accuracy: 0.8370\n", + "Epoch 3/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 20ms/step - loss: 0.1458 - sparse_categorical_accuracy: 0.9688\n", + "Epoch 3: val_sparse_categorical_accuracy improved from 0.83700 to 0.85600, saving model to training_1/checkpoint.model.keras\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.2721 - sparse_categorical_accuracy: 0.9236 - val_loss: 0.4716 - val_sparse_categorical_accuracy: 0.8560\n", + "Epoch 4/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - loss: 0.2223 - sparse_categorical_accuracy: 0.9375\n", + "Epoch 4: val_sparse_categorical_accuracy did not improve from 0.85600\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.2159 - sparse_categorical_accuracy: 0.9547 - val_loss: 0.4682 - val_sparse_categorical_accuracy: 0.8540\n", + "Epoch 5/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 16ms/step - loss: 0.1483 - sparse_categorical_accuracy: 0.9688\n", + "Epoch 5: val_sparse_categorical_accuracy improved from 0.85600 to 0.86900, saving model to training_1/checkpoint.model.keras\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 2ms/step - loss: 0.1457 - sparse_categorical_accuracy: 0.9716 - val_loss: 0.4285 - val_sparse_categorical_accuracy: 0.8690\n", + "Epoch 6/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - loss: 0.0836 - sparse_categorical_accuracy: 0.9688\n", + "Epoch 6: val_sparse_categorical_accuracy did not improve from 0.86900\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.1292 - sparse_categorical_accuracy: 0.9712 - val_loss: 0.4551 - val_sparse_categorical_accuracy: 0.8580\n", + "Epoch 7/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 12ms/step - loss: 0.0920 - sparse_categorical_accuracy: 0.9688\n", + "Epoch 7: val_sparse_categorical_accuracy did not improve from 0.86900\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.0974 - sparse_categorical_accuracy: 0.9822 - val_loss: 0.4016 - val_sparse_categorical_accuracy: 0.8670\n", + "Epoch 8/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 12ms/step - loss: 0.0993 - sparse_categorical_accuracy: 0.9688\n", + "Epoch 8: val_sparse_categorical_accuracy did not improve from 0.86900\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.0702 - sparse_categorical_accuracy: 0.9920 - val_loss: 0.3999 - val_sparse_categorical_accuracy: 0.8650\n", + "Epoch 9/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 12ms/step - loss: 0.0599 - sparse_categorical_accuracy: 1.0000\n", + "Epoch 9: val_sparse_categorical_accuracy improved from 0.86900 to 0.87800, saving model to training_1/checkpoint.model.keras\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.0457 - sparse_categorical_accuracy: 0.9974 - val_loss: 0.4145 - val_sparse_categorical_accuracy: 0.8780\n", + "Epoch 10/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - loss: 0.0286 - sparse_categorical_accuracy: 1.0000\n", + "Epoch 10: val_sparse_categorical_accuracy did not improve from 0.87800\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.0351 - sparse_categorical_accuracy: 0.9987 - val_loss: 0.4200 - val_sparse_categorical_accuracy: 0.8720\n" ] }, { "data": { "text/plain": [ - "array([[ -9.547884 , -4.7447677, -0.956994 , 1.0100659, -15.265252 ,\n", - " -7.811299 , -15.518889 , 14.113535 , -4.9397273, -4.3322315]],\n", - " dtype=float32)" + "" ] }, "execution_count": 7, @@ -233,230 +394,273 @@ } ], "source": [ - "test_img = test_images[:1]\n", - "prediction = model.predict(test_img)\n", - "prediction" + "checkpoint_path = \"training_1/checkpoint.model.keras\"\n", + "checkpoint_dir = os.path.dirname(checkpoint_path)\n", + "\n", + "# Create a callback that saves the model's weights\n", + "cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,\n", + " monitor='val_sparse_categorical_accuracy',\n", + " mode='max',\n", + " save_best_only=True,\n", + " verbose=1)\n", + "\n", + "# Train the model with the new callback\n", + "model.fit(train_images, \n", + " train_labels, \n", + " epochs=10,\n", + " validation_data=(test_images, test_labels),\n", + " callbacks=[cp_callback]) # Pass callback to training\n", + "\n", + "# This may generate warnings related to saving the state of the optimizer.\n", + "# These warnings (and similar warnings throughout this notebook)\n", + "# are in place to discourage outdated usage, and can be ignored." ] }, { "cell_type": "code", "execution_count": 8, - "id": "e700b66a", + "id": "310eae08", "metadata": {}, "outputs": [ { "data": { - "image/png": "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IACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACuCHkCvvfaaXC5XwNSrV69gbwYA0MxFhGKlvXv31qZNm/69kYiQbAYA0IyFJBkiIiKUlJQUilUDAFqIkFwDOnDggFJSUtStWzc9+eSTOnToUINja2tr5fV6AyYAQMsX9ABKT0/XsmXLtGHDBi1evFhlZWUaOnSoTp48We/4goICeTwe/5SamhrslgAATZDLGGNCuYGqqip16dJFCxYs0NNPP11neW1trWpra/2vvV6vUlNTlaHRinBFhrI1AEAIXDDnVai1qq6uVkxMTIPjQn53QPv27dWjRw8dPHiw3uVut1tutzvUbQAAmpiQfw7o1KlTKi0tVXJycqg3BQBoRoIeQC+88IKKior0zTff6B//+IceffRRhYeH6/HHHw/2pgAAzVjQ34I7cuSIHn/8cZ04cULx8fEaMmSItm/frvj4+GBvCgDQjAU9gFauXBnsVQIAWiCeBQcAsIIAAgBYQQABAKwggAAAVhBAAAArCCAAgBUEEADACgIIAGAFAQQAsIIAAgBYQQABAKwggAAAVoT8C+lwc52YPMhxTeef1v9lgdey/1ii45pztc6/5fa2953XtDlyynGNJPn2/KtRdQCc4wwIAGAFAQQAsIIAAgBYQQABAKwggAAAVhBAAAArCCAAgBUEEADACgIIAGAFAQQAsIIAAgBYQQABAKwggAAAVvA07BbmxZ+vcFwzru33jdtY98aVOZbhvOSbC6cbtak3jz/QqDrcPP881sVxTdvfehq1rYjNuxpVh+vDGRAAwAoCCABgBQEEALCCAAIAWEEAAQCsIIAAAFYQQAAAKwggAIAVBBAAwAoCCABgBQEEALCCAAIAWMHDSFuYt14e77hmdr/G/R7S4WvjuOb7O12Oa6L6VTmumd/nI8c1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", "text/plain": [ - "
" + "['checkpoint.model.keras']" ] }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure()\n", - "plt.title(\"Prediction: {}\".format(np.argmax(prediction)))\n", - "plt.imshow(test_img.reshape(28,28))\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "135b42b0", - "metadata": {}, - "source": [ - "### Save Model" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "33f11a35", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 9, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "subprocess.call(\"rm -rf mnist_model\".split())" + "os.listdir(checkpoint_dir)" ] }, { "cell_type": "code", - "execution_count": 10, - "id": "86f9376d", + "execution_count": 9, + "id": "50eeb6e5", "metadata": {}, "outputs": [ { - "name": "stderr", + "name": "stdout", "output_type": "stream", "text": [ - "WARNING:absl:Found untraced functions such as _update_step_xla while saving (showing 1 of 1). These functions will not be directly callable after loading.\n" + "INFO:tensorflow:Assets written to: mnist_model/assets\n" ] }, { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ "INFO:tensorflow:Assets written to: mnist_model/assets\n" ] }, { - "name": "stderr", + "name": "stdout", "output_type": "stream", "text": [ - "INFO:tensorflow:Assets written to: mnist_model/assets\n" + "Saved artifact at 'mnist_model'. The following endpoints are available:\n", + "\n", + "* Endpoint 'serve'\n", + " args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 784), dtype=tf.float32, name='keras_tensor')\n", + "Output Type:\n", + " TensorSpec(shape=(None, 10), dtype=tf.float32, name=None)\n", + "Captures:\n", + " 139403584120848: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 139403240100240: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 139403240100048: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 139403240099856: TensorSpec(shape=(), dtype=tf.resource, name=None)\n" ] } ], "source": [ - "model.save('mnist_model')" - ] - }, - { - "cell_type": "markdown", - "id": "43a417c6", - "metadata": {}, - "source": [ - "### Inspect saved model" + "# Export model in saved_model format\n", + "model.export(\"mnist_model\")" ] }, { "cell_type": "code", - "execution_count": 11, - "id": "53a8ba4a", + "execution_count": 10, + "id": "6d3bba9e", "metadata": {}, "outputs": [ { - "name": "stdout", + "name": "stderr", "output_type": "stream", "text": [ - "\u001b[01;34mmnist_model\u001b[00m\n", - "├── \u001b[01;34massets\u001b[00m\n", - "├── fingerprint.pb\n", - "├── keras_metadata.pb\n", - "├── saved_model.pb\n", - "└── \u001b[01;34mvariables\u001b[00m\n", - " ├── variables.data-00000-of-00001\n", - " └── variables.index\n", - "\n", - "2 directories, 5 files\n" + "/home/rishic/anaconda3/envs/spark-dl-tf/lib/python3.11/site-packages/keras/src/layers/core/dense.py:87: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.\n", + " super().__init__(activity_regularizer=activity_regularizer, **kwargs)\n" ] }, { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "32/32 - 0s - 10ms/step - loss: 2.4196 - sparse_categorical_accuracy: 0.0590\n", + "Untrained model, accuracy: 5.90%\n" + ] } ], "source": [ - "subprocess.call(\"tree mnist_model\".split())" + "# Create a basic model instance\n", + "model = create_model()\n", + "\n", + "# Evaluate the model\n", + "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", + "print(\"Untrained model, accuracy: {:5.2f}%\".format(100 * acc))" ] }, { "cell_type": "code", - "execution_count": 12, - "id": "677e377a", + "execution_count": 11, + "id": "22ad1708", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "The given SavedModel SignatureDef contains the following input(s):\n", - " inputs['dense_input'] tensor_info:\n", - " dtype: DT_FLOAT\n", - " shape: (-1, 784)\n", - " name: serving_default_dense_input:0\n", - "The given SavedModel SignatureDef contains the following output(s):\n", - " outputs['dense_1'] tensor_info:\n", - " dtype: DT_FLOAT\n", - " shape: (-1, 10)\n", - " name: StatefulPartitionedCall:0\n", - "Method name is: tensorflow/serving/predict\n" + "32/32 - 0s - 713us/step - loss: 0.4145 - sparse_categorical_accuracy: 0.8780\n", + "Restored model, accuracy: 87.80%\n" ] }, { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/rishic/anaconda3/envs/spark-dl-tf/lib/python3.11/site-packages/keras/src/saving/saving_lib.py:713: UserWarning: Skipping variable loading for optimizer 'adam', because it has 2 variables whereas the saved optimizer has 10 variables. \n", + " saveable.load_own_variables(weights_store.get(inner_path))\n" + ] } ], "source": [ - "subprocess.call(\"saved_model_cli show --dir mnist_model --tag_set serve --signature_def serving_default\".split())" + "# Load the weights from the checkpoint\n", + "model.load_weights(checkpoint_path)\n", + "\n", + "# Re-evaluate the model\n", + "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", + "print(\"Restored model, accuracy: {:5.2f}%\".format(100 * acc))" ] }, { "cell_type": "markdown", - "id": "6f013a4b", + "id": "1c097d63", "metadata": {}, "source": [ - "### Load model" + "### Checkpoint callback options" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "cb336e89", + "metadata": {}, + "outputs": [], + "source": [ + "!rm -rf training_2\n", + "!mkdir training_2" ] }, { "cell_type": "code", "execution_count": 13, - "id": "c41008f2", + "id": "750b6deb", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Model: \"sequential\"\n", - "_________________________________________________________________\n", - " Layer (type) Output Shape Param # \n", - "=================================================================\n", - " dense (Dense) (None, 512) 401920 \n", - " \n", - " dropout (Dropout) (None, 512) 0 \n", - " \n", - " dense_1 (Dense) (None, 10) 5130 \n", - " \n", - "=================================================================\n", - "Total params: 407,050\n", - "Trainable params: 407,050\n", - "Non-trainable params: 0\n", - "_________________________________________________________________\n" + "\n", + "Epoch 5: saving model to training_2/cp-0005.weights.h5\n", + "\n", + "Epoch 10: saving model to training_2/cp-0010.weights.h5\n", + "\n", + "Epoch 15: saving model to training_2/cp-0015.weights.h5\n", + "\n", + "Epoch 20: saving model to training_2/cp-0020.weights.h5\n", + "\n", + "Epoch 25: saving model to training_2/cp-0025.weights.h5\n", + "\n", + "Epoch 30: saving model to training_2/cp-0030.weights.h5\n", + "\n", + "Epoch 35: saving model to training_2/cp-0035.weights.h5\n", + "\n", + "Epoch 40: saving model to training_2/cp-0040.weights.h5\n", + "\n", + "Epoch 45: saving model to training_2/cp-0045.weights.h5\n", + "\n", + "Epoch 50: saving model to training_2/cp-0050.weights.h5\n" ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "new_model = tf.keras.models.load_model('mnist_model')\n", - "new_model.summary()" + "# Include the epoch in the file name (uses `str.format`)\n", + "checkpoint_path = \"training_2/cp-{epoch:04d}.weights.h5\"\n", + "checkpoint_dir = os.path.dirname(checkpoint_path)\n", + "\n", + "batch_size = 32\n", + "\n", + "# Calculate the number of batches per epoch\n", + "import math\n", + "n_batches = len(train_images) / batch_size\n", + "n_batches = math.ceil(n_batches) # round up the number of batches to the nearest whole integer\n", + "\n", + "# Create a callback that saves the model's weights every 5 epochs\n", + "cp_callback = tf.keras.callbacks.ModelCheckpoint(\n", + " filepath=checkpoint_path, \n", + " verbose=1, \n", + " save_weights_only=True,\n", + " save_freq=5*n_batches)\n", + "\n", + "# Create a new model instance\n", + "model = create_model()\n", + "\n", + "# Save the weights using the `checkpoint_path` format\n", + "model.save_weights(checkpoint_path.format(epoch=0))\n", + "\n", + "# Train the model with the new callback\n", + "model.fit(train_images, \n", + " train_labels,\n", + " epochs=50, \n", + " batch_size=batch_size, \n", + " callbacks=[cp_callback],\n", + " validation_data=(test_images, test_labels),\n", + " verbose=0)" ] }, { "cell_type": "code", "execution_count": 14, - "id": "256662e8-30f1-437f-88b7-4534a7e76907", + "id": "1c43fd3d", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[]" + "['cp-0000.weights.h5',\n", + " 'cp-0015.weights.h5',\n", + " 'cp-0010.weights.h5',\n", + " 'cp-0035.weights.h5',\n", + " 'cp-0020.weights.h5',\n", + " 'cp-0040.weights.h5',\n", + " 'cp-0050.weights.h5',\n", + " 'cp-0005.weights.h5',\n", + " 'cp-0045.weights.h5',\n", + " 'cp-0025.weights.h5',\n", + " 'cp-0030.weights.h5']" ] }, "execution_count": 14, @@ -465,45 +669,44 @@ } ], "source": [ - "new_model.inputs" + "os.listdir(checkpoint_dir)" ] }, { - "cell_type": "markdown", - "id": "351c7b84", + "cell_type": "code", + "execution_count": 15, + "id": "0d7ae715", "metadata": {}, + "outputs": [], "source": [ - "### Predict" + "latest = \"training_2/cp-0030.weights.h5\"" ] }, { "cell_type": "code", - "execution_count": 15, - "id": "5dbeeb98", + "execution_count": 16, + "id": "d345c6f7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "1/1 [==============================] - 0s 30ms/step\n" + "32/32 - 0s - 9ms/step - loss: 0.4501 - sparse_categorical_accuracy: 0.8720\n", + "Restored model, accuracy: 87.20%\n" ] - }, - { - "data": { - "text/plain": [ - "array([[ -9.547884 , -4.7447677, -0.956994 , 1.0100659, -15.265252 ,\n", - " -7.811299 , -15.518889 , 14.113535 , -4.9397273, -4.3322315]],\n", - " dtype=float32)" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "new_model.predict(test_images[:1])" + "# Create a new model instance\n", + "model = create_model()\n", + "\n", + "# Load the previously saved weights\n", + "model.load_weights(latest)\n", + "\n", + "# Re-evaluate the model from the latest checkpoint\n", + "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", + "print(\"Restored model, accuracy: {:5.2f}%\".format(100 * acc))" ] }, { @@ -516,12 +719,44 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "id": "7fcf07bb", "metadata": {}, "outputs": [], "source": [ - "import pandas as pd" + "import pandas as pd\n", + "from pyspark.sql import SparkSession\n", + "from pyspark import SparkConf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c022c24", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", + "\n", + "conf = SparkConf()\n", + "if 'spark' not in globals():\n", + " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", + " import socket\n", + " hostname = socket.gethostname()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", + "conf.set(\"spark.task.maxFailures\", \"1\")\n", + "conf.set(\"spark.driver.memory\", \"8g\")\n", + "conf.set(\"spark.executor.memory\", \"8g\")\n", + "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", + "conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + "conf.set(\"spark.python.worker.reuse\", \"true\")\n", + "# Create Spark Session\n", + "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", + "sc = spark.sparkContext" ] }, { @@ -534,17 +769,17 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 19, "id": "49ff5203", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "(10000, 784)" + "(1000, 784)" ] }, - "execution_count": 17, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -557,7 +792,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 20, "id": "182ee0c7", "metadata": {}, "outputs": [ @@ -565,14 +800,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 1min, sys: 0 ns, total: 1min\n", - "Wall time: 1min 2s\n" + "CPU times: user 134 ms, sys: 15.5 ms, total: 149 ms\n", + "Wall time: 1.36 s\n" ] } ], "source": [ "%%time\n", - "df = spark.createDataFrame(test_pdf)" + "df = spark.createDataFrame(test_pdf).repartition(8)" ] }, { @@ -585,7 +820,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 21, "id": "0061c39a-0871-429e-a4ff-751d26bf4b04", "metadata": {}, "outputs": [ @@ -593,8 +828,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "23/05/19 17:46:15 WARN package: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.sql.debug.maxToStringFields'.\n", - "23/05/19 17:46:15 WARN TaskSetManager: Stage 0 contains a task of very large size (7067 KiB). The maximum recommended task size is 1000 KiB.\n", + "24/10/03 17:40:32 WARN SparkStringUtils: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.sql.debug.maxToStringFields'.\n", "[Stage 0:> (0 + 8) / 8]\r" ] }, @@ -602,8 +836,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 12.1 ms, sys: 0 ns, total: 12.1 ms\n", - "Wall time: 5.72 s\n" + "CPU times: user 2.49 ms, sys: 1.65 ms, total: 4.13 ms\n", + "Wall time: 1.66 s\n" ] }, { @@ -629,7 +863,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 22, "id": "302c73ec", "metadata": {}, "outputs": [ @@ -637,17 +871,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 261 ms, sys: 0 ns, total: 261 ms\n", - "Wall time: 258 ms\n" + "CPU times: user 6.71 ms, sys: 4.92 ms, total: 11.6 ms\n", + "Wall time: 11.4 ms\n" ] }, { "data": { "text/plain": [ - "(10000, 1)" + "(1000, 1)" ] }, - "execution_count": 20, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -661,7 +895,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 23, "id": "5495901b", "metadata": {}, "outputs": [ @@ -669,8 +903,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 12.5 s, sys: 0 ns, total: 12.5 s\n", - "Wall time: 12.6 s\n" + "CPU times: user 46.6 ms, sys: 4.71 ms, total: 51.3 ms\n", + "Wall time: 91.7 ms\n" ] } ], @@ -681,31 +915,16 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 24, "id": "5fa7faa8-c6bd-41b0-b5f7-fb121f0332e6", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/05/19 17:46:33 WARN TaskSetManager: Stage 1 contains a task of very large size (7070 KiB). The maximum recommended task size is 1000 KiB.\n", - "[Stage 1:> (0 + 8) / 8]\r" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 9.88 ms, sys: 0 ns, total: 9.88 ms\n", - "Wall time: 1.36 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" + "CPU times: user 807 μs, sys: 724 μs, total: 1.53 ms\n", + "Wall time: 211 ms\n" ] } ], @@ -724,18 +943,10 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 25, "id": "3d4ca414", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "23/05/19 17:46:34 WARN TaskSetManager: Stage 2 contains a task of very large size (7070 KiB). The maximum recommended task size is 1000 KiB.\n" - ] - } - ], + "outputs": [], "source": [ "spark.conf.set(\"spark.sql.execution.arrow.maxRecordsPerBatch\", \"128\")\n", "# This line will fail if the vectorized reader runs out of memory\n", @@ -760,7 +971,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 26, "id": "db30fba6-24d0-4c00-8502-04f9b10e7e16", "metadata": {}, "outputs": [], @@ -776,24 +987,34 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 27, "id": "b9cf62f8-96b2-4716-80bd-bb93d5f939bd", "metadata": {}, "outputs": [], "source": [ "# get absolute path to model\n", - "model_dir = \"{}/mnist_model\".format(os.getcwd())" + "model_dir = \"{}/training_1/checkpoint.model.keras\".format(os.getcwd())" ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 28, "id": "b81fa297-d9d0-4600-880d-dbdcdf8bccc6", "metadata": {}, "outputs": [], "source": [ "def predict_batch_fn():\n", " import tensorflow as tf\n", + "\n", + " # Enable GPU memory growth to avoid CUDA OOM\n", + " gpus = tf.config.experimental.list_physical_devices('GPU')\n", + " if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)\n", + "\n", " model = tf.keras.models.load_model(model_dir)\n", " def predict(inputs: np.ndarray) -> np.ndarray:\n", " return model.predict(inputs)\n", @@ -803,7 +1024,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 29, "id": "72a689bd-dd82-492e-8740-1738a215325f", "metadata": {}, "outputs": [], @@ -816,7 +1037,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 30, "id": "60a70150-26b1-4145-9e7d-6e17389216b7", "metadata": {}, "outputs": [ @@ -826,7 +1047,7 @@ "1" ] }, - "execution_count": 28, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } @@ -838,7 +1059,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 31, "id": "e027f0d2-0f65-47b7-a562-2f0965faceec", "metadata": {}, "outputs": [ @@ -866,7 +1087,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 32, "id": "f0c3fb2e-469e-47bc-b948-8f6b0d7f6513", "metadata": {}, "outputs": [ @@ -874,15 +1095,22 @@ "name": "stderr", "output_type": "stream", "text": [ - " \r" + "[Stage 4:===================================================> (7 + 1) / 8]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 827 ms, sys: 0 ns, total: 827 ms\n", - "Wall time: 6.2 s\n" + "CPU times: user 18.5 ms, sys: 13.3 ms, total: 31.8 ms\n", + "Wall time: 5.03 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" ] } ], @@ -894,23 +1122,16 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 33, "id": "cdfa229a-f4a9-4c11-a410-de4a21c02c82", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 628 ms, sys: 0 ns, total: 628 ms\n", - "Wall time: 2.18 s\n" + "CPU times: user 37.3 ms, sys: 12.4 ms, total: 49.8 ms\n", + "Wall time: 259 ms\n" ] } ], @@ -921,23 +1142,16 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 34, "id": "5586ce49-6f93-4343-9b66-0dbb64972179", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 612 ms, sys: 0 ns, total: 612 ms\n", - "Wall time: 2.05 s\n" + "CPU times: user 22.9 ms, sys: 5.96 ms, total: 28.8 ms\n", + "Wall time: 237 ms\n" ] } ], @@ -958,10 +1172,17 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 35, "id": "4f947dc0-6b18-4605-810b-e83250a161db", "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, { "data": { "text/html": [ @@ -991,60 +1212,60 @@ " \n", " 0\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-9.66701889038086, -3.6094393730163574, -3.31...\n", + " [-5.88436, -3.1058547, 0.10873719, 12.67319, -...\n", " \n", " \n", " 1\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-16.348304748535156, 3.1133787631988525, 6.73...\n", + " [-3.273286, -8.362554, 1.8936121, -3.8881433, ...\n", " \n", " \n", " 2\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-21.153539657592773, -6.192655086517334, -6.6...\n", + " [-3.3856308, 0.6785604, 1.3146863, 0.9275978, ...\n", " \n", " \n", " 3\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-13.79001522064209, -16.20423126220703, -8.87...\n", + " [-2.7754688, -7.3659225, 11.768427, 1.3434286,...\n", " \n", " \n", " 4\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-18.723485946655273, -7.806203365325928, -8.6...\n", + " [-4.9426627, 4.0774136, -0.4529277, -0.9312789...\n", " \n", " \n", " 5\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [10.495272636413574, -10.992117881774902, -2.4...\n", + " [-5.226616, -3.1389174, 2.6100307, 3.695045, -...\n", " \n", " \n", " 6\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-9.437854766845703, -3.7454347610473633, -3.5...\n", + " [-4.3006196, 5.1169925, 0.5850615, -0.76248693...\n", " \n", " \n", " 7\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-12.314886093139648, -2.106672763824463, -0.7...\n", + " [-2.3985956, -1.4814724, -4.884057, -0.2391600...\n", " \n", " \n", " 8\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-22.142608642578125, -2.8917746543884277, -4....\n", + " [0.82160115, -2.8640625, -1.6951559, -4.489290...\n", " \n", " \n", " 9\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-12.939343452453613, 0.40699127316474915, 15....\n", + " [-1.2338604, -2.151981, -4.171742, 1.6106845, ...\n", " \n", " \n", "\n", "" ], "text/plain": [ - " data \n", - "0 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \\\n", + " data \\\n", + "0 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", "1 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", "2 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", "3 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", @@ -1056,19 +1277,19 @@ "9 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", "\n", " preds \n", - "0 [-9.66701889038086, -3.6094393730163574, -3.31... \n", - "1 [-16.348304748535156, 3.1133787631988525, 6.73... \n", - "2 [-21.153539657592773, -6.192655086517334, -6.6... \n", - "3 [-13.79001522064209, -16.20423126220703, -8.87... \n", - "4 [-18.723485946655273, -7.806203365325928, -8.6... \n", - "5 [10.495272636413574, -10.992117881774902, -2.4... \n", - "6 [-9.437854766845703, -3.7454347610473633, -3.5... \n", - "7 [-12.314886093139648, -2.106672763824463, -0.7... \n", - "8 [-22.142608642578125, -2.8917746543884277, -4.... \n", - "9 [-12.939343452453613, 0.40699127316474915, 15.... " + "0 [-5.88436, -3.1058547, 0.10873719, 12.67319, -... \n", + "1 [-3.273286, -8.362554, 1.8936121, -3.8881433, ... \n", + "2 [-3.3856308, 0.6785604, 1.3146863, 0.9275978, ... \n", + "3 [-2.7754688, -7.3659225, 11.768427, 1.3434286,... \n", + "4 [-4.9426627, 4.0774136, -0.4529277, -0.9312789... \n", + "5 [-5.226616, -3.1389174, 2.6100307, 3.695045, -... \n", + "6 [-4.3006196, 5.1169925, 0.5850615, -0.76248693... \n", + "7 [-2.3985956, -1.4814724, -4.884057, -0.2391600... \n", + "8 [0.82160115, -2.8640625, -1.6951559, -4.489290... \n", + "9 [-1.2338604, -2.151981, -4.171742, 1.6106845, ... " ] }, - "execution_count": 33, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" } @@ -1080,26 +1301,19 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 36, "id": "de4964e0-d1f8-4753-afa1-a8f95ca3f151", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[-9.66701889038086,\n", - " -3.6094393730163574,\n", - " -3.3102951049804688,\n", - " -0.32629871368408203,\n", - " -8.564104080200195,\n", - " -3.614396095275879,\n", - " -5.390956878662109,\n", - " -3.0429909229278564,\n", - " 9.717466354370117,\n", - " -5.417511463165283]" + "array([ -5.88436 , -3.1058547 , 0.10873719, 12.67319 ,\n", + " -5.143787 , 4.0859914 , -10.203137 , -1.4333997 ,\n", + " -3.3865087 , -3.8473575 ], dtype=float32)" ] }, - "execution_count": 34, + "execution_count": 36, "metadata": {}, "output_type": "execute_result" } @@ -1111,7 +1325,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 37, "id": "44e9a874-e301-4b72-8df7-bf1c5133c287", "metadata": {}, "outputs": [], @@ -1122,7 +1336,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 38, "id": "c60e5af4-fc1e-4575-a717-f304664235be", "metadata": {}, "outputs": [], @@ -1133,13 +1347,13 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 39, "id": "eb45ecc9-d376-40c4-ad7b-2bd08ca5aaf6", "metadata": {}, "outputs": [ { "data": { - "image/png": "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po2Ki4uv2PbFF18oLCxMqamp3+m9gnHpC741NTVXbDt//rwuXLjQYPtGy8c9IFw3/umf/kk1NTV66aWXrth24cIFnTx5UtLFe0yRkZFavHhxwFXDokWLrrmP2267TWlpaVq0aJH//S759ntd+k7S5WMuFx4erhEjRmjt2rX68ssv/esrKiq0YsUKDR48WDExMdfs63Lf9THsm266SWFhYVq1alVA/4cPH9ZHH32kH/7wh473DVzCFRCuG3fccYemT5+uvLw87d27VyNGjFBkZKQOHDig1atX61e/+pX+8R//UfHx8XryySeVl5ene+65R6NGjdKePXv05z//WXFxcVfdR1hYmJYsWaLRo0fr1ltv1ZQpU5ScnKwvvvhCn332mT744ANJUr9+/SRJjz/+uLKyshQeHq6JEyfW+Z4LFizQhg0bNHjwYD322GOKiIjQa6+9purqai1cuDCoY/FdH8OOj4/Xww8/rN/+9rcaPny4xo8fr1OnTunVV1/V2bNnlZubG9T+AYkAwnVm6dKl6tevn1577TU988wzioiI0I033qiHHnpIgwYN8o9bsGCBWrVqpaVLl2rLli3KyMjQhx9+qLvvvvua+8jKytKWLVs0f/58/fKXv1Rtba26deumqVOn+seMHz9es2bN0sqVK/X73/9exph6A6h379766KOPlJubq7y8PNXW1iojI0O///3vr/gOUENYsmSJ0tPT9frrr/sDp3///nrrrbc0dOjQBt8/Wi6XCebOJAAA3xP3gAAAVhBAAAArCCAAgBUEEADACgIIAGAFAQQAsKLJfQ+otrZWR44cUXR0dFCzBwMA7DLG6NSpU0pJSbliTsZva3IBdOTIkQad2woA0DjKysqumJX+25pcAEVHR0uSBmuUIhRpuRsAgFMXdF7btM7/73l9GiyA8vPz9fLLL6u8vFzp6elavHixBgwYcM26Sx+7RShSES4CCACanf8/v861bqM0yEMIq1at0ty5czVv3jx9+umnSk9PV1ZWlv8HfgEA0CAB9Morr2jq1KmaMmWKfvCDH2jp0qVq06aN3njjjYbYHQCgGQp5AJ07d067d+8O+GFcYWFhyszM1Pbt268YX11dLZ/PF7AAAFq+kAfQ119/rZqaGiUmJgasT0xMVHl5+RXj8/Ly5PF4/AtPwAHA9cH6F1Fzc3Pl9Xr9S1lZme2WAACNIORPwcXFxSk8PNz/s+QvqaioUFJS0hXj3W633G53qNsAADRxIb8CioqKUr9+/bRp0yb/utraWm3atEkDBw4M9e4AAM1Ug3wPaO7cuZo0aZJ+9KMfacCAAVq0aJEqKys1ZcqUhtgdAKAZapAAuu+++3T8+HE9//zzKi8v16233qr169df8WACAOD65TLGGNtNfJvP55PH49EwjWEmBABohi6Y8yrUWnm9XsXExNQ7zvpTcACA6xMBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArIiw3QBwLeExMY5r/vZc76D29XDWZsc1z8QVO66pMbWOa768cMZxzagdjzmukaQui1yOa1zb/yuofeH6xRUQAMAKAggAYEXIA+iFF16Qy+UKWHr16hXq3QAAmrkGuQfUu3dvbdy48e87ieBWEwAgUIMkQ0REhJKSkhrirQEALUSD3AM6cOCAUlJS1LVrVz344IM6dOhQvWOrq6vl8/kCFgBAyxfyAMrIyFBBQYHWr1+vJUuWqLS0VEOGDNGpU6fqHJ+XlyePx+NfUlNTQ90SAKAJCnkAZWdn695771Xfvn2VlZWldevW6eTJk3rnnXfqHJ+bmyuv1+tfysrKQt0SAKAJavCnA9q3b68ePXro4MGDdW53u91yu90N3QYAoIlp8O8BnT59WiUlJUpOTm7oXQEAmpGQB9CTTz6poqIiffnll/rkk080btw4hYeH6/777w/1rgAAzVjIP4I7fPiw7r//fp04cULx8fEaPHiwduzYofj4+FDvCgDQjLmMMcZ2E9/m8/nk8Xg0TGMU4Yq03Q5CzAy61XHNi7973XFNf7fzyTTxd3+o7OC4piDjNsc1Nd9847gGTd8Fc16FWiuv16uYq0wmzFxwAAArCCAAgBUEEADACgII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mjlzptasWaPNmzcrLS0tYHu/fv0UGRkZcD4UFxfr0KFDLep8uNZxqMvevXslqWmdD7afgvguVq5cadxutykoKDB//etfzbRp00z79u1NeXm57dYa1U9+8hNTWFhoSktLzccff2wyMzNNXFycOXbsmO3WGtSpU6fMnj17zJ49e4wk88orr5g9e/aYr776yhhjzM9//nPTvn17s3btWrNv3z4zZswYk5aWZs6ePWu589C62nE4deqUefLJJ8327dtNaWmp2bhxo7nttttM9+7dTVVVle3WQ2bGjBnG4/GYwsJCc/ToUf9y5swZ/5hHH33UdO7c2WzevNns2rXLDBw40AwcONBi16F3reNw8OBB8+KLL5pdu3aZ0tJSs3btWtO1a1czdOhQy50HahYBZIwxixcvNp07dzZRUVFmwIABZseOHbZbanT33XefSU5ONlFRUeaGG24w9913nzl48KDtthrcli1bjKQrlkmTJhljLj6K/dxzz5nExETjdrvN8OHDTXFxsd2mG8DVjsOZM2fMiBEjTHx8vImMjDRdunQxU6dObXH/Savr9y/JLFu2zD/m7Nmz5rHHHjMdOnQwbdq0MePGjTNHjx6113QDuNZxOHTokBk6dKiJjY01brfb3HTTTeanP/2p8Xq9dhu/DD8PCABgRZO/BwQAaJkIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMCK/wcgFXDPfhuVLAAAAABJRU5ErkJggg==", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGzCAYAAABpdMNsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAkfElEQVR4nO3dfXQUdZ7v8U/nqSEkaR7yLAFCFHRAcAYly/AgSiQEZUCYGUG9F7gziJiggI6KR0Udzsksrg7qIHjcHVhHEGWOyMoiDg9JGBRwwTCIM2QhJ0g4kIBcSYcAIaR/9w+uvbQkQDUdfkl4v86pc+iq37fqm6Lgk+qqrnYZY4wAALjKwmw3AAC4NhFAAAArCCAAgBUEEADACgIIAGAFAQQAsIIAAgBYQQABAKwggAAAVhBAgAPdunXTpEmT/K8LCwvlcrlUWFgYsm24XC698MILIVsf0FwRQGgxlixZIpfL5Z/atGmjHj16KC8vT5WVlbbbc2TNmjUtJmTefvtt3X777UpKSpLb7VZ6eromT56s/fv3224NLVyE7QYAp1566SWlp6fr9OnT2rx5sxYuXKg1a9Zo9+7dio6Ovqq9DBkyRKdOnVJUVJSjujVr1mjBggUNhtCpU6cUEdF8/mkWFxcrPT1dP/vZz9ShQweVlZXp7bff1urVq/W3v/1NqamptltEC9V8jnLgMuXk5OjWW2+VJP36179Wp06d9Oqrr2rVqlWaMGFCgzU1NTVq165dyHsJCwtTmzZtQrrOUK/vSr355psXzBszZoxuvfVWvfPOO3r66actdIXWgLfg0OLdeeedkqSysjJJ0qRJkxQTE6PS0lKNHDlSsbGxeuCBByRJPp9P8+fPV69evdSmTRslJSVp6tSp+u677wLWaYzR3Llz1blzZ0VHR+uOO+7Q119/fcG2G7sGtG3bNo0cOVIdOnRQu3bt1KdPH7322mv+/hYsWCBJAW8pfq+ha0DFxcXKyclRXFycYmJiNGzYMG3dujVgzPdvUX722WeaNWuWEhIS1K5dO9177706evRowNiqqirt2bNHVVVVl7OLL9CtWzdJ0vHjx4OqByTOgNAKlJaWSpI6derkn3f27FllZ2dr0KBB+pd/+Rf/W3NTp07VkiVLNHnyZD366KMqKyvTH/7wBxUXF+uzzz5TZGSkJOn555/X3LlzNXLkSI0cOVJffvmlhg8frjNnzlyyn3Xr1umee+5RSkqKHnvsMSUnJ+sf//iHVq9erccee0xTp07VoUOHtG7dOv3pT3+65Pq+/vprDR48WHFxcXryyScVGRmpt956S0OHDlVRUZEyMzMDxk+fPl0dOnTQnDlztH//fs2fP195eXl6//33/WNWrlypyZMna/HixQE3VVzMsWPHVF9frwMHDuill16SJA0bNuyyaoEGGaCFWLx4sZFk1q9fb44ePWrKy8vN8uXLTadOnUzbtm3NwYMHjTHGTJw40UgyTz/9dED9X//6VyPJLF26NGD+2rVrA+YfOXLEREVFmbvvvtv4fD7/uGeeecZIMhMnTvTPKygoMJJMQUGBMcaYs2fPmvT0dNO1a1fz3XffBWzn/HXl5uaaxv75STJz5szxvx4zZoyJiooypaWl/nmHDh0ysbGxZsiQIRfsn6ysrIBtzZw504SHh5vjx49fMHbx4sUN9tAQt9ttJBlJplOnTub111+/7FqgIbwFhxYnKytLCQkJSktL0/jx4xUTE6OVK1fquuuuCxg3bdq0gNcrVqyQx+PRXXfdpW+//dY/9evXTzExMSooKJAkrV+/XmfOnNH06dMD3hqbMWPGJXsrLi5WWVmZZsyYofbt2wcsO39dl6u+vl5/+ctfNGbMGHXv3t0/PyUlRffff782b94sr9cbUPPQQw8FbGvw4MGqr6/XN9984583adIkGWMu++xHkj755BOtWbNGr7zyirp06aKamhrHPw9wPt6CQ4uzYMEC9ejRQxEREUpKSlLPnj0VFhb4u1RERIQ6d+4cMG/v3r2qqqpSYmJig+s9cuSIJPn/o77hhhsClickJKhDhw4X7e37twN79+59+T/QRRw9elQnT55Uz549L1h20003yefzqby8XL169fLP79KlS8C473v+4XUup+644w5J524CGT16tHr37q2YmBjl5eVd0Xpx7SKA0OL079/ffxdcY9xu9wWh5PP5lJiYqKVLlzZYk5CQELIebQoPD29wvjEmZNvIyMjQj3/8Yy1dupQAQtAIIFwzMjIytH79eg0cOFBt27ZtdFzXrl0lnTtjOv9tr6NHj17yLCIjI0OStHv3bmVlZTU67nLfjktISFB0dLRKSkouWLZnzx6FhYUpLS3tstYVaqdOnVJtba2VbaN14BoQrhm//OUvVV9fr9/+9rcXLDt79qz/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YWGhKSsrM5999pnJysoy8fHx5siRI7Zba1LV1dWmuLjYFBcXG0nm1VdfNcXFxeabb74xxhjzu9/9zrRv396sWrXK7Nq1y4wePdqkp6ebU6dOWe48tC62H6qrq80TTzxhtmzZYsrKysz69evNT37yE3PDDTeY06dP2249ZKZNm2Y8Ho8pLCw0hw8f9k8nT570j3n44YdNly5dzMaNG8327dvNgAEDzIABAyx2HXqX2g/79u0zL730ktm+fbspKyszq1atMt27dzdDhgyx3HmgFhFAxhjzxhtvmC5dupioqCjTv39/s3XrVtstXXX33XefSUlJMVFRUea6664z9913n9m3b5/ttppcQUGBkXTBNHHiRGPMuVuxn3vuOZOUlGTcbrcZNmyYKSkpsdt0E7jYfjh58qQZPny4SUhIMJGRkaZr165mypQpre6XtIZ+fklm8eLF/jGnTp0yjzzyiOnQoYOJjo429957rzl8+LC9ppvApfbDgQMHzJAhQ0zHjh2N2+02119/vfnNb35jqqqq7Db+A3wfEADAimZ/DQgA0DoRQAAAKwggAIAVBBAAwAoCCABgBQEEALCCAAIAWEEAAQCsIIAAAFYQQAAAKwggAIAV/w/hgVLrpVGHsAAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -1165,7 +1379,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 40, "id": "f1285e8b-1b96-437b-973a-eb868e33afb7", "metadata": {}, "outputs": [], @@ -1179,13 +1393,22 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 41, "id": "6bea332e-f6de-494f-a0db-795d9fe3e134", "metadata": {}, "outputs": [], "source": [ "def predict_batch_fn():\n", " import tensorflow as tf\n", + " # Enable GPU memory growth\n", + " gpus = tf.config.experimental.list_physical_devices('GPU')\n", + " if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)\n", + " \n", " model = tf.keras.models.load_model(model_dir)\n", " def predict(inputs: np.ndarray) -> np.ndarray:\n", " return model.predict(inputs)\n", @@ -1195,7 +1418,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 42, "id": "731d234c-549f-4df3-8a2b-312e63195396", "metadata": {}, "outputs": [], @@ -1208,7 +1431,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 43, "id": "a40fe207-6246-4b0e-abde-823979878d97", "metadata": {}, "outputs": [ @@ -1218,7 +1441,7 @@ "784" ] }, - "execution_count": 41, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } @@ -1230,7 +1453,7 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 44, "id": "10904f12-03e7-4518-8f12-2aa11989ddf5", "metadata": {}, "outputs": [ @@ -1238,15 +1461,22 @@ "name": "stderr", "output_type": "stream", "text": [ - " \r" + "[Stage 10:=======> (1 + 7) / 8]\r" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 971 ms, sys: 83 ms, total: 1.05 s\n", - "Wall time: 8.63 s\n" + "CPU times: user 45.6 ms, sys: 26 ms, total: 71.6 ms\n", + "Wall time: 5.51 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" ] } ], @@ -1257,23 +1487,16 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 45, "id": "671128df-f0f4-4f54-b35c-d63a78c7f89a", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 823 ms, sys: 136 ms, total: 959 ms\n", - "Wall time: 3.45 s\n" + "CPU times: user 46.5 ms, sys: 34 ms, total: 80.5 ms\n", + "Wall time: 884 ms\n" ] } ], @@ -1284,7 +1507,7 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 46, "id": "ce35deaf-7d49-4f34-9bf9-b4e6fc5761f4", "metadata": {}, "outputs": [], @@ -1303,10 +1526,17 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 47, "id": "f9119632-b284-45d7-a262-c262e034c15c", "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, { "data": { "text/html": [ @@ -1374,7 +1604,7 @@ " 0.0\n", " 0.0\n", " 0.0\n", - " [-9.66701889038086, -3.6094393730163574, -3.31...\n", + " [-5.88436, -3.1058552, 0.108737305, 12.67319, ...\n", " \n", " \n", " 1\n", @@ -1398,7 +1628,7 @@ " 0.0\n", " 0.0\n", " 0.0\n", - " [-16.348304748535156, 3.1133787631988525, 6.73...\n", + " [-3.2732859, -8.362555, 1.893612, -3.888143, 0...\n", " \n", " \n", " 2\n", @@ -1422,7 +1652,7 @@ " 0.0\n", " 0.0\n", " 0.0\n", - " [-21.153539657592773, -6.192655086517334, -6.6...\n", + " [-3.3856308, 0.6785604, 1.3146865, 0.9275978, ...\n", " \n", " \n", " 3\n", @@ -1446,7 +1676,7 @@ " 0.0\n", " 0.0\n", " 0.0\n", - " [-13.79001522064209, -16.20423126220703, -8.87...\n", + " [-2.775469, -7.3659234, 11.768431, 1.3434289, ...\n", " \n", " \n", " 4\n", @@ -1470,7 +1700,7 @@ " 0.0\n", " 0.0\n", " 0.0\n", - " [-18.723485946655273, -7.806203365325928, -8.6...\n", + " [-4.942663, 4.0774136, -0.45292768, -0.9312788...\n", " \n", " \n", " 5\n", @@ -1494,7 +1724,7 @@ " 0.0\n", " 0.0\n", " 0.0\n", - " [10.495272636413574, -10.992117881774902, -2.4...\n", + " [-5.226616, -3.1389174, 2.6100307, 3.695045, -...\n", " \n", " \n", " 6\n", @@ -1518,7 +1748,7 @@ " 0.0\n", " 0.0\n", " 0.0\n", - " [-9.437854766845703, -3.7454347610473633, -3.5...\n", + " [-4.3006196, 5.116993, 0.5850617, -0.7624871, ...\n", " \n", " \n", " 7\n", @@ -1542,7 +1772,7 @@ " 0.0\n", " 0.0\n", " 0.0\n", - " [-12.314886093139648, -2.106672763824463, -0.7...\n", + " [-2.398596, -1.4814726, -4.8840575, -0.2391601...\n", " \n", " \n", " 8\n", @@ -1566,7 +1796,7 @@ " 0.0\n", " 0.0\n", " 0.0\n", - " [-22.142608642578125, -2.8917746543884277, -4....\n", + " [0.82160157, -2.8640628, -1.6951559, -4.489291...\n", " \n", " \n", " 9\n", @@ -1590,7 +1820,7 @@ " 0.0\n", " 0.0\n", " 0.0\n", - " [-12.939343452453613, 0.40699127316474915, 15....\n", + " [-1.2338604, -2.151981, -4.1717424, 1.6106843,...\n", " \n", " \n", "\n", @@ -1598,8 +1828,8 @@ "" ], "text/plain": [ - " 0 1 2 3 4 5 6 7 8 9 ... 775 776 777 778 \n", - "0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \\\n", + " 0 1 2 3 4 5 6 7 8 9 ... 775 776 777 778 \\\n", + "0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", "1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", "2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", "3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", @@ -1611,21 +1841,21 @@ "9 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", "\n", " 779 780 781 782 783 preds \n", - "0 0.0 0.0 0.0 0.0 0.0 [-9.66701889038086, -3.6094393730163574, -3.31... \n", - "1 0.0 0.0 0.0 0.0 0.0 [-16.348304748535156, 3.1133787631988525, 6.73... \n", - "2 0.0 0.0 0.0 0.0 0.0 [-21.153539657592773, -6.192655086517334, -6.6... \n", - "3 0.0 0.0 0.0 0.0 0.0 [-13.79001522064209, -16.20423126220703, -8.87... \n", - "4 0.0 0.0 0.0 0.0 0.0 [-18.723485946655273, -7.806203365325928, -8.6... \n", - "5 0.0 0.0 0.0 0.0 0.0 [10.495272636413574, -10.992117881774902, -2.4... \n", - "6 0.0 0.0 0.0 0.0 0.0 [-9.437854766845703, -3.7454347610473633, -3.5... \n", - "7 0.0 0.0 0.0 0.0 0.0 [-12.314886093139648, -2.106672763824463, -0.7... \n", - "8 0.0 0.0 0.0 0.0 0.0 [-22.142608642578125, -2.8917746543884277, -4.... \n", - "9 0.0 0.0 0.0 0.0 0.0 [-12.939343452453613, 0.40699127316474915, 15.... \n", + "0 0.0 0.0 0.0 0.0 0.0 [-5.88436, -3.1058552, 0.108737305, 12.67319, ... \n", + "1 0.0 0.0 0.0 0.0 0.0 [-3.2732859, -8.362555, 1.893612, -3.888143, 0... \n", + "2 0.0 0.0 0.0 0.0 0.0 [-3.3856308, 0.6785604, 1.3146865, 0.9275978, ... \n", + "3 0.0 0.0 0.0 0.0 0.0 [-2.775469, -7.3659234, 11.768431, 1.3434289, ... \n", + "4 0.0 0.0 0.0 0.0 0.0 [-4.942663, 4.0774136, -0.45292768, -0.9312788... \n", + "5 0.0 0.0 0.0 0.0 0.0 [-5.226616, -3.1389174, 2.6100307, 3.695045, -... \n", + "6 0.0 0.0 0.0 0.0 0.0 [-4.3006196, 5.116993, 0.5850617, -0.7624871, ... \n", + "7 0.0 0.0 0.0 0.0 0.0 [-2.398596, -1.4814726, -4.8840575, -0.2391601... \n", + "8 0.0 0.0 0.0 0.0 0.0 [0.82160157, -2.8640628, -1.6951559, -4.489291... \n", + "9 0.0 0.0 0.0 0.0 0.0 [-1.2338604, -2.151981, -4.1717424, 1.6106843,... \n", "\n", "[10 rows x 785 columns]" ] }, - "execution_count": 45, + "execution_count": 47, "metadata": {}, "output_type": "execute_result" } @@ -1637,7 +1867,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 48, "id": "7c067c62-03a6-461e-a1ff-4653276fbea1", "metadata": {}, "outputs": [], @@ -1648,26 +1878,19 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 49, "id": "a7084ad0-c021-4296-bad0-7a238971f53b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[-9.66701889038086,\n", - " -3.6094393730163574,\n", - " -3.3102951049804688,\n", - " -0.32629871368408203,\n", - " -8.564104080200195,\n", - " -3.614396095275879,\n", - " -5.390956878662109,\n", - " -3.0429909229278564,\n", - " 9.717466354370117,\n", - " -5.417511463165283]" + "array([ -5.88436 , -3.1058552, 0.1087373, 12.67319 , -5.1437874,\n", + " 4.085992 , -10.203137 , -1.4333997, -3.3865087, -3.8473575],\n", + " dtype=float32)" ] }, - "execution_count": 47, + "execution_count": 49, "metadata": {}, "output_type": "execute_result" } @@ -1679,7 +1902,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 50, "id": "8167c832-93ef-4f50-873b-07b67c19ef53", "metadata": {}, "outputs": [], @@ -1691,13 +1914,13 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 51, "id": "297811e1-aecb-4afd-9a6a-30c49e8881cc", "metadata": {}, "outputs": [ { "data": { - "image/png": "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po2Ki4uv2PbFF18oLCxMqamp3+m9gnHpC741NTVXbDt//rwuXLjQYPtGy8c9IFw3/umf/kk1NTV66aWXrth24cIFnTx5UtLFe0yRkZFavHhxwFXDokWLrrmP2267TWlpaVq0aJH//S759ntd+k7S5WMuFx4erhEjRmjt2rX68ssv/esrKiq0YsUKDR48WDExMdfs63Lf9THsm266SWFhYVq1alVA/4cPH9ZHH32kH/7wh473DVzCFRCuG3fccYemT5+uvLw87d27VyNGjFBkZKQOHDig1atX61e/+pX+8R//UfHx8XryySeVl5ene+65R6NGjdKePXv05z//WXFxcVfdR1hYmJYsWaLRo0fr1ltv1ZQpU5ScnKwvvvhCn332mT744ANJUr9+/SRJjz/+uLKyshQeHq6JEyfW+Z4LFizQhg0bNHjwYD322GOKiIjQa6+9purqai1cuDCoY/FdH8OOj4/Xww8/rN/+9rcaPny4xo8fr1OnTunVV1/V2bNnlZubG9T+AYkAwnVm6dKl6tevn1577TU988wzioiI0I033qiHHnpIgwYN8o9bsGCBWrVqpaVLl2rLli3KyMjQhx9+qLvvvvua+8jKytKWLVs0f/58/fKXv1Rtba26deumqVOn+seMHz9es2bN0sqVK/X73/9exph6A6h379766KOPlJubq7y8PNXW1iojI0O///3vr/gOUENYsmSJ0tPT9frrr/sDp3///nrrrbc0dOjQBt8/Wi6XCebOJAAA3xP3gAAAVhBAAAArCCAAgBUEEADACgIIAGAFAQQAsKLJfQ+otrZWR44cUXR0dFCzBwMA7DLG6NSpU0pJSbliTsZva3IBdOTIkQad2woA0DjKysqumJX+25pcAEVHR0uSBmuUIhRpuRsAgFMXdF7btM7/73l9GiyA8vPz9fLLL6u8vFzp6elavHixBgwYcM26Sx+7RShSES4CCACanf8/v861bqM0yEMIq1at0ty5czVv3jx9+umnSk9PV1ZWlv8HfgEA0CAB9Morr2jq1KmaMmWKfvCDH2jp0qVq06aN3njjjYbYHQCgGQp5AJ07d067d+8O+GFcYWFhyszM1Pbt268YX11dLZ/PF7AAAFq+kAfQ119/rZqaGiUmJgasT0xMVHl5+RXj8/Ly5PF4/AtPwAHA9cH6F1Fzc3Pl9Xr9S1lZme2WAACNIORPwcXFxSk8PNz/s+QvqaioUFJS0hXj3W633G53qNsAADRxIb8CioqKUr9+/bRp0yb/utraWm3atEkDBw4M9e4AAM1Ug3wPaO7cuZo0aZJ+9KMfacCAAVq0aJEqKys1ZcqUhtgdAKAZapAAuu+++3T8+HE9//zzKi8v16233qr169df8WACAOD65TLGGNtNfJvP55PH49EwjWEmBABohi6Y8yrUWnm9XsXExNQ7zvpTcACA6xMBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArIiw3QBwLeExMY5r/vZc76D29XDWZsc1z8QVO66pMbWOa768cMZxzagdjzmukaQui1yOa1zb/yuofeH6xRUQAMAKAggAYEXIA+iFF16Qy+UKWHr16hXq3QAAmrkGuQfUu3dvbdy48e87ieBWEwAgUIMkQ0REhJKSkhrirQEALUSD3AM6cOCAUlJS1LVrVz344IM6dOhQvWOrq6vl8/kCFgBAyxfyAMrIyFBBQYHWr1+vJUuWqLS0VEOGDNGpU6fqHJ+XlyePx+NfUlNTQ90SAKAJCnkAZWdn695771Xfvn2VlZWldevW6eTJk3rnnXfqHJ+bmyuv1+tfysrKQt0SAKAJavCnA9q3b68ePXro4MGDdW53u91yu90N3QYAoIlp8O8BnT59WiUlJUpOTm7oXQEAmpGQB9CTTz6poqIiffnll/rkk080btw4hYeH6/777w/1rgAAzVjIP4I7fPiw7r//fp04cULx8fEaPHiwduzYofj4+FDvCgDQjLmMMcZ2E9/m8/nk8Xg0TGMU4Yq03Q5CzAy61XHNi7973XFNf7fzyTTxd3+o7OC4piDjNsc1Nd9847gGTd8Fc16FWiuv16uYq0wmzFxwAAArCCAAgBUEEADACgII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mjlzptasWaPNmzcrLS0tYHu/fv0UGRkZcD4UFxfr0KFDLep8uNZxqMvevXslqWmdD7afgvguVq5cadxutykoKDB//etfzbRp00z79u1NeXm57dYa1U9+8hNTWFhoSktLzccff2wyMzNNXFycOXbsmO3WGtSpU6fMnj17zJ49e4wk88orr5g9e/aYr776yhhjzM9//nPTvn17s3btWrNv3z4zZswYk5aWZs6ePWu589C62nE4deqUefLJJ8327dtNaWmp2bhxo7nttttM9+7dTVVVle3WQ2bGjBnG4/GYwsJCc/ToUf9y5swZ/5hHH33UdO7c2WzevNns2rXLDBw40AwcONBi16F3reNw8OBB8+KLL5pdu3aZ0tJSs3btWtO1a1czdOhQy50HahYBZIwxixcvNp07dzZRUVFmwIABZseOHbZbanT33XefSU5ONlFRUeaGG24w9913nzl48KDtthrcli1bjKQrlkmTJhljLj6K/dxzz5nExETjdrvN8OHDTXFxsd2mG8DVjsOZM2fMiBEjTHx8vImMjDRdunQxU6dObXH/Savr9y/JLFu2zD/m7Nmz5rHHHjMdOnQwbdq0MePGjTNHjx6113QDuNZxOHTokBk6dKiJjY01brfb3HTTTeanP/2p8Xq9dhu/DD8PCABgRZO/BwQAaJkIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMCK/wcgFXDPfhuVLAAAAABJRU5ErkJggg==", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGzCAYAAABpdMNsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAkfElEQVR4nO3dfXQUdZ7v8U/nqSEkaR7yLAFCFHRAcAYly/AgSiQEZUCYGUG9F7gziJiggI6KR0Udzsksrg7qIHjcHVhHEGWOyMoiDg9JGBRwwTCIM2QhJ0g4kIBcSYcAIaR/9w+uvbQkQDUdfkl4v86pc+iq37fqm6Lgk+qqrnYZY4wAALjKwmw3AAC4NhFAAAArCCAAgBUEEADACgIIAGAFAQQAsIIAAgBYQQABAKwggAAAVhBAgAPdunXTpEmT/K8LCwvlcrlUWFgYsm24XC698MILIVsf0FwRQGgxlixZIpfL5Z/atGmjHj16KC8vT5WVlbbbc2TNmjUtJmTefvtt3X777UpKSpLb7VZ6eromT56s/fv3224NLVyE7QYAp1566SWlp6fr9OnT2rx5sxYuXKg1a9Zo9+7dio6Ovqq9DBkyRKdOnVJUVJSjujVr1mjBggUNhtCpU6cUEdF8/mkWFxcrPT1dP/vZz9ShQweVlZXp7bff1urVq/W3v/1NqamptltEC9V8jnLgMuXk5OjWW2+VJP36179Wp06d9Oqrr2rVqlWaMGFCgzU1NTVq165dyHsJCwtTmzZtQrrOUK/vSr355psXzBszZoxuvfVWvfPOO3r66actdIXWgLfg0OLdeeedkqSysjJJ0qRJkxQTE6PS0lKNHDlSsbGxeuCBByRJPp9P8+fPV69evdSmTRslJSVp6tSp+u677wLWaYzR3Llz1blzZ0VHR+uOO+7Q119/fcG2G7sGtG3bNo0cOVIdOnRQu3bt1KdPH7322mv+/hYsWCBJAW8pfq+ha0DFxcXKyclRXFycYmJiNGzYMG3dujVgzPdvUX722WeaNWuWEhIS1K5dO9177706evRowNiqqirt2bNHVVVVl7OLL9CtWzdJ0vHjx4OqByTOgNAKlJaWSpI6derkn3f27FllZ2dr0KBB+pd/+Rf/W3NTp07VkiVLNHnyZD366KMqKyvTH/7wBxUXF+uzzz5TZGSkJOn555/X3LlzNXLkSI0cOVJffvmlhg8frjNnzlyyn3Xr1umee+5RSkqKHnvsMSUnJ+sf//iHVq9erccee0xTp07VoUOHtG7dOv3pT3+65Pq+/vprDR48WHFxcXryyScVGRmpt956S0OHDlVRUZEyMzMDxk+fPl0dOnTQnDlztH//fs2fP195eXl6//33/WNWrlypyZMna/HixQE3VVzMsWPHVF9frwMHDuill16SJA0bNuyyaoEGGaCFWLx4sZFk1q9fb44ePWrKy8vN8uXLTadOnUzbtm3NwYMHjTHGTJw40UgyTz/9dED9X//6VyPJLF26NGD+2rVrA+YfOXLEREVFmbvvvtv4fD7/uGeeecZIMhMnTvTPKygoMJJMQUGBMcaYs2fPmvT0dNO1a1fz3XffBWzn/HXl5uaaxv75STJz5szxvx4zZoyJiooypaWl/nmHDh0ysbGxZsiQIRfsn6ysrIBtzZw504SHh5vjx49fMHbx4sUN9tAQt9ttJBlJplOnTub111+/7FqgIbwFhxYnKytLCQkJSktL0/jx4xUTE6OVK1fquuuuCxg3bdq0gNcrVqyQx+PRXXfdpW+//dY/9evXTzExMSooKJAkrV+/XmfOnNH06dMD3hqbMWPGJXsrLi5WWVmZZsyYofbt2wcsO39dl6u+vl5/+ctfNGbMGHXv3t0/PyUlRffff782b94sr9cbUPPQQw8FbGvw4MGqr6/XN9984583adIkGWMu++xHkj755BOtWbNGr7zyirp06aKamhrHPw9wPt6CQ4uzYMEC9ejRQxEREUpKSlLPnj0VFhb4u1RERIQ6d+4cMG/v3r2qqqpSYmJig+s9cuSIJPn/o77hhhsClickJKhDhw4X7e37twN79+59+T/QRRw9elQnT55Uz549L1h20003yefzqby8XL169fLP79KlS8C473v+4XUup+644w5J524CGT16tHr37q2YmBjl5eVd0Xpx7SKA0OL079/ffxdcY9xu9wWh5PP5lJiYqKVLlzZYk5CQELIebQoPD29wvjEmZNvIyMjQj3/8Yy1dupQAQtAIIFwzMjIytH79eg0cOFBt27ZtdFzXrl0lnTtjOv9tr6NHj17yLCIjI0OStHv3bmVlZTU67nLfjktISFB0dLRKSkouWLZnzx6FhYUpLS3tstYVaqdOnVJtba2VbaN14BoQrhm//OUvVV9fr9/+9rcXLDt79qz/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YWGhKSsrM5999pnJysoy8fHx5siRI7Zba1LV1dWmuLjYFBcXG0nm1VdfNcXFxeabb74xxhjzu9/9zrRv396sWrXK7Nq1y4wePdqkp6ebU6dOWe48tC62H6qrq80TTzxhtmzZYsrKysz69evNT37yE3PDDTeY06dP2249ZKZNm2Y8Ho8pLCw0hw8f9k8nT570j3n44YdNly5dzMaNG8327dvNgAEDzIABAyx2HXqX2g/79u0zL730ktm+fbspKyszq1atMt27dzdDhgyx3HmgFhFAxhjzxhtvmC5dupioqCjTv39/s3XrVtstXXX33XefSUlJMVFRUea6664z9913n9m3b5/ttppcQUGBkXTBNHHiRGPMuVuxn3vuOZOUlGTcbrcZNmyYKSkpsdt0E7jYfjh58qQZPny4SUhIMJGRkaZr165mypQpre6XtIZ+fklm8eLF/jGnTp0yjzzyiOnQoYOJjo429957rzl8+LC9ppvApfbDgQMHzJAhQ0zHjh2N2+02119/vfnNb35jqqqq7Db+A3wfEADAimZ/DQgA0DoRQAAAKwggAIAVBBAAwAoCCABgBQEEALCCAAIAWEEAAQCsIIAAAFYQQAAAKwggAIAV/w/hgVLrpVGHsAAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -1725,7 +1948,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 52, "id": "a64d19b1-ba4a-4dc7-b3a9-368dc47d0fd8", "metadata": {}, "outputs": [], @@ -1738,7 +1961,7 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 53, "id": "8fa92fe4-2e04-4d82-a357-bfdfca38bd8c", "metadata": {}, "outputs": [], @@ -1763,7 +1986,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 54, "id": "0f7ecb25-be16-40c4-bdbb-441e2f537000", "metadata": {}, "outputs": [ @@ -1780,7 +2003,7 @@ "[True]" ] }, - "execution_count": 52, + "execution_count": 54, "metadata": {}, "output_type": "execute_result" } @@ -1802,7 +2025,7 @@ " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", " else:\n", " container=client.containers.run(\n", - " \"nvcr.io/nvidia/tritonserver:23.04-py3\", \"tritonserver --model-repository=/models\",\n", + " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", " detach=True,\n", " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", " name=\"spark-triton\",\n", @@ -1830,7 +2053,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 55, "id": "43b93753-1d52-4060-9986-f24c30a67528", "metadata": {}, "outputs": [ @@ -1840,7 +2063,7 @@ "StructType([StructField('data', ArrayType(DoubleType(), True), True)])" ] }, - "execution_count": 53, + "execution_count": 55, "metadata": {}, "output_type": "execute_result" } @@ -1852,127 +2075,131 @@ }, { "cell_type": "markdown", - "id": "b37d5026-8abc-45c3-a03c-3222c15e7d93", + "id": "036680eb-babd-4b07-8b2c-ce6e724f4e85", "metadata": {}, "source": [ - "#### Using custom predict_batch_fn" + "#### Run inference" ] }, { "cell_type": "code", - "execution_count": 54, - "id": "f5d4c2c6-d65a-4969-8ffd-8457b6dd35fb", + "execution_count": 56, + "id": "3af08bd0-3838-4769-a8de-2643db4101c6", "metadata": {}, "outputs": [], "source": [ - "def predict_batch_fn():\n", + "def triton_fn(triton_uri, model_name):\n", " import numpy as np\n", " import tritonclient.grpc as grpcclient\n", - " client = grpcclient.InferenceServerClient(\"localhost:8001\")\n", + "\n", + " np_types = {\n", + " \"BOOL\": np.dtype(np.bool_),\n", + " \"INT8\": np.dtype(np.int8),\n", + " \"INT16\": np.dtype(np.int16),\n", + " \"INT32\": np.dtype(np.int32),\n", + " \"INT64\": np.dtype(np.int64),\n", + " \"FP16\": np.dtype(np.float16),\n", + " \"FP32\": np.dtype(np.float32),\n", + " \"FP64\": np.dtype(np.float64),\n", + " \"FP64\": np.dtype(np.double),\n", + " \"BYTES\": np.dtype(object)\n", + " }\n", + "\n", + " client = grpcclient.InferenceServerClient(triton_uri)\n", + " model_meta = client.get_model_metadata(model_name)\n", + "\n", " def predict(inputs):\n", - " request = [grpcclient.InferInput(\"dense_input\", inputs.shape, \"FP32\")]\n", - " request[0].set_data_from_numpy(inputs.astype(np.float32))\n", - " response = client.infer(\"mnist_model\", inputs=request)\n", - " return response.as_numpy(\"dense_1\")\n", + " if isinstance(inputs, np.ndarray):\n", + " # single ndarray input\n", + " request = [grpcclient.InferInput(model_meta.inputs[0].name, inputs.shape, model_meta.inputs[0].datatype)]\n", + " request[0].set_data_from_numpy(inputs.astype(np_types[model_meta.inputs[0].datatype]))\n", + " else:\n", + " # dict of multiple ndarray inputs\n", + " request = [grpcclient.InferInput(i.name, inputs[i.name].shape, i.datatype) for i in model_meta.inputs]\n", + " for i in request:\n", + " i.set_data_from_numpy(inputs[i.name()].astype(np_types[i.datatype()]))\n", + "\n", + " response = client.infer(model_name, inputs=request)\n", + "\n", + " if len(model_meta.outputs) > 1:\n", + " # return dictionary of numpy arrays\n", + " return {o.name: response.as_numpy(o.name) for o in model_meta.outputs}\n", + " else:\n", + " # return single numpy array\n", + " return response.as_numpy(model_meta.outputs[0].name)\n", + "\n", " return predict" ] }, { "cell_type": "code", - "execution_count": 55, - "id": "a158490c-eaf6-4c0a-9f2f-af20df45d126", + "execution_count": 57, + "id": "6658d2a1-ef7b-4ca1-9fb6-f2ac9050f3e5", "metadata": {}, "outputs": [], "source": [ - "mnist = predict_batch_udf(predict_batch_fn,\n", - " input_tensor_shapes=[[784]],\n", - " return_type=ArrayType(FloatType()),\n", - " batch_size=8192)" + "from functools import partial\n", + "\n", + "predict = predict_batch_udf(partial(triton_fn, \"localhost:8001\", \"mnist_model\"),\n", + " return_type=ArrayType(FloatType()),\n", + " input_tensor_shapes=[[784]],\n", + " batch_size=8192)" ] }, { "cell_type": "code", - "execution_count": 56, - "id": "b7bd2504-1ed2-4dfe-a63a-7ed660dd1c80", + "execution_count": 58, + "id": "8397aa14-82fd-4351-a477-dc8e8b321fa2", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 458 ms, sys: 80.5 ms, total: 538 ms\n", - "Wall time: 2.29 s\n" + "CPU times: user 20.1 ms, sys: 3.41 ms, total: 23.5 ms\n", + "Wall time: 625 ms\n" ] } ], "source": [ "%%time\n", - "preds = df.withColumn(\"preds\", mnist(struct(\"data\"))).collect()" + "preds = df.withColumn(\"preds\", predict(struct(\"data\"))).collect()" ] }, { "cell_type": "code", - "execution_count": 57, - "id": "4b26e237-3690-4350-a5b8-a354e668e9b7", + "execution_count": 59, + "id": "82698bd9-377a-4415-8971-835487f876cc", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 455 ms, sys: 157 ms, total: 612 ms\n", - "Wall time: 1.31 s\n" + "CPU times: user 30.3 ms, sys: 8.81 ms, total: 39.2 ms\n", + "Wall time: 154 ms\n" ] } ], "source": [ "%%time\n", - "preds = df.withColumn(\"preds\", mnist(\"data\")).collect()" + "preds = df.withColumn(\"preds\", predict(\"data\")).collect()" ] }, { "cell_type": "code", - "execution_count": 58, - "id": "d6c19561-16a9-4ce4-b7df-dca9820d6173", + "execution_count": 60, + "id": "419ad7bd-fa28-49d3-b98d-db9fba5aeaef", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 874 ms, sys: 68.9 ms, total: 943 ms\n", - "Wall time: 1.53 s\n" + "CPU times: user 2.67 ms, sys: 4.2 ms, total: 6.87 ms\n", + "Wall time: 131 ms\n" ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", mnist(col(\"data\"))).collect()" - ] - }, - { - "cell_type": "markdown", - "id": "50b58a82-78de-4749-a7b9-d6f38352fc69", - "metadata": { - "tags": [] - }, - "source": [ - "#### Check predictions" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "id": "bcf123ea-c0f4-4ec7-b52f-c1e9581b83e7", - "metadata": {}, - "outputs": [ + }, { "data": { "text/html": [ @@ -2002,60 +2229,60 @@ " \n", " 0\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-9.66701889038086, -3.6094400882720947, -3.31...\n", + " [-5.7614846, -3.52228, -1.1202906, 13.053683, ...\n", " \n", " \n", " 1\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-16.348302841186523, 3.1133782863616943, 6.73...\n", + " [-3.1390061, -8.71185, 0.82955813, -4.034869, ...\n", " \n", " \n", " 2\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-21.153541564941406, -6.192654132843018, -6.6...\n", + " [-3.046528, 0.3521706, 0.6788677, 0.72303534, ...\n", " \n", " \n", " 3\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-13.790016174316406, -16.204233169555664, -8....\n", + " [-2.401024, -7.6780066, 11.145876, 1.2857256, ...\n", " \n", " \n", " 4\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-18.723485946655273, -7.8062005043029785, -8....\n", + " [-5.0012593, 3.806796, -0.8154834, -0.9550028,...\n", " \n", " \n", " 5\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [10.495272636413574, -10.992119789123535, -2.4...\n", + " [-5.0425925, -3.4815094, 1.641246, 3.608149, -...\n", " \n", " \n", " 6\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-9.437854766845703, -3.745434284210205, -3.59...\n", + " [-4.288771, 5.0072904, 0.27649477, -0.797148, ...\n", " \n", " \n", " 7\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-12.314884185791016, -2.106672525405884, -0.7...\n", + " [-2.2032878, -1.6879876, -5.874276, -0.5945335...\n", " \n", " \n", " 8\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-22.142610549926758, -2.891775369644165, -4.8...\n", + " [1.1337761, -3.1751056, -2.5246286, -5.028277,...\n", " \n", " \n", " 9\n", " [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...\n", - " [-12.939340591430664, 0.40699198842048645, 15....\n", + " [-0.92484117, -2.4703276, -5.023897, 1.46669, ...\n", " \n", " \n", "\n", "" ], "text/plain": [ - " data \n", - "0 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \\\n", + " data \\\n", + "0 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", "1 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", "2 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", "3 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", @@ -2067,32 +2294,33 @@ "9 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", "\n", " preds \n", - "0 [-9.66701889038086, -3.6094400882720947, -3.31... \n", - "1 [-16.348302841186523, 3.1133782863616943, 6.73... \n", - "2 [-21.153541564941406, -6.192654132843018, -6.6... \n", - "3 [-13.790016174316406, -16.204233169555664, -8.... \n", - "4 [-18.723485946655273, -7.8062005043029785, -8.... \n", - "5 [10.495272636413574, -10.992119789123535, -2.4... \n", - "6 [-9.437854766845703, -3.745434284210205, -3.59... \n", - "7 [-12.314884185791016, -2.106672525405884, -0.7... \n", - "8 [-22.142610549926758, -2.891775369644165, -4.8... \n", - "9 [-12.939340591430664, 0.40699198842048645, 15.... " + "0 [-5.7614846, -3.52228, -1.1202906, 13.053683, ... \n", + "1 [-3.1390061, -8.71185, 0.82955813, -4.034869, ... \n", + "2 [-3.046528, 0.3521706, 0.6788677, 0.72303534, ... \n", + "3 [-2.401024, -7.6780066, 11.145876, 1.2857256, ... \n", + "4 [-5.0012593, 3.806796, -0.8154834, -0.9550028,... \n", + "5 [-5.0425925, -3.4815094, 1.641246, 3.608149, -... \n", + "6 [-4.288771, 5.0072904, 0.27649477, -0.797148, ... \n", + "7 [-2.2032878, -1.6879876, -5.874276, -0.5945335... \n", + "8 [1.1337761, -3.1751056, -2.5246286, -5.028277,... \n", + "9 [-0.92484117, -2.4703276, -5.023897, 1.46669, ... " ] }, - "execution_count": 59, + "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "preds = df.withColumn(\"preds\", mnist(*df.columns)).limit(10).toPandas()\n", + "%%time\n", + "preds = df.withColumn(\"preds\", predict(col(\"data\"))).limit(10).toPandas()\n", "preds" ] }, { "cell_type": "code", - "execution_count": 60, - "id": "525f0157-6dac-4b62-a88c-4294a9b5e7f5", + "execution_count": 61, + "id": "79d90a26", "metadata": {}, "outputs": [], "source": [ @@ -2100,44 +2328,16 @@ "import numpy as np" ] }, - { - "cell_type": "code", - "execution_count": 61, - "id": "e20b2b47-f5c3-44ad-b971-184b1037c721", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[-9.66701889038086,\n", - " -3.6094400882720947,\n", - " -3.310295581817627,\n", - " -0.3262983560562134,\n", - " -8.564104080200195,\n", - " -3.614396095275879,\n", - " -5.3909592628479,\n", - " -3.0429911613464355,\n", - " 9.717466354370117,\n", - " -5.417511940002441]" - ] - }, - "execution_count": 61, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sample = preds.iloc[0]\n", - "sample.preds" - ] - }, { "cell_type": "code", "execution_count": 62, - "id": "ca2811fa-f9d4-4c14-b203-c92f56924d8b", + "id": "4ca495f5", "metadata": {}, "outputs": [], "source": [ + "sample = preds.iloc[0]\n", + "sample.preds\n", + "\n", "prediction = np.argmax(sample.preds)\n", "img = np.array(sample.data).reshape(28,28)" ] @@ -2145,12 +2345,12 @@ { "cell_type": "code", "execution_count": 63, - "id": "60dd6b57-85a0-4357-b46c-75bce626ecce", + "id": "a5d10903", "metadata": {}, "outputs": [ { "data": { - "image/png": "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po2Ki4uv2PbFF18oLCxMqamp3+m9gnHpC741NTVXbDt//rwuXLjQYPtGy8c9IFw3/umf/kk1NTV66aWXrth24cIFnTx5UtLFe0yRkZFavHhxwFXDokWLrrmP2267TWlpaVq0aJH//S759ntd+k7S5WMuFx4erhEjRmjt2rX68ssv/esrKiq0YsUKDR48WDExMdfs63Lf9THsm266SWFhYVq1alVA/4cPH9ZHH32kH/7wh473DVzCFRCuG3fccYemT5+uvLw87d27VyNGjFBkZKQOHDig1atX61e/+pX+8R//UfHx8XryySeVl5ene+65R6NGjdKePXv05z//WXFxcVfdR1hYmJYsWaLRo0fr1ltv1ZQpU5ScnKwvvvhCn332mT744ANJUr9+/SRJjz/+uLKyshQeHq6JEyfW+Z4LFizQhg0bNHjwYD322GOKiIjQa6+9purqai1cuDCoY/FdH8OOj4/Xww8/rN/+9rcaPny4xo8fr1OnTunVV1/V2bNnlZubG9T+AYkAwnVm6dKl6tevn1577TU988wzioiI0I033qiHHnpIgwYN8o9bsGCBWrVqpaVLl2rLli3KyMjQhx9+qLvvvvua+8jKytKWLVs0f/58/fKXv1Rtba26deumqVOn+seMHz9es2bN0sqVK/X73/9exph6A6h379766KOPlJubq7y8PNXW1iojI0O///3vr/gOUENYsmSJ0tPT9frrr/sDp3///nrrrbc0dOjQBt8/Wi6XCebOJAAA3xP3gAAAVhBAAAArCCAAgBUEEADACgIIAGAFAQQAsKLJfQ+otrZWR44cUXR0dFCzBwMA7DLG6NSpU0pJSbliTsZva3IBdOTIkQad2woA0DjKysqumJX+25pcAEVHR0uSBmuUIhRpuRsAgFMXdF7btM7/73l9GiyA8vPz9fLLL6u8vFzp6elavHixBgwYcM26Sx+7RShSES4CCACanf8/v861bqM0yEMIq1at0ty5czVv3jx9+umnSk9PV1ZWlv8HfgEA0CAB9Morr2jq1KmaMmWKfvCDH2jp0qVq06aN3njjjYbYHQCgGQp5AJ07d067d+8O+GFcYWFhyszM1Pbt268YX11dLZ/PF7AAAFq+kAfQ119/rZqaGiUmJgasT0xMVHl5+RXj8/Ly5PF4/AtPwAHA9cH6F1Fzc3Pl9Xr9S1lZme2WAACNIORPwcXFxSk8PNz/s+QvqaioUFJS0hXj3W633G53qNsAADRxIb8CioqKUr9+/bRp0yb/utraWm3atEkDBw4M9e4AAM1Ug3wPaO7cuZo0aZJ+9KMfacCAAVq0aJEqKys1ZcqUhtgdAKAZapAAuu+++3T8+HE9//zzKi8v16233qr169df8WACAOD65TLGGNtNfJvP55PH49EwjWEmBABohi6Y8yrUWnm9XsXExNQ7zvpTcACA6xMBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArIiw3QBwLeExMY5r/vZc76D29XDWZsc1z8QVO66pMbWOa768cMZxzagdjzmukaQui1yOa1zb/yuofeH6xRUQAMAKAggAYEXIA+iFF16Qy+UKWHr16hXq3QAAmrkGuQfUu3dvbdy48e87ieBWEwAgUIMkQ0REhJKSkhrirQEALUSD3AM6cOCAUlJS1LVrVz344IM6dOhQvWOrq6vl8/kCFgBAyxfyAMrIyFBBQYHWr1+vJUuWqLS0VEOGDNGpU6fqHJ+XlyePx+NfUlNTQ90SAKAJCnkAZWdn695771Xfvn2VlZWldevW6eTJk3rnnXfqHJ+bmyuv1+tfysrKQt0SAKAJavCnA9q3b68ePXro4MGDdW53u91yu90N3QYAoIlp8O8BnT59WiUlJUpOTm7oXQEAmpGQB9CTTz6poqIiffnll/rkk080btw4hYeH6/777w/1rgAAzVjIP4I7fPiw7r//fp04cULx8fEaPHiwduzYofj4+FDvCgDQjLmMMcZ2E9/m8/nk8Xg0TGMU4Yq03Q5CzAy61XHNi7973XFNf7fzyTTxd3+o7OC4piDjNsc1Nd9847gGTd8Fc16FWiuv16uYq0wmzFxwAAArCCAAgBUEEADACgII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mjlzptasWaPNmzcrLS0tYHu/fv0UGRkZcD4UFxfr0KFDLep8uNZxqMvevXslqWmdD7afgvguVq5cadxutykoKDB//etfzbRp00z79u1NeXm57dYa1U9+8hNTWFhoSktLzccff2wyMzNNXFycOXbsmO3WGtSpU6fMnj17zJ49e4wk88orr5g9e/aYr776yhhjzM9//nPTvn17s3btWrNv3z4zZswYk5aWZs6ePWu589C62nE4deqUefLJJ8327dtNaWmp2bhxo7nttttM9+7dTVVVle3WQ2bGjBnG4/GYwsJCc/ToUf9y5swZ/5hHH33UdO7c2WzevNns2rXLDBw40AwcONBi16F3reNw8OBB8+KLL5pdu3aZ0tJSs3btWtO1a1czdOhQy50HahYBZIwxixcvNp07dzZRUVFmwIABZseOHbZbanT33XefSU5ONlFRUeaGG24w9913nzl48KDtthrcli1bjKQrlkmTJhljLj6K/dxzz5nExETjdrvN8OHDTXFxsd2mG8DVjsOZM2fMiBEjTHx8vImMjDRdunQxU6dObXH/Savr9y/JLFu2zD/m7Nmz5rHHHjMdOnQwbdq0MePGjTNHjx6113QDuNZxOHTokBk6dKiJjY01brfb3HTTTeanP/2p8Xq9dhu/DD8PCABgRZO/BwQAaJkIIACAFQQQAMAKAggAYAUBBACwggACAFhBAAEArCCAAABWEEAAACsIIACAFQQQAMCK/wcgFXDPfhuVLAAAAABJRU5ErkJggg==", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGzCAYAAABpdMNsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAkfElEQVR4nO3dfXQUdZ7v8U/nqSEkaR7yLAFCFHRAcAYly/AgSiQEZUCYGUG9F7gziJiggI6KR0Udzsksrg7qIHjcHVhHEGWOyMoiDg9JGBRwwTCIM2QhJ0g4kIBcSYcAIaR/9w+uvbQkQDUdfkl4v86pc+iq37fqm6Lgk+qqrnYZY4wAALjKwmw3AAC4NhFAAAArCCAAgBUEEADACgIIAGAFAQQAsIIAAgBYQQABAKwggAAAVhBAgAPdunXTpEmT/K8LCwvlcrlUWFgYsm24XC698MILIVsf0FwRQGgxlixZIpfL5Z/atGmjHj16KC8vT5WVlbbbc2TNmjUtJmTefvtt3X777UpKSpLb7VZ6eromT56s/fv3224NLVyE7QYAp1566SWlp6fr9OnT2rx5sxYuXKg1a9Zo9+7dio6Ovqq9DBkyRKdOnVJUVJSjujVr1mjBggUNhtCpU6cUEdF8/mkWFxcrPT1dP/vZz9ShQweVlZXp7bff1urVq/W3v/1NqamptltEC9V8jnLgMuXk5OjWW2+VJP36179Wp06d9Oqrr2rVqlWaMGFCgzU1NTVq165dyHsJCwtTmzZtQrrOUK/vSr355psXzBszZoxuvfVWvfPOO3r66actdIXWgLfg0OLdeeedkqSysjJJ0qRJkxQTE6PS0lKNHDlSsbGxeuCBByRJPp9P8+fPV69evdSmTRslJSVp6tSp+u677wLWaYzR3Llz1blzZ0VHR+uOO+7Q119/fcG2G7sGtG3bNo0cOVIdOnRQu3bt1KdPH7322mv+/hYsWCBJAW8pfq+ha0DFxcXKyclRXFycYmJiNGzYMG3dujVgzPdvUX722WeaNWuWEhIS1K5dO9177706evRowNiqqirt2bNHVVVVl7OLL9CtWzdJ0vHjx4OqByTOgNAKlJaWSpI6derkn3f27FllZ2dr0KBB+pd/+Rf/W3NTp07VkiVLNHnyZD366KMqKyvTH/7wBxUXF+uzzz5TZGSkJOn555/X3LlzNXLkSI0cOVJffvmlhg8frjNnzlyyn3Xr1umee+5RSkqKHnvsMSUnJ+sf//iHVq9erccee0xTp07VoUOHtG7dOv3pT3+65Pq+/vprDR48WHFxcXryyScVGRmpt956S0OHDlVRUZEyMzMDxk+fPl0dOnTQnDlztH//fs2fP195eXl6//33/WNWrlypyZMna/HixQE3VVzMsWPHVF9frwMHDuill16SJA0bNuyyaoEGGaCFWLx4sZFk1q9fb44ePWrKy8vN8uXLTadOnUzbtm3NwYMHjTHGTJw40UgyTz/9dED9X//6VyPJLF26NGD+2rVrA+YfOXLEREVFmbvvvtv4fD7/uGeeecZIMhMnTvTPKygoMJJMQUGBMcaYs2fPmvT0dNO1a1fz3XffBWzn/HXl5uaaxv75STJz5szxvx4zZoyJiooypaWl/nmHDh0ysbGxZsiQIRfsn6ysrIBtzZw504SHh5vjx49fMHbx4sUN9tAQt9ttJBlJplOnTub111+/7FqgIbwFhxYnKytLCQkJSktL0/jx4xUTE6OVK1fquuuuCxg3bdq0gNcrVqyQx+PRXXfdpW+//dY/9evXTzExMSooKJAkrV+/XmfOnNH06dMD3hqbMWPGJXsrLi5WWVmZZsyYofbt2wcsO39dl6u+vl5/+ctfNGbMGHXv3t0/PyUlRffff782b94sr9cbUPPQQw8FbGvw4MGqr6/XN9984583adIkGWMu++xHkj755BOtWbNGr7zyirp06aKamhrHPw9wPt6CQ4uzYMEC9ejRQxEREUpKSlLPnj0VFhb4u1RERIQ6d+4cMG/v3r2qqqpSYmJig+s9cuSIJPn/o77hhhsClickJKhDhw4X7e37twN79+59+T/QRRw9elQnT55Uz549L1h20003yefzqby8XL169fLP79KlS8C473v+4XUup+644w5J524CGT16tHr37q2YmBjl5eVd0Xpx7SKA0OL079/ffxdcY9xu9wWh5PP5lJiYqKVLlzZYk5CQELIebQoPD29wvjEmZNvIyMjQj3/8Yy1dupQAQtAIIFwzMjIytH79eg0cOFBt27ZtdFzXrl0lnTtjOv9tr6NHj17yLCIjI0OStHv3bmVlZTU67nLfjktISFB0dLRKSkouWLZnzx6FhYUpLS3tstYVaqdOnVJtba2VbaN14BoQrhm//OUvVV9fr9/+9rcXLDt79qz/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YWGhKSsrM5999pnJysoy8fHx5siRI7Zba1LV1dWmuLjYFBcXG0nm1VdfNcXFxeabb74xxhjzu9/9zrRv396sWrXK7Nq1y4wePdqkp6ebU6dOWe48tC62H6qrq80TTzxhtmzZYsrKysz69evNT37yE3PDDTeY06dP2249ZKZNm2Y8Ho8pLCw0hw8f9k8nT570j3n44YdNly5dzMaNG8327dvNgAEDzIABAyx2HXqX2g/79u0zL730ktm+fbspKyszq1atMt27dzdDhgyx3HmgFhFAxhjzxhtvmC5dupioqCjTv39/s3XrVtstXXX33XefSUlJMVFRUea6664z9913n9m3b5/ttppcQUGBkXTBNHHiRGPMuVuxn3vuOZOUlGTcbrcZNmyYKSkpsdt0E7jYfjh58qQZPny4SUhIMJGRkaZr165mypQpre6XtIZ+fklm8eLF/jGnTp0yjzzyiOnQoYOJjo429957rzl8+LC9ppvApfbDgQMHzJAhQ0zHjh2N2+02119/vfnNb35jqqqq7Db+A3wfEADAimZ/DQgA0DoRQAAAKwggAIAVBBAAwAoCCABgBQEEALCCAAIAWEEAAQCsIIAAAFYQQAAAKwggAIAV/w/hgVLrpVGHsAAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -2166,146 +2366,6 @@ "plt.show()" ] }, - { - "cell_type": "markdown", - "id": "036680eb-babd-4b07-8b2c-ce6e724f4e85", - "metadata": {}, - "source": [ - "#### Using generic Triton function" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "id": "3af08bd0-3838-4769-a8de-2643db4101c6", - "metadata": {}, - "outputs": [], - "source": [ - "def triton_fn(triton_uri, model_name):\n", - " import numpy as np\n", - " import tritonclient.grpc as grpcclient\n", - "\n", - " np_types = {\n", - " \"BOOL\": np.dtype(np.bool8),\n", - " \"INT8\": np.dtype(np.int8),\n", - " \"INT16\": np.dtype(np.int16),\n", - " \"INT32\": np.dtype(np.int32),\n", - " \"INT64\": np.dtype(np.int64),\n", - " \"FP16\": np.dtype(np.float16),\n", - " \"FP32\": np.dtype(np.float32),\n", - " \"FP64\": np.dtype(np.float64),\n", - " \"FP64\": np.dtype(np.double),\n", - " \"BYTES\": np.dtype(object)\n", - " }\n", - "\n", - " client = grpcclient.InferenceServerClient(triton_uri)\n", - " model_meta = client.get_model_metadata(model_name)\n", - "\n", - " def predict(inputs):\n", - " if isinstance(inputs, np.ndarray):\n", - " # single ndarray input\n", - " request = [grpcclient.InferInput(model_meta.inputs[0].name, inputs.shape, model_meta.inputs[0].datatype)]\n", - " request[0].set_data_from_numpy(inputs.astype(np_types[model_meta.inputs[0].datatype]))\n", - " else:\n", - " # dict of multiple ndarray inputs\n", - " request = [grpcclient.InferInput(i.name, inputs[i.name].shape, i.datatype) for i in model_meta.inputs]\n", - " for i in request:\n", - " i.set_data_from_numpy(inputs[i.name()].astype(np_types[i.datatype()]))\n", - "\n", - " response = client.infer(model_name, inputs=request)\n", - "\n", - " if len(model_meta.outputs) > 1:\n", - " # return dictionary of numpy arrays\n", - " return {o.name: response.as_numpy(o.name) for o in model_meta.outputs}\n", - " else:\n", - " # return single numpy array\n", - " return response.as_numpy(model_meta.outputs[0].name)\n", - "\n", - " return predict" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "id": "6658d2a1-ef7b-4ca1-9fb6-f2ac9050f3e5", - "metadata": {}, - "outputs": [], - "source": [ - "from functools import partial\n", - "\n", - "predict = predict_batch_udf(partial(triton_fn, \"localhost:8001\", \"mnist_model\"),\n", - " return_type=ArrayType(FloatType()),\n", - " input_tensor_shapes=[[784]],\n", - " batch_size=8192)" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "id": "8397aa14-82fd-4351-a477-dc8e8b321fa2", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 410 ms, sys: 104 ms, total: 514 ms\n", - "Wall time: 1.65 s\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", predict(struct(\"data\"))).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "id": "82698bd9-377a-4415-8971-835487f876cc", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 495 ms, sys: 81.4 ms, total: 576 ms\n", - "Wall time: 1.21 s\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", predict(\"data\")).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "id": "419ad7bd-fa28-49d3-b98d-db9fba5aeaef", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 858 ms, sys: 109 ms, total: 967 ms\n", - "Wall time: 1.58 s\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", predict(col(\"data\"))).collect()" - ] - }, { "cell_type": "markdown", "id": "6377f41a-5654-410b-8bad-d392e9dce7b8", @@ -2318,7 +2378,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 64, "id": "9c9fd967-5cd9-4265-add9-db5c1ccf9893", "metadata": {}, "outputs": [ @@ -2335,7 +2395,7 @@ "[True]" ] }, - "execution_count": 69, + "execution_count": 64, "metadata": {}, "output_type": "execute_result" } @@ -2359,7 +2419,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 65, "id": "f612dc0b-538f-4ecf-81f7-ef6b58c493ab", "metadata": {}, "outputs": [], @@ -2378,7 +2438,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "spark-dl-tf", "language": "python", "name": "python3" }, @@ -2392,7 +2452,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification_tf.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification_tf.ipynb new file mode 100644 index 000000000..5add2686b --- /dev/null +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification_tf.ipynb @@ -0,0 +1,2460 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "52d55e3f", + "metadata": {}, + "source": [ + "# Pyspark TensorFlow Inference\n", + "\n", + "## Image classification\n", + "Based on: https://www.tensorflow.org/tutorials/keras/save_and_load" + ] + }, + { + "cell_type": "markdown", + "id": "5233632d", + "metadata": {}, + "source": [ + "### Using TensorFlow\n", + "Note that cuFFT/cuDNN/cuBLAS registration errors are expected with `tf=2.17.0` and will not affect behavior, as noted in [this issue.](https://github.com/tensorflow/tensorflow/issues/62075) \n", + "This notebook does not demonstrate inference with TensorRT, as [TF-TRT](https://docs.nvidia.com/deeplearning/tensorrt/release-notes/index.html#tensorrt-10) does not yet support `tf=2.17.0`. See the `pytorch` notebooks for TensorRT demos." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "c8b28f02", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:40:20.324462: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2024-10-03 17:40:20.331437: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", + "2024-10-03 17:40:20.339109: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", + "2024-10-03 17:40:20.341362: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", + "2024-10-03 17:40:20.347337: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2024-10-03 17:40:20.672391: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.17.0\n" + ] + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import subprocess\n", + "import tensorflow as tf\n", + "import os\n", + "\n", + "from tensorflow import keras\n", + "\n", + "print(tf.version.VERSION)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "e2e67086", + "metadata": {}, + "outputs": [], + "source": [ + "# Enable GPU memory growth\n", + "gpus = tf.config.experimental.list_physical_devices('GPU')\n", + "if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)" + ] + }, + { + "cell_type": "markdown", + "id": "7e0c7ad6", + "metadata": {}, + "source": [ + "### Load and preprocess dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "5b007f7c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m11490434/11490434\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n" + ] + }, + { + "data": { + "text/plain": [ + "((60000, 28, 28), (10000, 28, 28))" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# load dataset as numpy arrays\n", + "(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()\n", + "train_images.shape, test_images.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "7b7cedd1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "((1000, 784), (1000, 784))" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_labels = train_labels[:1000]\n", + "test_labels = test_labels[:1000]\n", + "\n", + "train_images = train_images[:1000].reshape(-1, 28 * 28) / 255.0\n", + "test_images = test_images[:1000].reshape(-1, 28 * 28) / 255.0\n", + "\n", + "train_images.shape, test_images.shape" + ] + }, + { + "cell_type": "markdown", + "id": "867a4403", + "metadata": {}, + "source": [ + "### Define a model" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "746d94db", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/rishic/anaconda3/envs/spark-dl-tf/lib/python3.11/site-packages/keras/src/layers/core/dense.py:87: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.\n", + " super().__init__(activity_regularizer=activity_regularizer, **kwargs)\n", + "2024-10-03 17:40:21.624052: I tensorflow/core/common_runtime/gpu/gpu_device.cc:2021] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 45743 MB memory: -> device: 0, name: NVIDIA RTX A6000, pci bus id: 0000:01:00.0, compute capability: 8.6\n" + ] + }, + { + "data": { + "text/html": [ + "
Model: \"sequential\"\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1mModel: \"sequential\"\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
+       "┃ Layer (type)                     Output Shape                  Param # ┃\n",
+       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
+       "│ dense (Dense)                   │ (None, 512)            │       401,920 │\n",
+       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+       "│ dropout (Dropout)               │ (None, 512)            │             0 │\n",
+       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+       "│ dense_1 (Dense)                 │ (None, 10)             │         5,130 │\n",
+       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
+       "
\n" + ], + "text/plain": [ + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", + "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", + "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", + "│ dense (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m512\u001b[0m) │ \u001b[38;5;34m401,920\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ dropout (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m512\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ dense_1 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m10\u001b[0m) │ \u001b[38;5;34m5,130\u001b[0m │\n", + "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Total params: 407,050 (1.55 MB)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m407,050\u001b[0m (1.55 MB)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Trainable params: 407,050 (1.55 MB)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m407,050\u001b[0m (1.55 MB)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Define a simple sequential model\n", + "def create_model():\n", + " model = tf.keras.Sequential([\n", + " keras.layers.Dense(512, activation='relu', input_shape=(784,)),\n", + " keras.layers.Dropout(0.2),\n", + " keras.layers.Dense(10)\n", + " ])\n", + "\n", + " model.compile(optimizer='adam',\n", + " loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n", + " metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])\n", + "\n", + " return model\n", + "\n", + "# Create a basic model instance\n", + "model = create_model()\n", + "\n", + "# Display the model's architecture\n", + "model.summary()" + ] + }, + { + "cell_type": "markdown", + "id": "605d082a", + "metadata": {}, + "source": [ + "### Save checkpoints during training" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "244746be", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n", + "I0000 00:00:1727977222.161202 1835280 service.cc:146] XLA service 0x7ec778008e00 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:\n", + "I0000 00:00:1727977222.161216 1835280 service.cc:154] StreamExecutor device (0): NVIDIA RTX A6000, Compute Capability 8.6\n", + "2024-10-03 17:40:22.168848: I tensorflow/compiler/mlir/tensorflow/utils/dump_mlir_util.cc:268] disabling MLIR crash reproducer, set env var `MLIR_CRASH_REPRODUCER_DIRECTORY` to enable.\n", + "2024-10-03 17:40:22.206298: I external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:531] Loaded cuDNN version 8907\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m24s\u001b[0m 778ms/step - loss: 2.3278 - sparse_categorical_accuracy: 0.1250" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "I0000 00:00:1727977222.715572 1835280 device_compiler.h:188] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 17ms/step - loss: 1.5867 - sparse_categorical_accuracy: 0.5096 " + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:40:23.780912: I external/local_xla/xla/stream_executor/cuda/cuda_asm_compiler.cc:393] ptxas warning : Registers are spilled to local memory in function 'gemm_fusion_dot_33', 4 bytes spill stores, 4 bytes spill loads\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Epoch 1: val_sparse_categorical_accuracy improved from -inf to 0.78700, saving model to training_1/checkpoint.model.keras\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 44ms/step - loss: 1.5733 - sparse_categorical_accuracy: 0.5144 - val_loss: 0.7061 - val_sparse_categorical_accuracy: 0.7870\n", + "Epoch 2/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - loss: 0.5514 - sparse_categorical_accuracy: 0.8438\n", + "Epoch 2: val_sparse_categorical_accuracy improved from 0.78700 to 0.83700, saving model to training_1/checkpoint.model.keras\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 2ms/step - loss: 0.4276 - sparse_categorical_accuracy: 0.8935 - val_loss: 0.5268 - val_sparse_categorical_accuracy: 0.8370\n", + "Epoch 3/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 20ms/step - loss: 0.1458 - sparse_categorical_accuracy: 0.9688\n", + "Epoch 3: val_sparse_categorical_accuracy improved from 0.83700 to 0.85600, saving model to training_1/checkpoint.model.keras\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.2721 - sparse_categorical_accuracy: 0.9236 - val_loss: 0.4716 - val_sparse_categorical_accuracy: 0.8560\n", + "Epoch 4/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - loss: 0.2223 - sparse_categorical_accuracy: 0.9375\n", + "Epoch 4: val_sparse_categorical_accuracy did not improve from 0.85600\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.2159 - sparse_categorical_accuracy: 0.9547 - val_loss: 0.4682 - val_sparse_categorical_accuracy: 0.8540\n", + "Epoch 5/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 16ms/step - loss: 0.1483 - sparse_categorical_accuracy: 0.9688\n", + "Epoch 5: val_sparse_categorical_accuracy improved from 0.85600 to 0.86900, saving model to training_1/checkpoint.model.keras\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 2ms/step - loss: 0.1457 - sparse_categorical_accuracy: 0.9716 - val_loss: 0.4285 - val_sparse_categorical_accuracy: 0.8690\n", + "Epoch 6/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - loss: 0.0836 - sparse_categorical_accuracy: 0.9688\n", + "Epoch 6: val_sparse_categorical_accuracy did not improve from 0.86900\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.1292 - sparse_categorical_accuracy: 0.9712 - val_loss: 0.4551 - val_sparse_categorical_accuracy: 0.8580\n", + "Epoch 7/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 12ms/step - loss: 0.0920 - sparse_categorical_accuracy: 0.9688\n", + "Epoch 7: val_sparse_categorical_accuracy did not improve from 0.86900\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.0974 - sparse_categorical_accuracy: 0.9822 - val_loss: 0.4016 - val_sparse_categorical_accuracy: 0.8670\n", + "Epoch 8/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 12ms/step - loss: 0.0993 - sparse_categorical_accuracy: 0.9688\n", + "Epoch 8: val_sparse_categorical_accuracy did not improve from 0.86900\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.0702 - sparse_categorical_accuracy: 0.9920 - val_loss: 0.3999 - val_sparse_categorical_accuracy: 0.8650\n", + "Epoch 9/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 12ms/step - loss: 0.0599 - sparse_categorical_accuracy: 1.0000\n", + "Epoch 9: val_sparse_categorical_accuracy improved from 0.86900 to 0.87800, saving model to training_1/checkpoint.model.keras\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.0457 - sparse_categorical_accuracy: 0.9974 - val_loss: 0.4145 - val_sparse_categorical_accuracy: 0.8780\n", + "Epoch 10/10\n", + "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - loss: 0.0286 - sparse_categorical_accuracy: 1.0000\n", + "Epoch 10: val_sparse_categorical_accuracy did not improve from 0.87800\n", + "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.0351 - sparse_categorical_accuracy: 0.9987 - val_loss: 0.4200 - val_sparse_categorical_accuracy: 0.8720\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "checkpoint_path = \"training_1/checkpoint.model.keras\"\n", + "checkpoint_dir = os.path.dirname(checkpoint_path)\n", + "\n", + "# Create a callback that saves the model's weights\n", + "cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,\n", + " monitor='val_sparse_categorical_accuracy',\n", + " mode='max',\n", + " save_best_only=True,\n", + " verbose=1)\n", + "\n", + "# Train the model with the new callback\n", + "model.fit(train_images, \n", + " train_labels, \n", + " epochs=10,\n", + " validation_data=(test_images, test_labels),\n", + " callbacks=[cp_callback]) # Pass callback to training\n", + "\n", + "# This may generate warnings related to saving the state of the optimizer.\n", + "# These warnings (and similar warnings throughout this notebook)\n", + "# are in place to discourage outdated usage, and can be ignored." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "310eae08", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['checkpoint.model.keras']" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "os.listdir(checkpoint_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "50eeb6e5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "INFO:tensorflow:Assets written to: mnist_model/assets\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:tensorflow:Assets written to: mnist_model/assets\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Saved artifact at 'mnist_model'. The following endpoints are available:\n", + "\n", + "* Endpoint 'serve'\n", + " args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 784), dtype=tf.float32, name='keras_tensor')\n", + "Output Type:\n", + " TensorSpec(shape=(None, 10), dtype=tf.float32, name=None)\n", + "Captures:\n", + " 139403584120848: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 139403240100240: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 139403240100048: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", + " 139403240099856: TensorSpec(shape=(), dtype=tf.resource, name=None)\n" + ] + } + ], + "source": [ + "# Export model in saved_model format\n", + "model.export(\"mnist_model\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "6d3bba9e", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/rishic/anaconda3/envs/spark-dl-tf/lib/python3.11/site-packages/keras/src/layers/core/dense.py:87: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.\n", + " super().__init__(activity_regularizer=activity_regularizer, **kwargs)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "32/32 - 0s - 10ms/step - loss: 2.4196 - sparse_categorical_accuracy: 0.0590\n", + "Untrained model, accuracy: 5.90%\n" + ] + } + ], + "source": [ + "# Create a basic model instance\n", + "model = create_model()\n", + "\n", + "# Evaluate the model\n", + "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", + "print(\"Untrained model, accuracy: {:5.2f}%\".format(100 * acc))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "22ad1708", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "32/32 - 0s - 713us/step - loss: 0.4145 - sparse_categorical_accuracy: 0.8780\n", + "Restored model, accuracy: 87.80%\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/rishic/anaconda3/envs/spark-dl-tf/lib/python3.11/site-packages/keras/src/saving/saving_lib.py:713: UserWarning: Skipping variable loading for optimizer 'adam', because it has 2 variables whereas the saved optimizer has 10 variables. \n", + " saveable.load_own_variables(weights_store.get(inner_path))\n" + ] + } + ], + "source": [ + "# Load the weights from the checkpoint\n", + "model.load_weights(checkpoint_path)\n", + "\n", + "# Re-evaluate the model\n", + "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", + "print(\"Restored model, accuracy: {:5.2f}%\".format(100 * acc))" + ] + }, + { + "cell_type": "markdown", + "id": "1c097d63", + "metadata": {}, + "source": [ + "### Checkpoint callback options" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "cb336e89", + "metadata": {}, + "outputs": [], + "source": [ + "!rm -rf training_2\n", + "!mkdir training_2" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "750b6deb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Epoch 5: saving model to training_2/cp-0005.weights.h5\n", + "\n", + "Epoch 10: saving model to training_2/cp-0010.weights.h5\n", + "\n", + "Epoch 15: saving model to training_2/cp-0015.weights.h5\n", + "\n", + "Epoch 20: saving model to training_2/cp-0020.weights.h5\n", + "\n", + "Epoch 25: saving model to training_2/cp-0025.weights.h5\n", + "\n", + "Epoch 30: saving model to training_2/cp-0030.weights.h5\n", + "\n", + "Epoch 35: saving model to training_2/cp-0035.weights.h5\n", + "\n", + "Epoch 40: saving model to training_2/cp-0040.weights.h5\n", + "\n", + "Epoch 45: saving model to training_2/cp-0045.weights.h5\n", + "\n", + "Epoch 50: saving model to training_2/cp-0050.weights.h5\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Include the epoch in the file name (uses `str.format`)\n", + "checkpoint_path = \"training_2/cp-{epoch:04d}.weights.h5\"\n", + "checkpoint_dir = os.path.dirname(checkpoint_path)\n", + "\n", + "batch_size = 32\n", + "\n", + "# Calculate the number of batches per epoch\n", + "import math\n", + "n_batches = len(train_images) / batch_size\n", + "n_batches = math.ceil(n_batches) # round up the number of batches to the nearest whole integer\n", + "\n", + "# Create a callback that saves the model's weights every 5 epochs\n", + "cp_callback = tf.keras.callbacks.ModelCheckpoint(\n", + " filepath=checkpoint_path, \n", + " verbose=1, \n", + " save_weights_only=True,\n", + " save_freq=5*n_batches)\n", + "\n", + "# Create a new model instance\n", + "model = create_model()\n", + "\n", + "# Save the weights using the `checkpoint_path` format\n", + "model.save_weights(checkpoint_path.format(epoch=0))\n", + "\n", + "# Train the model with the new callback\n", + "model.fit(train_images, \n", + " train_labels,\n", + " epochs=50, \n", + " batch_size=batch_size, \n", + " callbacks=[cp_callback],\n", + " validation_data=(test_images, test_labels),\n", + " verbose=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "1c43fd3d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['cp-0000.weights.h5',\n", + " 'cp-0015.weights.h5',\n", + " 'cp-0010.weights.h5',\n", + " 'cp-0035.weights.h5',\n", + " 'cp-0020.weights.h5',\n", + " 'cp-0040.weights.h5',\n", + " 'cp-0050.weights.h5',\n", + " 'cp-0005.weights.h5',\n", + " 'cp-0045.weights.h5',\n", + " 'cp-0025.weights.h5',\n", + " 'cp-0030.weights.h5']" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "os.listdir(checkpoint_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "0d7ae715", + "metadata": {}, + "outputs": [], + "source": [ + "latest = \"training_2/cp-0030.weights.h5\"" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "d345c6f7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "32/32 - 0s - 9ms/step - loss: 0.4501 - sparse_categorical_accuracy: 0.8720\n", + "Restored model, accuracy: 87.20%\n" + ] + } + ], + "source": [ + "# Create a new model instance\n", + "model = create_model()\n", + "\n", + "# Load the previously saved weights\n", + "model.load_weights(latest)\n", + "\n", + "# Re-evaluate the model from the latest checkpoint\n", + "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", + "print(\"Restored model, accuracy: {:5.2f}%\".format(100 * acc))" + ] + }, + { + "cell_type": "markdown", + "id": "a86f4700", + "metadata": {}, + "source": [ + "## PySpark" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "7fcf07bb", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "from pyspark.sql import SparkSession\n", + "from pyspark import SparkConf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c022c24", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", + "\n", + "conf = SparkConf()\n", + "if 'spark' not in globals():\n", + " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", + " import socket\n", + " hostname = socket.gethostname()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", + "conf.set(\"spark.task.maxFailures\", \"1\")\n", + "conf.set(\"spark.driver.memory\", \"8g\")\n", + "conf.set(\"spark.executor.memory\", \"8g\")\n", + "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", + "conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + "conf.set(\"spark.python.worker.reuse\", \"true\")\n", + "# Create Spark Session\n", + "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", + "sc = spark.sparkContext" + ] + }, + { + "cell_type": "markdown", + "id": "c81d0b1b", + "metadata": {}, + "source": [ + "### Convert numpy array to Spark DataFrame (via Pandas DataFrame)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "49ff5203", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(1000, 784)" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# numpy array to pandas DataFrame\n", + "test_pdf = pd.DataFrame(test_images)\n", + "test_pdf.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "182ee0c7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 134 ms, sys: 15.5 ms, total: 149 ms\n", + "Wall time: 1.36 s\n" + ] + } + ], + "source": [ + "%%time\n", + "df = spark.createDataFrame(test_pdf).repartition(8)" + ] + }, + { + "cell_type": "markdown", + "id": "d4e1c7ec-64fa-43c4-9bcf-0868a401d1f2", + "metadata": {}, + "source": [ + "### Save as Parquet (784 columns of float)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "0061c39a-0871-429e-a4ff-751d26bf4b04", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "24/10/03 17:40:32 WARN SparkStringUtils: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.sql.debug.maxToStringFields'.\n", + "[Stage 0:> (0 + 8) / 8]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.49 ms, sys: 1.65 ms, total: 4.13 ms\n", + "Wall time: 1.66 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "df.write.mode(\"overwrite\").parquet(\"mnist_784\")" + ] + }, + { + "cell_type": "markdown", + "id": "18315afb-3fa2-4953-9297-52c04dd70c32", + "metadata": {}, + "source": [ + "### Save as Parquet (1 column of 784 float)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "302c73ec", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 6.71 ms, sys: 4.92 ms, total: 11.6 ms\n", + "Wall time: 11.4 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "(1000, 1)" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "test_pdf['data'] = test_pdf.values.tolist()\n", + "pdf = test_pdf[['data']]\n", + "pdf.shape" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "5495901b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 46.6 ms, sys: 4.71 ms, total: 51.3 ms\n", + "Wall time: 91.7 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "df = spark.createDataFrame(pdf)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "5fa7faa8-c6bd-41b0-b5f7-fb121f0332e6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 807 μs, sys: 724 μs, total: 1.53 ms\n", + "Wall time: 211 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "df.write.mode(\"overwrite\").parquet(\"mnist_1\")" + ] + }, + { + "cell_type": "markdown", + "id": "c87b444e", + "metadata": {}, + "source": [ + "### Check arrow memory configuration" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "3d4ca414", + "metadata": {}, + "outputs": [], + "source": [ + "spark.conf.set(\"spark.sql.execution.arrow.maxRecordsPerBatch\", \"128\")\n", + "# This line will fail if the vectorized reader runs out of memory\n", + "assert len(df.head()) > 0, \"`df` should not be empty\" " + ] + }, + { + "cell_type": "markdown", + "id": "9b6dde30-98a9-45db-ab3a-d4546f9bed99", + "metadata": {}, + "source": [ + "## Inference using Spark DL API" + ] + }, + { + "cell_type": "markdown", + "id": "4238fb28-d002-4b4d-9aa1-8af1fbd5d569", + "metadata": {}, + "source": [ + "### 1 column of 784 float" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "db30fba6-24d0-4c00-8502-04f9b10e7e16", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import os\n", + "import pandas as pd\n", + "\n", + "from pyspark.ml.functions import predict_batch_udf\n", + "from pyspark.sql.functions import array, col, struct\n", + "from pyspark.sql.types import ArrayType, FloatType, Union, Dict" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "b9cf62f8-96b2-4716-80bd-bb93d5f939bd", + "metadata": {}, + "outputs": [], + "source": [ + "# get absolute path to model\n", + "model_dir = \"{}/training_1/checkpoint.model.keras\".format(os.getcwd())" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "b81fa297-d9d0-4600-880d-dbdcdf8bccc6", + "metadata": {}, + "outputs": [], + "source": [ + "def predict_batch_fn():\n", + " import tensorflow as tf\n", + "\n", + " # Enable GPU memory growth to avoid CUDA OOM\n", + " gpus = tf.config.experimental.list_physical_devices('GPU')\n", + " if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)\n", + "\n", + " model = tf.keras.models.load_model(model_dir)\n", + " def predict(inputs: np.ndarray) -> np.ndarray:\n", + " return model.predict(inputs)\n", + " \n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "72a689bd-dd82-492e-8740-1738a215325f", + "metadata": {}, + "outputs": [], + "source": [ + "mnist = predict_batch_udf(predict_batch_fn,\n", + " return_type=ArrayType(FloatType()),\n", + " batch_size=1024,\n", + " input_tensor_shapes=[[784]])" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "60a70150-26b1-4145-9e7d-6e17389216b7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = spark.read.parquet(\"mnist_1\")\n", + "len(df.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "e027f0d2-0f65-47b7-a562-2f0965faceec", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------+\n", + "| data|\n", + "+--------------------+\n", + "|[0.0, 0.0, 0.0, 0...|\n", + "|[0.0, 0.0, 0.0, 0...|\n", + "|[0.0, 0.0, 0.0, 0...|\n", + "|[0.0, 0.0, 0.0, 0...|\n", + "|[0.0, 0.0, 0.0, 0...|\n", + "+--------------------+\n", + "only showing top 5 rows\n", + "\n" + ] + } + ], + "source": [ + "df.show(5)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "f0c3fb2e-469e-47bc-b948-8f6b0d7f6513", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 4:===================================================> (7 + 1) / 8]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 18.5 ms, sys: 13.3 ms, total: 31.8 ms\n", + "Wall time: 5.03 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "# first pass caches model/fn\n", + "preds = df.withColumn(\"preds\", mnist(struct(df.columns))).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "cdfa229a-f4a9-4c11-a410-de4a21c02c82", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 37.3 ms, sys: 12.4 ms, total: 49.8 ms\n", + "Wall time: 259 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", mnist(*df.columns)).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "5586ce49-6f93-4343-9b66-0dbb64972179", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 22.9 ms, sys: 5.96 ms, total: 28.8 ms\n", + "Wall time: 237 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", mnist(*[col(c) for c in df.columns])).collect()" + ] + }, + { + "cell_type": "markdown", + "id": "004f1599-3c62-499e-9fd8-ed5cb0c90de4", + "metadata": { + "tags": [] + }, + "source": [ + "#### Check predictions" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "4f947dc0-6b18-4605-810b-e83250a161db", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "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", + "
datapreds
0[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-5.88436, -3.1058547, 0.10873719, 12.67319, -...
1[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-3.273286, -8.362554, 1.8936121, -3.8881433, ...
2[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-3.3856308, 0.6785604, 1.3146863, 0.9275978, ...
3[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-2.7754688, -7.3659225, 11.768427, 1.3434286,...
4[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-4.9426627, 4.0774136, -0.4529277, -0.9312789...
5[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-5.226616, -3.1389174, 2.6100307, 3.695045, -...
6[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-4.3006196, 5.1169925, 0.5850615, -0.76248693...
7[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-2.3985956, -1.4814724, -4.884057, -0.2391600...
8[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[0.82160115, -2.8640625, -1.6951559, -4.489290...
9[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-1.2338604, -2.151981, -4.171742, 1.6106845, ...
\n", + "
" + ], + "text/plain": [ + " data \\\n", + "0 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "1 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "2 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "3 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "4 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "5 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "6 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "7 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "8 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "9 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "\n", + " preds \n", + "0 [-5.88436, -3.1058547, 0.10873719, 12.67319, -... \n", + "1 [-3.273286, -8.362554, 1.8936121, -3.8881433, ... \n", + "2 [-3.3856308, 0.6785604, 1.3146863, 0.9275978, ... \n", + "3 [-2.7754688, -7.3659225, 11.768427, 1.3434286,... \n", + "4 [-4.9426627, 4.0774136, -0.4529277, -0.9312789... \n", + "5 [-5.226616, -3.1389174, 2.6100307, 3.695045, -... \n", + "6 [-4.3006196, 5.1169925, 0.5850615, -0.76248693... \n", + "7 [-2.3985956, -1.4814724, -4.884057, -0.2391600... \n", + "8 [0.82160115, -2.8640625, -1.6951559, -4.489290... \n", + "9 [-1.2338604, -2.151981, -4.171742, 1.6106845, ... " + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "preds = df.withColumn(\"preds\", mnist(*df.columns)).limit(10).toPandas()\n", + "preds" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "de4964e0-d1f8-4753-afa1-a8f95ca3f151", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ -5.88436 , -3.1058547 , 0.10873719, 12.67319 ,\n", + " -5.143787 , 4.0859914 , -10.203137 , -1.4333997 ,\n", + " -3.3865087 , -3.8473575 ], dtype=float32)" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sample = preds.iloc[0]\n", + "sample.preds" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "44e9a874-e301-4b72-8df7-bf1c5133c287", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "c60e5af4-fc1e-4575-a717-f304664235be", + "metadata": {}, + "outputs": [], + "source": [ + "prediction = np.argmax(sample.preds)\n", + "img = np.array(sample.data).reshape(28,28)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "eb45ecc9-d376-40c4-ad7b-2bd08ca5aaf6", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGzCAYAAABpdMNsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAkfElEQVR4nO3dfXQUdZ7v8U/nqSEkaR7yLAFCFHRAcAYly/AgSiQEZUCYGUG9F7gziJiggI6KR0Udzsksrg7qIHjcHVhHEGWOyMoiDg9JGBRwwTCIM2QhJ0g4kIBcSYcAIaR/9w+uvbQkQDUdfkl4v86pc+iq37fqm6Lgk+qqrnYZY4wAALjKwmw3AAC4NhFAAAArCCAAgBUEEADACgIIAGAFAQQAsIIAAgBYQQABAKwggAAAVhBAgAPdunXTpEmT/K8LCwvlcrlUWFgYsm24XC698MILIVsf0FwRQGgxlixZIpfL5Z/atGmjHj16KC8vT5WVlbbbc2TNmjUtJmTefvtt3X777UpKSpLb7VZ6eromT56s/fv3224NLVyE7QYAp1566SWlp6fr9OnT2rx5sxYuXKg1a9Zo9+7dio6Ovqq9DBkyRKdOnVJUVJSjujVr1mjBggUNhtCpU6cUEdF8/mkWFxcrPT1dP/vZz9ShQweVlZXp7bff1urVq/W3v/1NqamptltEC9V8jnLgMuXk5OjWW2+VJP36179Wp06d9Oqrr2rVqlWaMGFCgzU1NTVq165dyHsJCwtTmzZtQrrOUK/vSr355psXzBszZoxuvfVWvfPOO3r66actdIXWgLfg0OLdeeedkqSysjJJ0qRJkxQTE6PS0lKNHDlSsbGxeuCBByRJPp9P8+fPV69evdSmTRslJSVp6tSp+u677wLWaYzR3Llz1blzZ0VHR+uOO+7Q119/fcG2G7sGtG3bNo0cOVIdOnRQu3bt1KdPH7322mv+/hYsWCBJAW8pfq+ha0DFxcXKyclRXFycYmJiNGzYMG3dujVgzPdvUX722WeaNWuWEhIS1K5dO9177706evRowNiqqirt2bNHVVVVl7OLL9CtWzdJ0vHjx4OqByTOgNAKlJaWSpI6derkn3f27FllZ2dr0KBB+pd/+Rf/W3NTp07VkiVLNHnyZD366KMqKyvTH/7wBxUXF+uzzz5TZGSkJOn555/X3LlzNXLkSI0cOVJffvmlhg8frjNnzlyyn3Xr1umee+5RSkqKHnvsMSUnJ+sf//iHVq9erccee0xTp07VoUOHtG7dOv3pT3+65Pq+/vprDR48WHFxcXryyScVGRmpt956S0OHDlVRUZEyMzMDxk+fPl0dOnTQnDlztH//fs2fP195eXl6//33/WNWrlypyZMna/HixQE3VVzMsWPHVF9frwMHDuill16SJA0bNuyyaoEGGaCFWLx4sZFk1q9fb44ePWrKy8vN8uXLTadOnUzbtm3NwYMHjTHGTJw40UgyTz/9dED9X//6VyPJLF26NGD+2rVrA+YfOXLEREVFmbvvvtv4fD7/uGeeecZIMhMnTvTPKygoMJJMQUGBMcaYs2fPmvT0dNO1a1fz3XffBWzn/HXl5uaaxv75STJz5szxvx4zZoyJiooypaWl/nmHDh0ysbGxZsiQIRfsn6ysrIBtzZw504SHh5vjx49fMHbx4sUN9tAQt9ttJBlJplOnTub111+/7FqgIbwFhxYnKytLCQkJSktL0/jx4xUTE6OVK1fquuuuCxg3bdq0gNcrVqyQx+PRXXfdpW+//dY/9evXTzExMSooKJAkrV+/XmfOnNH06dMD3hqbMWPGJXsrLi5WWVmZZsyYofbt2wcsO39dl6u+vl5/+ctfNGbMGHXv3t0/PyUlRffff782b94sr9cbUPPQQw8FbGvw4MGqr6/XN9984583adIkGWMu++xHkj755BOtWbNGr7zyirp06aKamhrHPw9wPt6CQ4uzYMEC9ejRQxEREUpKSlLPnj0VFhb4u1RERIQ6d+4cMG/v3r2qqqpSYmJig+s9cuSIJPn/o77hhhsClickJKhDhw4X7e37twN79+59+T/QRRw9elQnT55Uz549L1h20003yefzqby8XL169fLP79KlS8C473v+4XUup+644w5J524CGT16tHr37q2YmBjl5eVd0Xpx7SKA0OL079/ffxdcY9xu9wWh5PP5lJiYqKVLlzZYk5CQELIebQoPD29wvjEmZNvIyMjQj3/8Yy1dupQAQtAIIFwzMjIytH79eg0cOFBt27ZtdFzXrl0lnTtjOv9tr6NHj17yLCIjI0OStHv3bmVlZTU67nLfjktISFB0dLRKSkouWLZnzx6FhYUpLS3tstYVaqdOnVJtba2VbaN14BoQrhm//OUvVV9fr9/+9rcXLDt79qz/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YWGhKSsrM5999pnJysoy8fHx5siRI7Zba1LV1dWmuLjYFBcXG0nm1VdfNcXFxeabb74xxhjzu9/9zrRv396sWrXK7Nq1y4wePdqkp6ebU6dOWe48tC62H6qrq80TTzxhtmzZYsrKysz69evNT37yE3PDDTeY06dP2249ZKZNm2Y8Ho8pLCw0hw8f9k8nT570j3n44YdNly5dzMaNG8327dvNgAEDzIABAyx2HXqX2g/79u0zL730ktm+fbspKyszq1atMt27dzdDhgyx3HmgFhFAxhjzxhtvmC5dupioqCjTv39/s3XrVtstXXX33XefSUlJMVFRUea6664z9913n9m3b5/ttppcQUGBkXTBNHHiRGPMuVuxn3vuOZOUlGTcbrcZNmyYKSkpsdt0E7jYfjh58qQZPny4SUhIMJGRkaZr165mypQpre6XtIZ+fklm8eLF/jGnTp0yjzzyiOnQoYOJjo429957rzl8+LC9ppvApfbDgQMHzJAhQ0zHjh2N2+02119/vfnNb35jqqqq7Db+A3wfEADAimZ/DQgA0DoRQAAAKwggAIAVBBAAwAoCCABgBQEEALCCAAIAWEEAAQCsIIAAAFYQQAAAKwggAIAV/w/hgVLrpVGHsAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure()\n", + "plt.title(\"Prediction: {}\".format(prediction))\n", + "plt.imshow(img)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "39167347-0b99-4972-998c-e1230bf1d4d5", + "metadata": {}, + "source": [ + "### 784 columns of float" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "f1285e8b-1b96-437b-973a-eb868e33afb7", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "from pyspark.ml.functions import predict_batch_udf\n", + "from pyspark.sql.functions import array, col, struct\n", + "from pyspark.sql.types import ArrayType, FloatType, Union, Dict" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "6bea332e-f6de-494f-a0db-795d9fe3e134", + "metadata": {}, + "outputs": [], + "source": [ + "def predict_batch_fn():\n", + " import tensorflow as tf\n", + " # Enable GPU memory growth\n", + " gpus = tf.config.experimental.list_physical_devices('GPU')\n", + " if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)\n", + " \n", + " model = tf.keras.models.load_model(model_dir)\n", + " def predict(inputs: np.ndarray) -> np.ndarray:\n", + " return model.predict(inputs)\n", + " \n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "731d234c-549f-4df3-8a2b-312e63195396", + "metadata": {}, + "outputs": [], + "source": [ + "mnist = predict_batch_udf(predict_batch_fn,\n", + " return_type=ArrayType(FloatType()),\n", + " batch_size=1024,\n", + " input_tensor_shapes=[[784]])" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "a40fe207-6246-4b0e-abde-823979878d97", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "784" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = spark.read.parquet(\"mnist_784\")\n", + "len(df.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "10904f12-03e7-4518-8f12-2aa11989ddf5", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 10:=======> (1 + 7) / 8]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 45.6 ms, sys: 26 ms, total: 71.6 ms\n", + "Wall time: 5.51 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", mnist(struct(*df.columns))).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "671128df-f0f4-4f54-b35c-d63a78c7f89a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 46.5 ms, sys: 34 ms, total: 80.5 ms\n", + "Wall time: 884 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", mnist(array(*df.columns))).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "ce35deaf-7d49-4f34-9bf9-b4e6fc5761f4", + "metadata": {}, + "outputs": [], + "source": [ + "# should raise ValueError\n", + "# preds = df.withColumn(\"preds\", mnist(*df.columns)).collect()" + ] + }, + { + "cell_type": "markdown", + "id": "01709833-484b-451f-9aa8-37be5b7baf14", + "metadata": {}, + "source": [ + "### Check prediction" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "f9119632-b284-45d7-a262-c262e034c15c", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "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", + " \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", + " \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", + "
0123456789...775776777778779780781782783preds
00.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-5.88436, -3.1058552, 0.108737305, 12.67319, ...
10.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-3.2732859, -8.362555, 1.893612, -3.888143, 0...
20.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-3.3856308, 0.6785604, 1.3146865, 0.9275978, ...
30.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-2.775469, -7.3659234, 11.768431, 1.3434289, ...
40.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-4.942663, 4.0774136, -0.45292768, -0.9312788...
50.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-5.226616, -3.1389174, 2.6100307, 3.695045, -...
60.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-4.3006196, 5.116993, 0.5850617, -0.7624871, ...
70.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-2.398596, -1.4814726, -4.8840575, -0.2391601...
80.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[0.82160157, -2.8640628, -1.6951559, -4.489291...
90.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-1.2338604, -2.151981, -4.1717424, 1.6106843,...
\n", + "

10 rows × 785 columns

\n", + "
" + ], + "text/plain": [ + " 0 1 2 3 4 5 6 7 8 9 ... 775 776 777 778 \\\n", + "0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", + "1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", + "2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", + "3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", + "4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", + "5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", + "6 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", + "7 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", + "8 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", + "9 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", + "\n", + " 779 780 781 782 783 preds \n", + "0 0.0 0.0 0.0 0.0 0.0 [-5.88436, -3.1058552, 0.108737305, 12.67319, ... \n", + "1 0.0 0.0 0.0 0.0 0.0 [-3.2732859, -8.362555, 1.893612, -3.888143, 0... \n", + "2 0.0 0.0 0.0 0.0 0.0 [-3.3856308, 0.6785604, 1.3146865, 0.9275978, ... \n", + "3 0.0 0.0 0.0 0.0 0.0 [-2.775469, -7.3659234, 11.768431, 1.3434289, ... \n", + "4 0.0 0.0 0.0 0.0 0.0 [-4.942663, 4.0774136, -0.45292768, -0.9312788... \n", + "5 0.0 0.0 0.0 0.0 0.0 [-5.226616, -3.1389174, 2.6100307, 3.695045, -... \n", + "6 0.0 0.0 0.0 0.0 0.0 [-4.3006196, 5.116993, 0.5850617, -0.7624871, ... \n", + "7 0.0 0.0 0.0 0.0 0.0 [-2.398596, -1.4814726, -4.8840575, -0.2391601... \n", + "8 0.0 0.0 0.0 0.0 0.0 [0.82160157, -2.8640628, -1.6951559, -4.489291... \n", + "9 0.0 0.0 0.0 0.0 0.0 [-1.2338604, -2.151981, -4.1717424, 1.6106843,... \n", + "\n", + "[10 rows x 785 columns]" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "preds = df.withColumn(\"preds\", mnist(struct(df.columns))).limit(10).toPandas()\n", + "preds" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "7c067c62-03a6-461e-a1ff-4653276fbea1", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "a7084ad0-c021-4296-bad0-7a238971f53b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ -5.88436 , -3.1058552, 0.1087373, 12.67319 , -5.1437874,\n", + " 4.085992 , -10.203137 , -1.4333997, -3.3865087, -3.8473575],\n", + " dtype=float32)" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sample = preds.iloc[0]\n", + "sample.preds" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "8167c832-93ef-4f50-873b-07b67c19ef53", + "metadata": {}, + "outputs": [], + "source": [ + "prediction = np.argmax(sample.preds)\n", + "img = sample.drop('preds').to_numpy(dtype=float)\n", + "img = np.array(img).reshape(28,28)" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "297811e1-aecb-4afd-9a6a-30c49e8881cc", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGzCAYAAABpdMNsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAkfElEQVR4nO3dfXQUdZ7v8U/nqSEkaR7yLAFCFHRAcAYly/AgSiQEZUCYGUG9F7gziJiggI6KR0Udzsksrg7qIHjcHVhHEGWOyMoiDg9JGBRwwTCIM2QhJ0g4kIBcSYcAIaR/9w+uvbQkQDUdfkl4v86pc+iq37fqm6Lgk+qqrnYZY4wAALjKwmw3AAC4NhFAAAArCCAAgBUEEADACgIIAGAFAQQAsIIAAgBYQQABAKwggAAAVhBAgAPdunXTpEmT/K8LCwvlcrlUWFgYsm24XC698MILIVsf0FwRQGgxlixZIpfL5Z/atGmjHj16KC8vT5WVlbbbc2TNmjUtJmTefvtt3X777UpKSpLb7VZ6eromT56s/fv3224NLVyE7QYAp1566SWlp6fr9OnT2rx5sxYuXKg1a9Zo9+7dio6Ovqq9DBkyRKdOnVJUVJSjujVr1mjBggUNhtCpU6cUEdF8/mkWFxcrPT1dP/vZz9ShQweVlZXp7bff1urVq/W3v/1NqamptltEC9V8jnLgMuXk5OjWW2+VJP36179Wp06d9Oqrr2rVqlWaMGFCgzU1NTVq165dyHsJCwtTmzZtQrrOUK/vSr355psXzBszZoxuvfVWvfPOO3r66actdIXWgLfg0OLdeeedkqSysjJJ0qRJkxQTE6PS0lKNHDlSsbGxeuCBByRJPp9P8+fPV69evdSmTRslJSVp6tSp+u677wLWaYzR3Llz1blzZ0VHR+uOO+7Q119/fcG2G7sGtG3bNo0cOVIdOnRQu3bt1KdPH7322mv+/hYsWCBJAW8pfq+ha0DFxcXKyclRXFycYmJiNGzYMG3dujVgzPdvUX722WeaNWuWEhIS1K5dO9177706evRowNiqqirt2bNHVVVVl7OLL9CtWzdJ0vHjx4OqByTOgNAKlJaWSpI6derkn3f27FllZ2dr0KBB+pd/+Rf/W3NTp07VkiVLNHnyZD366KMqKyvTH/7wBxUXF+uzzz5TZGSkJOn555/X3LlzNXLkSI0cOVJffvmlhg8frjNnzlyyn3Xr1umee+5RSkqKHnvsMSUnJ+sf//iHVq9erccee0xTp07VoUOHtG7dOv3pT3+65Pq+/vprDR48WHFxcXryyScVGRmpt956S0OHDlVRUZEyMzMDxk+fPl0dOnTQnDlztH//fs2fP195eXl6//33/WNWrlypyZMna/HixQE3VVzMsWPHVF9frwMHDuill16SJA0bNuyyaoEGGaCFWLx4sZFk1q9fb44ePWrKy8vN8uXLTadOnUzbtm3NwYMHjTHGTJw40UgyTz/9dED9X//6VyPJLF26NGD+2rVrA+YfOXLEREVFmbvvvtv4fD7/uGeeecZIMhMnTvTPKygoMJJMQUGBMcaYs2fPmvT0dNO1a1fz3XffBWzn/HXl5uaaxv75STJz5szxvx4zZoyJiooypaWl/nmHDh0ysbGxZsiQIRfsn6ysrIBtzZw504SHh5vjx49fMHbx4sUN9tAQt9ttJBlJplOnTub111+/7FqgIbwFhxYnKytLCQkJSktL0/jx4xUTE6OVK1fquuuuCxg3bdq0gNcrVqyQx+PRXXfdpW+//dY/9evXTzExMSooKJAkrV+/XmfOnNH06dMD3hqbMWPGJXsrLi5WWVmZZsyYofbt2wcsO39dl6u+vl5/+ctfNGbMGHXv3t0/PyUlRffff782b94sr9cbUPPQQw8FbGvw4MGqr6/XN9984583adIkGWMu++xHkj755BOtWbNGr7zyirp06aKamhrHPw9wPt6CQ4uzYMEC9ejRQxEREUpKSlLPnj0VFhb4u1RERIQ6d+4cMG/v3r2qqqpSYmJig+s9cuSIJPn/o77hhhsClickJKhDhw4X7e37twN79+59+T/QRRw9elQnT55Uz549L1h20003yefzqby8XL169fLP79KlS8C473v+4XUup+644w5J524CGT16tHr37q2YmBjl5eVd0Xpx7SKA0OL079/ffxdcY9xu9wWh5PP5lJiYqKVLlzZYk5CQELIebQoPD29wvjEmZNvIyMjQj3/8Yy1dupQAQtAIIFwzMjIytH79eg0cOFBt27ZtdFzXrl0lnTtjOv9tr6NHj17yLCIjI0OStHv3bmVlZTU67nLfjktISFB0dLRKSkouWLZnzx6FhYUpLS3tstYVaqdOnVJtba2VbaN14BoQrhm//OUvVV9fr9/+9rcXLDt79qz/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YWGhKSsrM5999pnJysoy8fHx5siRI7Zba1LV1dWmuLjYFBcXG0nm1VdfNcXFxeabb74xxhjzu9/9zrRv396sWrXK7Nq1y4wePdqkp6ebU6dOWe48tC62H6qrq80TTzxhtmzZYsrKysz69evNT37yE3PDDTeY06dP2249ZKZNm2Y8Ho8pLCw0hw8f9k8nT570j3n44YdNly5dzMaNG8327dvNgAEDzIABAyx2HXqX2g/79u0zL730ktm+fbspKyszq1atMt27dzdDhgyx3HmgFhFAxhjzxhtvmC5dupioqCjTv39/s3XrVtstXXX33XefSUlJMVFRUea6664z9913n9m3b5/ttppcQUGBkXTBNHHiRGPMuVuxn3vuOZOUlGTcbrcZNmyYKSkpsdt0E7jYfjh58qQZPny4SUhIMJGRkaZr165mypQpre6XtIZ+fklm8eLF/jGnTp0yjzzyiOnQoYOJjo429957rzl8+LC9ppvApfbDgQMHzJAhQ0zHjh2N2+02119/vfnNb35jqqqq7Db+A3wfEADAimZ/DQgA0DoRQAAAKwggAIAVBBAAwAoCCABgBQEEALCCAAIAWEEAAQCsIIAAAFYQQAAAKwggAIAV/w/hgVLrpVGHsAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure()\n", + "plt.title(\"Prediction: {}\".format(prediction))\n", + "plt.imshow(img)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "5961593d-182e-4620-9a5e-f98ba3d2534d", + "metadata": {}, + "source": [ + "### Using Triton Inference Server\n", + "\n", + "Note: you can restart the kernel and run from this point to simulate running in a different node or environment." + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "a64d19b1-ba4a-4dc7-b3a9-368dc47d0fd8", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from pyspark.ml.functions import predict_batch_udf\n", + "from pyspark.sql.functions import col, struct\n", + "from pyspark.sql.types import ArrayType, FloatType" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "8fa92fe4-2e04-4d82-a357-bfdfca38bd8c", + "metadata": {}, + "outputs": [], + "source": [ + "%%bash\n", + "# copy model to expected layout for Triton\n", + "rm -rf models\n", + "mkdir -p models/mnist_model/1\n", + "cp -r mnist_model models/mnist_model/1/model.savedmodel\n", + "\n", + "# add config.pbtxt\n", + "cp models_config/mnist_model/config.pbtxt models/mnist_model/config.pbtxt" + ] + }, + { + "cell_type": "markdown", + "id": "f1673e0e-5c75-44e1-88c6-5f5cf1275e4b", + "metadata": {}, + "source": [ + "#### Start Triton Server on each executor" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "0f7ecb25-be16-40c4-bdbb-441e2f537000", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "[True]" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "num_executors = 1\n", + "triton_models_dir = \"{}/models\".format(os.getcwd())\n", + "nodeRDD = sc.parallelize(list(range(num_executors)), num_executors)\n", + "\n", + "def start_triton(it):\n", + " import docker\n", + " import time\n", + " import tritonclient.grpc as grpcclient\n", + " \n", + " client=docker.from_env()\n", + " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", + " if containers:\n", + " \n", + " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", + " else:\n", + " container=client.containers.run(\n", + " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", + " detach=True,\n", + " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", + " name=\"spark-triton\",\n", + " network_mode=\"host\",\n", + " remove=True,\n", + " shm_size=\"64M\",\n", + " volumes={triton_models_dir: {\"bind\": \"/models\", \"mode\": \"ro\"}}\n", + " )\n", + " print(\">>>> starting triton: {}\".format(container.short_id))\n", + "\n", + " # wait for triton to be running\n", + " time.sleep(15)\n", + " client = grpcclient.InferenceServerClient(\"localhost:8001\")\n", + " ready = False\n", + " while not ready:\n", + " try:\n", + " ready = client.is_server_ready()\n", + " except Exception as e:\n", + " time.sleep(5)\n", + " \n", + " return [True]\n", + "\n", + "nodeRDD.barrier().mapPartitions(start_triton).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "43b93753-1d52-4060-9986-f24c30a67528", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "StructType([StructField('data', ArrayType(DoubleType(), True), True)])" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = spark.read.parquet(\"mnist_1\")\n", + "df.schema" + ] + }, + { + "cell_type": "markdown", + "id": "036680eb-babd-4b07-8b2c-ce6e724f4e85", + "metadata": {}, + "source": [ + "#### Run inference" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "3af08bd0-3838-4769-a8de-2643db4101c6", + "metadata": {}, + "outputs": [], + "source": [ + "def triton_fn(triton_uri, model_name):\n", + " import numpy as np\n", + " import tritonclient.grpc as grpcclient\n", + "\n", + " np_types = {\n", + " \"BOOL\": np.dtype(np.bool_),\n", + " \"INT8\": np.dtype(np.int8),\n", + " \"INT16\": np.dtype(np.int16),\n", + " \"INT32\": np.dtype(np.int32),\n", + " \"INT64\": np.dtype(np.int64),\n", + " \"FP16\": np.dtype(np.float16),\n", + " \"FP32\": np.dtype(np.float32),\n", + " \"FP64\": np.dtype(np.float64),\n", + " \"FP64\": np.dtype(np.double),\n", + " \"BYTES\": np.dtype(object)\n", + " }\n", + "\n", + " client = grpcclient.InferenceServerClient(triton_uri)\n", + " model_meta = client.get_model_metadata(model_name)\n", + "\n", + " def predict(inputs):\n", + " if isinstance(inputs, np.ndarray):\n", + " # single ndarray input\n", + " request = [grpcclient.InferInput(model_meta.inputs[0].name, inputs.shape, model_meta.inputs[0].datatype)]\n", + " request[0].set_data_from_numpy(inputs.astype(np_types[model_meta.inputs[0].datatype]))\n", + " else:\n", + " # dict of multiple ndarray inputs\n", + " request = [grpcclient.InferInput(i.name, inputs[i.name].shape, i.datatype) for i in model_meta.inputs]\n", + " for i in request:\n", + " i.set_data_from_numpy(inputs[i.name()].astype(np_types[i.datatype()]))\n", + "\n", + " response = client.infer(model_name, inputs=request)\n", + "\n", + " if len(model_meta.outputs) > 1:\n", + " # return dictionary of numpy arrays\n", + " return {o.name: response.as_numpy(o.name) for o in model_meta.outputs}\n", + " else:\n", + " # return single numpy array\n", + " return response.as_numpy(model_meta.outputs[0].name)\n", + "\n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "6658d2a1-ef7b-4ca1-9fb6-f2ac9050f3e5", + "metadata": {}, + "outputs": [], + "source": [ + "from functools import partial\n", + "\n", + "predict = predict_batch_udf(partial(triton_fn, \"localhost:8001\", \"mnist_model\"),\n", + " return_type=ArrayType(FloatType()),\n", + " input_tensor_shapes=[[784]],\n", + " batch_size=8192)" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "8397aa14-82fd-4351-a477-dc8e8b321fa2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 20.1 ms, sys: 3.41 ms, total: 23.5 ms\n", + "Wall time: 625 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", predict(struct(\"data\"))).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "82698bd9-377a-4415-8971-835487f876cc", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 30.3 ms, sys: 8.81 ms, total: 39.2 ms\n", + "Wall time: 154 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", predict(\"data\")).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "id": "419ad7bd-fa28-49d3-b98d-db9fba5aeaef", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 2.67 ms, sys: 4.2 ms, total: 6.87 ms\n", + "Wall time: 131 ms\n" + ] + }, + { + "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", + "
datapreds
0[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-5.7614846, -3.52228, -1.1202906, 13.053683, ...
1[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-3.1390061, -8.71185, 0.82955813, -4.034869, ...
2[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-3.046528, 0.3521706, 0.6788677, 0.72303534, ...
3[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-2.401024, -7.6780066, 11.145876, 1.2857256, ...
4[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-5.0012593, 3.806796, -0.8154834, -0.9550028,...
5[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-5.0425925, -3.4815094, 1.641246, 3.608149, -...
6[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-4.288771, 5.0072904, 0.27649477, -0.797148, ...
7[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-2.2032878, -1.6879876, -5.874276, -0.5945335...
8[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[1.1337761, -3.1751056, -2.5246286, -5.028277,...
9[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-0.92484117, -2.4703276, -5.023897, 1.46669, ...
\n", + "
" + ], + "text/plain": [ + " data \\\n", + "0 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "1 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "2 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "3 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "4 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "5 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "6 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "7 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "8 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "9 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", + "\n", + " preds \n", + "0 [-5.7614846, -3.52228, -1.1202906, 13.053683, ... \n", + "1 [-3.1390061, -8.71185, 0.82955813, -4.034869, ... \n", + "2 [-3.046528, 0.3521706, 0.6788677, 0.72303534, ... \n", + "3 [-2.401024, -7.6780066, 11.145876, 1.2857256, ... \n", + "4 [-5.0012593, 3.806796, -0.8154834, -0.9550028,... \n", + "5 [-5.0425925, -3.4815094, 1.641246, 3.608149, -... \n", + "6 [-4.288771, 5.0072904, 0.27649477, -0.797148, ... \n", + "7 [-2.2032878, -1.6879876, -5.874276, -0.5945335... \n", + "8 [1.1337761, -3.1751056, -2.5246286, -5.028277,... \n", + "9 [-0.92484117, -2.4703276, -5.023897, 1.46669, ... " + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "preds = df.withColumn(\"preds\", predict(col(\"data\"))).limit(10).toPandas()\n", + "preds" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "id": "79d90a26", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "id": "4ca495f5", + "metadata": {}, + "outputs": [], + "source": [ + "sample = preds.iloc[0]\n", + "sample.preds\n", + "\n", + "prediction = np.argmax(sample.preds)\n", + "img = np.array(sample.data).reshape(28,28)" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "a5d10903", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGzCAYAAABpdMNsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAkfElEQVR4nO3dfXQUdZ7v8U/nqSEkaR7yLAFCFHRAcAYly/AgSiQEZUCYGUG9F7gziJiggI6KR0Udzsksrg7qIHjcHVhHEGWOyMoiDg9JGBRwwTCIM2QhJ0g4kIBcSYcAIaR/9w+uvbQkQDUdfkl4v86pc+iq37fqm6Lgk+qqrnYZY4wAALjKwmw3AAC4NhFAAAArCCAAgBUEEADACgIIAGAFAQQAsIIAAgBYQQABAKwggAAAVhBAgAPdunXTpEmT/K8LCwvlcrlUWFgYsm24XC698MILIVsf0FwRQGgxlixZIpfL5Z/atGmjHj16KC8vT5WVlbbbc2TNmjUtJmTefvtt3X777UpKSpLb7VZ6eromT56s/fv3224NLVyE7QYAp1566SWlp6fr9OnT2rx5sxYuXKg1a9Zo9+7dio6Ovqq9DBkyRKdOnVJUVJSjujVr1mjBggUNhtCpU6cUEdF8/mkWFxcrPT1dP/vZz9ShQweVlZXp7bff1urVq/W3v/1NqamptltEC9V8jnLgMuXk5OjWW2+VJP36179Wp06d9Oqrr2rVqlWaMGFCgzU1NTVq165dyHsJCwtTmzZtQrrOUK/vSr355psXzBszZoxuvfVWvfPOO3r66actdIXWgLfg0OLdeeedkqSysjJJ0qRJkxQTE6PS0lKNHDlSsbGxeuCBByRJPp9P8+fPV69evdSmTRslJSVp6tSp+u677wLWaYzR3Llz1blzZ0VHR+uOO+7Q119/fcG2G7sGtG3bNo0cOVIdOnRQu3bt1KdPH7322mv+/hYsWCBJAW8pfq+ha0DFxcXKyclRXFycYmJiNGzYMG3dujVgzPdvUX722WeaNWuWEhIS1K5dO9177706evRowNiqqirt2bNHVVVVl7OLL9CtWzdJ0vHjx4OqByTOgNAKlJaWSpI6derkn3f27FllZ2dr0KBB+pd/+Rf/W3NTp07VkiVLNHnyZD366KMqKyvTH/7wBxUXF+uzzz5TZGSkJOn555/X3LlzNXLkSI0cOVJffvmlhg8frjNnzlyyn3Xr1umee+5RSkqKHnvsMSUnJ+sf//iHVq9erccee0xTp07VoUOHtG7dOv3pT3+65Pq+/vprDR48WHFxcXryyScVGRmpt956S0OHDlVRUZEyMzMDxk+fPl0dOnTQnDlztH//fs2fP195eXl6//33/WNWrlypyZMna/HixQE3VVzMsWPHVF9frwMHDuill16SJA0bNuyyaoEGGaCFWLx4sZFk1q9fb44ePWrKy8vN8uXLTadOnUzbtm3NwYMHjTHGTJw40UgyTz/9dED9X//6VyPJLF26NGD+2rVrA+YfOXLEREVFmbvvvtv4fD7/uGeeecZIMhMnTvTPKygoMJJMQUGBMcaYs2fPmvT0dNO1a1fz3XffBWzn/HXl5uaaxv75STJz5szxvx4zZoyJiooypaWl/nmHDh0ysbGxZsiQIRfsn6ysrIBtzZw504SHh5vjx49fMHbx4sUN9tAQt9ttJBlJplOnTub111+/7FqgIbwFhxYnKytLCQkJSktL0/jx4xUTE6OVK1fquuuuCxg3bdq0gNcrVqyQx+PRXXfdpW+//dY/9evXTzExMSooKJAkrV+/XmfOnNH06dMD3hqbMWPGJXsrLi5WWVmZZsyYofbt2wcsO39dl6u+vl5/+ctfNGbMGHXv3t0/PyUlRffff782b94sr9cbUPPQQw8FbGvw4MGqr6/XN9984583adIkGWMu++xHkj755BOtWbNGr7zyirp06aKamhrHPw9wPt6CQ4uzYMEC9ejRQxEREUpKSlLPnj0VFhb4u1RERIQ6d+4cMG/v3r2qqqpSYmJig+s9cuSIJPn/o77hhhsClickJKhDhw4X7e37twN79+59+T/QRRw9elQnT55Uz549L1h20003yefzqby8XL169fLP79KlS8C473v+4XUup+644w5J524CGT16tHr37q2YmBjl5eVd0Xpx7SKA0OL079/ffxdcY9xu9wWh5PP5lJiYqKVLlzZYk5CQELIebQoPD29wvjEmZNvIyMjQj3/8Yy1dupQAQtAIIFwzMjIytH79eg0cOFBt27ZtdFzXrl0lnTtjOv9tr6NHj17yLCIjI0OStHv3bmVlZTU67nLfjktISFB0dLRKSkouWLZnzx6FhYUpLS3tstYVaqdOnVJtba2VbaN14BoQrhm//OUvVV9fr9/+9rcXLDt79qz/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YWGhKSsrM5999pnJysoy8fHx5siRI7Zba1LV1dWmuLjYFBcXG0nm1VdfNcXFxeabb74xxhjzu9/9zrRv396sWrXK7Nq1y4wePdqkp6ebU6dOWe48tC62H6qrq80TTzxhtmzZYsrKysz69evNT37yE3PDDTeY06dP2249ZKZNm2Y8Ho8pLCw0hw8f9k8nT570j3n44YdNly5dzMaNG8327dvNgAEDzIABAyx2HXqX2g/79u0zL730ktm+fbspKyszq1atMt27dzdDhgyx3HmgFhFAxhjzxhtvmC5dupioqCjTv39/s3XrVtstXXX33XefSUlJMVFRUea6664z9913n9m3b5/ttppcQUGBkXTBNHHiRGPMuVuxn3vuOZOUlGTcbrcZNmyYKSkpsdt0E7jYfjh58qQZPny4SUhIMJGRkaZr165mypQpre6XtIZ+fklm8eLF/jGnTp0yjzzyiOnQoYOJjo429957rzl8+LC9ppvApfbDgQMHzJAhQ0zHjh2N2+02119/vfnNb35jqqqq7Db+A3wfEADAimZ/DQgA0DoRQAAAKwggAIAVBBAAwAoCCABgBQEEALCCAAIAWEEAAQCsIIAAAFYQQAAAKwggAIAV/w/hgVLrpVGHsAAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure()\n", + "plt.title(\"Prediction: {}\".format(prediction))\n", + "plt.imshow(img)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "6377f41a-5654-410b-8bad-d392e9dce7b8", + "metadata": { + "tags": [] + }, + "source": [ + "#### Stop Triton Server on each executor" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "id": "9c9fd967-5cd9-4265-add9-db5c1ccf9893", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "[True]" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def stop_triton(it):\n", + " import docker\n", + " import time\n", + " \n", + " client=docker.from_env()\n", + " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", + " print(\">>>> stopping containers: {}\".format([c.short_id for c in containers]))\n", + " if containers:\n", + " container=containers[0]\n", + " container.stop(timeout=120)\n", + "\n", + " return [True]\n", + "\n", + "nodeRDD.barrier().mapPartitions(stop_triton).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "f612dc0b-538f-4ecf-81f7-ef6b58c493ab", + "metadata": {}, + "outputs": [], + "source": [ + "spark.stop()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "490fc849-e47a-48d7-accc-429ff1cced6b", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "spark-dl-tf", + "language": "python", + "name": "python3" + }, + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/keras-metadata.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/keras-metadata_tf.ipynb similarity index 58% rename from examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/keras-metadata.ipynb rename to examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/keras-metadata_tf.ipynb index f9db34ca8..e0683e388 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/keras-metadata.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/keras-metadata_tf.ipynb @@ -9,12 +9,36 @@ "From: https://docs.databricks.com/_static/notebooks/deep-learning/keras-metadata.html" ] }, + { + "cell_type": "markdown", + "id": "858e3a8d", + "metadata": {}, + "source": [ + "### Using TensorFlow\n", + "Note that cuFFT/cuDNN/cuBLAS registration errors are expected with `tf=2.17.0` and will not affect behavior, as noted in [this issue.](https://github.com/tensorflow/tensorflow/issues/62075) \n", + "This notebook does not demonstrate inference with TensorRT, as [TF-TRT](https://docs.nvidia.com/deeplearning/tensorrt/release-notes/index.html#tensorrt-10) does not yet support `tf=2.17.0`. See the `pytorch` notebooks for TensorRT demos." + ] + }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "id": "cf329ac8-0763-44bc-b0f6-b634b7dc480e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:41:30.112764: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2024-10-03 17:41:30.119504: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", + "2024-10-03 17:41:30.126948: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", + "2024-10-03 17:41:30.129111: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", + "2024-10-03 17:41:30.134946: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2024-10-03 17:41:30.497048: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" + ] + } + ], "source": [ "import os\n", "import shutil\n", @@ -28,12 +52,61 @@ "import tensorflow as tf\n", "from tensorflow.keras.applications.resnet50 import ResNet50\n", " \n", - "from pyspark.sql.functions import col, pandas_udf, PandasUDFType" + "from pyspark.sql.functions import col, pandas_udf, PandasUDFType\n", + "from pyspark.sql import SparkSession\n", + "from pyspark import SparkConf" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, + "id": "44d72768", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", + "\n", + "conf = SparkConf()\n", + "if 'spark' not in globals():\n", + " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", + " import socket\n", + " hostname = socket.gethostname()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", + "conf.set(\"spark.task.maxFailures\", \"1\")\n", + "conf.set(\"spark.driver.memory\", \"8g\")\n", + "conf.set(\"spark.executor.memory\", \"8g\")\n", + "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", + "conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + "conf.set(\"spark.python.worker.reuse\", \"true\")\n", + "# Create Spark Session\n", + "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", + "sc = spark.sparkContext" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "833e36bc", + "metadata": {}, + "outputs": [], + "source": [ + "# Enable GPU memory growth\n", + "gpus = tf.config.experimental.list_physical_devices('GPU')\n", + "if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, "id": "950b0470-a21e-4778-a80e-b8f6ef792dff", "metadata": {}, "outputs": [], @@ -60,10 +133,26 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 6, "id": "2ddc715a-cdbc-4c49-93e9-58c9d88511da", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:41:32.482802: I tensorflow/core/common_runtime/gpu/gpu_device.cc:2021] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 45311 MB memory: -> device: 0, name: NVIDIA RTX A6000, pci bus id: 0000:01:00.0, compute capability: 8.6\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/resnet/resnet50_weights_tf_dim_ordering_tf_kernels.h5\n", + "\u001b[1m102967424/102967424\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 0us/step\n" + ] + } + ], "source": [ "model = ResNet50()\n", "bc_model_weights = sc.broadcast(model.get_weights())" @@ -79,10 +168,19 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 7, "id": "c0738bec-97d4-4946-8c49-5e6d07ff1afc", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz\n", + "\u001b[1m228813984/228813984\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m4s\u001b[0m 0us/step\n" + ] + } + ], "source": [ "import pathlib\n", "dataset_url = \"https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz\"\n", @@ -94,7 +192,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "id": "014644f4-2a45-4474-8afb-0daf90043253", "metadata": {}, "outputs": [ @@ -113,7 +211,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 9, "id": "d54f470a-d308-4426-8ed0-33f95155bb4f", "metadata": {}, "outputs": [ @@ -123,7 +221,7 @@ "2048" ] }, - "execution_count": 6, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -137,7 +235,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 10, "id": "fd883dc0-4846-4411-a4d6-4f5f252ac707", "metadata": {}, "outputs": [ @@ -145,7 +243,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "/home/leey/.keras/datasets/flower_photos\n" + "/home/rishic/.keras/datasets/flower_photos\n" ] } ], @@ -155,7 +253,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 11, "id": "64f94ee0-f1ea-47f6-a77e-be8da5d1b87a", "metadata": {}, "outputs": [], @@ -184,7 +282,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 12, "id": "670328e3-7274-4d78-b315-487750166a3f", "metadata": {}, "outputs": [ @@ -194,54 +292,14 @@ "0" ] }, - "execution_count": 9, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "subprocess.call(\"rm -rf resnet50_model\".split())" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "39c663a9-0526-4573-b7b0-27920e5b0004", - "metadata": { - "scrolled": true - }, - "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" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING:absl:Found untraced functions such as _jit_compiled_convolution_op, _jit_compiled_convolution_op, _jit_compiled_convolution_op, _jit_compiled_convolution_op, _jit_compiled_convolution_op while saving (showing 5 of 53). These functions will not be directly callable after loading.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "INFO:tensorflow:Assets written to: resnet50_model/assets\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:tensorflow:Assets written to: resnet50_model/assets\n" - ] - } - ], - "source": [ - "model.save('resnet50_model')" + "subprocess.call(\"rm -rf resnet50_model\".split())\n", + "model.export(\"resnet50_model\", verbose=0)" ] }, { @@ -254,30 +312,16 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 14, "id": "8ddc22d0-b88a-4906-bd47-bf247e34feeb", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 1:> (0 + 8) / 8]\r" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ "2048\n" ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] } ], "source": [ @@ -288,7 +332,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 15, "id": "c7adf1d9-1fa7-4456-ae32-cf7d1d43bfd3", "metadata": {}, "outputs": [], @@ -299,7 +343,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 16, "id": "97173c07-a96e-4262-b60f-82865b997e99", "metadata": {}, "outputs": [ @@ -327,7 +371,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 17, "id": "a67b3128-13c1-44f1-a0c0-7cf7a836fee3", "metadata": {}, "outputs": [], @@ -341,7 +385,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 18, "id": "7b33185f-6d1e-4ca9-9757-fdc3d736496b", "metadata": {}, "outputs": [ @@ -349,7 +393,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/home/leey/devpub/spark/python/pyspark/sql/pandas/functions.py:399: UserWarning: In Python 3.6+ and Spark 3.0+, it is preferred to specify type hints for pandas UDF instead of specifying pandas UDF type which will be deprecated in the future releases. See SPARK-28264 for more details.\n", + "/home/rishic/anaconda3/envs/spark-dl-tf/lib/python3.11/site-packages/pyspark/sql/pandas/functions.py:407: UserWarning: In Python 3.6+ and Spark 3.0+, it is preferred to specify type hints for pandas UDF instead of specifying pandas UDF type which will be deprecated in the future releases. See SPARK-28264 for more details.\n", " warnings.warn(\n" ] } @@ -357,6 +401,16 @@ "source": [ "@pandas_udf(ArrayType(FloatType()), PandasUDFType.SCALAR_ITER)\n", "def predict_batch_udf(image_batch_iter):\n", + "\n", + " # Enable GPU memory growth to avoid CUDA OOM\n", + " gpus = tf.config.experimental.list_physical_devices('GPU')\n", + " if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)\n", + "\n", " batch_size = 64\n", " model = ResNet50(weights=None)\n", " model.set_weights(bc_model_weights.value)\n", @@ -371,7 +425,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 19, "id": "ad8c05da-db38-45ef-81d0-1f862f575ced", "metadata": {}, "outputs": [ @@ -379,7 +433,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "[Stage 7:============================================> (3 + 1) / 4]\r" + " \r" ] }, { @@ -389,38 +443,31 @@ "+------------------------------------------------------------------------------------------------------------------------+\n", "| prediction|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", - "|[1.7195931E-4, 3.2735552E-4, 7.533328E-5, 1.9810574E-4, 6.6188135E-5, 4.304618E-4, 1.3097588E-5, 5.2791635E-5, 2.3571...|\n", - "|[7.738322E-5, 5.935413E-4, 1.3075814E-4, 1.8000253E-4, 1.3001164E-4, 2.2790757E-4, 5.0780895E-5, 2.3768713E-4, 3.8676...|\n", - "|[2.3994662E-5, 3.4409956E-4, 1.8440963E-4, 1.6311614E-4, 1.4301096E-4, 8.883273E-5, 2.6071444E-5, 2.3609246E-4, 1.481...|\n", - "|[7.33013E-5, 2.6747186E-4, 1.2007599E-4, 2.0717822E-4, 8.630799E-5, 2.2318888E-4, 1.3459768E-5, 8.564859E-5, 1.482114...|\n", - "|[5.592278E-5, 2.5165555E-4, 1.3106635E-4, 1.5746983E-4, 8.4952095E-5, 2.1269226E-4, 9.83865E-6, 1.6246884E-4, 1.24666...|\n", - "|[1.1709497E-4, 3.0075156E-4, 9.33239E-5, 1.6481965E-4, 6.906736E-5, 4.821755E-4, 8.922642E-6, 5.9618797E-5, 1.72143E-...|\n", - "|[1.1801151E-4, 2.1426812E-4, 5.9151847E-5, 1.1427055E-4, 5.1385836E-5, 4.3937864E-4, 4.607807E-6, 3.3783803E-5, 8.869...|\n", - "|[1.04612736E-4, 2.7663654E-4, 9.435623E-5, 1.6525248E-4, 7.4158685E-5, 4.257633E-4, 8.704045E-6, 5.3063635E-5, 1.2789...|\n", - "|[7.352998E-5, 3.3315457E-4, 7.0680355E-5, 1.7582536E-4, 7.606573E-5, 2.8071608E-4, 1.5708138E-5, 7.895344E-5, 1.63833...|\n", - "|[5.4112577E-5, 3.4097856E-4, 4.273796E-5, 6.867077E-5, 4.2725427E-5, 3.6373304E-4, 4.102062E-6, 1.15471645E-4, 1.3269...|\n", - "|[1.6299986E-5, 3.011269E-4, 1.0530894E-4, 1.0999596E-4, 6.247357E-5, 8.1669314E-5, 8.867516E-6, 1.9714379E-4, 9.89142...|\n", - "|[2.4569267E-4, 5.179993E-4, 1.7478937E-4, 2.2669601E-4, 1.2160459E-4, 4.5433E-4, 3.953984E-5, 7.979992E-5, 3.3513832E...|\n", - "|[9.029223E-5, 3.9454165E-4, 1.665605E-4, 1.9196334E-4, 1.1372031E-4, 2.0514896E-4, 2.7878115E-5, 1.4796885E-4, 3.3018...|\n", - "|[8.730619E-6, 3.4874916E-4, 5.797578E-5, 4.9443646E-5, 5.4349573E-5, 4.1568164E-5, 1.4966195E-5, 6.196577E-4, 2.33120...|\n", - "|[2.1702444E-5, 2.3885888E-4, 1.0117506E-4, 7.988898E-5, 7.155834E-5, 1.2449219E-4, 7.99208E-6, 2.611562E-4, 1.5751371...|\n", - "|[8.29938E-5, 3.1705064E-4, 1.587315E-4, 2.3244774E-4, 9.55335E-5, 1.9356904E-4, 1.7146796E-5, 9.8108874E-5, 1.8489505...|\n", - "|[6.3181215E-5, 2.6232892E-4, 1.0581372E-4, 2.0251807E-4, 6.83598E-5, 2.0704906E-4, 1.1209849E-5, 8.139733E-5, 1.70928...|\n", - "|[1.5359989E-4, 3.3213175E-4, 7.3188654E-5, 1.3153376E-4, 6.174973E-5, 3.554963E-4, 1.0753482E-5, 6.729857E-5, 2.27700...|\n", - "|[7.3694064E-5, 3.3086358E-4, 1.6089129E-4, 1.9742687E-4, 1.0419457E-4, 2.0769038E-4, 1.9587573E-5, 1.2341993E-4, 1.45...|\n", - "|[6.0036982E-5, 3.690938E-4, 9.357083E-5, 1.2322696E-4, 7.118597E-5, 2.5646162E-4, 1.1585914E-5, 2.2628417E-4, 2.26159...|\n", + "|[1.2938889E-4, 2.4666305E-4, 6.765791E-5, 1.2263245E-4, 5.7486624E-5, 3.9616702E-4, 7.0566134E-6, 4.1722178E-5, 1.225...|\n", + "|[4.4501914E-5, 3.5403698E-4, 4.6702033E-5, 8.102543E-5, 3.1704556E-5, 1.9194305E-4, 7.905952E-6, 1.3744082E-4, 1.9563...|\n", + "|[1.05672516E-4, 2.2686279E-4, 3.0055395E-5, 6.523785E-5, 2.352077E-5, 3.7122983E-4, 3.3315896E-6, 2.2584054E-5, 9.775...|\n", + "|[2.0331638E-5, 2.2746396E-4, 7.828012E-5, 6.986782E-5, 4.705316E-5, 9.80732E-5, 5.561918E-6, 2.3519044E-4, 1.3803913E...|\n", + "|[1.130241E-4, 2.3187004E-4, 5.296914E-5, 1.0871329E-4, 4.027478E-5, 3.7183522E-4, 5.5931855E-6, 3.4792112E-5, 1.14155...|\n", + "|[9.094467E-5, 2.06384E-4, 4.514821E-5, 7.665891E-5, 3.2262324E-5, 3.3875552E-4, 3.831814E-6, 4.1848412E-5, 9.94389E-6...|\n", + "|[1.07847634E-4, 3.7848807E-4, 7.660533E-5, 1.2446754E-4, 4.7595917E-5, 3.333814E-4, 1.0669675E-5, 9.133265E-5, 1.8015...|\n", + "|[2.2261223E-5, 2.734666E-4, 3.8122747E-5, 6.2266954E-5, 1.7935155E-5, 1.7268128E-4, 6.034271E-6, 1.06450585E-4, 1.789...|\n", + "|[1.1065645E-4, 2.900581E-4, 4.2585547E-5, 1.074203E-4, 3.052314E-5, 4.794604E-4, 6.4872897E-6, 3.646897E-5, 1.3717402...|\n", + "|[9.673917E-5, 2.058331E-4, 7.4652424E-5, 1.1323769E-4, 4.6106186E-5, 2.8604185E-4, 5.62365E-6, 5.471466E-5, 9.664386E...|\n", + "|[7.411196E-5, 3.291524E-4, 1.3454164E-4, 1.7738447E-4, 8.467504E-5, 2.2466244E-4, 1.3621126E-5, 1.1778668E-4, 1.83372...|\n", + "|[8.721524E-5, 2.7338538E-4, 3.5964815E-5, 7.792533E-5, 2.3559302E-5, 3.6789547E-4, 3.5665628E-6, 3.648153E-5, 1.07589...|\n", + "|[9.723709E-5, 2.7619812E-4, 5.7464153E-5, 1.10104906E-4, 3.8317143E-5, 3.490506E-4, 6.1553183E-6, 4.413095E-5, 1.1236...|\n", + "|[6.940235E-5, 2.5377885E-4, 5.057188E-5, 1.1485363E-4, 3.0059196E-5, 2.7862669E-4, 5.024019E-6, 5.1511077E-5, 1.16149...|\n", + "|[4.2095784E-5, 2.4891715E-4, 1.236292E-4, 1.4306813E-4, 7.3354306E-5, 1.6047148E-4, 7.958807E-6, 1.3556339E-4, 1.4698...|\n", + "|[2.7327887E-5, 3.8553146E-4, 1.2939748E-4, 1.5762268E-4, 7.307493E-5, 8.5530424E-5, 1.2648808E-5, 1.9154618E-4, 2.307...|\n", + "|[3.036101E-5, 3.5572305E-4, 1.600718E-4, 2.1437313E-4, 8.063033E-5, 1.02061334E-4, 1.3876456E-5, 1.561292E-4, 1.63637...|\n", + "|[3.3109587E-5, 2.8182982E-4, 1.7998899E-4, 2.0246049E-4, 1.3720036E-4, 1.01000114E-4, 3.427488E-5, 3.887249E-4, 3.189...|\n", + "|[4.549448E-5, 2.8782588E-4, 2.3703449E-4, 2.448979E-4, 1.20997625E-4, 1.3744453E-4, 1.62803E-5, 2.2094708E-4, 1.56962...|\n", + "|[1.2242574E-4, 2.8095162E-4, 6.332559E-5, 1.0209269E-4, 4.335324E-5, 3.906304E-4, 8.205706E-6, 6.202823E-5, 1.5312888...|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n", - "CPU times: user 42.3 ms, sys: 2.17 ms, total: 44.5 ms\n", - "Wall time: 12.3 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" + "CPU times: user 10.8 ms, sys: 4.93 ms, total: 15.7 ms\n", + "Wall time: 9.25 s\n" ] } ], @@ -432,7 +479,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 20, "id": "40799f8e-443e-40ca-919b-391f901cb3f4", "metadata": {}, "outputs": [ @@ -447,8 +494,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 26 ms, sys: 8.71 ms, total: 34.7 ms\n", - "Wall time: 49.9 s\n" + "CPU times: user 9.96 ms, sys: 3.32 ms, total: 13.3 ms\n", + "Wall time: 14 s\n" ] }, { @@ -476,7 +523,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 21, "id": "e6af27b2-ddc0-42ee-94cc-9ba5ffee6868", "metadata": {}, "outputs": [], @@ -488,7 +535,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 22, "id": "dda88b46-6300-4bf7-bc10-7403f4fbbf92", "metadata": {}, "outputs": [], @@ -496,6 +543,16 @@ "def predict_batch_fn():\n", " import tensorflow as tf\n", " from tensorflow.keras.applications.resnet50 import ResNet50\n", + "\n", + " # Enable GPU memory growth\n", + " gpus = tf.config.experimental.list_physical_devices('GPU')\n", + " if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)\n", + "\n", " model = ResNet50()\n", " def predict(inputs):\n", " inputs = inputs * (2. / 255) - 1\n", @@ -505,7 +562,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 23, "id": "cff0e851-563d-40b6-9d05-509c22b3b7f9", "metadata": {}, "outputs": [], @@ -518,7 +575,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 24, "id": "f733c38b-867d-48c1-b9a6-74a931561896", "metadata": {}, "outputs": [], @@ -529,7 +586,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 25, "id": "aa7c156f-e2b3-4837-9427-ccf3a5720412", "metadata": {}, "outputs": [], @@ -539,7 +596,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 26, "id": "80bc50ad-eaf5-4fce-a354-5e17d65e2da5", "metadata": { "tags": [] @@ -559,31 +616,31 @@ "+------------------------------------------------------------------------------------------------------------------------+\n", "| prediction|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", - "|[1.7195931E-4, 3.2735552E-4, 7.533328E-5, 1.9810574E-4, 6.6188135E-5, 4.304618E-4, 1.3097588E-5, 5.2791635E-5, 2.3571...|\n", - "|[7.738322E-5, 5.935413E-4, 1.3075814E-4, 1.8000253E-4, 1.3001164E-4, 2.2790757E-4, 5.0780895E-5, 2.3768713E-4, 3.8676...|\n", - "|[2.3994662E-5, 3.4409956E-4, 1.8440963E-4, 1.6311614E-4, 1.4301096E-4, 8.883273E-5, 2.6071444E-5, 2.3609246E-4, 1.481...|\n", - "|[7.33013E-5, 2.6747186E-4, 1.2007599E-4, 2.0717822E-4, 8.630799E-5, 2.2318888E-4, 1.3459768E-5, 8.564859E-5, 1.482114...|\n", - "|[5.592278E-5, 2.5165555E-4, 1.3106635E-4, 1.5746983E-4, 8.4952095E-5, 2.1269226E-4, 9.83865E-6, 1.6246884E-4, 1.24666...|\n", - "|[1.1709497E-4, 3.0075156E-4, 9.33239E-5, 1.6481965E-4, 6.906736E-5, 4.821755E-4, 8.922642E-6, 5.9618797E-5, 1.72143E-...|\n", - "|[1.1801151E-4, 2.1426812E-4, 5.9151847E-5, 1.1427055E-4, 5.1385836E-5, 4.3937864E-4, 4.607807E-6, 3.3783803E-5, 8.869...|\n", - "|[1.04612736E-4, 2.7663654E-4, 9.435623E-5, 1.6525248E-4, 7.4158685E-5, 4.257633E-4, 8.704045E-6, 5.3063635E-5, 1.2789...|\n", - "|[7.352998E-5, 3.3315457E-4, 7.0680355E-5, 1.7582536E-4, 7.606573E-5, 2.8071608E-4, 1.5708138E-5, 7.895344E-5, 1.63833...|\n", - "|[5.4112577E-5, 3.4097856E-4, 4.273796E-5, 6.867077E-5, 4.2725427E-5, 3.6373304E-4, 4.102062E-6, 1.15471645E-4, 1.3269...|\n", - "|[1.6299986E-5, 3.011269E-4, 1.0530894E-4, 1.0999596E-4, 6.247357E-5, 8.1669314E-5, 8.867516E-6, 1.9714379E-4, 9.89142...|\n", - "|[2.4569267E-4, 5.179993E-4, 1.7478937E-4, 2.2669601E-4, 1.2160459E-4, 4.5433E-4, 3.953984E-5, 7.979992E-5, 3.3513832E...|\n", - "|[9.029223E-5, 3.9454165E-4, 1.665605E-4, 1.9196334E-4, 1.1372031E-4, 2.0514896E-4, 2.7878115E-5, 1.4796885E-4, 3.3018...|\n", - "|[8.730619E-6, 3.4874916E-4, 5.797578E-5, 4.9443646E-5, 5.4349573E-5, 4.1568164E-5, 1.4966195E-5, 6.196577E-4, 2.33120...|\n", - "|[2.1702444E-5, 2.3885888E-4, 1.0117506E-4, 7.988898E-5, 7.155834E-5, 1.2449219E-4, 7.99208E-6, 2.611562E-4, 1.5751371...|\n", - "|[8.29938E-5, 3.1705064E-4, 1.587315E-4, 2.3244774E-4, 9.55335E-5, 1.9356904E-4, 1.7146796E-5, 9.8108874E-5, 1.8489505...|\n", - "|[6.3181215E-5, 2.6232892E-4, 1.0581372E-4, 2.0251807E-4, 6.83598E-5, 2.0704906E-4, 1.1209849E-5, 8.139733E-5, 1.70928...|\n", - "|[1.5359989E-4, 3.3213175E-4, 7.3188654E-5, 1.3153376E-4, 6.174973E-5, 3.554963E-4, 1.0753482E-5, 6.729857E-5, 2.27700...|\n", - "|[7.3694064E-5, 3.3086358E-4, 1.6089129E-4, 1.9742687E-4, 1.0419457E-4, 2.0769038E-4, 1.9587573E-5, 1.2341993E-4, 1.45...|\n", - "|[6.0036982E-5, 3.690938E-4, 9.357083E-5, 1.2322696E-4, 7.118597E-5, 2.5646162E-4, 1.1585914E-5, 2.2628417E-4, 2.26159...|\n", + "|[1.296447E-4, 2.465122E-4, 6.7463385E-5, 1.2231144E-4, 5.731739E-5, 3.9644213E-4, 7.0297688E-6, 4.1668914E-5, 1.22212...|\n", + "|[4.4481887E-5, 3.526653E-4, 4.683818E-5, 8.1168495E-5, 3.178377E-5, 1.9188467E-4, 7.885617E-6, 1.3758946E-4, 1.956621...|\n", + "|[1.05946536E-4, 2.2744355E-4, 3.0219735E-5, 6.548672E-5, 2.3649674E-5, 3.7177472E-4, 3.353236E-6, 2.271976E-5, 9.8115...|\n", + "|[2.0392703E-5, 2.2817637E-4, 7.840744E-5, 6.9875685E-5, 4.702542E-5, 9.8244425E-5, 5.5829764E-6, 2.3530141E-4, 1.3836...|\n", + "|[1.1312391E-4, 2.31244E-4, 5.279228E-5, 1.0859927E-4, 4.0202678E-5, 3.721753E-4, 5.563934E-6, 3.4674114E-5, 1.1389492...|\n", + "|[9.126345E-5, 2.0679034E-4, 4.5165678E-5, 7.679106E-5, 3.234611E-5, 3.3994843E-4, 3.84E-6, 4.1930372E-5, 9.949454E-6,...|\n", + "|[1.07930486E-4, 3.7741542E-4, 7.613175E-5, 1.2414041E-4, 4.7409427E-5, 3.332554E-4, 1.05853915E-5, 9.1026224E-5, 1.79...|\n", + "|[2.2216762E-5, 2.7354853E-4, 3.8192928E-5, 6.2340725E-5, 1.7952003E-5, 1.7253387E-4, 6.020507E-6, 1.0669143E-4, 1.786...|\n", + "|[1.10480236E-4, 2.89734E-4, 4.239379E-5, 1.0727814E-4, 3.047985E-5, 4.7992737E-4, 6.4530495E-6, 3.6428817E-5, 1.36967...|\n", + "|[9.6864875E-5, 2.0573521E-4, 7.4498465E-5, 1.1323085E-4, 4.6088306E-5, 2.8680824E-4, 5.604823E-6, 5.461046E-5, 9.6629...|\n", + "|[7.4198484E-5, 3.2886668E-4, 1.3441108E-4, 1.7755068E-4, 8.469927E-5, 2.2534095E-4, 1.3617541E-5, 1.1781904E-4, 1.833...|\n", + "|[8.7561886E-5, 2.7312653E-4, 3.5959012E-5, 7.7946424E-5, 2.3565723E-5, 3.6881721E-4, 3.5630535E-6, 3.642736E-5, 1.074...|\n", + "|[9.743975E-5, 2.7615853E-4, 5.74148E-5, 1.10329434E-4, 3.83045E-5, 3.500394E-4, 6.167429E-6, 4.4207005E-5, 1.1250093E...|\n", + "|[6.9320704E-5, 2.53287E-4, 5.0612853E-5, 1.14936556E-4, 3.0210098E-5, 2.7870742E-4, 5.031114E-6, 5.169024E-5, 1.16021...|\n", + "|[4.2203726E-5, 2.4911022E-4, 1.2378568E-4, 1.4274308E-4, 7.32259E-5, 1.6058519E-4, 7.9425035E-6, 1.3519496E-4, 1.4662...|\n", + "|[2.7190901E-5, 3.8381666E-4, 1.2918573E-4, 1.570463E-4, 7.310112E-5, 8.554618E-5, 1.2614603E-5, 1.9213595E-4, 2.30354...|\n", + "|[3.0573912E-5, 3.5561546E-4, 1.5945674E-4, 2.1361349E-4, 8.046549E-5, 1.0269262E-4, 1.3862439E-5, 1.5622783E-4, 1.638...|\n", + "|[3.3117096E-5, 2.8073433E-4, 1.7961214E-4, 2.020287E-4, 1.3662946E-4, 1.0117796E-4, 3.4090703E-5, 3.8897162E-4, 3.181...|\n", + "|[4.5728237E-5, 2.8880237E-4, 2.3783019E-4, 2.4589908E-4, 1.2160292E-4, 1.3812551E-4, 1.6343482E-5, 2.2073709E-4, 1.57...|\n", + "|[1.2280059E-4, 2.806991E-4, 6.3642765E-5, 1.02471764E-4, 4.351664E-5, 3.9150563E-4, 8.235125E-6, 6.211928E-5, 1.53269...|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n", - "CPU times: user 19.7 ms, sys: 7.84 ms, total: 27.5 ms\n", - "Wall time: 7.41 s\n" + "CPU times: user 8.12 ms, sys: 3.38 ms, total: 11.5 ms\n", + "Wall time: 5.59 s\n" ] }, { @@ -603,7 +660,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 27, "id": "41cace80-7a4b-4929-8e63-9c83f9745e02", "metadata": {}, "outputs": [ @@ -621,31 +678,31 @@ "+------------------------------------------------------------------------------------------------------------------------+\n", "| prediction|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", - "|[1.7195931E-4, 3.2735552E-4, 7.533328E-5, 1.9810574E-4, 6.6188135E-5, 4.304618E-4, 1.3097588E-5, 5.2791635E-5, 2.3571...|\n", - "|[7.738322E-5, 5.935413E-4, 1.3075814E-4, 1.8000253E-4, 1.3001164E-4, 2.2790757E-4, 5.0780895E-5, 2.3768713E-4, 3.8676...|\n", - "|[2.3994662E-5, 3.4409956E-4, 1.8440963E-4, 1.6311614E-4, 1.4301096E-4, 8.883273E-5, 2.6071444E-5, 2.3609246E-4, 1.481...|\n", - "|[7.33013E-5, 2.6747186E-4, 1.2007599E-4, 2.0717822E-4, 8.630799E-5, 2.2318888E-4, 1.3459768E-5, 8.564859E-5, 1.482114...|\n", - "|[5.592278E-5, 2.5165555E-4, 1.3106635E-4, 1.5746983E-4, 8.4952095E-5, 2.1269226E-4, 9.83865E-6, 1.6246884E-4, 1.24666...|\n", - "|[1.1709497E-4, 3.0075156E-4, 9.33239E-5, 1.6481965E-4, 6.906736E-5, 4.821755E-4, 8.922642E-6, 5.9618797E-5, 1.72143E-...|\n", - "|[1.1801151E-4, 2.1426812E-4, 5.9151847E-5, 1.1427055E-4, 5.1385836E-5, 4.3937864E-4, 4.607807E-6, 3.3783803E-5, 8.869...|\n", - "|[1.04612736E-4, 2.7663654E-4, 9.435623E-5, 1.6525248E-4, 7.4158685E-5, 4.257633E-4, 8.704045E-6, 5.3063635E-5, 1.2789...|\n", - "|[7.352998E-5, 3.3315457E-4, 7.0680355E-5, 1.7582536E-4, 7.606573E-5, 2.8071608E-4, 1.5708138E-5, 7.895344E-5, 1.63833...|\n", - "|[5.4112577E-5, 3.4097856E-4, 4.273796E-5, 6.867077E-5, 4.2725427E-5, 3.6373304E-4, 4.102062E-6, 1.15471645E-4, 1.3269...|\n", - "|[1.6299986E-5, 3.011269E-4, 1.0530894E-4, 1.0999596E-4, 6.247357E-5, 8.1669314E-5, 8.867516E-6, 1.9714379E-4, 9.89142...|\n", - "|[2.4569267E-4, 5.179993E-4, 1.7478937E-4, 2.2669601E-4, 1.2160459E-4, 4.5433E-4, 3.953984E-5, 7.979992E-5, 3.3513832E...|\n", - "|[9.029223E-5, 3.9454165E-4, 1.665605E-4, 1.9196334E-4, 1.1372031E-4, 2.0514896E-4, 2.7878115E-5, 1.4796885E-4, 3.3018...|\n", - "|[8.730619E-6, 3.4874916E-4, 5.797578E-5, 4.9443646E-5, 5.4349573E-5, 4.1568164E-5, 1.4966195E-5, 6.196577E-4, 2.33120...|\n", - "|[2.1702444E-5, 2.3885888E-4, 1.0117506E-4, 7.988898E-5, 7.155834E-5, 1.2449219E-4, 7.99208E-6, 2.611562E-4, 1.5751371...|\n", - "|[8.29938E-5, 3.1705064E-4, 1.587315E-4, 2.3244774E-4, 9.55335E-5, 1.9356904E-4, 1.7146796E-5, 9.8108874E-5, 1.8489505...|\n", - "|[6.3181215E-5, 2.6232892E-4, 1.0581372E-4, 2.0251807E-4, 6.83598E-5, 2.0704906E-4, 1.1209849E-5, 8.139733E-5, 1.70928...|\n", - "|[1.5359989E-4, 3.3213175E-4, 7.3188654E-5, 1.3153376E-4, 6.174973E-5, 3.554963E-4, 1.0753482E-5, 6.729857E-5, 2.27700...|\n", - "|[7.3694064E-5, 3.3086358E-4, 1.6089129E-4, 1.9742687E-4, 1.0419457E-4, 2.0769038E-4, 1.9587573E-5, 1.2341993E-4, 1.45...|\n", - "|[6.0036982E-5, 3.690938E-4, 9.357083E-5, 1.2322696E-4, 7.118597E-5, 2.5646162E-4, 1.1585914E-5, 2.2628417E-4, 2.26159...|\n", + "|[1.293178E-4, 2.4644283E-4, 6.760039E-5, 1.2260793E-4, 5.7431564E-5, 3.9597694E-4, 7.0522524E-6, 4.1717416E-5, 1.2240...|\n", + "|[4.4487308E-5, 3.5378174E-4, 4.6667028E-5, 8.102564E-5, 3.168566E-5, 1.9189132E-4, 7.903805E-6, 1.3741471E-4, 1.95482...|\n", + "|[1.0566196E-4, 2.2684377E-4, 3.00564E-5, 6.5251304E-5, 2.3520754E-5, 3.7116173E-4, 3.331476E-6, 2.2584616E-5, 9.77515...|\n", + "|[2.0337258E-5, 2.2749524E-4, 7.8351426E-5, 6.991163E-5, 4.7081656E-5, 9.8092445E-5, 5.564894E-6, 2.3517481E-4, 1.3805...|\n", + "|[1.12979564E-4, 2.3172122E-4, 5.2946547E-5, 1.0876398E-4, 4.0259067E-5, 3.7143996E-4, 5.5940513E-6, 3.4814777E-5, 1.1...|\n", + "|[9.093228E-5, 2.0639994E-4, 4.5151268E-5, 7.666316E-5, 3.2264295E-5, 3.387436E-4, 3.832487E-6, 4.185193E-5, 9.944773E...|\n", + "|[1.0783461E-4, 3.7850672E-4, 7.660902E-5, 1.2446321E-4, 4.7591406E-5, 3.3328883E-4, 1.067249E-5, 9.131178E-5, 1.80121...|\n", + "|[2.2258617E-5, 2.7345872E-4, 3.814439E-5, 6.229726E-5, 1.79387E-5, 1.7259057E-4, 6.0371217E-6, 1.0649798E-4, 1.789726...|\n", + "|[1.1067773E-4, 2.8997674E-4, 4.2570035E-5, 1.0747747E-4, 3.0524247E-5, 4.7921995E-4, 6.489833E-6, 3.6502548E-5, 1.371...|\n", + "|[9.676251E-5, 2.0588847E-4, 7.467098E-5, 1.1326933E-4, 4.6123736E-5, 2.8609246E-4, 5.627118E-6, 5.4726373E-5, 9.66839...|\n", + "|[7.4104944E-5, 3.290917E-4, 1.3448784E-4, 1.7742367E-4, 8.463227E-5, 2.2462371E-4, 1.3614881E-5, 1.17794625E-4, 1.833...|\n", + "|[8.7211796E-5, 2.7337394E-4, 3.5953894E-5, 7.7924225E-5, 2.3554327E-5, 3.67775E-4, 3.5652213E-6, 3.647724E-5, 1.07577...|\n", + "|[9.7237185E-5, 2.762026E-4, 5.7450008E-5, 1.1019135E-4, 3.831896E-5, 3.4878452E-4, 6.1574788E-6, 4.415526E-5, 1.12374...|\n", + "|[6.938849E-5, 2.5376282E-4, 5.0565883E-5, 1.14880335E-4, 3.0061366E-5, 2.7866007E-4, 5.024482E-6, 5.152425E-5, 1.1617...|\n", + "|[4.2096388E-5, 2.4889092E-4, 1.2363133E-4, 1.4304162E-4, 7.337785E-5, 1.6042824E-4, 7.959722E-6, 1.3552785E-4, 1.4693...|\n", + "|[2.730248E-5, 3.851789E-4, 1.293143E-4, 1.5753493E-4, 7.302161E-5, 8.547956E-5, 1.26348905E-5, 1.9148648E-4, 2.304900...|\n", + "|[3.0354899E-5, 3.5562844E-4, 1.6008675E-4, 2.1440513E-4, 8.062159E-5, 1.02023136E-4, 1.3876455E-5, 1.5611007E-4, 1.63...|\n", + "|[3.3083066E-5, 2.8158593E-4, 1.7979987E-4, 2.0232225E-4, 1.3704685E-4, 1.0091762E-4, 3.4243407E-5, 3.8870922E-4, 3.18...|\n", + "|[4.5485373E-5, 2.878148E-4, 2.3707838E-4, 2.4493985E-4, 1.21028905E-4, 1.3738636E-4, 1.6280053E-5, 2.2104722E-4, 1.56...|\n", + "|[1.22468E-4, 2.809503E-4, 6.3342835E-5, 1.021957E-4, 4.3373006E-5, 3.905496E-4, 8.212427E-6, 6.2081075E-5, 1.5323925E...|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n", - "CPU times: user 31.5 ms, sys: 6.18 ms, total: 37.6 ms\n", - "Wall time: 6.06 s\n" + "CPU times: user 2.75 ms, sys: 3.03 ms, total: 5.78 ms\n", + "Wall time: 4.79 s\n" ] }, { @@ -664,7 +721,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 28, "id": "56a2ec8a-de09-4d7c-9666-1b3c76f10657", "metadata": {}, "outputs": [ @@ -679,8 +736,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 30.8 ms, sys: 4.88 ms, total: 35.7 ms\n", - "Wall time: 49.1 s\n" + "CPU times: user 10.7 ms, sys: 4.25 ms, total: 14.9 ms\n", + "Wall time: 16.9 s\n" ] }, { @@ -709,7 +766,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 29, "id": "2605d134-ef75-4d94-9b16-2c6d85f29bef", "metadata": {}, "outputs": [], @@ -722,7 +779,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 30, "id": "4666e618-8038-4dc5-9be7-793aedbf4500", "metadata": {}, "outputs": [], @@ -747,7 +804,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 31, "id": "8c8c0744-0558-4dac-bbfe-8bdde4b2af2d", "metadata": {}, "outputs": [ @@ -764,7 +821,7 @@ "[True]" ] }, - "execution_count": 28, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } @@ -785,7 +842,7 @@ " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", " else:\n", " container=client.containers.run(\n", - " \"nvcr.io/nvidia/tritonserver:23.04-py3\", \"tritonserver --model-repository=/models\",\n", + " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", " detach=True,\n", " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", " name=\"spark-triton\",\n", @@ -821,7 +878,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 32, "id": "bcd46360-6851-4a9d-8590-c086e001242a", "metadata": {}, "outputs": [], @@ -831,7 +888,7 @@ " import tritonclient.grpc as grpcclient\n", " \n", " np_types = {\n", - " \"BOOL\": np.dtype(np.bool8),\n", + " \"BOOL\": np.dtype(np.bool_),\n", " \"INT8\": np.dtype(np.int8),\n", " \"INT16\": np.dtype(np.int16),\n", " \"INT32\": np.dtype(np.int32),\n", @@ -872,7 +929,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 33, "id": "9fabcaeb-5a44-42bb-8097-5dbc2d0cee3e", "metadata": {}, "outputs": [], @@ -887,7 +944,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 34, "id": "b17f33c8-a0f0-4bce-91f8-5838ba9b12a7", "metadata": {}, "outputs": [], @@ -898,7 +955,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 35, "id": "8e5b9e99-a1cf-43d3-a795-c7271a917057", "metadata": {}, "outputs": [], @@ -908,7 +965,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 36, "id": "e595473d-1a5d-46a6-a6ba-89d2ea903de9", "metadata": { "tags": [] @@ -928,31 +985,31 @@ "+------------------------------------------------------------------------------------------------------------------------+\n", "| prediction|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", - "|[1.7042673E-4, 3.267522E-4, 7.581915E-5, 1.9806583E-4, 6.629557E-5, 4.2843417E-4, 1.31030665E-5, 5.2828378E-5, 2.3425...|\n", - "|[7.658893E-5, 5.898446E-4, 1.3134143E-4, 1.7956285E-4, 1.2959713E-4, 2.2623697E-4, 5.0602717E-5, 2.387755E-4, 3.85566...|\n", - "|[2.3643051E-5, 3.3990925E-4, 1.8499317E-4, 1.6320233E-4, 1.4257104E-4, 8.804509E-5, 2.6084534E-5, 2.3692146E-4, 1.479...|\n", - "|[7.265595E-5, 2.660495E-4, 1.2043192E-4, 2.0687138E-4, 8.6514396E-5, 2.2079627E-4, 1.3474356E-5, 8.564823E-5, 1.47982...|\n", - "|[5.583156E-5, 2.5246604E-4, 1.3152408E-4, 1.5752943E-4, 8.486259E-5, 2.1114835E-4, 9.902404E-6, 1.6352077E-4, 1.25058...|\n", - "|[1.1620977E-4, 2.9887763E-4, 9.283447E-5, 1.6428927E-4, 6.8689915E-5, 4.8077543E-4, 8.824636E-6, 5.926726E-5, 1.70530...|\n", - "|[1.1755548E-4, 2.1347901E-4, 5.9497E-5, 1.1462011E-4, 5.154583E-5, 4.378169E-4, 4.606332E-6, 3.3860095E-5, 8.858123E-...|\n", - "|[1.0416699E-4, 2.7650507E-4, 9.4154115E-5, 1.6408198E-4, 7.396577E-5, 4.2134034E-4, 8.686047E-6, 5.308059E-5, 1.27552...|\n", - "|[7.3212854E-5, 3.3290745E-4, 7.060745E-5, 1.7570716E-4, 7.5938726E-5, 2.7863326E-4, 1.5730891E-5, 7.8610516E-5, 1.641...|\n", - "|[5.3438263E-5, 3.4120653E-4, 4.2561773E-5, 6.7946996E-5, 4.2590156E-5, 3.6005717E-4, 4.079908E-6, 1.1698964E-4, 1.331...|\n", - "|[1.6286886E-5, 3.0098078E-4, 1.0513259E-4, 1.0939782E-4, 6.222565E-5, 8.1393446E-5, 8.843026E-6, 1.9695786E-4, 9.9110...|\n", - "|[2.4522765E-4, 5.1859417E-4, 1.7468519E-4, 2.262611E-4, 1.2124745E-4, 4.519367E-4, 3.961034E-5, 7.9740654E-5, 3.36356...|\n", - "|[8.990819E-5, 3.942771E-4, 1.682308E-4, 1.9284713E-4, 1.1525641E-4, 2.0554545E-4, 2.831427E-5, 1.4873769E-4, 3.316071...|\n", - "|[8.54337E-6, 3.4811173E-4, 5.7887002E-5, 4.8874565E-5, 5.402399E-5, 4.112481E-5, 1.4895271E-5, 6.21633E-4, 2.3461927E...|\n", - "|[2.1293292E-5, 2.3748633E-4, 9.990328E-5, 7.8908284E-5, 7.079569E-5, 1.2173247E-4, 7.88914E-6, 2.6103947E-4, 1.563249...|\n", - "|[8.190444E-5, 3.168154E-4, 1.590983E-4, 2.3166533E-4, 9.556332E-5, 1.9129038E-4, 1.7210512E-5, 9.8816345E-5, 1.854863...|\n", - "|[6.291183E-5, 2.6241466E-4, 1.054902E-4, 2.0039888E-4, 6.793013E-5, 2.0695888E-4, 1.1183583E-5, 8.1747305E-5, 1.71265...|\n", - "|[1.5287477E-4, 3.303019E-4, 7.293286E-5, 1.3093611E-4, 6.1460145E-5, 3.5471437E-4, 1.069333E-5, 6.7022884E-5, 2.26818...|\n", - "|[7.34195E-5, 3.2822473E-4, 1.6043369E-4, 1.9740193E-4, 1.036919E-4, 2.0666287E-4, 1.9626465E-5, 1.2458269E-4, 1.46395...|\n", - "|[5.8976515E-5, 3.6673344E-4, 9.322759E-5, 1.222245E-4, 7.065327E-5, 2.5420502E-4, 1.145865E-5, 2.2733102E-4, 2.255583...|\n", + "|[1.2838157E-4, 2.442499E-4, 6.756602E-5, 1.223822E-4, 5.718728E-5, 3.9370774E-4, 6.9826538E-6, 4.180329E-5, 1.21474E-...|\n", + "|[4.3975022E-5, 3.5182733E-4, 4.6756446E-5, 8.051952E-5, 3.157192E-5, 1.8915786E-4, 7.8848925E-6, 1.3820908E-4, 1.9617...|\n", + "|[1.0483801E-4, 2.2482511E-4, 2.9800098E-5, 6.471683E-5, 2.3306355E-5, 3.6853546E-4, 3.2802545E-6, 2.2436941E-5, 9.655...|\n", + "|[2.0184121E-5, 2.2646098E-4, 7.754879E-5, 6.9126E-5, 4.6796213E-5, 9.757494E-5, 5.5280707E-6, 2.3486002E-4, 1.3758638...|\n", + "|[1.1207414E-4, 2.3036542E-4, 5.2748997E-5, 1.0843094E-4, 3.9970357E-5, 3.692824E-4, 5.5317682E-6, 3.467135E-5, 1.1321...|\n", + "|[9.028466E-5, 2.0533502E-4, 4.5085282E-5, 7.65107E-5, 3.217092E-5, 3.3741904E-4, 3.8024857E-6, 4.1927728E-5, 9.920564...|\n", + "|[1.0625615E-4, 3.759827E-4, 7.6174496E-5, 1.2342798E-4, 4.7335903E-5, 3.3091815E-4, 1.0598523E-5, 9.161089E-5, 1.7926...|\n", + "|[2.2157477E-5, 2.726377E-4, 3.831429E-5, 6.2276886E-5, 1.8050652E-5, 1.7177712E-4, 6.0331595E-6, 1.06755506E-4, 1.790...|\n", + "|[1.0993216E-4, 2.8824335E-4, 4.2543048E-5, 1.06903855E-4, 3.039875E-5, 4.7743318E-4, 6.441006E-6, 3.6423717E-5, 1.361...|\n", + "|[9.6276366E-5, 2.047977E-4, 7.4698546E-5, 1.128771E-4, 4.6044628E-5, 2.8445767E-4, 5.6014956E-6, 5.475251E-5, 9.63856...|\n", + "|[7.3160336E-5, 3.2700456E-4, 1.3447899E-4, 1.7689951E-4, 8.4440886E-5, 2.2350134E-4, 1.3515168E-5, 1.1746432E-4, 1.81...|\n", + "|[8.632592E-5, 2.7143923E-4, 3.583003E-5, 7.763873E-5, 2.3417528E-5, 3.6477615E-4, 3.527159E-6, 3.646688E-5, 1.0721673...|\n", + "|[9.640316E-5, 2.7391897E-4, 5.7131063E-5, 1.09568326E-4, 3.8045353E-5, 3.472495E-4, 6.057242E-6, 4.3799748E-5, 1.1118...|\n", + "|[6.912533E-5, 2.5222785E-4, 5.0288483E-5, 1.1415517E-4, 2.9881658E-5, 2.7816373E-4, 4.972507E-6, 5.121496E-5, 1.15293...|\n", + "|[4.189945E-5, 2.4779947E-4, 1.2303083E-4, 1.4200866E-4, 7.2787174E-5, 1.600041E-4, 7.901948E-6, 1.3503798E-4, 1.46427...|\n", + "|[2.7033573E-5, 3.8410365E-4, 1.2880778E-4, 1.5630701E-4, 7.2431474E-5, 8.455686E-5, 1.2551222E-5, 1.9146077E-4, 2.293...|\n", + "|[2.9902518E-5, 3.521676E-4, 1.6034822E-4, 2.1348803E-4, 8.053424E-5, 1.00774814E-4, 1.3777179E-5, 1.5595586E-4, 1.615...|\n", + "|[3.2834323E-5, 2.8044736E-4, 1.8003663E-4, 2.017913E-4, 1.3718085E-4, 1.0062256E-4, 3.4619785E-5, 3.8973117E-4, 3.187...|\n", + "|[4.4552748E-5, 2.8623734E-4, 2.3419394E-4, 2.4108509E-4, 1.1926766E-4, 1.3529808E-4, 1.6018543E-5, 2.210266E-4, 1.558...|\n", + "|[1.2160183E-4, 2.8021698E-4, 6.289166E-5, 1.0147789E-4, 4.3161614E-5, 3.8964444E-4, 8.174407E-6, 6.2043844E-5, 1.5228...|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n", - "CPU times: user 18.5 ms, sys: 11.6 ms, total: 30.1 ms\n", - "Wall time: 6.85 s\n" + "CPU times: user 4.79 ms, sys: 1.93 ms, total: 6.72 ms\n", + "Wall time: 3.06 s\n" ] }, { @@ -972,7 +1029,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 37, "id": "5f66d468-e0b1-4589-8606-b3848063a823", "metadata": {}, "outputs": [ @@ -990,31 +1047,31 @@ "+------------------------------------------------------------------------------------------------------------------------+\n", "| prediction|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", - "|[1.7042673E-4, 3.267522E-4, 7.581915E-5, 1.9806583E-4, 6.629557E-5, 4.2843417E-4, 1.31030665E-5, 5.2828378E-5, 2.3425...|\n", - "|[7.658893E-5, 5.898446E-4, 1.3134143E-4, 1.7956285E-4, 1.2959713E-4, 2.2623697E-4, 5.0602717E-5, 2.387755E-4, 3.85566...|\n", - "|[2.3643051E-5, 3.3990925E-4, 1.8499317E-4, 1.6320233E-4, 1.4257104E-4, 8.804509E-5, 2.6084534E-5, 2.3692146E-4, 1.479...|\n", - "|[7.265595E-5, 2.660495E-4, 1.2043192E-4, 2.0687138E-4, 8.6514396E-5, 2.2079627E-4, 1.3474356E-5, 8.564823E-5, 1.47982...|\n", - "|[5.583156E-5, 2.5246604E-4, 1.3152408E-4, 1.5752943E-4, 8.486259E-5, 2.1114835E-4, 9.902404E-6, 1.6352077E-4, 1.25058...|\n", - "|[1.1620977E-4, 2.9887763E-4, 9.283447E-5, 1.6428927E-4, 6.8689915E-5, 4.8077543E-4, 8.824636E-6, 5.926726E-5, 1.70530...|\n", - "|[1.1755548E-4, 2.1347901E-4, 5.9497E-5, 1.1462011E-4, 5.154583E-5, 4.378169E-4, 4.606332E-6, 3.3860095E-5, 8.858123E-...|\n", - "|[1.0416699E-4, 2.7650507E-4, 9.4154115E-5, 1.6408198E-4, 7.396577E-5, 4.2134034E-4, 8.686047E-6, 5.308059E-5, 1.27552...|\n", - "|[7.3212854E-5, 3.3290745E-4, 7.060745E-5, 1.7570716E-4, 7.5938726E-5, 2.7863326E-4, 1.5730891E-5, 7.8610516E-5, 1.641...|\n", - "|[5.3438263E-5, 3.4120653E-4, 4.2561773E-5, 6.7946996E-5, 4.2590156E-5, 3.6005717E-4, 4.079908E-6, 1.1698964E-4, 1.331...|\n", - "|[1.6286886E-5, 3.0098078E-4, 1.0513259E-4, 1.0939782E-4, 6.222565E-5, 8.1393446E-5, 8.843026E-6, 1.9695786E-4, 9.9110...|\n", - "|[2.4522765E-4, 5.1859417E-4, 1.7468519E-4, 2.262611E-4, 1.2124745E-4, 4.519367E-4, 3.961034E-5, 7.9740654E-5, 3.36356...|\n", - "|[8.990819E-5, 3.942771E-4, 1.682308E-4, 1.9284713E-4, 1.1525641E-4, 2.0554545E-4, 2.831427E-5, 1.4873769E-4, 3.316071...|\n", - "|[8.54337E-6, 3.4811173E-4, 5.7887002E-5, 4.8874565E-5, 5.402399E-5, 4.112481E-5, 1.4895271E-5, 6.21633E-4, 2.3461927E...|\n", - "|[2.1293292E-5, 2.3748633E-4, 9.990328E-5, 7.8908284E-5, 7.079569E-5, 1.2173247E-4, 7.88914E-6, 2.6103947E-4, 1.563249...|\n", - "|[8.190444E-5, 3.168154E-4, 1.590983E-4, 2.3166533E-4, 9.556332E-5, 1.9129038E-4, 1.7210512E-5, 9.8816345E-5, 1.854863...|\n", - "|[6.291183E-5, 2.6241466E-4, 1.054902E-4, 2.0039888E-4, 6.793013E-5, 2.0695888E-4, 1.1183583E-5, 8.1747305E-5, 1.71265...|\n", - "|[1.5287477E-4, 3.303019E-4, 7.293286E-5, 1.3093611E-4, 6.1460145E-5, 3.5471437E-4, 1.069333E-5, 6.7022884E-5, 2.26818...|\n", - "|[7.34195E-5, 3.2822473E-4, 1.6043369E-4, 1.9740193E-4, 1.036919E-4, 2.0666287E-4, 1.9626465E-5, 1.2458269E-4, 1.46395...|\n", - "|[5.8976515E-5, 3.6673344E-4, 9.322759E-5, 1.222245E-4, 7.065327E-5, 2.5420502E-4, 1.145865E-5, 2.2733102E-4, 2.255583...|\n", + "|[1.2838157E-4, 2.442499E-4, 6.756602E-5, 1.223822E-4, 5.718728E-5, 3.9370774E-4, 6.9826538E-6, 4.180329E-5, 1.21474E-...|\n", + "|[4.3975022E-5, 3.5182733E-4, 4.6756446E-5, 8.051952E-5, 3.157192E-5, 1.8915786E-4, 7.8848925E-6, 1.3820908E-4, 1.9617...|\n", + "|[1.0483801E-4, 2.2482511E-4, 2.9800098E-5, 6.471683E-5, 2.3306355E-5, 3.6853546E-4, 3.2802545E-6, 2.2436941E-5, 9.655...|\n", + "|[2.0184121E-5, 2.2646098E-4, 7.754879E-5, 6.9126E-5, 4.6796213E-5, 9.757494E-5, 5.5280707E-6, 2.3486002E-4, 1.3758638...|\n", + "|[1.1207414E-4, 2.3036542E-4, 5.2748997E-5, 1.0843094E-4, 3.9970357E-5, 3.692824E-4, 5.5317682E-6, 3.467135E-5, 1.1321...|\n", + "|[9.028466E-5, 2.0533502E-4, 4.5085282E-5, 7.65107E-5, 3.217092E-5, 3.3741904E-4, 3.8024857E-6, 4.1927728E-5, 9.920564...|\n", + "|[1.0625615E-4, 3.759827E-4, 7.6174496E-5, 1.2342798E-4, 4.7335903E-5, 3.3091815E-4, 1.0598523E-5, 9.161089E-5, 1.7926...|\n", + "|[2.2157477E-5, 2.726377E-4, 3.831429E-5, 6.2276886E-5, 1.8050652E-5, 1.7177712E-4, 6.0331595E-6, 1.06755506E-4, 1.790...|\n", + "|[1.0993216E-4, 2.8824335E-4, 4.2543048E-5, 1.06903855E-4, 3.039875E-5, 4.7743318E-4, 6.441006E-6, 3.6423717E-5, 1.361...|\n", + "|[9.6276366E-5, 2.047977E-4, 7.4698546E-5, 1.128771E-4, 4.6044628E-5, 2.8445767E-4, 5.6014956E-6, 5.475251E-5, 9.63856...|\n", + "|[7.3160336E-5, 3.2700456E-4, 1.3447899E-4, 1.7689951E-4, 8.4440886E-5, 2.2350134E-4, 1.3515168E-5, 1.1746432E-4, 1.81...|\n", + "|[8.632592E-5, 2.7143923E-4, 3.583003E-5, 7.763873E-5, 2.3417528E-5, 3.6477615E-4, 3.527159E-6, 3.646688E-5, 1.0721673...|\n", + "|[9.640316E-5, 2.7391897E-4, 5.7131063E-5, 1.09568326E-4, 3.8045353E-5, 3.472495E-4, 6.057242E-6, 4.3799748E-5, 1.1118...|\n", + "|[6.912533E-5, 2.5222785E-4, 5.0288483E-5, 1.1415517E-4, 2.9881658E-5, 2.7816373E-4, 4.972507E-6, 5.121496E-5, 1.15293...|\n", + "|[4.189945E-5, 2.4779947E-4, 1.2303083E-4, 1.4200866E-4, 7.2787174E-5, 1.600041E-4, 7.901948E-6, 1.3503798E-4, 1.46427...|\n", + "|[2.7033573E-5, 3.8410365E-4, 1.2880778E-4, 1.5630701E-4, 7.2431474E-5, 8.455686E-5, 1.2551222E-5, 1.9146077E-4, 2.293...|\n", + "|[2.9902518E-5, 3.521676E-4, 1.6034822E-4, 2.1348803E-4, 8.053424E-5, 1.00774814E-4, 1.3777179E-5, 1.5595586E-4, 1.615...|\n", + "|[3.2834323E-5, 2.8044736E-4, 1.8003663E-4, 2.017913E-4, 1.3718085E-4, 1.0062256E-4, 3.4619785E-5, 3.8973117E-4, 3.187...|\n", + "|[4.4552748E-5, 2.8623734E-4, 2.3419394E-4, 2.4108509E-4, 1.1926766E-4, 1.3529808E-4, 1.6018543E-5, 2.210266E-4, 1.558...|\n", + "|[1.2160183E-4, 2.8021698E-4, 6.289166E-5, 1.0147789E-4, 4.3161614E-5, 3.8964444E-4, 8.174407E-6, 6.2043844E-5, 1.5228...|\n", "+------------------------------------------------------------------------------------------------------------------------+\n", "only showing top 20 rows\n", "\n", - "CPU times: user 5.48 ms, sys: 4.51 ms, total: 9.99 ms\n", - "Wall time: 3.9 s\n" + "CPU times: user 3.16 ms, sys: 3.36 ms, total: 6.52 ms\n", + "Wall time: 2.24 s\n" ] }, { @@ -1033,7 +1090,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 38, "id": "632c4c3a-fa52-4c3d-b71e-7526286e353a", "metadata": {}, "outputs": [ @@ -1048,8 +1105,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "CPU times: user 18.8 ms, sys: 6.13 ms, total: 25 ms\n", - "Wall time: 22.2 s\n" + "CPU times: user 7.57 ms, sys: 5.2 ms, total: 12.8 ms\n", + "Wall time: 13.3 s\n" ] }, { @@ -1078,7 +1135,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 39, "id": "bbfcaa51-3b9f-43ff-a4a8-4b46766115b8", "metadata": {}, "outputs": [ @@ -1095,7 +1152,7 @@ "[True]" ] }, - "execution_count": 36, + "execution_count": 39, "metadata": {}, "output_type": "execute_result" } @@ -1119,7 +1176,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 40, "id": "0d88639b-d934-4eb4-ae2f-cc13b9b10456", "metadata": {}, "outputs": [], @@ -1138,7 +1195,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "spark-dl-tf", "language": "python", "name": "python3" }, @@ -1152,7 +1209,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.10" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/models_config/feature_columns/1/model.py b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/models_config/feature_columns/1/model.py index aa251e3d0..a2fa9635a 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/models_config/feature_columns/1/model.py +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/models_config/feature_columns/1/model.py @@ -69,7 +69,7 @@ def initialize(self, args): # Memory growth must be set before GPUs have been initialized print(e) - self.model = tf.keras.models.load_model("/my_pet_classifier") + self.model = tf.keras.models.load_model("/my_pet_classifier.keras") # You must parse model_config. JSON string is not parsed here self.model_config = model_config = json.loads(args['model_config']) @@ -134,7 +134,7 @@ def identity(input_tensor): # Get input numpy inputs = {name: transform(pb_utils.get_input_tensor_by_name(request, name)) for name, transform in input_transforms.items()} - pred = self.model.predict(inputs) + pred = self.model.predict(inputs, verbose=0) # Create output tensors. You need pb_utils.Tensor # objects to create pb_utils.InferenceResponse. diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/models_config/text_classification/1/model.py b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/models_config/text_classification/1/model.py index 50afea521..1bdef0b9c 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/models_config/text_classification/1/model.py +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/models_config/text_classification/1/model.py @@ -26,6 +26,7 @@ import numpy as np import json +import tensorflow as tf # triton_python_backend_utils is available in every Triton Python model. You # need to use this module to create inference requests and responses. It also @@ -57,7 +58,6 @@ def initialize(self, args): """ import re import string - import tensorflow as tf from tensorflow.keras import layers print("tf: {}".format(tf.__version__)) @@ -83,7 +83,7 @@ def custom_standardization(input_data): "custom_standardization": custom_standardization} with tf.keras.utils.custom_object_scope(custom_objects): self.model = tf.keras.models.load_model( - "/text_model" + "/text_model_cleaned.keras", compile=False ) # You must parse model_config. JSON string is not parsed here @@ -126,11 +126,12 @@ def execute(self, requests): for request in requests: # Get input numpy sentence_input = pb_utils.get_input_tensor_by_name(request, "sentence") - sentences = list(sentence_input.as_numpy()) + sentences = sentence_input.as_numpy() sentences = np.squeeze(sentences).tolist() sentences = [s.decode('utf-8') for s in sentences] + sentences = tf.convert_to_tensor(sentences) - pred = self.model.predict(sentences) + pred = self.model.predict(sentences, verbose=0) # Create output tensors. You need pb_utils.Tensor # objects to create pb_utils.InferenceResponse. diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/text_classification.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/text_classification.ipynb deleted file mode 100644 index ed1289b11..000000000 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/text_classification.ipynb +++ /dev/null @@ -1,1638 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "2cd2accf-5877-4136-a243-7a33a13ce2b4", - "metadata": {}, - "source": [ - "# Pyspark TensorFlow Inference\n", - "\n", - "## Text classification\n", - "Based on: https://www.tensorflow.org/tutorials/keras/text_classification" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "76f0f5df-502f-444e-b2ee-1122e1dea870", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import re\n", - "import shutil\n", - "import string\n", - "\n", - "import matplotlib.pyplot as plt\n", - "import tensorflow as tf\n", - "from tensorflow.keras import layers, losses" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "a364ad5f-b269-45b5-ab8b-d8f34fb642b7", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2.12.0\n" - ] - } - ], - "source": [ - "print(tf.__version__)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "d229c1b6-3967-46b5-9ea8-68f4b42dd211", - "metadata": {}, - "outputs": [], - "source": [ - "url = \"https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz\"\n", - "\n", - "dataset = tf.keras.utils.get_file(\n", - " \"aclImdb_v1\", url, untar=True, cache_dir=\".\", cache_subdir=\"\"\n", - ")\n", - "\n", - "dataset_dir = os.path.join(os.path.dirname(dataset), \"aclImdb\")" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "1f8038ae-8bc1-46bf-ae4c-6da08886c473", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['imdbEr.txt', 'imdb.vocab', 'train', 'test', 'README']" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "os.listdir(dataset_dir)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "12faaa3f-3441-4361-b9eb-4317e8c2c2f7", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['urls_unsup.txt',\n", - " 'neg',\n", - " 'unsupBow.feat',\n", - " 'unsup',\n", - " 'urls_pos.txt',\n", - " 'urls_neg.txt',\n", - " 'labeledBow.feat',\n", - " 'pos']" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "train_dir = os.path.join(dataset_dir, \"train\")\n", - "os.listdir(train_dir)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "152cc0cc-65d0-4e17-9ee8-222390df45b5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Rachel Griffiths writes and directs this award winning short film. A heartwarming story about coping with grief and cherishing the memory of those we've loved and lost. Although, only 15 minutes long, Griffiths manages to capture so much emotion and truth onto film in the short space of time. Bud Tingwell gives a touching performance as Will, a widower struggling to cope with his wife's death. Will is confronted by the harsh reality of loneliness and helplessness as he proceeds to take care of Ruth's pet cow, Tulip. The film displays the grief and responsibility one feels for those they have loved and lost. Good cinematography, great direction, and superbly acted. It will bring tears to all those who have lost a loved one, and survived.\n" - ] - } - ], - "source": [ - "sample_file = os.path.join(train_dir, \"pos/1181_9.txt\")\n", - "with open(sample_file) as f:\n", - " print(f.read())" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "b2277f58-78c8-4a12-bc98-5103e7c81a35", - "metadata": {}, - "outputs": [], - "source": [ - "remove_dir = os.path.join(train_dir, \"unsup\")\n", - "shutil.rmtree(remove_dir)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "ed83de92-ebb3-4170-b2bf-25265c6a6942", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Found 25000 files belonging to 2 classes.\n", - "Using 20000 files for training.\n" - ] - } - ], - "source": [ - "batch_size = 32\n", - "seed = 42\n", - "\n", - "raw_train_ds = tf.keras.utils.text_dataset_from_directory(\n", - " \"aclImdb/train\",\n", - " batch_size=batch_size,\n", - " validation_split=0.2,\n", - " subset=\"training\",\n", - " seed=seed,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "57c30568-daa8-4b2b-b30a-577c984a8af5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Review b'\"Pandemonium\" is a horror movie spoof that comes off more stupid than funny. Believe me when I tell you, I love comedies. Especially comedy spoofs. \"Airplane\", \"The Naked Gun\" trilogy, \"Blazing Saddles\", \"High Anxiety\", and \"Spaceballs\" are some of my favorite comedies that spoof a particular genre. \"Pandemonium\" is not up there with those films. Most of the scenes in this movie had me sitting there in stunned silence because the movie wasn\\'t all that funny. There are a few laughs in the film, but when you watch a comedy, you expect to laugh a lot more than a few times and that\\'s all this film has going for it. Geez, \"Scream\" had more laughs than this film and that was more of a horror film. How bizarre is that?

*1/2 (out of four)'\n", - "Label 0\n", - "Review b\"David Mamet is a very interesting and a very un-equal director. His first movie 'House of Games' was the one I liked best, and it set a series of films with characters whose perspective of life changes as they get into complicated situations, and so does the perspective of the viewer.

So is 'Homicide' which from the title tries to set the mind of the viewer to the usual crime drama. The principal characters are two cops, one Jewish and one Irish who deal with a racially charged area. The murder of an old Jewish shop owner who proves to be an ancient veteran of the Israeli Independence war triggers the Jewish identity in the mind and heart of the Jewish detective.

This is were the flaws of the film are the more obvious. The process of awakening is theatrical and hard to believe, the group of Jewish militants is operatic, and the way the detective eventually walks to the final violent confrontation is pathetic. The end of the film itself is Mamet-like smart, but disappoints from a human emotional perspective.

Joe Mantegna and William Macy give strong performances, but the flaws of the story are too evident to be easily compensated.\"\n", - "Label 0\n", - "Review b'Great documentary about the lives of NY firefighters during the worst terrorist attack of all time.. That reason alone is why this should be a must see collectors item.. What shocked me was not only the attacks, but the\"High Fat Diet\" and physical appearance of some of these firefighters. I think a lot of Doctors would agree with me that,in the physical shape they were in, some of these firefighters would NOT of made it to the 79th floor carrying over 60 lbs of gear. Having said that i now have a greater respect for firefighters and i realize becoming a firefighter is a life altering job. The French have a history of making great documentary\\'s and that is what this is, a Great Documentary.....'\n", - "Label 1\n" - ] - } - ], - "source": [ - "for text_batch, label_batch in raw_train_ds.take(1):\n", - " for i in range(3):\n", - " print(\"Review\", text_batch.numpy()[i])\n", - " print(\"Label\", label_batch.numpy()[i])" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "1e863eb6-4bd7-4da0-b10d-d951b5ee52bd", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Label 0 corresponds to neg\n", - "Label 1 corresponds to pos\n" - ] - } - ], - "source": [ - "print(\"Label 0 corresponds to\", raw_train_ds.class_names[0])\n", - "print(\"Label 1 corresponds to\", raw_train_ds.class_names[1])" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "1593e2e5-df51-4fbf-b4be-c786e740ddab", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Found 25000 files belonging to 2 classes.\n", - "Using 5000 files for validation.\n" - ] - } - ], - "source": [ - "raw_val_ds = tf.keras.utils.text_dataset_from_directory(\n", - " \"aclImdb/train\",\n", - " batch_size=batch_size,\n", - " validation_split=0.2,\n", - " subset=\"validation\",\n", - " seed=seed,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "944fd61d-3926-4296-889a-b2a375a1b039", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Found 25000 files belonging to 2 classes.\n" - ] - } - ], - "source": [ - "raw_test_ds = tf.keras.utils.text_dataset_from_directory(\n", - " \"aclImdb/test\", batch_size=batch_size\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "cb141709-fcc1-4cee-bc98-9c89aaba8648", - "metadata": {}, - "outputs": [], - "source": [ - "def custom_standardization(input_data):\n", - " lowercase = tf.strings.lower(input_data)\n", - " stripped_html = tf.strings.regex_replace(lowercase, \"
\", \" \")\n", - " return tf.strings.regex_replace(\n", - " stripped_html, \"[%s]\" % re.escape(string.punctuation), \"\"\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "d4e80ea9-536a-4ebc-8b35-1eca73dbba7d", - "metadata": {}, - "outputs": [], - "source": [ - "max_features = 10000\n", - "sequence_length = 250\n", - "\n", - "vectorize_layer = layers.TextVectorization(\n", - " standardize=custom_standardization,\n", - " max_tokens=max_features,\n", - " output_mode=\"int\",\n", - " output_sequence_length=sequence_length,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "ad1e5d81-7dae-4b08-b520-ca45501b9510", - "metadata": {}, - "outputs": [], - "source": [ - "# Make a text-only dataset (without labels), then call adapt\n", - "train_text = raw_train_ds.map(lambda x, y: x)\n", - "vectorize_layer.adapt(train_text)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "80f243f5-edd3-4e1c-bddc-abc1cc6673ef", - "metadata": {}, - "outputs": [], - "source": [ - "def vectorize_text(text, label):\n", - " text = tf.expand_dims(text, -1)\n", - " return vectorize_layer(text), label" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "8f37e95c-515c-4edb-a1ee-fc47be5df4b9", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Review tf.Tensor(b'Great movie - especially the music - Etta James - \"At Last\". This speaks volumes when you have finally found that special someone.', shape=(), dtype=string)\n", - "Label neg\n", - "Vectorized review (, )\n" - ] - } - ], - "source": [ - "# retrieve a batch (of 32 reviews and labels) from the dataset\n", - "text_batch, label_batch = next(iter(raw_train_ds))\n", - "first_review, first_label = text_batch[0], label_batch[0]\n", - "print(\"Review\", first_review)\n", - "print(\"Label\", raw_train_ds.class_names[first_label])\n", - "print(\"Vectorized review\", vectorize_text(first_review, first_label))" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "60c9208a-39ac-4e6c-a603-61038cdf3d10", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1287 ---> silent\n", - " 313 ---> night\n", - "Vocabulary size: 10000\n" - ] - } - ], - "source": [ - "print(\"1287 ---> \",vectorize_layer.get_vocabulary()[1287])\n", - "print(\" 313 ---> \",vectorize_layer.get_vocabulary()[313])\n", - "print('Vocabulary size: {}'.format(len(vectorize_layer.get_vocabulary())))" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "3cf90d4b-8dae-44b2-b32b-80cb0092c430", - "metadata": {}, - "outputs": [], - "source": [ - "train_ds = raw_train_ds.map(vectorize_text)\n", - "val_ds = raw_val_ds.map(vectorize_text)\n", - "test_ds = raw_test_ds.map(vectorize_text)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "115a5aba-8a00-458f-be25-0aae9f55de22", - "metadata": {}, - "outputs": [], - "source": [ - "AUTOTUNE = tf.data.AUTOTUNE\n", - "\n", - "train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)\n", - "val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)\n", - "test_ds = test_ds.cache().prefetch(buffer_size=AUTOTUNE)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "d64f4495-102d-4244-9b42-1ba9976a366e", - "metadata": {}, - "outputs": [], - "source": [ - "embedding_dim = 16" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "3dc95d22-935f-4091-b0ee-da95174eb9a0", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model: \"sequential\"\n", - "_________________________________________________________________\n", - " Layer (type) Output Shape Param # \n", - "=================================================================\n", - " embedding (Embedding) (None, None, 16) 160016 \n", - " \n", - " dropout (Dropout) (None, None, 16) 0 \n", - " \n", - " global_average_pooling1d (G (None, 16) 0 \n", - " lobalAveragePooling1D) \n", - " \n", - " dropout_1 (Dropout) (None, 16) 0 \n", - " \n", - " dense (Dense) (None, 1) 17 \n", - " \n", - "=================================================================\n", - "Total params: 160,033\n", - "Trainable params: 160,033\n", - "Non-trainable params: 0\n", - "_________________________________________________________________\n" - ] - } - ], - "source": [ - "model = tf.keras.Sequential([\n", - " layers.Embedding(max_features + 1, embedding_dim),\n", - " layers.Dropout(0.2),\n", - " layers.GlobalAveragePooling1D(),\n", - " layers.Dropout(0.2),\n", - " layers.Dense(1)])\n", - "\n", - "model.summary()" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "d9059b93-7666-46db-bf15-517c4c205df9", - "metadata": {}, - "outputs": [], - "source": [ - "model.compile(loss=losses.BinaryCrossentropy(from_logits=True),\n", - " optimizer='adam',\n", - " metrics=tf.metrics.BinaryAccuracy(threshold=0.0))" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "b1d5959f-1bd8-48da-9815-8239599519b2", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 1/10\n", - "625/625 [==============================] - 5s 7ms/step - loss: 0.6647 - binary_accuracy: 0.6946 - val_loss: 0.6154 - val_binary_accuracy: 0.7736\n", - "Epoch 2/10\n", - "625/625 [==============================] - 4s 7ms/step - loss: 0.5483 - binary_accuracy: 0.8021 - val_loss: 0.4979 - val_binary_accuracy: 0.8232\n", - "Epoch 3/10\n", - "625/625 [==============================] - 4s 7ms/step - loss: 0.4444 - binary_accuracy: 0.8442 - val_loss: 0.4200 - val_binary_accuracy: 0.8468\n", - "Epoch 4/10\n", - "625/625 [==============================] - 4s 7ms/step - loss: 0.3781 - binary_accuracy: 0.8654 - val_loss: 0.3738 - val_binary_accuracy: 0.8598\n", - "Epoch 5/10\n", - "625/625 [==============================] - 4s 7ms/step - loss: 0.3351 - binary_accuracy: 0.8786 - val_loss: 0.3447 - val_binary_accuracy: 0.8674\n", - "Epoch 6/10\n", - "625/625 [==============================] - 4s 7ms/step - loss: 0.3054 - binary_accuracy: 0.8877 - val_loss: 0.3261 - val_binary_accuracy: 0.8704\n", - "Epoch 7/10\n", - "625/625 [==============================] - 4s 7ms/step - loss: 0.2802 - binary_accuracy: 0.8977 - val_loss: 0.3128 - val_binary_accuracy: 0.8734\n", - "Epoch 8/10\n", - "625/625 [==============================] - 4s 7ms/step - loss: 0.2616 - binary_accuracy: 0.9056 - val_loss: 0.3031 - val_binary_accuracy: 0.8756\n", - "Epoch 9/10\n", - "625/625 [==============================] - 4s 7ms/step - loss: 0.2461 - binary_accuracy: 0.9111 - val_loss: 0.2965 - val_binary_accuracy: 0.8778\n", - "Epoch 10/10\n", - "625/625 [==============================] - 4s 7ms/step - loss: 0.2309 - binary_accuracy: 0.9170 - val_loss: 0.2918 - val_binary_accuracy: 0.8794\n" - ] - } - ], - "source": [ - "epochs = 10\n", - "history = model.fit(\n", - " train_ds,\n", - " validation_data=val_ds,\n", - " epochs=epochs)" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "656afe07-354f-4ff2-8e3e-d02bad6c5958", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "782/782 [==============================] - 3s 3ms/step - loss: 0.3103 - binary_accuracy: 0.8737\n", - "Loss: 0.3103351294994354\n", - "Accuracy: 0.8736799955368042\n" - ] - } - ], - "source": [ - "loss, accuracy = model.evaluate(test_ds)\n", - "\n", - "print(\"Loss: \", loss)\n", - "print(\"Accuracy: \", accuracy)" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "a01d0f13-d0b8-4d78-9ddc-ede5ed402446", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "dict_keys(['loss', 'binary_accuracy', 'val_loss', 'val_binary_accuracy'])" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "history_dict = history.history\n", - "history_dict.keys()" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "1f7484c3-3cdf-46d5-b95d-80316f0e6240", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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uHAhdevWpUaNGuk+b7FixfD398+KEu8qJCQEHx+fHLlWXqVwIyIibuPRRx+lWLFiLFq0yGl/XFwcy5Yt45lnnuGvv/7iiSeeoESJEvj7+1O9enWWLFmS6nn/3i116NAhmjZtiq+vL1WrVmXDhg1J3jN06FAqVqyIv78/ZcuWZdSoUdy6dQuARYsWMW7cOH766SdsNhs2m81R89+7pfbt28f999+Pn58fRYoU4bnnniMuLs7xes+ePWnfvj1vvvkmoaGhFClShL59+zqulRbx8fGMHz+ekiVL4uPjQ61atVi7dq3j9Zs3b9KvXz9CQ0Px9fUlIiKCSZMmAWAYBmPHjqVUqVL4+PgQFhbGgAED0nztjNDyCyIikiUMA65eteba/v5gs939OC8vL7p3786iRYsYMWIEtv9/07Jly7Db7TzxxBPExcVRp04dhg4dSmBgIF999RVPPfUU5cqVo379+ne9Rnx8PB07diQ4OJj//ve/xMTEOI3PSVCgQAEWLVpEWFgY+/bto3fv3hQoUIB//etfREZG8ssvv7B27Vo2btwIQFBQUJJzXLlyhZYtW9KwYUN27drF2bNnefbZZ+nXr59TgNu8eTOhoaFs3ryZw4cPExkZSa1atejdu/fd/9KA6dOnM3XqVN59911q167NggULaNu2Lfv376dChQrMmDGDVatW8emnn1KqVClOnDjBiRMnAPjss894++23+eSTT6hWrRrR0dH89NNPabpuhhluJiYmxgCMmJgYq0sREcmzrl27Zvz666/GtWvXHPvi4gzDjDg5/4iLS3vtBw4cMABj8+bNjn1NmjQxunXrluJ7HnnkEePll192PG/WrJkxcOBAx/OIiAjj7bffNgzDMNatW2d4eXkZJ0+edLy+Zs0aAzBWrFiR4jWmTJli1KlTx/F8zJgxRs2aNZMcl/g88+bNMwoVKmTEJfoL+OqrrwwPDw8jOjraMAzD6NGjhxEREWHcvn3bcczjjz9uREZGpljL368dFhZmvPbaa07H1KtXz3jxxRcNwzCM/v37G/fff78RHx+f5FxTp041KlasaNy8eTPF6yVI7vcqQXq+v9UtJSIibqVy5co0atSIBQsWAHD48GG2bt3KM888A4DdbmfChAlUr16dwoULExAQwLp16zh+/Hiazn/gwAHCw8MJCwtz7GvYsGGS45YuXUrjxo0JCQkhICCAkSNHpvkaia9Vs2ZN8ufP79jXuHFj4uPjOXjwoGNftWrV8PT0dDwPDQ3l7NmzabpGbGwsp06donHjxk77GzduzIEDBwCz62vv3r1UqlSJAQMGsH79esdxjz/+ONeuXaNs2bL07t2bFStWcPv27XR9zvRSuBERkSzh7w9xcdY80juW95lnnuGzzz7j8uXLLFy4kHLlytGsWTMApkyZwvTp0xk6dCibN29m7969tGzZkps3b2bZ39WOHTvo2rUrDz/8MF9++SV79uxhxIgRWXqNxPLly+f03GazER8fn2Xnv/feezly5AgTJkzg2rVrdO7cmU6dOgHmauYHDx5k9uzZ+Pn58eKLL9K0adN0jflJL425ERGRLGGzQaIGhFytc+fODBw4kI8//pgPPviAPn36OMbfbNu2jXbt2tGtWzfAHEPz+++/U7Vq1TSdu0qVKpw4cYLTp08TGhoKwPfff+90zPbt24mIiGDEiBGOfceOHXM6xtvbG7vdftdrLVq0iCtXrjhab7Zt24aHhweVKlVKU713ExgYSFhYGNu2bXMEwITrJB6DFBgYSGRkJJGRkXTq1IlWrVpx4cIFChcujJ+fH23atKFNmzb07duXypUrs2/fPu69994sqfHvFG5ERMTtBAQEEBkZyfDhw4mNjaVnz56O1ypUqMDy5cvZvn07hQoV4q233uLMmTNpDjctWrSgYsWK9OjRgylTphAbG+sUYhKucfz4cT755BPq1avHV199xYoVK5yOKV26NEeOHGHv3r2ULFmSAgUKJLkFvGvXrowZM4YePXowduxYzp07R//+/XnqqacIDg7O2F9OMl555RXGjBlDuXLlqFWrFgsXLmTv3r189NFHALz11luEhoZSu3ZtPDw8WLZsGSEhIRQsWJBFixZht9tp0KAB/v7+fPjhh/j5+REREZFl9f2duqVERMQtPfPMM1y8eJGWLVs6jY8ZOXIk9957Ly1btqR58+aEhITQvn37NJ/Xw8ODFStWcO3aNerXr8+zzz7La6+95nRM27Zteemll+jXrx+1atVi+/btjBo1yumYxx57jFatWnHfffdRrFixZG9H9/f3Z926dVy4cIF69erRqVMnHnjgAWbNmpW+v4y7GDBgAIMHD+bll1+mevXqrF27llWrVlGhQgXAvPNr8uTJ1K1bl3r16nH06FFWr16Nh4cHBQsW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uWJ1aW5t165dvPvuu9SoUcPqUtzaxYsXady4Mfny5WPNmjX8+uuvTJ06lUKFClldmlt64403mDNnDrNmzeLAgQO88cYbTJ48mZkzZ1pdmlu4cuUKNWvW5J133kn29cmTJzNjxgzmzp3Lf//7X/Lnz0/Lli25fv16jtSnW8ElRefOnaN48eJ88803NG3a1Opy3FJcXBz33nsvs2fP5tVXX6VWrVpMmzbN6rLc0rBhw9i2bRtbt261uhQBHn30UYKDg3nvvfcc+x577DH8/Pz48MMPLazM/dhsNlasWEH79u0Bs9UmLCyMl19+mSFDhgAQExNDcHAwixYtokuXLtlek1puJEUxMTEAFC5c2OJK3Fffvn155JFHaNGihdWluL1Vq1ZRt25dHn/8cYoXL07t2rWZP3++1WW5rUaNGrFp0yZ+//13AH766Se+++47WrdubXFlcuTIEaKjo53+vxUUFESDBg3YsWNHjtTgdgtnStrEx8czaNAgGjduzD333GN1OW7pk08+Yffu3ezatcvqUgT4448/mDNnDoMHD+bf//43u3btYsCAAXh7e9OjRw+ry3M7w4YNIzY2lsqVK+Pp6Yndbue1116ja9euVpfm9qKjowEIDg522h8cHOx4Lbsp3Eiy+vbtyy+//MJ3331ndSlu6cSJEwwcOJANGzbg6+trdTmCGfjr1q3LxIkTAahduza//PILc+fOVbixwKeffspHH33Exx9/TLVq1di7dy+DBg0iLCxMPw9Rt5Qk1a9fP7788ks2b95MyZIlrS7HLf3444+cPXuWe++9Fy8vL7y8vPjmm2+YMWMGXl5e2O12q0t0O6GhoVStWtVpX5UqVTh+/LhFFbm3V155hWHDhtGlSxeqV6/OU089xUsvvcSkSZOsLs3thYSEAHDmzBmn/WfOnHG8lt0UbsTBMAz69evHihUr+PrrrylTpozVJbmtBx54gH379rF3717Ho27dunTt2pW9e/fi6elpdYlup3HjxkmmRvj999+JiIiwqCL3dvXqVTw8nL/CPD09iY+Pt6giSVCmTBlCQkLYtGmTY19sbCz//e9/adiwYY7UoG4pcejbty8ff/wxn3/+OQUKFHD0jQYFBeHn52dxde6lQIECScY65c+fnyJFimgMlEVeeuklGjVqxMSJE+ncuTM7d+5k3rx5zJs3z+rS3FKbNm147bXXKFWqFNWqVWPPnj289dZbPP3001aX5hbi4uI4fPiw4/mRI0fYu3cvhQsXplSpUgwaNIhXX32VChUqUKZMGUaNGkVYWJjjjqpsZ4j8PyDZx8KFC60uTQzDaNasmTFw4ECry3BrX3zxhXHPPfcYPj4+RuXKlY158+ZZXZLbio2NNQYOHGiUKlXK8PX1NcqWLWuMGDHCuHHjhtWluYXNmzcn+33Ro0cPwzAMIz4+3hg1apQRHBxs+Pj4GA888IBx8ODBHKtP89yIiIiIS9GYGxEREXEpCjciIiLiUhRuRERExKUo3IiIiIhLUbgRERERl6JwIyIiIi5F4UZERERcisKNiLglm83GypUrrS5DRLKBwo2I5LiePXtis9mSPFq1amV1aSLiArS2lIhYolWrVixcuNBpn4+Pj0XViIgrUcuNiFjCx8eHkJAQp0ehQoUAs8tozpw5tG7dGj8/P8qWLcvy5cud3r9v3z7uv/9+/Pz8KFKkCM899xxxcXFOxyxYsIBq1arh4+NDaGgo/fr1c3r9/PnzdOjQAX9/fypUqMCqVascr128eJGuXbtSrFgx/Pz8qFChQpIwJiK5k8KNiORKo0aN4rHHHuOnn36ia9eudOnShQMHDgBw5coVWrZsSaFChdi1axfLli1j48aNTuFlzpw59O3bl+eee459+/axatUqypcv73SNcePG0blzZ37++WcefvhhunbtyoULFxzX//XXX1mzZg0HDhxgzpw5FC1aNOf+AkQk43JsiU4Rkf/Xo0cPw9PT08ifP7/T47XXXjMMw1yh/oUXXnB6T4MGDYw+ffoYhmEY8+bNMwoVKmTExcU5Xv/qq68MDw8PIzo62jAMwwgLCzNGjBiRYg2AMXLkSMfzuLg4AzDWrFljGIZhtGnTxujVq1fWfGARyVEacyMilrjvvvuYM2eO077ChQs7ths2bOj0WsOGDdm7dy8ABw4coGbNmuTPn9/xeuPGjYmPj+fgwYPYbDZOnTrFAw88kGoNNWrUcGznz5+fwMBAzp49C0CfPn147LHH2L17Nw899BDt27enUaNGGfqsIpKzFG5ExBL58+dP0k2UVfz8/NJ0XL58+Zye22w24uPjAWjdujXHjh1j9erVbNiwgQceeIC+ffvy5ptvZnm9IpK1NOZGRHKl77//PsnzKlWqAFClShV++uknrly54nh927ZteHh4UKlSJQoUKEDp0qXZtGlTpmooVqwYPXr04MMPP2TatGnMmzcvU+cTkZyhlhsRscSNGzeIjo522ufl5eUYtLts2TLq1q3LP//5Tz766CN27tzJe++9B0DXrl0ZM2YMPXr0YOzYsZw7d47+/fvz1FNPERwcDMDYsWN54YUXKF68OK1bt+by5cts27aN/v37p6m+0aNHU6dOHapVq8aNGzf48ssvHeFKRHI3hRsRscTatWsJDQ112lepUiV+++03wLyT6ZNPPuHFF18kNDSUJUuWULVqVQD8/f1Zt24dAwcOpF69evj7+/PYY4/x1ltvOc7Vo0cPrl+/zttvv82QIUMoWrQonTp1SnN93t7eDB8+nKNHj+Ln50eTJk345JNPsuCTi0h2sxmGYVhdhIhIYjabjRUrVtC+fXurSxGRPEhjbkRERMSlKNyIiIiIS9GYGxHJddRbLiKZoZYbERERcSkKNyIiIuJSFG5ERETEpSjciIiIiEtRuBERERGXonAjIiIiLkXhRkRERFyKwo2IiIi4FIUbERERcSn/ByuJn8U9bHqcAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "acc = history_dict['binary_accuracy']\n", - "val_acc = history_dict['val_binary_accuracy']\n", - "loss = history_dict['loss']\n", - "val_loss = history_dict['val_loss']\n", - "\n", - "epochs = range(1, len(acc) + 1)\n", - "\n", - "# \"bo\" is for \"blue dot\"\n", - "plt.plot(epochs, loss, 'bo', label='Training loss')\n", - "# b is for \"solid blue line\"\n", - "plt.plot(epochs, val_loss, 'b', label='Validation loss')\n", - "plt.title('Training and validation loss')\n", - "plt.xlabel('Epochs')\n", - "plt.ylabel('Loss')\n", - "plt.legend()\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "af51178e-fe0b-40ca-9260-2190fb52d960", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkAAAAHHCAYAAABXx+fLAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABXZUlEQVR4nO3deXhMZ/8G8HsySSb7IoksEgmhtsZObEErbdCmiCWWElu1ilLVonZetKjGVsobay0pQr1VKlJqX4pYaqm1ISTEkkgQyeT8/ji/TDIyiZlsZ5Jzf65rLplnzjnznckwt+d5znMUgiAIICIiIpIRE6kLICIiIiptDEBEREQkOwxAREREJDsMQERERCQ7DEBEREQkOwxAREREJDsMQERERCQ7DEBEREQkOwxAREREJDsMQETFoH///vDx8SnUvlOnToVCoSjegozMrVu3oFAosHr16lJ93v3790OhUGD//v2aNn1/VyVVs4+PD/r371+sxyQiwzEAUbmmUCj0uuX+giQqqiNHjmDq1Kl48uSJ1KUQUT5MpS6AqCStW7dO6/7atWsRHR2dp71WrVpFep4VK1YgKyurUPtOnDgR48aNK9Lzk/6K8rvS15EjRzBt2jT0798fDg4OWo9duXIFJib8vyeR1BiAqFz78MMPte4fO3YM0dHRedpf9ezZM1hZWen9PGZmZoWqDwBMTU1hasq/iqWlKL+r4qBSqSR9/rIiLS0N1tbWUpdB5Rj/G0Ky17ZtW7z55ps4deoUWrduDSsrK3z99dcAgF9++QXvvfcePDw8oFKp4OvrixkzZkCtVmsd49V5JdnzR+bNm4fly5fD19cXKpUKTZo0wcmTJ7X21TUHSKFQYPjw4di+fTvefPNNqFQq1KlTB7t3785T//79+9G4cWNYWFjA19cXP/74o97zig4ePIju3bujcuXKUKlU8PLywueff47nz5/neX02NjaIj49H586dYWNjAxcXF4wZMybPe/HkyRP0798f9vb2cHBwQFhYmF5DQX/99RcUCgXWrFmT57Hff/8dCoUCv/76KwDg33//xaeffooaNWrA0tISTk5O6N69O27duvXa59E1B0jfms+dO4f+/fujatWqsLCwgJubGwYOHIiHDx9qtpk6dSq+/PJLAECVKlU0w6zZtemaA3Tjxg10794dFSpUgJWVFZo1a4adO3dqbZM9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8vIq/IsiIiIioyf5HKCiiIiIgJ+fH5o2barV3rNnT83Pfn5+qFu3Lnx9fbF//360a9cuz3HGjx+P0aNHa+6npKQwBBEREZVjkvYAOTs7Q6lUIjExUas9MTERbm5uBe6blpaGTZs2YdCgQa99nqpVq8LZ2RnXrl3T+bhKpYKdnZ3WjYiIiMovSQOQubk5GjVqhJiYGE1bVlYWYmJi0Lx58wL33bx5M9LT0/Hhhx++9nnu3LmDhw8fwt3dvcg1ExERUdkn+Vlgo0ePxooVK7BmzRpcunQJQ4cORVpaGgYMGAAA6NevH8aPH59nv4iICHTu3BlOTk5a7ampqfjyyy9x7Ngx3Lp1CzExMejUqROqVauGoKCgUnlNREREZNwknwMUGhqKBw8eYPLkyUhISED9+vWxe/duzcTouLg4mJho57QrV67g0KFD2LNnT57jKZVKnDt3DmvWrMGTJ0/g4eGBd999FzNmzOBaQERERAQAUAiCIEhdhLFJSUmBvb09kpOTOR+IiIiojDDk+1vyITAiIiKi0sYARERERLLDAERERESywwBEREREssMARERERLLDAERERESywwBEREREssMARERERLLDAERERESywwBEREREssMARERERLLDAERERESywwBEREREssMARERERLLDAERERESywwBEREREssMARERERLLDAERERESywwBEREREssMARERERLLDAERERESywwBEREREssMARERERLLDAERERESywwBEREREssMARERERLLDAERERESywwBEREREssMARERERLLDAERERESywwBEREREssMARERERLLDAERERESywwBEREREssMARERERLLDAERERESywwBEREREssMARERERLLDAERERESywwBEREREsmMqdQFERCQvarUaGRkZUpdBZZCZmRmUSmWxHIsBiIiISoUgCEhISMCTJ0+kLoXKMAcHB7i5uUGhUBTpOAxARERUKrLDT8WKFWFlZVXkLzCSF0EQ8OzZM9y/fx8A4O7uXqTjMQAREVGJU6vVmvDj5OQkdTlURllaWgIA7t+/j4oVKxZpOIyToImIqMRlz/mxsrKSuBIq67I/Q0WdR8YAREREpYbDXlRUxfUZYgAiIiIqRT4+PggPD9d7+/3790OhUHDyeDHjHCAiIioz1Grg4EHg3j3A3R0ICACK6azoPF7X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oXr16tixY4fmscePH6NPnz5wcXGBpaUlqlevniewEZFxYgAiojJr0qRJ6Nq1K86ePYs+ffqgZ8+euHTpEgAgLS0NQUFBcHR0xMmTJ7F582bs3btXK+AsXboUw4YNw5AhQ3D+/Hns2LED1apV03qOadOmoUePHjh37hw6duyIPn364NGjR5rnv3jxInbt2oVLly5h6dKlcHZ2Lr03gIgKr9Quu0pEZICwsDBBqVQK1tbWWreZM2cKgiAIAIRPPvlEax9/f39h6NChgiAIwvLlywVHR0chNTVV8/jOnTsFExMTISEhQRAEQfDw8BAmTJiQbw0AhIkTJ2rup6amCgCEXbt2CYIgCMHBwcKAAQOK5wUTUaniHCAiMlpvvfUWli5dqtVWoUIFzc/NmzfXeqx58+aIjY0FAFy6dAn16tWDtbW15vGWLVsiKysLV65cgUKhwN27d9GuXbsCa6hbt67mZ2tra9jZ2eH+/fsAgKFDh6Jr1644ffo03n33XXTu3BktWrQo1GslotLFAERERsva2jrPkFRxsbS01Gs7MzMzrfsKhQJZWVkAgA4dOuDff//Fb7/9hujoaLRr1w7Dhg3DvHnzir1eIipenANERGXWsWPH8tyvVasWAKBWrVo4e/Ys0tLSNI8fPnwYJiYmqFGjBmxtbeHj44OYmJgi1eDi4oKwsDD89NNPCA8Px/Lly4t0PCIqHewBIiKjlZ6ejoSEBK02U1NTzUTjzZs3o3HjxmjVqhXWr1+PEydOICIiAgDQp08fTJkyBWFhYZg6dSoePHiAESNGoG/fvnB1dQUATJ06FZ988gkqVqyIDh064OnTpzh8+DBGjBihV32TJ09Go0aNUKdOHaSnp+PXX3/VBDAiMm4MQERktHbv3g13d3ettho1auDy5csAxDO0Nm3ahE8//RTu7u7YuHEjateuDQCwsrLC77//jpEjR6JJkyawsrJC165dMX/+fM2xwsLC8OLFC3z//fcYM2YMnJ2d0a1bN73rMzc3x/jx43Hr1i1YWloiICAAmzZtKoZXTkQlTSEIgiB1EUREhlIoFNi2bRs6d+4sdSlEVAZxDhARERHJDgMQERERyQ7nABFRmcTReyIqCvYAERERkewwABEREZHsMAARERGR7DAAERERkewwABEREZHsMAARERGR7DAAERERkewwABEREZHsMAARERGR7Pwfdn0MxQovG2kAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(epochs, acc, 'bo', label='Training acc')\n", - "plt.plot(epochs, val_acc, 'b', label='Validation acc')\n", - "plt.title('Training and validation accuracy')\n", - "plt.xlabel('Epochs')\n", - "plt.ylabel('Accuracy')\n", - "plt.legend(loc='lower right')\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "93b0a42c-437e-41bb-99e7-d58cb8036a3a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "782/782 [==============================] - 5s 6ms/step - loss: 0.3103 - accuracy: 0.8737\n", - "0.8736799955368042\n" - ] - } - ], - "source": [ - "export_model = tf.keras.Sequential([\n", - " vectorize_layer,\n", - " model,\n", - " layers.Activation('sigmoid')\n", - "])\n", - "\n", - "export_model.compile(\n", - " loss=losses.BinaryCrossentropy(from_logits=False), optimizer=\"adam\", metrics=['accuracy']\n", - ")\n", - "\n", - "# Test it with `raw_test_ds`, which yields raw strings\n", - "loss, accuracy = export_model.evaluate(raw_test_ds)\n", - "print(accuracy)" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "8939539b-a600-48b1-a55e-3f1087f4a855", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1/1 [==============================] - 0s 99ms/step\n" - ] - }, - { - "data": { - "text/plain": [ - "array([[0.6167954],\n", - " [0.4397881],\n", - " [0.3572815]], dtype=float32)" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "examples = [\n", - " \"The movie was great!\",\n", - " \"The movie was okay.\",\n", - " \"The movie was terrible...\"\n", - "]\n", - "\n", - "export_model.predict(examples)" - ] - }, - { - "cell_type": "markdown", - "id": "f6b40a59-8d3b-44ec-a4f7-92c5742a0c1c", - "metadata": {}, - "source": [ - "### Save Model" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "e2aa1770-2bf9-436b-af32-16b64fc97490", - "metadata": {}, - "outputs": [], - "source": [ - "!rm -rf text_model" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "7f22cc32-2708-4808-8e76-99024da87a21", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING:absl:Found untraced functions such as _update_step_xla, _update_step_xla while saving (showing 2 of 2). These functions will not be directly callable after loading.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "INFO:tensorflow:Assets written to: text_model/assets\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:tensorflow:Assets written to: text_model/assets\n" - ] - } - ], - "source": [ - "export_model.save('text_model')" - ] - }, - { - "cell_type": "markdown", - "id": "3add8a92-bb90-415b-ae21-417a6b722a8b", - "metadata": {}, - "source": [ - "### Inspect saved model" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "d5dda184-8288-4de2-95a9-41d0a9744b2c", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[01;34mtext_model\u001b[00m\n", - "├── \u001b[01;34massets\u001b[00m\n", - "├── fingerprint.pb\n", - "├── keras_metadata.pb\n", - "├── saved_model.pb\n", - "└── \u001b[01;34mvariables\u001b[00m\n", - " ├── variables.data-00000-of-00001\n", - " └── variables.index\n", - "\n", - "2 directories, 5 files\n" - ] - } - ], - "source": [ - "!tree text_model" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "e756f01d-dcef-4132-a0e6-4231792356de", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The given SavedModel SignatureDef contains the following input(s):\n", - " inputs['text_vectorization_input'] tensor_info:\n", - " dtype: DT_STRING\n", - " shape: (-1)\n", - " name: serving_default_text_vectorization_input:0\n", - "The given SavedModel SignatureDef contains the following output(s):\n", - " outputs['activation'] tensor_info:\n", - " dtype: DT_FLOAT\n", - " shape: (-1, 1)\n", - " name: StatefulPartitionedCall:0\n", - "Method name is: tensorflow/serving/predict\n" - ] - } - ], - "source": [ - "!saved_model_cli show --dir text_model --tag_set serve --signature_def serving_default" - ] - }, - { - "cell_type": "markdown", - "id": "e0461f74-fdd0-4f30-9f44-0be7ad00d9b0", - "metadata": {}, - "source": [ - "### Load model" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "c9cf2c7f-5e86-4ff8-984e-dd0ed7a3ece9", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model: \"sequential_1\"\n", - "_________________________________________________________________\n", - " Layer (type) Output Shape Param # \n", - "=================================================================\n", - " text_vectorization (TextVec (None, 250) 0 \n", - " torization) \n", - " \n", - " sequential (Sequential) (None, 1) 160033 \n", - " \n", - " activation (Activation) (None, 1) 0 \n", - " \n", - "=================================================================\n", - "Total params: 160,033\n", - "Trainable params: 160,033\n", - "Non-trainable params: 0\n", - "_________________________________________________________________\n" - ] - } - ], - "source": [ - "# register callables as custom objects before loading\n", - "custom_objects = {\"vectorize_layer\": vectorize_layer, \"custom_standardization\": custom_standardization}\n", - "with tf.keras.utils.custom_object_scope(custom_objects):\n", - " new_model = tf.keras.models.load_model('text_model')\n", - "\n", - "new_model.summary()" - ] - }, - { - "cell_type": "markdown", - "id": "242a4f7e-fa45-4d21-b103-fe3718bc0f10", - "metadata": {}, - "source": [ - "### Predict" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "531680b2-42ef-4205-9a38-6995aee9f340", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1/1 [==============================] - 0s 69ms/step\n" - ] - }, - { - "data": { - "text/plain": [ - "array([[0.6167954],\n", - " [0.4397881],\n", - " [0.3572815]], dtype=float32)" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "new_model.predict(examples)" - ] - }, - { - "cell_type": "markdown", - "id": "a82ae387-1587-4175-b4b2-66586e4668f7", - "metadata": {}, - "source": [ - "## PySpark" - ] - }, - { - "cell_type": "markdown", - "id": "0b5ac416-a37f-4f0b-8c77-628f0fcede69", - "metadata": {}, - "source": [ - "## Inference using Spark DL API\n", - "Note: you can restart the kernel and run from this point to simulate running in a different node or environment." - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "d6d515c2-ce53-4af5-a936-ae91fdecea99", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "from pyspark.ml.functions import predict_batch_udf\n", - "from pyspark.sql.functions import struct, col\n", - "from pyspark.sql.types import ArrayType, FloatType, DoubleType" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "6d0d567a-0ef8-4a93-8235-e89ace2c82ad", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 1:> (0 + 1) / 1]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------------------------------------------------------------------------------------------------+\n", - "| lines|\n", - "+----------------------------------------------------------------------------------------------------+\n", - "|...But not this one! I always wanted to know \"what happened\" next. We will never know for sure wh...|\n", - "|Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pimp story without the...|\n", - "|I watched this movie to see the direction one of the most promising young talents in movies was g...|\n", - "|This movie makes you wish imdb would let you vote a zero. One of the two movies I've ever walked ...|\n", - "|I never want to see this movie again!

Not only is it dreadfully bad, but I can't stand...|\n", - "|(As a note, I'd like to say that I saw this movie at my annual church camp, where the entire yout...|\n", - "|Don't get me wrong, I love the TV series of League Of Gentlemen. It was funny, twisted and comple...|\n", - "|Did you ever think, like after watching a horror movie with a group of friends: \"Wow, this is so ...|\n", - "|Awful, awful, awful...

I loved the original film. It was funny, charming, and had hear...|\n", - "|This movie seems a little clunky around the edges, like not quite enough zaniness was thrown it w...|\n", - "|I rented this movie hoping that it would provide some good entertainment and some cool poker know...|\n", - "|Well, where to start describing this celluloid debacle? You already know the big fat NADA passing...|\n", - "|I hoped for this show to be somewhat realistic. It stroke me as just another mainstream show afte...|\n", - "|All I have to say is one word...SUCKS!!!!. The only reason I gave this a 2 is because Josh Hartne...|\n", - "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy screenplay.

...|\n", - "|This critique tells the story of 4 little friends who went to watch Angels and Demons the movie o...|\n", - "|This review contains a partial spoiler.

Shallow from the outset, 'D.O.A.' at least sta...|\n", - "|I'm rather surprised that anybody found this film touching or moving.

The basic premis...|\n", - "|If you like bad movies (and you must to watch this one) here's a good one. Not quite as funny as ...|\n", - "|This is really bad, the characters were bland, the story was boring, and there is no sex scene. F...|\n", - "+----------------------------------------------------------------------------------------------------+\n", - "only showing top 20 rows\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "# note: using IMDB parquet dataset from huggingface/conditional_generation.ipynb\n", - "df = spark.read.parquet(\"../huggingface/imdb_test\")\n", - "df.show(truncate=100)" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "id": "7b7a8395-e2ae-4c3c-bf57-763dfde600ad", - "metadata": {}, - "outputs": [], - "source": [ - "text_model_path = \"{}/text_model\".format(os.getcwd())" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "id": "8c0524cf-3a75-4fb8-8025-f0654acce13e", - "metadata": {}, - "outputs": [], - "source": [ - "def predict_batch_fn():\n", - " # since this function runs on the executor, any required imports should be added inside the function.\n", - " import re\n", - " import string\n", - " import tensorflow as tf\n", - " from tensorflow.keras import layers\n", - "\n", - " def custom_standardization(input_data):\n", - " lowercase = tf.strings.lower(input_data)\n", - " stripped_html = tf.strings.regex_replace(lowercase, \"
\", \" \")\n", - " return tf.strings.regex_replace(\n", - " stripped_html, \"[%s]\" % re.escape(string.punctuation), \"\"\n", - " )\n", - "\n", - " max_features = 10000\n", - " sequence_length = 250\n", - "\n", - " vectorize_layer = layers.TextVectorization(\n", - " standardize=custom_standardization,\n", - " max_tokens=max_features,\n", - " output_mode=\"int\",\n", - " output_sequence_length=sequence_length,\n", - " )\n", - "\n", - " custom_objects = {\"vectorize_layer\": vectorize_layer,\n", - " \"custom_standardization\": custom_standardization}\n", - " with tf.keras.utils.custom_object_scope(custom_objects):\n", - " model = tf.keras.models.load_model(text_model_path)\n", - "\n", - " def predict(inputs):\n", - " return model.predict(inputs)\n", - "\n", - " return predict" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "id": "0d603644-d938-4c87-aa8a-2512251638d5", - "metadata": {}, - "outputs": [], - "source": [ - "classify = predict_batch_udf(predict_batch_fn,\n", - " return_type=FloatType(),\n", - " batch_size=256)" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "id": "0b480622-8dc1-4879-933e-c43112768630", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 269 ms, sys: 76.7 ms, total: 345 ms\n", - "Wall time: 6.81 s\n" - ] - } - ], - "source": [ - "%%time\n", - "predictions = df.withColumn(\"preds\", classify(struct(\"lines\")))\n", - "results = predictions.collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "id": "31b0a262-387e-4a5e-a60e-b9b8ee456199", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 106 ms, sys: 10 ms, total: 116 ms\n", - "Wall time: 2.47 s\n" - ] - } - ], - "source": [ - "%%time\n", - "predictions = df.withColumn(\"preds\", classify(\"lines\"))\n", - "results = predictions.collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "id": "7ef9e431-59f5-4b29-9f79-ae16a9cfb0b9", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 93.7 ms, sys: 21.3 ms, total: 115 ms\n", - "Wall time: 2.51 s\n" - ] - } - ], - "source": [ - "%%time\n", - "predictions = df.withColumn(\"preds\", classify(col(\"lines\")))\n", - "results = predictions.collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "id": "9a325ee2-3268-414a-bb75-a5fcf794f512", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------------------------------------------------------------------+------------+\n", - "| lines| preds|\n", - "+--------------------------------------------------------------------------------+------------+\n", - "|...But not this one! I always wanted to know \"what happened\" next. We will ne...| 0.55854315|\n", - "|Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pi...| 0.20151669|\n", - "|I watched this movie to see the direction one of the most promising young tal...| 0.2886543|\n", - "|This movie makes you wish imdb would let you vote a zero. One of the two movi...| 0.4254548|\n", - "|I never want to see this movie again!

Not only is it dreadfully ba...| 0.007963314|\n", - "|(As a note, I'd like to say that I saw this movie at my annual church camp, w...| 0.52016854|\n", - "|Don't get me wrong, I love the TV series of League Of Gentlemen. It was funny...|3.7298937E-4|\n", - "|Did you ever think, like after watching a horror movie with a group of friend...|0.0073868474|\n", - "|Awful, awful, awful...

I loved the original film. It was funny, ch...|0.0020545013|\n", - "|This movie seems a little clunky around the edges, like not quite enough zani...| 0.19478825|\n", - "|I rented this movie hoping that it would provide some good entertainment and ...| 0.010234797|\n", - "|Well, where to start describing this celluloid debacle? You already know the ...| 0.02019683|\n", - "|I hoped for this show to be somewhat realistic. It stroke me as just another ...| 0.39049864|\n", - "|All I have to say is one word...SUCKS!!!!. The only reason I gave this a 2 is...| 0.19343555|\n", - "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy scr...| 3.712686E-5|\n", - "|This critique tells the story of 4 little friends who went to watch Angels an...| 0.16827627|\n", - "|This review contains a partial spoiler.

Shallow from the outset, '...| 0.043480344|\n", - "|I'm rather surprised that anybody found this film touching or moving.
>>> containers: {}\".format([c.short_id for c in containers]))\n", - " else:\n", - " container=client.containers.run(\n", - " \"nvcr.io/nvidia/tritonserver:23.04-py3\", \"tritonserver --model-repository=/models\",\n", - " detach=True,\n", - " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", - " name=\"spark-triton\",\n", - " network_mode=\"host\",\n", - " remove=True,\n", - " shm_size=\"128M\",\n", - " volumes={\n", - " triton_models_dir: {\"bind\": \"/models\", \"mode\": \"ro\"},\n", - " text_model_dir: {\"bind\": \"/text_model\", \"mode\": \"ro\"}\n", - " }\n", - " )\n", - " print(\">>>> starting triton: {}\".format(container.short_id))\n", - "\n", - " # wait for triton to be running\n", - " time.sleep(15)\n", - " client = grpcclient.InferenceServerClient(\"localhost:8001\")\n", - " ready = False\n", - " while not ready:\n", - " try:\n", - " ready = client.is_server_ready()\n", - " except Exception as e:\n", - " time.sleep(5)\n", - " \n", - " return [True]\n", - "\n", - "nodeRDD.barrier().mapPartitions(start_triton).collect()" - ] - }, - { - "cell_type": "markdown", - "id": "287873da-6202-4b55-97fb-cda8644b1fee", - "metadata": {}, - "source": [ - "#### Run inference" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "id": "41106a02-236e-4cb3-ac51-76aa64b663c2", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+----------------------------------------------------------------------------------------------------+\n", - "| lines|\n", - "+----------------------------------------------------------------------------------------------------+\n", - "|...But not this one! I always wanted to know \"what happened\" next. We will never know for sure wh...|\n", - "|Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pimp story without the...|\n", - "|I watched this movie to see the direction one of the most promising young talents in movies was g...|\n", - "|This movie makes you wish imdb would let you vote a zero. One of the two movies I've ever walked ...|\n", - "|I never want to see this movie again!

Not only is it dreadfully bad, but I can't stand...|\n", - "|(As a note, I'd like to say that I saw this movie at my annual church camp, where the entire yout...|\n", - "|Don't get me wrong, I love the TV series of League Of Gentlemen. It was funny, twisted and comple...|\n", - "|Did you ever think, like after watching a horror movie with a group of friends: \"Wow, this is so ...|\n", - "|Awful, awful, awful...

I loved the original film. It was funny, charming, and had hear...|\n", - "|This movie seems a little clunky around the edges, like not quite enough zaniness was thrown it w...|\n", - "|I rented this movie hoping that it would provide some good entertainment and some cool poker know...|\n", - "|Well, where to start describing this celluloid debacle? You already know the big fat NADA passing...|\n", - "|I hoped for this show to be somewhat realistic. It stroke me as just another mainstream show afte...|\n", - "|All I have to say is one word...SUCKS!!!!. The only reason I gave this a 2 is because Josh Hartne...|\n", - "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy screenplay.

...|\n", - "|This critique tells the story of 4 little friends who went to watch Angels and Demons the movie o...|\n", - "|This review contains a partial spoiler.

Shallow from the outset, 'D.O.A.' at least sta...|\n", - "|I'm rather surprised that anybody found this film touching or moving.

The basic premis...|\n", - "|If you like bad movies (and you must to watch this one) here's a good one. Not quite as funny as ...|\n", - "|This is really bad, the characters were bland, the story was boring, and there is no sex scene. F...|\n", - "+----------------------------------------------------------------------------------------------------+\n", - "only showing top 20 rows\n", - "\n" - ] - } - ], - "source": [ - "# note: using IMDB parquet dataset from huggingface/conditional_generation.ipynb\n", - "df = spark.read.parquet(\"../huggingface/imdb_test\").repartition(1)\n", - "df.show(truncate=100)" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "id": "8b763167-7f50-4278-9bc9-6c3433b62294", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['lines']" - ] - }, - "execution_count": 50, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "columns = df.columns\n", - "columns" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "id": "29b0cc0d-c480-4e4a-bd41-207dc314cba5", - "metadata": {}, - "outputs": [], - "source": [ - "def triton_fn(triton_uri, model_name):\n", - " import numpy as np\n", - " import tritonclient.grpc as grpcclient\n", - " \n", - " np_types = {\n", - " \"BOOL\": np.dtype(np.bool8),\n", - " \"INT8\": np.dtype(np.int8),\n", - " \"INT16\": np.dtype(np.int16),\n", - " \"INT32\": np.dtype(np.int32),\n", - " \"INT64\": np.dtype(np.int64),\n", - " \"FP16\": np.dtype(np.float16),\n", - " \"FP32\": np.dtype(np.float32),\n", - " \"FP64\": np.dtype(np.float64),\n", - " \"FP64\": np.dtype(np.double),\n", - " \"BYTES\": np.dtype(object)\n", - " }\n", - "\n", - " client = grpcclient.InferenceServerClient(triton_uri)\n", - " model_meta = client.get_model_metadata(model_name)\n", - " \n", - " def predict(inputs):\n", - " if isinstance(inputs, np.ndarray):\n", - " # single ndarray input\n", - " request = [grpcclient.InferInput(model_meta.inputs[0].name, inputs.shape, model_meta.inputs[0].datatype)]\n", - " request[0].set_data_from_numpy(inputs.astype(np_types[model_meta.inputs[0].datatype]))\n", - " else:\n", - " # dict of multiple ndarray inputs\n", - " request = [grpcclient.InferInput(i.name, inputs[i.name].shape, i.datatype) for i in model_meta.inputs]\n", - " for i in request:\n", - " i.set_data_from_numpy(inputs[i.name()].astype(np_types[i.datatype()]))\n", - " \n", - " response = client.infer(model_name, inputs=request)\n", - " \n", - " if len(model_meta.outputs) > 1:\n", - " # return dictionary of numpy arrays\n", - " return {o.name: response.as_numpy(o.name) for o in model_meta.outputs}\n", - " else:\n", - " # return single numpy array\n", - " return response.as_numpy(model_meta.outputs[0].name)\n", - " \n", - " return predict" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "id": "8e06d33f-5cef-4a48-afc3-5d468f8ec2b4", - "metadata": {}, - "outputs": [], - "source": [ - "from functools import partial\n", - "\n", - "classify = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"text_classification\"),\n", - " input_tensor_shapes=[[1]],\n", - " return_type=FloatType(),\n", - " batch_size=2048)" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "id": "d89e74ad-e551-4bfa-ad08-98725878630a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------------------------------------------------------------------+------------+\n", - "| lines| preds|\n", - "+--------------------------------------------------------------------------------+------------+\n", - "|...But not this one! I always wanted to know \"what happened\" next. We will ne...| 0.55854315|\n", - "|Hard up, No proper jobs going down at the pit, why not rent your kids! DIY pi...| 0.20151669|\n", - "|I watched this movie to see the direction one of the most promising young tal...| 0.2886543|\n", - "|This movie makes you wish imdb would let you vote a zero. One of the two movi...| 0.4254548|\n", - "|I never want to see this movie again!

Not only is it dreadfully ba...| 0.007963314|\n", - "|(As a note, I'd like to say that I saw this movie at my annual church camp, w...| 0.52016854|\n", - "|Don't get me wrong, I love the TV series of League Of Gentlemen. It was funny...|3.7298937E-4|\n", - "|Did you ever think, like after watching a horror movie with a group of friend...|0.0073868474|\n", - "|Awful, awful, awful...

I loved the original film. It was funny, ch...|0.0020545013|\n", - "|This movie seems a little clunky around the edges, like not quite enough zani...| 0.19478825|\n", - "|I rented this movie hoping that it would provide some good entertainment and ...| 0.010234797|\n", - "|Well, where to start describing this celluloid debacle? You already know the ...| 0.02019683|\n", - "|I hoped for this show to be somewhat realistic. It stroke me as just another ...| 0.39049864|\n", - "|All I have to say is one word...SUCKS!!!!. The only reason I gave this a 2 is...| 0.19343555|\n", - "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy scr...| 3.712686E-5|\n", - "|This critique tells the story of 4 little friends who went to watch Angels an...| 0.16827627|\n", - "|This review contains a partial spoiler.

Shallow from the outset, '...| 0.043480344|\n", - "|I'm rather surprised that anybody found this film touching or moving.

Not only is it dreadfully ba...| 0.007963314|\n", - "|(As a note, I'd like to say that I saw this movie at my annual church camp, w...| 0.52016854|\n", - "|Don't get me wrong, I love the TV series of League Of Gentlemen. It was funny...|3.7298937E-4|\n", - "|Did you ever think, like after watching a horror movie with a group of friend...|0.0073868474|\n", - "|Awful, awful, awful...

I loved the original film. It was funny, ch...|0.0020545013|\n", - "|This movie seems a little clunky around the edges, like not quite enough zani...| 0.19478825|\n", - "|I rented this movie hoping that it would provide some good entertainment and ...| 0.010234797|\n", - "|Well, where to start describing this celluloid debacle? You already know the ...| 0.02019683|\n", - "|I hoped for this show to be somewhat realistic. It stroke me as just another ...| 0.39049864|\n", - "|All I have to say is one word...SUCKS!!!!. The only reason I gave this a 2 is...| 0.19343555|\n", - "|Honestly awful film, bad editing, awful lighting, dire dialog and scrappy scr...| 3.712686E-5|\n", - "|This critique tells the story of 4 little friends who went to watch Angels an...| 0.16827627|\n", - "|This review contains a partial spoiler.

Shallow from the outset, '...| 0.043480344|\n", - "|I'm rather surprised that anybody found this film touching or moving.
>>> stopping containers: {}\".format([c.short_id for c in containers]))\n", - " if containers:\n", - " container=containers[0]\n", - " container.stop(timeout=120)\n", - "\n", - " return [True]\n", - "\n", - "nodeRDD.barrier().mapPartitions(stop_triton).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "id": "54a90574-7cbb-487b-b7a8-dcda0e6e301f", - "metadata": {}, - "outputs": [], - "source": [ - "spark.stop()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "88e3bfea-a825-46eb-b8c2-921a932c0089", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "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.9.10" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/text_classification_tf.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/text_classification_tf.ipynb new file mode 100644 index 000000000..971bf393d --- /dev/null +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/text_classification_tf.ipynb @@ -0,0 +1,1850 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2cd2accf-5877-4136-a243-7a33a13ce2b4", + "metadata": {}, + "source": [ + "# Pyspark TensorFlow Inference\n", + "\n", + "## Text classification\n", + "Based on: https://www.tensorflow.org/tutorials/keras/text_classification" + ] + }, + { + "cell_type": "markdown", + "id": "bc72d0ed", + "metadata": {}, + "source": [ + "### Using TensorFlow\n", + "Note that cuFFT/cuDNN/cuBLAS registration errors are expected with `tf=2.17.0` and will not affect behavior, as noted in [this issue.](https://github.com/tensorflow/tensorflow/issues/62075) \n", + "This notebook does not demonstrate inference with TensorRT, as [TF-TRT](https://docs.nvidia.com/deeplearning/tensorrt/release-notes/index.html#tensorrt-10) does not yet support `tf=2.17.0`. See the `pytorch` notebooks for TensorRT demos." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "76f0f5df-502f-444e-b2ee-1122e1dea870", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:43:56.140645: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2024-10-03 17:43:56.147227: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", + "2024-10-03 17:43:56.154601: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", + "2024-10-03 17:43:56.156763: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", + "2024-10-03 17:43:56.162424: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2024-10-03 17:43:56.485452: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" + ] + } + ], + "source": [ + "import os\n", + "import re\n", + "import shutil\n", + "import string\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import tensorflow as tf\n", + "from tensorflow.keras import layers, losses" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "a364ad5f-b269-45b5-ab8b-d8f34fb642b7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.17.0\n" + ] + } + ], + "source": [ + "print(tf.__version__)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "57b1d71f", + "metadata": {}, + "outputs": [], + "source": [ + "# Enable GPU memory growth\n", + "gpus = tf.config.experimental.list_physical_devices('GPU')\n", + "if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d229c1b6-3967-46b5-9ea8-68f4b42dd211", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading data from https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz\n", + "\u001b[1m84125825/84125825\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m4s\u001b[0m 0us/step\n" + ] + } + ], + "source": [ + "url = \"https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz\"\n", + "\n", + "dataset = tf.keras.utils.get_file(\n", + " \"aclImdb_v1\", url, untar=True, cache_dir=\".\", cache_subdir=\"\"\n", + ")\n", + "\n", + "dataset_dir = os.path.join(os.path.dirname(dataset), \"aclImdb\")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "1f8038ae-8bc1-46bf-ae4c-6da08886c473", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['README', 'imdb.vocab', 'test', 'train', 'imdbEr.txt']" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "os.listdir(dataset_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "12faaa3f-3441-4361-b9eb-4317e8c2c2f7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['pos',\n", + " 'labeledBow.feat',\n", + " 'urls_pos.txt',\n", + " 'neg',\n", + " 'urls_unsup.txt',\n", + " 'unsupBow.feat',\n", + " 'urls_neg.txt',\n", + " 'unsup']" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "train_dir = os.path.join(dataset_dir, \"train\")\n", + "os.listdir(train_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "152cc0cc-65d0-4e17-9ee8-222390df45b5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Rachel Griffiths writes and directs this award winning short film. A heartwarming story about coping with grief and cherishing the memory of those we've loved and lost. Although, only 15 minutes long, Griffiths manages to capture so much emotion and truth onto film in the short space of time. Bud Tingwell gives a touching performance as Will, a widower struggling to cope with his wife's death. Will is confronted by the harsh reality of loneliness and helplessness as he proceeds to take care of Ruth's pet cow, Tulip. The film displays the grief and responsibility one feels for those they have loved and lost. Good cinematography, great direction, and superbly acted. It will bring tears to all those who have lost a loved one, and survived.\n" + ] + } + ], + "source": [ + "sample_file = os.path.join(train_dir, \"pos/1181_9.txt\")\n", + "with open(sample_file) as f:\n", + " print(f.read())" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "b2277f58-78c8-4a12-bc98-5103e7c81a35", + "metadata": {}, + "outputs": [], + "source": [ + "remove_dir = os.path.join(train_dir, \"unsup\")\n", + "shutil.rmtree(remove_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "ed83de92-ebb3-4170-b2bf-25265c6a6942", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 25000 files belonging to 2 classes.\n", + "Using 20000 files for training.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:44:07.678162: I tensorflow/core/common_runtime/gpu/gpu_device.cc:2021] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 44790 MB memory: -> device: 0, name: NVIDIA RTX A6000, pci bus id: 0000:01:00.0, compute capability: 8.6\n" + ] + } + ], + "source": [ + "batch_size = 32\n", + "seed = 42\n", + "\n", + "raw_train_ds = tf.keras.utils.text_dataset_from_directory(\n", + " \"aclImdb/train\",\n", + " batch_size=batch_size,\n", + " validation_split=0.2,\n", + " subset=\"training\",\n", + " seed=seed,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "57c30568-daa8-4b2b-b30a-577c984a8af5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Review b'\"Pandemonium\" is a horror movie spoof that comes off more stupid than funny. Believe me when I tell you, I love comedies. Especially comedy spoofs. \"Airplane\", \"The Naked Gun\" trilogy, \"Blazing Saddles\", \"High Anxiety\", and \"Spaceballs\" are some of my favorite comedies that spoof a particular genre. \"Pandemonium\" is not up there with those films. Most of the scenes in this movie had me sitting there in stunned silence because the movie wasn\\'t all that funny. There are a few laughs in the film, but when you watch a comedy, you expect to laugh a lot more than a few times and that\\'s all this film has going for it. Geez, \"Scream\" had more laughs than this film and that was more of a horror film. How bizarre is that?

*1/2 (out of four)'\n", + "Label 0\n", + "Review b\"David Mamet is a very interesting and a very un-equal director. His first movie 'House of Games' was the one I liked best, and it set a series of films with characters whose perspective of life changes as they get into complicated situations, and so does the perspective of the viewer.

So is 'Homicide' which from the title tries to set the mind of the viewer to the usual crime drama. The principal characters are two cops, one Jewish and one Irish who deal with a racially charged area. The murder of an old Jewish shop owner who proves to be an ancient veteran of the Israeli Independence war triggers the Jewish identity in the mind and heart of the Jewish detective.

This is were the flaws of the film are the more obvious. The process of awakening is theatrical and hard to believe, the group of Jewish militants is operatic, and the way the detective eventually walks to the final violent confrontation is pathetic. The end of the film itself is Mamet-like smart, but disappoints from a human emotional perspective.

Joe Mantegna and William Macy give strong performances, but the flaws of the story are too evident to be easily compensated.\"\n", + "Label 0\n", + "Review b'Great documentary about the lives of NY firefighters during the worst terrorist attack of all time.. That reason alone is why this should be a must see collectors item.. What shocked me was not only the attacks, but the\"High Fat Diet\" and physical appearance of some of these firefighters. I think a lot of Doctors would agree with me that,in the physical shape they were in, some of these firefighters would NOT of made it to the 79th floor carrying over 60 lbs of gear. Having said that i now have a greater respect for firefighters and i realize becoming a firefighter is a life altering job. The French have a history of making great documentary\\'s and that is what this is, a Great Documentary.....'\n", + "Label 1\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:44:08.132892: I tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence\n" + ] + } + ], + "source": [ + "for text_batch, label_batch in raw_train_ds.take(1):\n", + " for i in range(3):\n", + " print(\"Review\", text_batch.numpy()[i])\n", + " print(\"Label\", label_batch.numpy()[i])" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "1e863eb6-4bd7-4da0-b10d-d951b5ee52bd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Label 0 corresponds to neg\n", + "Label 1 corresponds to pos\n" + ] + } + ], + "source": [ + "print(\"Label 0 corresponds to\", raw_train_ds.class_names[0])\n", + "print(\"Label 1 corresponds to\", raw_train_ds.class_names[1])" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "1593e2e5-df51-4fbf-b4be-c786e740ddab", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 25000 files belonging to 2 classes.\n", + "Using 5000 files for validation.\n" + ] + } + ], + "source": [ + "raw_val_ds = tf.keras.utils.text_dataset_from_directory(\n", + " \"aclImdb/train\",\n", + " batch_size=batch_size,\n", + " validation_split=0.2,\n", + " subset=\"validation\",\n", + " seed=seed,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "944fd61d-3926-4296-889a-b2a375a1b039", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 25000 files belonging to 2 classes.\n" + ] + } + ], + "source": [ + "raw_test_ds = tf.keras.utils.text_dataset_from_directory(\n", + " \"aclImdb/test\", batch_size=batch_size\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "cb141709-fcc1-4cee-bc98-9c89aaba8648", + "metadata": {}, + "outputs": [], + "source": [ + "def custom_standardization(input_data):\n", + " lowercase = tf.strings.lower(input_data)\n", + " stripped_html = tf.strings.regex_replace(lowercase, \"
\", \" \")\n", + " return tf.strings.regex_replace(\n", + " stripped_html, \"[%s]\" % re.escape(string.punctuation), \"\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "d4e80ea9-536a-4ebc-8b35-1eca73dbba7d", + "metadata": {}, + "outputs": [], + "source": [ + "max_features = 10000\n", + "sequence_length = 250\n", + "\n", + "vectorize_layer = layers.TextVectorization(\n", + " standardize=custom_standardization,\n", + " max_tokens=max_features,\n", + " output_mode=\"int\",\n", + " output_sequence_length=sequence_length,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "ad1e5d81-7dae-4b08-b520-ca45501b9510", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-10-03 17:44:10.225130: I tensorflow/core/framework/local_rendezvous.cc:404] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence\n" + ] + } + ], + "source": [ + "# Make a text-only dataset (without labels), then call adapt\n", + "train_text = raw_train_ds.map(lambda x, y: x)\n", + "vectorize_layer.adapt(train_text)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "80f243f5-edd3-4e1c-bddc-abc1cc6673ef", + "metadata": {}, + "outputs": [], + "source": [ + "def vectorize_text(text, label):\n", + " text = tf.expand_dims(text, -1)\n", + " return vectorize_layer(text), label" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "8f37e95c-515c-4edb-a1ee-fc47be5df4b9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Review tf.Tensor(b'Silent Night, Deadly Night 5 is the very last of the series, and like part 4, it\\'s unrelated to the first three except by title and the fact that it\\'s a Christmas-themed horror flick.

Except to the oblivious, there\\'s some obvious things going on here...Mickey Rooney plays a toymaker named Joe Petto and his creepy son\\'s name is Pino. Ring a bell, anyone? Now, a little boy named Derek heard a knock at the door one evening, and opened it to find a present on the doorstep for him. Even though it said \"don\\'t open till Christmas\", he begins to open it anyway but is stopped by his dad, who scolds him and sends him to bed, and opens the gift himself. Inside is a little red ball that sprouts Santa arms and a head, and proceeds to kill dad. Oops, maybe he should have left well-enough alone. Of course Derek is then traumatized by the incident since he watched it from the stairs, but he doesn\\'t grow up to be some killer Santa, he just stops talking.

There\\'s a mysterious stranger lurking around, who seems very interested in the toys that Joe Petto makes. We even see him buying a bunch when Derek\\'s mom takes him to the store to find a gift for him to bring him out of his trauma. And what exactly is this guy doing? Well, we\\'re not sure but he does seem to be taking these toys apart to see what makes them tick. He does keep his landlord from evicting him by promising him to pay him in cash the next day and presents him with a \"Larry the Larvae\" toy for his kid, but of course \"Larry\" is not a good toy and gets out of the box in the car and of course, well, things aren\\'t pretty.

Anyway, eventually what\\'s going on with Joe Petto and Pino is of course revealed, and as with the old story, Pino is not a \"real boy\". Pino is probably even more agitated and naughty because he suffers from \"Kenitalia\" (a smooth plastic crotch) so that could account for his evil ways. And the identity of the lurking stranger is revealed too, and there\\'s even kind of a happy ending of sorts. Whee.

A step up from part 4, but not much of one. Again, Brian Yuzna is involved, and Screaming Mad George, so some decent special effects, but not enough to make this great. A few leftovers from part 4 are hanging around too, like Clint Howard and Neith Hunter, but that doesn\\'t really make any difference. Anyway, I now have seeing the whole series out of my system. Now if I could get some of it out of my brain. 4 out of 5.', shape=(), dtype=string)\n", + "Label neg\n", + "Vectorized review (, )\n" + ] + } + ], + "source": [ + "# retrieve a batch (of 32 reviews and labels) from the dataset\n", + "text_batch, label_batch = next(iter(raw_train_ds))\n", + "first_review, first_label = text_batch[0], label_batch[0]\n", + "print(\"Review\", first_review)\n", + "print(\"Label\", raw_train_ds.class_names[first_label])\n", + "print(\"Vectorized review\", vectorize_text(first_review, first_label))" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "60c9208a-39ac-4e6c-a603-61038cdf3d10", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1287 ---> silent\n", + " 313 ---> night\n", + "Vocabulary size: 10000\n" + ] + } + ], + "source": [ + "print(\"1287 ---> \",vectorize_layer.get_vocabulary()[1287])\n", + "print(\" 313 ---> \",vectorize_layer.get_vocabulary()[313])\n", + "print('Vocabulary size: {}'.format(len(vectorize_layer.get_vocabulary())))" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "3cf90d4b-8dae-44b2-b32b-80cb0092c430", + "metadata": {}, + "outputs": [], + "source": [ + "train_ds = raw_train_ds.map(vectorize_text)\n", + "val_ds = raw_val_ds.map(vectorize_text)\n", + "test_ds = raw_test_ds.map(vectorize_text)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "115a5aba-8a00-458f-be25-0aae9f55de22", + "metadata": {}, + "outputs": [], + "source": [ + "AUTOTUNE = tf.data.AUTOTUNE\n", + "\n", + "train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)\n", + "val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)\n", + "test_ds = test_ds.cache().prefetch(buffer_size=AUTOTUNE)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "d64f4495-102d-4244-9b42-1ba9976a366e", + "metadata": {}, + "outputs": [], + "source": [ + "embedding_dim = 16" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "3dc95d22-935f-4091-b0ee-da95174eb9a0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Model: \"sequential\"\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1mModel: \"sequential\"\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
+       "┃ Layer (type)                     Output Shape                  Param # ┃\n",
+       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
+       "│ embedding (Embedding)           │ ?                      │   0 (unbuilt) │\n",
+       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+       "│ dropout (Dropout)               │ ?                      │   0 (unbuilt) │\n",
+       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+       "│ global_average_pooling1d        │ ?                      │   0 (unbuilt) │\n",
+       "│ (GlobalAveragePooling1D)        │                        │               │\n",
+       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+       "│ dropout_1 (Dropout)             │ ?                      │   0 (unbuilt) │\n",
+       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+       "│ dense (Dense)                   │ ?                      │   0 (unbuilt) │\n",
+       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
+       "
\n" + ], + "text/plain": [ + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", + "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", + "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", + "│ embedding (\u001b[38;5;33mEmbedding\u001b[0m) │ ? │ \u001b[38;5;34m0\u001b[0m (unbuilt) │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ dropout (\u001b[38;5;33mDropout\u001b[0m) │ ? │ \u001b[38;5;34m0\u001b[0m (unbuilt) │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ global_average_pooling1d │ ? │ \u001b[38;5;34m0\u001b[0m (unbuilt) │\n", + "│ (\u001b[38;5;33mGlobalAveragePooling1D\u001b[0m) │ │ │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ dropout_1 (\u001b[38;5;33mDropout\u001b[0m) │ ? │ \u001b[38;5;34m0\u001b[0m (unbuilt) │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ dense (\u001b[38;5;33mDense\u001b[0m) │ ? │ \u001b[38;5;34m0\u001b[0m (unbuilt) │\n", + "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Total params: 0 (0.00 B)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Trainable params: 0 (0.00 B)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "model = tf.keras.Sequential([\n", + " layers.Embedding(max_features, embedding_dim),\n", + " layers.Dropout(0.2),\n", + " layers.GlobalAveragePooling1D(),\n", + " layers.Dropout(0.2),\n", + " layers.Dense(1, activation='sigmoid')])\n", + "\n", + "model.summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "d9059b93-7666-46db-bf15-517c4c205df9", + "metadata": {}, + "outputs": [], + "source": [ + "model.compile(loss=losses.BinaryCrossentropy(),\n", + " optimizer='adam',\n", + " metrics=[tf.metrics.BinaryAccuracy(threshold=0.5)])" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "b1d5959f-1bd8-48da-9815-8239599519b2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n", + "I0000 00:00:1727977450.773487 1857915 service.cc:146] XLA service 0xac47fb0 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:\n", + "I0000 00:00:1727977450.773523 1857915 service.cc:154] StreamExecutor device (0): NVIDIA RTX A6000, Compute Capability 8.6\n", + "2024-10-03 17:44:10.785495: I tensorflow/compiler/mlir/tensorflow/utils/dump_mlir_util.cc:268] disabling MLIR crash reproducer, set env var `MLIR_CRASH_REPRODUCER_DIRECTORY` to enable.\n", + "2024-10-03 17:44:10.838694: I external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:531] Loaded cuDNN version 8907\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m 88/625\u001b[0m \u001b[32m━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 2ms/step - binary_accuracy: 0.5075 - loss: 0.6925 " + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "I0000 00:00:1727977451.426198 1857915 device_compiler.h:188] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 2ms/step - binary_accuracy: 0.5797 - loss: 0.6821 - val_binary_accuracy: 0.7248 - val_loss: 0.6141\n", + "Epoch 2/10\n", + "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 699us/step - binary_accuracy: 0.7588 - loss: 0.5810 - val_binary_accuracy: 0.8092 - val_loss: 0.4989\n", + "Epoch 3/10\n", + "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 477us/step - binary_accuracy: 0.8197 - loss: 0.4674 - val_binary_accuracy: 0.8282 - val_loss: 0.4282\n", + "Epoch 4/10\n", + "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 449us/step - binary_accuracy: 0.8514 - loss: 0.3946 - val_binary_accuracy: 0.8402 - val_loss: 0.3870\n", + "Epoch 5/10\n", + "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 408us/step - binary_accuracy: 0.8673 - loss: 0.3488 - val_binary_accuracy: 0.8494 - val_loss: 0.3608\n", + "Epoch 6/10\n", + "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 406us/step - binary_accuracy: 0.8809 - loss: 0.3174 - val_binary_accuracy: 0.8498 - val_loss: 0.3477\n", + "Epoch 7/10\n", + "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 466us/step - binary_accuracy: 0.8899 - loss: 0.2913 - val_binary_accuracy: 0.8554 - val_loss: 0.3325\n", + "Epoch 8/10\n", + "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 410us/step - binary_accuracy: 0.8977 - loss: 0.2703 - val_binary_accuracy: 0.8580 - val_loss: 0.3232\n", + "Epoch 9/10\n", + "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 397us/step - binary_accuracy: 0.9057 - loss: 0.2539 - val_binary_accuracy: 0.8580 - val_loss: 0.3208\n", + "Epoch 10/10\n", + "\u001b[1m625/625\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 784us/step - binary_accuracy: 0.9084 - loss: 0.2405 - val_binary_accuracy: 0.8638 - val_loss: 0.3121\n" + ] + } + ], + "source": [ + "epochs = 10\n", + "history = model.fit(\n", + " train_ds,\n", + " validation_data=val_ds,\n", + " epochs=epochs)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "656afe07-354f-4ff2-8e3e-d02bad6c5958", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m 1/782\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m21s\u001b[0m 28ms/step - binary_accuracy: 0.9062 - loss: 0.2768" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m782/782\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 705us/step - binary_accuracy: 0.8542 - loss: 0.3343\n", + "Loss: 0.33130890130996704\n", + "Accuracy: 0.856440007686615\n" + ] + } + ], + "source": [ + "loss, accuracy = model.evaluate(test_ds)\n", + "\n", + "print(\"Loss: \", loss)\n", + "print(\"Accuracy: \", accuracy)" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "a01d0f13-d0b8-4d78-9ddc-ede5ed402446", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['binary_accuracy', 'loss', 'val_binary_accuracy', 'val_loss'])" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "history_dict = history.history\n", + "history_dict.keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "1f7484c3-3cdf-46d5-b95d-80316f0e6240", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAHHCAYAAABDUnkqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAABVv0lEQVR4nO3dd3gU1f7H8fcmIQ2S0JNAQkLvTUAEpKgoWFCkGBSlqHhFqggClyLlAgqooAiIVwFBEcWAIB0EpSlcKSJiAKVJRyShBtjM74/5ZcmSENIn2f28nmcfZmdnZ75LovvhnDPn2AzDMBARERFxER5WFyAiIiKSlRRuRERExKUo3IiIiIhLUbgRERERl6JwIyIiIi5F4UZERERcisKNiIiIuBSFGxEREXEpCjciIiLiUhRuRCzQpUsXIiMjM/TeESNGYLPZsragXObQoUPYbDZmzZqVo9ddv349NpuN9evXO/al9WeVXTVHRkbSpUuXLD1nWsyaNQubzcahQ4dy/NoimaVwI5KEzWZL0yPpl59IZm3evJkRI0Zw/vx5q0sRcQleVhcgkpvMmTPH6fmnn37K6tWrk+2vXLlypq7z0UcfkZCQkKH3Dh06lEGDBmXq+pJ2mflZpdXmzZsZOXIkXbp0oWDBgk6vxcTE4OGhf4eKpIfCjUgSzz77rNPzH3/8kdWrVyfbf6vLly/j7++f5uvky5cvQ/UBeHl54eWl/3RzSmZ+VlnBx8fH0uuL5EX654BIOjVr1oxq1arx888/06RJE/z9/fn3v/8NwDfffMOjjz5KiRIl8PHxoWzZsowePRq73e50jlvHcSSO15g4cSIzZsygbNmy+Pj4UK9ePbZt2+b03pTG3NhsNnr27MmiRYuoVq0aPj4+VK1alRUrViSrf/369dStWxdfX1/Kli3Lhx9+mOZxPBs2bKB9+/aUKlUKHx8fwsPDefXVV7ly5Uqyz1egQAGOHTtG69atKVCgAMWKFaN///7J/i7Onz9Ply5dCAoKomDBgnTu3DlN3TP/+9//sNlszJ49O9lrK1euxGaz8e233wJw+PBhXnnlFSpWrIifnx9FihShffv2aRpPktKYm7TW/Msvv9ClSxfKlCmDr68vISEhPP/88/z999+OY0aMGMGAAQMAKF26tKPrM7G2lMbc/Pnnn7Rv357ChQvj7+/PPffcw9KlS52OSRw/9OWXXzJmzBjCwsLw9fXlgQce4MCBA3f83LczdepUqlatio+PDyVKlKBHjx7JPvv+/ftp27YtISEh+Pr6EhYWRocOHYiNjXUcs3r1au69914KFixIgQIFqFixouO/I5HM0j//RDLg77//5uGHH6ZDhw48++yzBAcHA+YgzAIFCtCvXz8KFCjAd999x/Dhw4mLi2PChAl3PO/nn3/OhQsX+Ne//oXNZmP8+PG0adOGP//8844tCBs3biQ6OppXXnmFgIAA3nvvPdq2bcuRI0coUqQIADt27KBly5aEhoYycuRI7HY7o0aNolixYmn63F999RWXL1+me/fuFClShK1bt/L+++/z119/8dVXXzkda7fbadGiBfXr12fixImsWbOGt99+m7Jly9K9e3cADMPgiSeeYOPGjbz88stUrlyZhQsX0rlz5zvWUrduXcqUKcOXX36Z7Pj58+dTqFAhWrRoAcC2bdvYvHkzHTp0ICwsjEOHDjFt2jSaNWvGb7/9lq5Wt/TUvHr1av7880+6du1KSEgIe/bsYcaMGezZs4cff/wRm81GmzZt2LdvH/PmzePdd9+laNGiALf9mZw6dYqGDRty+fJlevfuTZEiRZg9ezaPP/44CxYs4Mknn3Q6/s0338TDw4P+/fsTGxvL+PHj6dixIz/99FOaP3OiESNGMHLkSJo3b0737t2JiYlh2rRpbNu2jU2bNpEvXz6uXbtGixYtiI+Pp1evXoSEhHDs2DG+/fZbzp8/T1BQEHv27OGxxx6jRo0ajBo1Ch8fHw4cOMCmTZvSXZNIigwRua0ePXoYt/5n0rRpUwMwpk+fnuz4y5cvJ9v3r3/9y/D39zeuXr3q2Ne5c2cjIiLC8fzgwYMGYBQpUsQ4d+6cY/8333xjAMaSJUsc+954441kNQGGt7e3ceDAAce+Xbt2GYDx/vvvO/a1atXK8Pf3N44dO+bYt3//fsPLyyvZOVOS0ucbN26cYbPZjMOHDzt9PsAYNWqU07G1a9c26tSp43i+aNEiAzDGjx/v2Hfjxg2jcePGBmDMnDkz1XoGDx5s5MuXz+nvLD4+3ihYsKDx/PPPp1r3li1bDMD49NNPHfvWrVtnAMa6deucPkvSn1V6ak7puvPmzTMA44cffnDsmzBhggEYBw8eTHZ8RESE0blzZ8fzvn37GoCxYcMGx74LFy4YpUuXNiIjIw273e70WSpXrmzEx8c7jp08ebIBGLt37052raRmzpzpVNPp06cNb29v46GHHnJcwzAMY8qUKQZgfPLJJ4ZhGMaOHTsMwPjqq69ue+53333XAIwzZ86kWoNIRqlbSiQDfHx86Nq1a7L9fn5+ju0LFy5w9uxZGjduzOXLl/n999/veN6oqCgKFSrkeN64cWPA7Ia4k+bNm1O2bFnH8xo1ahAYGOh4r91uZ82aNbRu3ZoSJUo4jitXrhwPP/zwHc8Pzp/v0qVLnD17loYNG2IYBjt27Eh2/Msvv+z0vHHjxk6fZdmyZXh5eTlacgA8PT3p1atXmuqJiori+vXrREdHO/atWrWK8+fPExUVlWLd169f5++//6ZcuXIULFiQ7du3p+laGak56XWvXr3K2bNnueeeewDSfd2k17/77ru59957HfsKFCjASy+9xKFDh/jtt9+cju/atSve3t6O5+n5nUpqzZo1XLt2jb59+zoNcO7WrRuBgYGObrGgoCDA7Bq8fPlyiudKHDT9zTffZPtgbXFPCjciGVCyZEmnL4xEe/bs4cknnyQoKIjAwECKFSvmGIycdLzB7ZQqVcrpeWLQ+eeff9L93sT3J7739OnTXLlyhXLlyiU7LqV9KTly5AhdunShcOHCjnE0TZs2BZJ/Pl9f32RdK0nrAXMsTGhoKAUKFHA6rmLFimmqp2bNmlSqVIn58+c79s2fP5+iRYty//33O/ZduXKF4cOHEx4ejo+PD0WLFqVYsWKcP38+TT+XpNJT87lz5+jTpw/BwcH4+flRrFgxSpcuDaTt9+F210/pWol38B0+fNhpf2Z+p269LiT/nN7e3pQpU8bxeunSpenXrx///e9/KVq0KC1atOCDDz5w+rxRUVE0atSIF198keDgYDp06MCXX36poCNZRmNuRDIg6b/IE50/f56mTZsSGBjIqFGjKFu2LL6+vmzfvp2BAwem6X/cnp6eKe43DCNb35sWdrudBx98kHPnzjFw4EAqVapE/vz5OXbsGF26dEn2+W5XT1aLiopizJgxnD17loCAABYvXszTTz/tdEdZr169mDlzJn379qVBgwYEBQVhs9no0KFDtn6hPvXUU2zevJkBAwZQq1YtChQoQEJCAi1btsyxL/Ls/r1Iydtvv02XLl345ptvWLVqFb1792bcuHH8+OOPhIWF4efnxw8//MC6detYunQpK1asYP78+dx///2sWrUqx353xHUp3IhkkfXr1/P3338THR1NkyZNHPsPHjxoYVU3FS9eHF9f3xTvlEnL3TO7d+9m3759zJ49m06dOjn2r169OsM1RUREsHbtWi5evOjUEhITE5Pmc0RFRTFy5Ei+/vprgoODiYuLo0OHDk7HLFiwgM6dO/P222879l29ejVDk+alteZ//vmHtWvXMnLkSIYPH+7Yv3///mTnTM+M0xERESn+/SR2e0ZERKT5XOmReN6YmBjKlCnj2H/t2jUOHjxI8+bNnY6vXr061atXZ+jQoWzevJlGjRoxffp0/vOf/wDg4eHBAw88wAMPPMA777zD2LFjGTJkCOvWrUt2LpH0UreUSBZJ/Ndm0n8RX7t2jalTp1pVkhNPT0+aN2/OokWLOH78uGP/gQMHWL58eZreD86fzzAMJk+enOGaHnnkEW7cuMG0adMc++x2O++//36az1G5cmWqV6/O/PnzmT9/PqGhoU7hMrH2W1sq3n///WS3pWdlzSn9fQFMmjQp2Tnz588PkKaw9cgjj7B161a2bNni2Hfp0iVmzJhBZGQkVapUSetHSZfmzZvj7e3Ne++95/SZPv74Y2JjY3n00UcBiIuL48aNG07vrV69Oh4eHsTHxwNmd92tatWqBeA4RiQz1HIjkkUaNmxIoUKF6Ny5M71798ZmszFnzpxsbf5PrxEjRrBq1SoaNWpE9+7dsdvtTJkyhWrVqrFz585U31upUiXKli1L//79OXbsGIGBgXz99dfpHruRVKtWrWjUqBGDBg3i0KFDVKlShejo6HSPR4mKimL48OH4+vrywgsvJJvR97HHHmPOnDkEBQVRpUoVtmzZwpo1axy3yGdHzYGBgTRp0oTx48dz/fp1SpYsyapVq1JsyatTpw4AQ4YMoUOHDuTLl49WrVo5Qk9SgwYNYt68eTz88MP07t2bwoULM3v2bA4ePMjXX3+dbbMZFytWjMGDBzNy5EhatmzJ448/TkxMDFOnTqVevXqOsWXfffcdPXv2pH379lSoUIEbN24wZ84cPD09adu2LQCjRo3ihx9+4NFHHyUiIoLTp08zdepUwsLCnAZKi2SUwo1IFilSpAjffvstr732GkOHDqVQoUI8++yzPPDAA475VqxWp04dli9fTv/+/Rk2bBjh4eGMGjWKvXv33vFurnz5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zZw5k7p161KjRo10n7dYsWL4+/tnRYl3FBISgo+PT45cK69SuBEREbfx2GOPUaxYMWbNmuW0/+LFi3z11Ve88MIL/P333zz99NOULFkSf39/qlevzrx581I9763dUvv376dJkyb4+vpSpUoVVq9enew9AwcOpEKFCvj7+1OmTBmGDRvG9evXAZg1axYjR45k165d2Gw2bDabo+Zbu6V2797N/fffj5+fH0WKFOGll17i4sWLjte7dOlC69atmThxIqGhoRQpUoQePXo4rpUWCQkJjBo1irCwMHx8fKhVqxYrVqxwvH7t2jV69uxJaGgovr6+REREMG7cOAAMw2DEiBGUKlUKHx8fSpQoQe/evdN87YzQ8gsiIpIlDAMuX7bm2v7+YLPd+TgvLy86derErFmzGDJkCLb/f9NXX32F3W7n6aef5uLFi9SpU4eBAwcSGBjI0qVLee655yhbtix33333Ha+RkJBAmzZtCA4O5qeffiI2NtZpfE6igIAAZs2aRYkSJdi9ezfdunUjICCA119/naioKH799VdWrFjBmjVrAAgKCkp2jkuXLtGiRQsaNGjAtm3bOH36NC+++CI9e/Z0CnDr1q0jNDSUdevWceDAAaKioqhVqxbdunW7818aMHnyZN5++20+/PBDateuzSeffMLjjz/Onj17KF++PO+99x6LFy/myy+/pFSpUhw9epSjR48C8PXXX/Puu+/yxRdfULVqVU6ePMmuXbvSdN0MM9xMbGysARixsbFWlyIikmdduXLF+O2334wrV6449l28aBhmxMn5x8WLaa997969BmCsW7fOsa9x48bGs88+e9v3PProo8Zrr73meN60aVOjT58+jucRERHGu+++axiGYaxcudLw8vIyjh075nh9+fLlBmAsXLjwtteYMGGCUadOHcfzN954w6hZs2ay45KeZ8aMGUahQoWMi0n+ApYuXWp4eHgYJ0+eNAzDMDp37mxEREQYN27ccBzTvn17Iyoq6ra13HrtEiVKGGPGjHE6pl69esYrr7xiGIZh9OrVy7j//vuNhISEZOd6++23jQoVKhjXrl277fUSpfR7lSg939/qlhIREbdSqVIlGjZsyCeffALAgQMH2LBhAy+88AIAdrud0aNHU716dQoXLkyBAgVYuXIlR44cSdP59+7dS3h4OCVKlHDsa9CgQbLj5s+fT6NG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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "acc = history_dict['binary_accuracy']\n", + "val_acc = history_dict['val_binary_accuracy']\n", + "loss = history_dict['loss']\n", + "val_loss = history_dict['val_loss']\n", + "\n", + "epochs = range(1, len(acc) + 1)\n", + "\n", + "# \"bo\" is for \"blue dot\"\n", + "plt.plot(epochs, loss, 'bo', label='Training loss')\n", + "# b is for \"solid blue line\"\n", + "plt.plot(epochs, val_loss, 'b', label='Validation loss')\n", + "plt.title('Training and validation loss')\n", + "plt.xlabel('Epochs')\n", + "plt.ylabel('Loss')\n", + "plt.legend()\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "af51178e-fe0b-40ca-9260-2190fb52d960", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(epochs, acc, 'bo', label='Training acc')\n", + "plt.plot(epochs, val_acc, 'b', label='Validation acc')\n", + "plt.title('Training and validation accuracy')\n", + "plt.xlabel('Epochs')\n", + "plt.ylabel('Accuracy')\n", + "plt.legend(loc='lower right')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "93b0a42c-437e-41bb-99e7-d58cb8036a3a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m782/782\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m4s\u001b[0m 5ms/step - accuracy: 0.4993 - binary_accuracy: 0.0000e+00 - loss: 0.0000e+00\n", + "{'accuracy': 0.5000399947166443, 'binary_accuracy': 0.0, 'loss': 0.0}\n" + ] + } + ], + "source": [ + "export_model = tf.keras.Sequential([\n", + " vectorize_layer,\n", + " model,\n", + " layers.Activation('sigmoid')\n", + "])\n", + "\n", + "export_model.compile(\n", + " loss=losses.BinaryCrossentropy(from_logits=False), optimizer=\"adam\", metrics=['accuracy']\n", + ")\n", + "\n", + "# Test it with `raw_test_ds`, which yields raw strings\n", + "metrics = export_model.evaluate(raw_test_ds, return_dict=True)\n", + "print(metrics)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "8939539b-a600-48b1-a55e-3f1087f4a855", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 52ms/step\n" + ] + }, + { + "data": { + "text/plain": [ + "array([[0.5858644 ],\n", + " [0.5499682 ],\n", + " [0.53613865]], dtype=float32)" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "examples = tf.constant([\n", + " \"The movie was great!\",\n", + " \"The movie was okay.\",\n", + " \"The movie was terrible...\"\n", + "])\n", + "\n", + "export_model.predict(examples)" + ] + }, + { + "cell_type": "markdown", + "id": "f6b40a59-8d3b-44ec-a4f7-92c5742a0c1c", + "metadata": {}, + "source": [ + "### Save Model" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "e2aa1770-2bf9-436b-af32-16b64fc97490", + "metadata": {}, + "outputs": [], + "source": [ + "!rm -rf text_model" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "7f22cc32-2708-4808-8e76-99024da87a21", + "metadata": {}, + "outputs": [], + "source": [ + "export_model.save('text_model.keras')" + ] + }, + { + "cell_type": "markdown", + "id": "e0461f74-fdd0-4f30-9f44-0be7ad00d9b0", + "metadata": {}, + "source": [ + "### Load model" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "c9cf2c7f-5e86-4ff8-984e-dd0ed7a3ece9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Model: \"sequential_1\"\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1mModel: \"sequential_1\"\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
+       "┃ Layer (type)                     Output Shape                  Param # ┃\n",
+       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
+       "│ text_vectorization              │ (None, 250)            │             0 │\n",
+       "│ (TextVectorization)             │                        │               │\n",
+       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+       "│ sequential (Sequential)         │ (None, 1)              │       160,017 │\n",
+       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+       "│ activation (Activation)         │ (None, 1)              │             0 │\n",
+       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
+       "
\n" + ], + "text/plain": [ + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", + "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", + "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", + "│ text_vectorization │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m250\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", + "│ (\u001b[38;5;33mTextVectorization\u001b[0m) │ │ │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ sequential (\u001b[38;5;33mSequential\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m) │ \u001b[38;5;34m160,017\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ activation (\u001b[38;5;33mActivation\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", + "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Total params: 160,017 (625.07 KB)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m160,017\u001b[0m (625.07 KB)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Trainable params: 160,017 (625.07 KB)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m160,017\u001b[0m (625.07 KB)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# register callables as custom objects before loading\n", + "custom_objects = {\"vectorize_layer\": vectorize_layer, \"custom_standardization\": custom_standardization}\n", + "with tf.keras.utils.custom_object_scope(custom_objects):\n", + " new_model = tf.keras.models.load_model('text_model.keras', compile=False)\n", + "\n", + "new_model.summary()" + ] + }, + { + "cell_type": "markdown", + "id": "242a4f7e-fa45-4d21-b103-fe3718bc0f10", + "metadata": {}, + "source": [ + "### Predict" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "531680b2-42ef-4205-9a38-6995aee9f340", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 51ms/step\n" + ] + }, + { + "data": { + "text/plain": [ + "array([[0.5858644 ],\n", + " [0.5499682 ],\n", + " [0.53613865]], dtype=float32)" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "new_model.predict(examples)" + ] + }, + { + "cell_type": "markdown", + "id": "a82ae387-1587-4175-b4b2-66586e4668f7", + "metadata": {}, + "source": [ + "## PySpark" + ] + }, + { + "cell_type": "markdown", + "id": "0b5ac416-a37f-4f0b-8c77-628f0fcede69", + "metadata": {}, + "source": [ + "## Inference using Spark DL API\n", + "Note: you can restart the kernel and run from this point to simulate running in a different node or environment." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "d6d515c2-ce53-4af5-a936-ae91fdecea99", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from pyspark.ml.functions import predict_batch_udf\n", + "from pyspark.sql.functions import struct, col\n", + "from pyspark.sql.types import ArrayType, FloatType, DoubleType\n", + "from pyspark.sql import SparkSession\n", + "from pyspark import SparkConf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b653c43", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", + "\n", + "conf = SparkConf()\n", + "if 'spark' not in globals():\n", + " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", + " import socket\n", + " hostname = socket.gethostname()\n", + " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", + "conf.set(\"spark.task.maxFailures\", \"1\")\n", + "conf.set(\"spark.driver.memory\", \"8g\")\n", + "conf.set(\"spark.executor.memory\", \"8g\")\n", + "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", + "conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", + "conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", + "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", + "conf.set(\"spark.python.worker.reuse\", \"true\")\n", + "# Create Spark Session\n", + "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", + "sc = spark.sparkContext" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "ef3309eb", + "metadata": {}, + "outputs": [], + "source": [ + "from datasets import load_dataset\n", + "\n", + "# load IMDB reviews (test) dataset\n", + "data = load_dataset(\"imdb\", split=\"test\")\n", + "lines = []\n", + "for example in data:\n", + " lines.append([example[\"text\"].split(\".\")[0]])\n", + " \n", + "df = spark.createDataFrame(lines, ['lines']).repartition(8)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "7b7a8395-e2ae-4c3c-bf57-763dfde600ad", + "metadata": {}, + "outputs": [], + "source": [ + "text_model_path = \"{}/text_model.keras\".format(os.getcwd())" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "8c0524cf-3a75-4fb8-8025-f0654acce13e", + "metadata": {}, + "outputs": [], + "source": [ + "def predict_batch_fn():\n", + " # since this function runs on the executor, any required imports should be added inside the function.\n", + " import re\n", + " import string\n", + " import tensorflow as tf\n", + " from tensorflow.keras import layers\n", + "\n", + " # Enable GPU memory growth to avoid CUDA OOM\n", + " gpus = tf.config.experimental.list_physical_devices('GPU')\n", + " if gpus:\n", + " try:\n", + " for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + " except RuntimeError as e:\n", + " print(e)\n", + "\n", + " def custom_standardization(input_data):\n", + " lowercase = tf.strings.lower(input_data)\n", + " stripped_html = tf.strings.regex_replace(lowercase, \"
\", \" \")\n", + " return tf.strings.regex_replace(\n", + " stripped_html, \"[%s]\" % re.escape(string.punctuation), \"\"\n", + " )\n", + "\n", + " max_features = 10000\n", + " sequence_length = 250\n", + "\n", + " vectorize_layer = layers.TextVectorization(\n", + " standardize=custom_standardization,\n", + " max_tokens=max_features,\n", + " output_mode=\"int\",\n", + " output_sequence_length=sequence_length,\n", + " )\n", + "\n", + " custom_objects = {\"vectorize_layer\": vectorize_layer,\n", + " \"custom_standardization\": custom_standardization}\n", + " with tf.keras.utils.custom_object_scope(custom_objects):\n", + " model = tf.keras.models.load_model(text_model_path)\n", + "\n", + " def predict(inputs):\n", + " return model.predict(inputs)\n", + "\n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "0d603644-d938-4c87-aa8a-2512251638d5", + "metadata": {}, + "outputs": [], + "source": [ + "classify = predict_batch_udf(predict_batch_fn,\n", + " return_type=FloatType(),\n", + " batch_size=256)" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "id": "0b480622-8dc1-4879-933e-c43112768630", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 22.3 ms, sys: 6.39 ms, total: 28.7 ms\n", + "Wall time: 5.95 s\n" + ] + } + ], + "source": [ + "%%time\n", + "predictions = df.withColumn(\"preds\", classify(struct(\"lines\")))\n", + "results = predictions.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "id": "31b0a262-387e-4a5e-a60e-b9b8ee456199", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 5:==============================================> (8 + 2) / 10]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 98.3 ms, sys: 8.08 ms, total: 106 ms\n", + "Wall time: 1.24 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "predictions = df.withColumn(\"preds\", classify(\"lines\"))\n", + "results = predictions.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "7ef9e431-59f5-4b29-9f79-ae16a9cfb0b9", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[Stage 8:==============================================> (8 + 2) / 10]\r" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 16.1 ms, sys: 4.41 ms, total: 20.6 ms\n", + "Wall time: 1.18 s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "predictions = df.withColumn(\"preds\", classify(col(\"lines\")))\n", + "results = predictions.collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "9a325ee2-3268-414a-bb75-a5fcf794f512", + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------------------------------------------------------------------+----------+\n", + "| lines| preds|\n", + "+--------------------------------------------------------------------------------+----------+\n", + "|i do not understand at all why this movie received such good grades from crit...| 0.5006337|\n", + "| I am a big fan of The ABC Movies of the Week genre|0.57577586|\n", + "| Strangeland is a terrible horror/technological thriller| 0.5441176|\n", + "|Sex,Drugs,Rock & Roll is without a doubt the worst product of Western Civiliz...|0.53261155|\n", + "| Not to be mistaken as the highly touted Samuel L| 0.5785005|\n", + "|Following the pleasingly atmospheric original and the amusingly silly second ...|0.51597977|\n", + "| No idea how this is rated as high as it is (5|0.55052567|\n", + "|When I saw this in the cinema, I remember wincing at the bad acting about a m...|0.52347463|\n", + "| I was shocked at how bad it was and unable to turn away from the disaster| 0.5262873|\n", + "|I don't know if this exceptionally dull movie was intended as an unofficial s...| 0.5175539|\n", + "|Greetings All,

Isn't it amazing the power that films have on you a...|0.64540815|\n", + "| I'm sorry but this guy is not funny| 0.5385401|\n", + "|This movie is so dull I spent half of it on IMDb while it was open in another...| 0.5182078|\n", + "| OK, lets start with the best| 0.5611213|\n", + "|This show had a promising start as sort of the opposite of 'Oceans 11' but ha...| 0.5557351|\n", + "|The 3rd in the series finds Paul Kersey (Bronson) turning vigilante to get re...|0.56089103|\n", + "| I'm not sure I've ever seen a film as bad as this| 0.54292|\n", + "| Steven Seagal has made a really dull, bad and boring movie| 0.5089991|\n", + "| You have to acknowledge Cimino's contribution to cinema| 0.5760211|\n", + "|***SPOILER ALERT*** Disjointed and confusing arson drama that has to do with ...| 0.5469447|\n", + "+--------------------------------------------------------------------------------+----------+\n", + "only showing top 20 rows\n", + "\n" + ] + } + ], + "source": [ + "predictions.show(truncate=80)" + ] + }, + { + "cell_type": "markdown", + "id": "579b53bf-5a8a-4f85-a5b5-fb82a4be7f06", + "metadata": {}, + "source": [ + "### Using Triton Inference Server\n", + "\n", + "Note: you can restart the kernel and run from this point to simulate running in a different node or environment." + ] + }, + { + "cell_type": "markdown", + "id": "8598edb1-acb7-4704-8f0d-20b0f431a323", + "metadata": {}, + "source": [ + "This notebook uses the [Python backend with a custom execution environment](https://github.com/triton-inference-server/python_backend#creating-custom-execution-environments) for Triton 24.08, using a conda-pack environment created as follows:\n", + "```\n", + "conda create -n tf-gpu -c conda-forge python=3.10.0\n", + "conda activate tf-gpu\n", + "\n", + "export PYTHONNOUSERSITE=True\n", + "pip install numpy==1.26.4 tensorflow[and-cuda] conda-pack\n", + "\n", + "conda pack # tf-gpu.tar.gz\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "772e337e-1098-4c7b-ba81-8cb221a518e2", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import os\n", + "from pyspark.ml.functions import predict_batch_udf\n", + "from pyspark.sql.functions import col, struct\n", + "from pyspark.sql.types import ArrayType, FloatType" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "69d0c93a-bb0b-46c5-9d28-7b08a2e70964", + "metadata": {}, + "outputs": [], + "source": [ + "%%bash\n", + "# copy custom model to expected layout for Triton\n", + "rm -rf models\n", + "mkdir -p models\n", + "cp -r models_config/text_classification models\n", + "\n", + "# add custom execution environment\n", + "cp tf-gpu.tar.gz models" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "f4f14c8f", + "metadata": {}, + "outputs": [], + "source": [ + "import unicodedata\n", + "\n", + "def normalize_vocabulary(vocab):\n", + " # Normalize each word in the vocabulary to remove non-ASCII characters\n", + " normalized_vocab = [\n", + " unicodedata.normalize('NFKD', word).encode('ascii', 'ignore').decode('utf-8')\n", + " for word in vocab\n", + " ]\n", + " normalized_vocab = filter(lambda x: x != '', normalized_vocab)\n", + " normalized_vocab = list(set(normalized_vocab)) \n", + "\n", + "\n", + " return normalized_vocab\n", + "\n", + "vocab = vectorize_layer.get_vocabulary()\n", + "normalized_vocab = normalize_vocabulary(vocab)\n", + "\n", + "# Reassign the cleaned vocabulary to the TextVectorization layer\n", + "vectorize_layer.set_vocabulary(normalized_vocab)\n", + "\n", + "# Save the model with the cleaned vocabulary\n", + "export_model.save('text_model_cleaned.keras')" + ] + }, + { + "cell_type": "markdown", + "id": "0d8c9ab3-57c4-45bb-9bcf-6433337ef9b5", + "metadata": {}, + "source": [ + "#### Start Triton Server on each executor" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "a7fb146c-5319-4831-85f7-f2f3c084b042", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "[True]" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "num_executors = 1\n", + "triton_models_dir = \"{}/models\".format(os.getcwd())\n", + "text_model_dir = \"{}/text_model_cleaned.keras\".format(os.getcwd())\n", + "nodeRDD = sc.parallelize(list(range(num_executors)), num_executors)\n", + "\n", + "def start_triton(it):\n", + " import docker\n", + " import time\n", + " import tritonclient.grpc as grpcclient\n", + " \n", + " client=docker.from_env()\n", + " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", + " if containers:\n", + " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", + " else:\n", + " container=client.containers.run(\n", + " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", + " detach=True,\n", + " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", + " name=\"spark-triton\",\n", + " network_mode=\"host\",\n", + " remove=True,\n", + " shm_size=\"128M\",\n", + " volumes={\n", + " triton_models_dir: {\"bind\": \"/models\", \"mode\": \"ro\"},\n", + " text_model_dir: {\"bind\": \"/text_model_cleaned.keras\", \"mode\": \"ro\"}\n", + " }\n", + " )\n", + " print(\">>>> starting triton: {}\".format(container.short_id))\n", + "\n", + " # wait for triton to be running\n", + " time.sleep(15)\n", + " client = grpcclient.InferenceServerClient(\"localhost:8001\")\n", + " ready = False\n", + " while not ready:\n", + " try:\n", + " ready = client.is_server_ready()\n", + " except Exception as e:\n", + " time.sleep(5)\n", + " \n", + " return [True]\n", + "\n", + "nodeRDD.barrier().mapPartitions(start_triton).collect()" + ] + }, + { + "cell_type": "markdown", + "id": "287873da-6202-4b55-97fb-cda8644b1fee", + "metadata": {}, + "source": [ + "#### Run inference" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "id": "41106a02-236e-4cb3-ac51-76aa64b663c2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+----------------------------------------------------------------------------------------------------+\n", + "| lines|\n", + "+----------------------------------------------------------------------------------------------------+\n", + "|i do not understand at all why this movie received such good grades from critics - - i've seen te...|\n", + "| I am a big fan of The ABC Movies of the Week genre|\n", + "| Strangeland is a terrible horror/technological thriller|\n", + "| Sex,Drugs,Rock & Roll is without a doubt the worst product of Western Civilization|\n", + "| Not to be mistaken as the highly touted Samuel L|\n", + "|Following the pleasingly atmospheric original and the amusingly silly second one, this incredibly...|\n", + "| No idea how this is rated as high as it is (5|\n", + "|When I saw this in the cinema, I remember wincing at the bad acting about a minute or two into th...|\n", + "| I was shocked at how bad it was and unable to turn away from the disaster|\n", + "|I don't know if this exceptionally dull movie was intended as an unofficial sequel to 'The French...|\n", + "|Greetings All,

Isn't it amazing the power that films have on you after the 1st viewing...|\n", + "| I'm sorry but this guy is not funny|\n", + "|This movie is so dull I spent half of it on IMDb while it was open in another tab on Netflix tryi...|\n", + "| OK, lets start with the best|\n", + "|This show had a promising start as sort of the opposite of 'Oceans 11' but has developed into a s...|\n", + "|The 3rd in the series finds Paul Kersey (Bronson) turning vigilante to get revenge on the thugs t...|\n", + "| I'm not sure I've ever seen a film as bad as this|\n", + "| Steven Seagal has made a really dull, bad and boring movie|\n", + "| You have to acknowledge Cimino's contribution to cinema|\n", + "|***SPOILER ALERT*** Disjointed and confusing arson drama that has to do with a sinister plan to b...|\n", + "+----------------------------------------------------------------------------------------------------+\n", + "only showing top 20 rows\n", + "\n" + ] + } + ], + "source": [ + "from datasets import load_dataset\n", + "\n", + "# load IMDB reviews (test) dataset\n", + "data = load_dataset(\"imdb\", split=\"test\")\n", + "lines = []\n", + "for example in data:\n", + " lines.append([example[\"text\"].split(\".\")[0]])\n", + "\n", + "df = spark.createDataFrame(lines, ['lines']).repartition(10)\n", + "df.show(truncate=100)" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "8b763167-7f50-4278-9bc9-6c3433b62294", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['lines']" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "columns = df.columns\n", + "columns" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "29b0cc0d-c480-4e4a-bd41-207dc314cba5", + "metadata": {}, + "outputs": [], + "source": [ + "def triton_fn(triton_uri, model_name):\n", + " import numpy as np\n", + " import tritonclient.grpc as grpcclient\n", + " \n", + " np_types = {\n", + " \"BOOL\": np.dtype(np.bool_),\n", + " \"INT8\": np.dtype(np.int8),\n", + " \"INT16\": np.dtype(np.int16),\n", + " \"INT32\": np.dtype(np.int32),\n", + " \"INT64\": np.dtype(np.int64),\n", + " \"FP16\": np.dtype(np.float16),\n", + " \"FP32\": np.dtype(np.float32),\n", + " \"FP64\": np.dtype(np.float64),\n", + " \"FP64\": np.dtype(np.double),\n", + " \"BYTES\": np.dtype(object)\n", + " }\n", + "\n", + " client = grpcclient.InferenceServerClient(triton_uri)\n", + " model_meta = client.get_model_metadata(model_name)\n", + " \n", + " def predict(inputs):\n", + " if isinstance(inputs, np.ndarray):\n", + " # single ndarray input\n", + " request = [grpcclient.InferInput(model_meta.inputs[0].name, inputs.shape, model_meta.inputs[0].datatype)]\n", + " request[0].set_data_from_numpy(inputs.astype(np_types[model_meta.inputs[0].datatype]))\n", + " else:\n", + " # dict of multiple ndarray inputs\n", + " request = [grpcclient.InferInput(i.name, inputs[i.name].shape, i.datatype) for i in model_meta.inputs]\n", + " for i in request:\n", + " i.set_data_from_numpy(inputs[i.name()].astype(np_types[i.datatype()]))\n", + " \n", + " response = client.infer(model_name, inputs=request)\n", + " \n", + " if len(model_meta.outputs) > 1:\n", + " # return dictionary of numpy arrays\n", + " return {o.name: response.as_numpy(o.name) for o in model_meta.outputs}\n", + " else:\n", + " # return single numpy array\n", + " return response.as_numpy(model_meta.outputs[0].name)\n", + " \n", + " return predict" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "8e06d33f-5cef-4a48-afc3-5d468f8ec2b4", + "metadata": {}, + "outputs": [], + "source": [ + "from functools import partial\n", + "\n", + "classify = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"text_classification\"),\n", + " input_tensor_shapes=[[1]],\n", + " return_type=FloatType(),\n", + " batch_size=2048)" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "d89e74ad-e551-4bfa-ad08-98725878630a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------------------------------------------------------------------+----------+\n", + "| lines| preds|\n", + "+--------------------------------------------------------------------------------+----------+\n", + "|i do not understand at all why this movie received such good grades from crit...| 0.5380144|\n", + "| I am a big fan of The ABC Movies of the Week genre|0.59806347|\n", + "| Strangeland is a terrible horror/technological thriller|0.54900867|\n", + "|Sex,Drugs,Rock & Roll is without a doubt the worst product of Western Civiliz...|0.56048334|\n", + "| Not to be mistaken as the highly touted Samuel L|0.56276447|\n", + "|Following the pleasingly atmospheric original and the amusingly silly second ...| 0.5571853|\n", + "| No idea how this is rated as high as it is (5| 0.5637812|\n", + "|When I saw this in the cinema, I remember wincing at the bad acting about a m...|0.66255826|\n", + "| I was shocked at how bad it was and unable to turn away from the disaster| 0.5871666|\n", + "|I don't know if this exceptionally dull movie was intended as an unofficial s...| 0.5578672|\n", + "|Greetings All,

Isn't it amazing the power that films have on you a...|0.56385136|\n", + "| I'm sorry but this guy is not funny| 0.5634932|\n", + "|This movie is so dull I spent half of it on IMDb while it was open in another...|0.58991694|\n", + "| OK, lets start with the best| 0.5795415|\n", + "|This show had a promising start as sort of the opposite of 'Oceans 11' but ha...|0.57494473|\n", + "|The 3rd in the series finds Paul Kersey (Bronson) turning vigilante to get re...| 0.6133918|\n", + "| I'm not sure I've ever seen a film as bad as this| 0.5336116|\n", + "| Steven Seagal has made a really dull, bad and boring movie|0.55780387|\n", + "| You have to acknowledge Cimino's contribution to cinema| 0.5763774|\n", + "|***SPOILER ALERT*** Disjointed and confusing arson drama that has to do with ...|0.56471467|\n", + "+--------------------------------------------------------------------------------+----------+\n", + "only showing top 20 rows\n", + "\n", + "CPU times: user 2.49 ms, sys: 1.47 ms, total: 3.96 ms\n", + "Wall time: 916 ms\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + } + ], + "source": [ + "%%time\n", + "df.withColumn(\"preds\", classify(struct(*columns))).show(truncate=80)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "b4fa7fc9-341c-49a6-9af2-e316f2355d67", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "+--------------------------------------------------------------------------------+----------+\n", + "| lines| preds|\n", + "+--------------------------------------------------------------------------------+----------+\n", + "|i do not understand at all why this movie received such good grades from crit...| 0.5380144|\n", + "| I am a big fan of The ABC Movies of the Week genre|0.59806347|\n", + "| Strangeland is a terrible horror/technological thriller|0.54900867|\n", + "|Sex,Drugs,Rock & Roll is without a doubt the worst product of Western Civiliz...|0.56048334|\n", + "| Not to be mistaken as the highly touted Samuel L|0.56276447|\n", + "|Following the pleasingly atmospheric original and the amusingly silly second ...| 0.5571853|\n", + "| No idea how this is rated as high as it is (5| 0.5637812|\n", + "|When I saw this in the cinema, I remember wincing at the bad acting about a m...|0.66255826|\n", + "| I was shocked at how bad it was and unable to turn away from the disaster| 0.5871666|\n", + "|I don't know if this exceptionally dull movie was intended as an unofficial s...| 0.5578672|\n", + "|Greetings All,

Isn't it amazing the power that films have on you a...|0.56385136|\n", + "| I'm sorry but this guy is not funny| 0.5634932|\n", + "|This movie is so dull I spent half of it on IMDb while it was open in another...|0.58991694|\n", + "| OK, lets start with the best| 0.5795415|\n", + "|This show had a promising start as sort of the opposite of 'Oceans 11' but ha...|0.57494473|\n", + "|The 3rd in the series finds Paul Kersey (Bronson) turning vigilante to get re...| 0.6133918|\n", + "| I'm not sure I've ever seen a film as bad as this| 0.5336116|\n", + "| Steven Seagal has made a really dull, bad and boring movie|0.55780387|\n", + "| You have to acknowledge Cimino's contribution to cinema| 0.5763774|\n", + "|***SPOILER ALERT*** Disjointed and confusing arson drama that has to do with ...|0.56471467|\n", + "+--------------------------------------------------------------------------------+----------+\n", + "only showing top 20 rows\n", + "\n", + "CPU times: user 571 μs, sys: 2.22 ms, total: 2.79 ms\n", + "Wall time: 528 ms\n" + ] + } + ], + "source": [ + "%%time\n", + "df.withColumn(\"preds\", classify(*columns)).show(truncate=80)" + ] + }, + { + "cell_type": "markdown", + "id": "d45e8981-ca44-429b-9b37-e04035c3a86b", + "metadata": { + "tags": [] + }, + "source": [ + "#### Stop Triton Server on each executor" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "a71ac9b6-47a2-4306-bc40-9ce7b4e968ec", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/plain": [ + "[True]" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def stop_triton(it):\n", + " import docker\n", + " import time\n", + " \n", + " client=docker.from_env()\n", + " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", + " print(\">>>> stopping containers: {}\".format([c.short_id for c in containers]))\n", + " if containers:\n", + " container=containers[0]\n", + " container.stop(timeout=120)\n", + "\n", + " return [True]\n", + "\n", + "nodeRDD.barrier().mapPartitions(stop_triton).collect()" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "54a90574-7cbb-487b-b7a8-dcda0e6e301f", + "metadata": {}, + "outputs": [], + "source": [ + "spark.stop()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88e3bfea-a825-46eb-b8c2-921a932c0089", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "spark-dl-tf", + "language": "python", + "name": "python3" + }, + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tf_requirements.txt b/examples/ML+DL-Examples/Spark-DL/dl_inference/tf_requirements.txt new file mode 100644 index 000000000..b78561bd8 --- /dev/null +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/tf_requirements.txt @@ -0,0 +1,3 @@ +-r requirements.txt +tensorflow[and-cuda] +tf-keras \ No newline at end of file diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/torch_requirements.txt b/examples/ML+DL-Examples/Spark-DL/dl_inference/torch_requirements.txt new file mode 100644 index 000000000..0f73b9105 --- /dev/null +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/torch_requirements.txt @@ -0,0 +1,8 @@ +-r requirements.txt +torch +torchvision +torch-tensorrt +tensorrt --extra-index-url https://download.pytorch.org/whl/cu121 +sentence_transformers +sentencepiece +nvidia-modelopt[all] --extra-index-url https://pypi.nvidia.com \ No newline at end of file From 4940bf8fb07c97ba08f52587ce6c924b2b10c00f Mon Sep 17 00:00:00 2001 From: "Rishi C." <77904151+rishic3@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:32:11 -0400 Subject: [PATCH 08/10] Fixes for CI/CD compatibility (#446) * Avoid hardcoding rapids jar install Signed-off-by: Rishi Chandra * Clarify README * Install jar if environment var is not set * Use unique timing cache path * regression timing cache * Delete duplicate notebook * Use github source links for tensorflow examples --------- Signed-off-by: Rishi Chandra --- .../Spark-DL/dl_inference/README.md | 6 +- .../pytorch/image_classification_torch.ipynb | 193 +- .../pytorch/regression_torch.ipynb | 32 +- .../tensorflow/image_classification.ipynb | 2460 ----------------- .../Spark-Rapids-ML/pca/README.md | 6 +- .../Spark-Rapids-ML/pca/notebooks/pca.ipynb | 9 +- 6 files changed, 143 insertions(+), 2563 deletions(-) delete mode 100644 examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification.ipynb diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/README.md b/examples/ML+DL-Examples/Spark-DL/dl_inference/README.md index 782db87c6..d704f2995 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/README.md +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/README.md @@ -37,10 +37,10 @@ Here is a full list of the notebooks with their published example links: | ------------- | ------------- | ------------- | ------------- | ------------- | 1 | PyTorch | Image Classification | Training a model to predict clothing categories in FashionMNIST, including accelerated inference with Torch-TensorRT. | [Link](https://pytorch.org/tutorials/beginner/basics/quickstart_tutorial.html) | 2 | PyTorch | Regression | Training a model to predict housing prices in the California Housing Dataset, including accelerated inference with Torch-TensorRT. | [Link](https://github.com/christianversloot/machine-learning-articles/blob/main/how-to-create-a-neural-network-for-regression-with-pytorch.md) -| 3 | Tensorflow | Image Classification | Training a model to predict hand-written digits in MNIST. | [Link](https://www.tensorflow.org/tutorials/keras/save_and_load) -| 4 | Tensorflow | Feature Columns | Training a model with preprocessing layers to predict likelihood of pet adoption in the PetFinder mini dataset. | [Link](https://www.tensorflow.org/tutorials/structured_data/preprocessing_layers) +| 3 | Tensorflow | Image Classification | Training a model to predict hand-written digits in MNIST. | [Link](https://github.com/tensorflow/docs/blob/master/site/en/tutorials/keras/save_and_load.ipynb) +| 4 | Tensorflow | Feature Columns | Training a model with preprocessing layers to predict likelihood of pet adoption in the PetFinder mini dataset. | [Link](https://github.com/tensorflow/docs/blob/master/site/en/tutorials/structured_data/preprocessing_layers.ipynb) | 5 | Tensorflow | Keras Metadata | Training ResNet-50 to perform flower recognition on Databricks. | [Link](https://docs.databricks.com/en/_extras/notebooks/source/deep-learning/keras-metadata.html) -| 6 | Tensorflow | Text Classification | Training a model to perform sentiment analysis on the IMDB dataset. | [Link](https://www.tensorflow.org/tutorials/keras/text_classification) +| 6 | Tensorflow | Text Classification | Training a model to perform sentiment analysis on the IMDB dataset. | [Link](https://github.com/tensorflow/docs/blob/master/site/en/tutorials/keras/text_classification.ipynb) | 7+8 | HuggingFace | Conditional Generation | Sentence translation using the T5 text-to-text transformer, with notebooks demoing both Torch and Tensorflow. | [Link](https://huggingface.co/docs/transformers/model_doc/t5#t5) | 9+10 | HuggingFace | Pipelines | Sentiment analysis using Huggingface pipelines, with notebooks demoing both Torch and Tensorflow. | [Link](https://huggingface.co/docs/transformers/quicktour#pipeline-usage) | 11 | HuggingFace | Sentence Transformers | Sentence embeddings using the SentenceTransformers framework in Torch. | [Link](https://huggingface.co/sentence-transformers) diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification_torch.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification_torch.ipynb index 47489dccb..ea07ce28a 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification_torch.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification_torch.ipynb @@ -263,78 +263,78 @@ "text": [ "Epoch 1\n", "-------------------------------\n", - "loss: 2.299719 [ 64/60000]\n", - "loss: 2.293332 [ 6464/60000]\n", - "loss: 2.269917 [12864/60000]\n", - "loss: 2.260744 [19264/60000]\n", - "loss: 2.247810 [25664/60000]\n", - "loss: 2.222256 [32064/60000]\n", - "loss: 2.225422 [38464/60000]\n", - "loss: 2.195026 [44864/60000]\n", - "loss: 2.194622 [51264/60000]\n", - "loss: 2.158175 [57664/60000]\n", + "loss: 2.301038 [ 64/60000]\n", + "loss: 2.289769 [ 6464/60000]\n", + "loss: 2.268618 [12864/60000]\n", + "loss: 2.264085 [19264/60000]\n", + "loss: 2.244277 [25664/60000]\n", + "loss: 2.209504 [32064/60000]\n", + "loss: 2.220515 [38464/60000]\n", + "loss: 2.185288 [44864/60000]\n", + "loss: 2.186121 [51264/60000]\n", + "loss: 2.149065 [57664/60000]\n", "Test Error: \n", - " Accuracy: 47.1%, Avg loss: 2.153042 \n", + " Accuracy: 37.8%, Avg loss: 2.151644 \n", "\n", "Epoch 2\n", "-------------------------------\n", - "loss: 2.162534 [ 64/60000]\n", - "loss: 2.154336 [ 6464/60000]\n", - "loss: 2.091042 [12864/60000]\n", - "loss: 2.104471 [19264/60000]\n", - "loss: 2.054451 [25664/60000]\n", - "loss: 2.001035 [32064/60000]\n", - "loss: 2.025180 [38464/60000]\n", - "loss: 1.949615 [44864/60000]\n", - "loss: 1.957106 [51264/60000]\n", - "loss: 1.876436 [57664/60000]\n", + "loss: 2.164946 [ 64/60000]\n", + "loss: 2.157853 [ 6464/60000]\n", + "loss: 2.100765 [12864/60000]\n", + "loss: 2.117897 [19264/60000]\n", + "loss: 2.058581 [25664/60000]\n", + "loss: 1.995217 [32064/60000]\n", + "loss: 2.026708 [38464/60000]\n", + "loss: 1.948186 [44864/60000]\n", + "loss: 1.959582 [51264/60000]\n", + "loss: 1.881658 [57664/60000]\n", "Test Error: \n", - " Accuracy: 54.6%, Avg loss: 1.876885 \n", + " Accuracy: 52.5%, Avg loss: 1.886264 \n", "\n", "Epoch 3\n", "-------------------------------\n", - "loss: 1.906243 [ 64/60000]\n", - "loss: 1.879715 [ 6464/60000]\n", - "loss: 1.758657 [12864/60000]\n", - "loss: 1.795318 [19264/60000]\n", - "loss: 1.692177 [25664/60000]\n", - "loss: 1.652430 [32064/60000]\n", - "loss: 1.669603 [38464/60000]\n", - "loss: 1.583420 [44864/60000]\n", - "loss: 1.603508 [51264/60000]\n", - "loss: 1.493881 [57664/60000]\n", + "loss: 1.922469 [ 64/60000]\n", + "loss: 1.893279 [ 6464/60000]\n", + "loss: 1.780482 [12864/60000]\n", + "loss: 1.822908 [19264/60000]\n", + "loss: 1.696129 [25664/60000]\n", + "loss: 1.653140 [32064/60000]\n", + "loss: 1.675662 [38464/60000]\n", + "loss: 1.584822 [44864/60000]\n", + "loss: 1.609127 [51264/60000]\n", + "loss: 1.500899 [57664/60000]\n", "Test Error: \n", - " Accuracy: 61.9%, Avg loss: 1.514976 \n", + " Accuracy: 60.3%, Avg loss: 1.521902 \n", "\n", "Epoch 4\n", "-------------------------------\n", - "loss: 1.573342 [ 64/60000]\n", - "loss: 1.548722 [ 6464/60000]\n", - "loss: 1.402007 [12864/60000]\n", - "loss: 1.461628 [19264/60000]\n", - "loss: 1.353920 [25664/60000]\n", - "loss: 1.358175 [32064/60000]\n", - "loss: 1.361608 [38464/60000]\n", - "loss: 1.302804 [44864/60000]\n", - "loss: 1.330850 [51264/60000]\n", - "loss: 1.224925 [57664/60000]\n", + "loss: 1.593910 [ 64/60000]\n", + "loss: 1.555975 [ 6464/60000]\n", + "loss: 1.412051 [12864/60000]\n", + "loss: 1.480928 [19264/60000]\n", + "loss: 1.348195 [25664/60000]\n", + "loss: 1.352939 [32064/60000]\n", + "loss: 1.361179 [38464/60000]\n", + "loss: 1.298819 [44864/60000]\n", + "loss: 1.325064 [51264/60000]\n", + "loss: 1.226879 [57664/60000]\n", "Test Error: \n", - " Accuracy: 63.8%, Avg loss: 1.254037 \n", + " Accuracy: 63.2%, Avg loss: 1.254962 \n", "\n", "Epoch 5\n", "-------------------------------\n", - "loss: 1.321162 [ 64/60000]\n", - "loss: 1.315946 [ 6464/60000]\n", - "loss: 1.152864 [12864/60000]\n", - "loss: 1.244943 [19264/60000]\n", - "loss: 1.130193 [25664/60000]\n", - "loss: 1.160290 [32064/60000]\n", - "loss: 1.168214 [38464/60000]\n", - "loss: 1.123758 [44864/60000]\n", - "loss: 1.158085 [51264/60000]\n", - "loss: 1.063427 [57664/60000]\n", + "loss: 1.337471 [ 64/60000]\n", + "loss: 1.314826 [ 6464/60000]\n", + "loss: 1.155245 [12864/60000]\n", + "loss: 1.257553 [19264/60000]\n", + "loss: 1.123370 [25664/60000]\n", + "loss: 1.155071 [32064/60000]\n", + "loss: 1.168100 [38464/60000]\n", + "loss: 1.119365 [44864/60000]\n", + "loss: 1.149572 [51264/60000]\n", + "loss: 1.067573 [57664/60000]\n", "Test Error: \n", - " Accuracy: 65.1%, Avg loss: 1.089330 \n", + " Accuracy: 64.4%, Avg loss: 1.090368 \n", "\n", "Done!\n" ] @@ -531,7 +531,32 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 24, + "id": "362b266b", + "metadata": {}, + "outputs": [], + "source": [ + "import torch_tensorrt as trt\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "f0ac1362", + "metadata": {}, + "outputs": [], + "source": [ + "# Optional: set the filename for the TensorRT timing cache\n", + "timestamp = time.time()\n", + "timing_cache = f\"/tmp/timing_cache-{timestamp}.bin\"\n", + "with open(timing_cache, \"wb\") as f:\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 20, "id": "f3e3bdc4", "metadata": {}, "outputs": [ @@ -539,10 +564,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "WARNING:torch_tensorrt.dynamo.conversion.aten_ops_converters:Unable to import quantization op. Please install modelopt library (https://github.com/NVIDIA/TensorRT-Model-Optimizer?tab=readme-ov-file#installation) to add support for compiling quantized models\n", "INFO:torch_tensorrt.dynamo.utils:Using Default Torch-TRT Runtime (as requested by user)\n", "INFO:torch_tensorrt.dynamo.utils:Device not specified, using Torch default current device - cuda:0. If this is incorrect, please specify an input device, via the device keyword.\n", - "INFO:torch_tensorrt.dynamo.utils:Compilation Settings: CompilationSettings(enabled_precisions={}, debug=False, workspace_size=0, min_block_size=5, torch_executed_ops=set(), pass_through_build_failures=False, max_aux_streams=None, version_compatible=False, optimization_level=None, use_python_runtime=False, truncate_double=False, use_fast_partitioner=True, enable_experimental_decompositions=False, device=Device(type=DeviceType.GPU, gpu_id=0), require_full_compilation=False, disable_tf32=False, assume_dynamic_shape_support=False, sparse_weights=False, refit=False, engine_capability=, num_avg_timing_iters=1, dla_sram_size=1048576, dla_local_dram_size=1073741824, dla_global_dram_size=536870912, dryrun=False, hardware_compatible=False, timing_cache_path='/tmp/timing_cache.bin')\n", + "INFO:torch_tensorrt.dynamo.utils:Compilation Settings: CompilationSettings(enabled_precisions={}, debug=False, workspace_size=0, min_block_size=5, torch_executed_ops=set(), pass_through_build_failures=False, max_aux_streams=None, version_compatible=False, optimization_level=None, use_python_runtime=False, truncate_double=False, use_fast_partitioner=True, enable_experimental_decompositions=False, device=Device(type=DeviceType.GPU, gpu_id=0), require_full_compilation=False, disable_tf32=False, assume_dynamic_shape_support=False, sparse_weights=False, refit=False, engine_capability=, num_avg_timing_iters=1, dla_sram_size=1048576, dla_local_dram_size=1073741824, dla_global_dram_size=536870912, dryrun=False, hardware_compatible=False, timing_cache_path='/tmp/timing_cache-1729187850.4862776.bin')\n", "\n", "WARNING:torch_tensorrt.dynamo._compiler:Node _param_constant1 of op type get_attr does not have metadata. This could sometimes lead to undefined behavior.\n", "WARNING:torch_tensorrt.dynamo._compiler:Some nodes do not have metadata (shape and dtype information). This could lead to problems sometimes if the graph has PyTorch and TensorRT segments.\n", @@ -552,23 +576,23 @@ "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch_tensorrt/dynamo/conversion/impl/activation/base.py:40: DeprecationWarning: Use Deprecated in TensorRT 10.1. Superseded by explicit quantization. instead.\n", " if input_val.dynamic_range is not None and dyn_range_fn is not None:\n", "\n", - "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT INetwork construction elapsed time: 0:00:00.005708\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT INetwork construction elapsed time: 0:00:00.005662\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Global timing cache in use. Profiling results in this builder pass will be stored.\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Detected 1 inputs and 1 output network tensors.\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Host Persistent Memory: 21984\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Device Persistent Memory: 0\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Scratch Memory: 0\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Started assigning block shifts. This will take 4 steps to complete.\n", - "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Algorithm ShiftNTopDown took 0.257559ms to assign 2 blocks to 4 nodes requiring 4096 bytes.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Algorithm ShiftNTopDown took 0.115746ms to assign 2 blocks to 4 nodes requiring 4096 bytes.\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Activation Memory: 4096\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Weights Memory: 2678824\n", - "INFO:torch_tensorrt [TensorRT Conversion Context]:Engine generation completed in 0.023755 seconds.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Engine generation completed in 1.58824 seconds.\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage of TRT CPU/GPU memory allocators: CPU 1 MiB, GPU 5 MiB\n", - "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage during Engine building and serialization: CPU: 3800 MiB\n", - "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:Build TRT engine elapsed time: 0:00:00.027501\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage during Engine building and serialization: CPU: 3950 MiB\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:Build TRT engine elapsed time: 0:00:01.591865\n", "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT Engine uses: 2832188 bytes of Memory\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 26 bytes of code generator cache.\n", - "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 176 timing cache entries\n" + "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 43 timing cache entries\n" ] }, { @@ -580,8 +604,6 @@ } ], "source": [ - "import torch_tensorrt as trt\n", - "\n", "inputs_bs1 = torch.randn((1, 784), dtype=torch.float).to(\"cuda\")\n", "# This indicates dimension 0 of inputs_bs1 is dynamic whose range of values is [1, 50]. No recompilation will happen when the batch size changes.\n", "torch._dynamo.mark_dynamic(inputs_bs1, 0, min=1, max=64)\n", @@ -590,6 +612,7 @@ " ir=\"torch_compile\",\n", " inputs=inputs_bs1,\n", " enabled_precisions={torch.float},\n", + " timing_cache_path=timing_cache,\n", ")\n", "\n", "stream = torch.cuda.Stream()\n", @@ -612,7 +635,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 21, "id": "6b8f1b45", "metadata": {}, "outputs": [ @@ -620,31 +643,31 @@ "name": "stderr", "output_type": "stream", "text": [ - "INFO:torch_tensorrt.dynamo._compiler:Compilation Settings: CompilationSettings(enabled_precisions={}, debug=False, workspace_size=0, min_block_size=5, torch_executed_ops=set(), pass_through_build_failures=False, max_aux_streams=None, version_compatible=False, optimization_level=None, use_python_runtime=False, truncate_double=False, use_fast_partitioner=True, enable_experimental_decompositions=False, device=Device(type=DeviceType.GPU, gpu_id=0), require_full_compilation=True, disable_tf32=False, assume_dynamic_shape_support=False, sparse_weights=False, refit=False, engine_capability=, num_avg_timing_iters=1, dla_sram_size=1048576, dla_local_dram_size=1073741824, dla_global_dram_size=536870912, dryrun=False, hardware_compatible=False, timing_cache_path='/tmp/timing_cache.bin')\n", + "INFO:torch_tensorrt.dynamo._compiler:Compilation Settings: CompilationSettings(enabled_precisions={}, debug=False, workspace_size=0, min_block_size=5, torch_executed_ops=set(), pass_through_build_failures=False, max_aux_streams=None, version_compatible=False, optimization_level=None, use_python_runtime=False, truncate_double=False, use_fast_partitioner=True, enable_experimental_decompositions=False, device=Device(type=DeviceType.GPU, gpu_id=0), require_full_compilation=True, disable_tf32=False, assume_dynamic_shape_support=False, sparse_weights=False, refit=False, engine_capability=, num_avg_timing_iters=1, dla_sram_size=1048576, dla_local_dram_size=1073741824, dla_global_dram_size=536870912, dryrun=False, hardware_compatible=False, timing_cache_path='/tmp/timing_cache-1729187850.4862776.bin')\n", "\n", "INFO:torch_tensorrt.dynamo._compiler:Partitioning the graph via the fast partitioner\n", - "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init CUDA: CPU +0, GPU +0, now: CPU 624, GPU 715 (MiB)\n", - "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init builder kernel library: CPU +1632, GPU +286, now: CPU 2256, GPU 1001 (MiB)\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init CUDA: CPU +0, GPU +0, now: CPU 758, GPU 715 (MiB)\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageChange] Init builder kernel library: CPU +1633, GPU +286, now: CPU 2391, GPU 1001 (MiB)\n", "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch_tensorrt/dynamo/conversion/impl/activation/base.py:40: DeprecationWarning: Use Deprecated in TensorRT 10.1. Superseded by explicit quantization. instead.\n", " if input_val.dynamic_range is not None and dyn_range_fn is not None:\n", "\n", - "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT INetwork construction elapsed time: 0:00:00.004551\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT INetwork construction elapsed time: 0:00:00.004664\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Global timing cache in use. Profiling results in this builder pass will be stored.\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Detected 1 inputs and 1 output network tensors.\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Host Persistent Memory: 21984\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Device Persistent Memory: 0\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Scratch Memory: 0\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Started assigning block shifts. This will take 4 steps to complete.\n", - "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Algorithm ShiftNTopDown took 0.133258ms to assign 2 blocks to 4 nodes requiring 4096 bytes.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[BlockAssignment] Algorithm ShiftNTopDown took 0.113766ms to assign 2 blocks to 4 nodes requiring 4096 bytes.\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Activation Memory: 4096\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Total Weights Memory: 2678824\n", - "INFO:torch_tensorrt [TensorRT Conversion Context]:Engine generation completed in 0.0190609 seconds.\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:Engine generation completed in 0.022595 seconds.\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage of TRT CPU/GPU memory allocators: CPU 1 MiB, GPU 5 MiB\n", - "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage during Engine building and serialization: CPU: 3818 MiB\n", - "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:Build TRT engine elapsed time: 0:00:00.021306\n", + "INFO:torch_tensorrt [TensorRT Conversion Context]:[MemUsageStats] Peak memory usage during Engine building and serialization: CPU: 3968 MiB\n", + "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:Build TRT engine elapsed time: 0:00:00.025016\n", "INFO:torch_tensorrt.dynamo.conversion._TRTInterpreter:TRT Engine uses: 2833124 bytes of Memory\n", "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 26 bytes of code generator cache.\n", - "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 176 timing cache entries\n" + "INFO:torch_tensorrt [TensorRT Conversion Context]:Serialized 43 timing cache entries\n" ] }, { @@ -662,7 +685,9 @@ "# Produce traced graph in the ExportedProgram format\n", "exp_program = trt.dynamo.trace(model_from_state, inputs)\n", "# Compile the traced graph to produce an optimized module\n", - "trt_gm = trt.dynamo.compile(exp_program, inputs=inputs, require_full_compilation=True)\n", + "trt_gm = trt.dynamo.compile(exp_program, \n", + " inputs=inputs, \n", + " timing_cache_path=timing_cache)\n", "\n", "stream = torch.cuda.Stream()\n", "with torch.no_grad(), torch.cuda.stream(stream):\n", @@ -681,22 +706,10 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 23, "id": "d87e4b20", "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch_tensorrt/dynamo/_exporter.py:364: UserWarning: Attempted to insert a get_attr Node with no underlying reference in the owning GraphModule! Call GraphModule.add_submodule to add the necessary submodule, GraphModule.add_parameter to add the necessary Parameter, or nn.Module.register_buffer to add the necessary buffer\n", - " engine_node = gm.graph.get_attr(engine_name)\n", - "\n", - "WARNING:py.warnings:/home/rishic/anaconda3/envs/spark-dl-torch/lib/python3.11/site-packages/torch/fx/graph.py:1545: UserWarning: Node _run_on_acc_0_engine target _run_on_acc_0_engine _run_on_acc_0_engine of does not reference an nn.Module, nn.Parameter, or buffer, which is what 'get_attr' Nodes typically target\n", - " warnings.warn(f'Node {node} target {node.target} {atom} of {seen_qualname} does '\n", - "\n" - ] - }, { "name": "stdout", "output_type": "stream", diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression_torch.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression_torch.ipynb index d2fd9157d..5ccc22ec2 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression_torch.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression_torch.ipynb @@ -539,6 +539,31 @@ "(You may see a warning about modelopt quantization. This is safe to ignore, as [implicit quantization](https://docs.nvidia.com/deeplearning/tensorrt/developer-guide/index.html#intro-quantization) is deprecated in the latest TensorRT. See [this link](https://pytorch.org/TensorRT/tutorials/_rendered_examples/dynamo/vgg16_fp8_ptq.html) for a guide to explicit quantization.)" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ffb27fc", + "metadata": {}, + "outputs": [], + "source": [ + "import torch_tensorrt as trt\n", + "import time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0c10f90", + "metadata": {}, + "outputs": [], + "source": [ + "# Optional: set the filename for the TensorRT timing cache\n", + "timestamp = time.time()\n", + "timing_cache = f\"/tmp/timing_cache-{timestamp}.bin\"\n", + "with open(timing_cache, \"wb\") as f:\n", + " pass" + ] + }, { "cell_type": "code", "execution_count": 20, @@ -599,8 +624,6 @@ } ], "source": [ - "import torch_tensorrt as trt\n", - "\n", "inputs_bs1 = torch.randn((10, 8), dtype=torch.float).to(\"cuda\")\n", "# This indicates dimension 0 of inputs_bs1 is dynamic whose range of values is [1, 50]. No recompilation will happen when the batch size changes.\n", "torch._dynamo.mark_dynamic(inputs_bs1, 0, min=1, max=50)\n", @@ -609,6 +632,7 @@ " ir=\"torch_compile\",\n", " inputs=inputs_bs1,\n", " enabled_precisions={torch.float},\n", + " timing_cache_path=timing_cache,\n", ")\n", "\n", "stream = torch.cuda.Stream()\n", @@ -719,7 +743,9 @@ "# Produce traced graph in the ExportedProgram format\n", "exp_program = trt.dynamo.trace(loaded_mlp, inputs)\n", "# Compile the traced graph to produce an optimized module\n", - "trt_gm = trt.dynamo.compile(exp_program, inputs=inputs, device='cuda:0')\n", + "trt_gm = trt.dynamo.compile(exp_program,\n", + " inputs=inputs,\n", + " timing_cache_path=timing_cache)\n", "\n", "stream = torch.cuda.Stream()\n", "with torch.no_grad(), torch.cuda.stream(stream):\n", diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification.ipynb deleted file mode 100644 index 5add2686b..000000000 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification.ipynb +++ /dev/null @@ -1,2460 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "52d55e3f", - "metadata": {}, - "source": [ - "# Pyspark TensorFlow Inference\n", - "\n", - "## Image classification\n", - "Based on: https://www.tensorflow.org/tutorials/keras/save_and_load" - ] - }, - { - "cell_type": "markdown", - "id": "5233632d", - "metadata": {}, - "source": [ - "### Using TensorFlow\n", - "Note that cuFFT/cuDNN/cuBLAS registration errors are expected with `tf=2.17.0` and will not affect behavior, as noted in [this issue.](https://github.com/tensorflow/tensorflow/issues/62075) \n", - "This notebook does not demonstrate inference with TensorRT, as [TF-TRT](https://docs.nvidia.com/deeplearning/tensorrt/release-notes/index.html#tensorrt-10) does not yet support `tf=2.17.0`. See the `pytorch` notebooks for TensorRT demos." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "c8b28f02", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-10-03 17:40:20.324462: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", - "2024-10-03 17:40:20.331437: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", - "2024-10-03 17:40:20.339109: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", - "2024-10-03 17:40:20.341362: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", - "2024-10-03 17:40:20.347337: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", - "To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", - "2024-10-03 17:40:20.672391: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2.17.0\n" - ] - } - ], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import subprocess\n", - "import tensorflow as tf\n", - "import os\n", - "\n", - "from tensorflow import keras\n", - "\n", - "print(tf.version.VERSION)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "e2e67086", - "metadata": {}, - "outputs": [], - "source": [ - "# Enable GPU memory growth\n", - "gpus = tf.config.experimental.list_physical_devices('GPU')\n", - "if gpus:\n", - " try:\n", - " for gpu in gpus:\n", - " tf.config.experimental.set_memory_growth(gpu, True)\n", - " except RuntimeError as e:\n", - " print(e)" - ] - }, - { - "cell_type": "markdown", - "id": "7e0c7ad6", - "metadata": {}, - "source": [ - "### Load and preprocess dataset" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "5b007f7c", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[1m11490434/11490434\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n" - ] - }, - { - "data": { - "text/plain": [ - "((60000, 28, 28), (10000, 28, 28))" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# load dataset as numpy arrays\n", - "(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()\n", - "train_images.shape, test_images.shape" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "7b7cedd1", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "((1000, 784), (1000, 784))" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "train_labels = train_labels[:1000]\n", - "test_labels = test_labels[:1000]\n", - "\n", - "train_images = train_images[:1000].reshape(-1, 28 * 28) / 255.0\n", - "test_images = test_images[:1000].reshape(-1, 28 * 28) / 255.0\n", - "\n", - "train_images.shape, test_images.shape" - ] - }, - { - "cell_type": "markdown", - "id": "867a4403", - "metadata": {}, - "source": [ - "### Define a model" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "746d94db", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/rishic/anaconda3/envs/spark-dl-tf/lib/python3.11/site-packages/keras/src/layers/core/dense.py:87: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.\n", - " super().__init__(activity_regularizer=activity_regularizer, **kwargs)\n", - "2024-10-03 17:40:21.624052: I tensorflow/core/common_runtime/gpu/gpu_device.cc:2021] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 45743 MB memory: -> device: 0, name: NVIDIA RTX A6000, pci bus id: 0000:01:00.0, compute capability: 8.6\n" - ] - }, - { - "data": { - "text/html": [ - "
Model: \"sequential\"\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[1mModel: \"sequential\"\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
-       "┃ Layer (type)                     Output Shape                  Param # ┃\n",
-       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
-       "│ dense (Dense)                   │ (None, 512)            │       401,920 │\n",
-       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
-       "│ dropout (Dropout)               │ (None, 512)            │             0 │\n",
-       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
-       "│ dense_1 (Dense)                 │ (None, 10)             │         5,130 │\n",
-       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
-       "
\n" - ], - "text/plain": [ - "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", - "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", - "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", - "│ dense (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m512\u001b[0m) │ \u001b[38;5;34m401,920\u001b[0m │\n", - "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", - "│ dropout (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m512\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", - "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", - "│ dense_1 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m10\u001b[0m) │ \u001b[38;5;34m5,130\u001b[0m │\n", - "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
 Total params: 407,050 (1.55 MB)\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m407,050\u001b[0m (1.55 MB)\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
 Trainable params: 407,050 (1.55 MB)\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m407,050\u001b[0m (1.55 MB)\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
 Non-trainable params: 0 (0.00 B)\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Define a simple sequential model\n", - "def create_model():\n", - " model = tf.keras.Sequential([\n", - " keras.layers.Dense(512, activation='relu', input_shape=(784,)),\n", - " keras.layers.Dropout(0.2),\n", - " keras.layers.Dense(10)\n", - " ])\n", - "\n", - " model.compile(optimizer='adam',\n", - " loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n", - " metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])\n", - "\n", - " return model\n", - "\n", - "# Create a basic model instance\n", - "model = create_model()\n", - "\n", - "# Display the model's architecture\n", - "model.summary()" - ] - }, - { - "cell_type": "markdown", - "id": "605d082a", - "metadata": {}, - "source": [ - "### Save checkpoints during training" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "244746be", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 1/10\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n", - "I0000 00:00:1727977222.161202 1835280 service.cc:146] XLA service 0x7ec778008e00 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:\n", - "I0000 00:00:1727977222.161216 1835280 service.cc:154] StreamExecutor device (0): NVIDIA RTX A6000, Compute Capability 8.6\n", - "2024-10-03 17:40:22.168848: I tensorflow/compiler/mlir/tensorflow/utils/dump_mlir_util.cc:268] disabling MLIR crash reproducer, set env var `MLIR_CRASH_REPRODUCER_DIRECTORY` to enable.\n", - "2024-10-03 17:40:22.206298: I external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:531] Loaded cuDNN version 8907\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m24s\u001b[0m 778ms/step - loss: 2.3278 - sparse_categorical_accuracy: 0.1250" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "I0000 00:00:1727977222.715572 1835280 device_compiler.h:188] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 17ms/step - loss: 1.5867 - sparse_categorical_accuracy: 0.5096 " - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-10-03 17:40:23.780912: I external/local_xla/xla/stream_executor/cuda/cuda_asm_compiler.cc:393] ptxas warning : Registers are spilled to local memory in function 'gemm_fusion_dot_33', 4 bytes spill stores, 4 bytes spill loads\n", - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Epoch 1: val_sparse_categorical_accuracy improved from -inf to 0.78700, saving model to training_1/checkpoint.model.keras\n", - "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m2s\u001b[0m 44ms/step - loss: 1.5733 - sparse_categorical_accuracy: 0.5144 - val_loss: 0.7061 - val_sparse_categorical_accuracy: 0.7870\n", - "Epoch 2/10\n", - "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - loss: 0.5514 - sparse_categorical_accuracy: 0.8438\n", - "Epoch 2: val_sparse_categorical_accuracy improved from 0.78700 to 0.83700, saving model to training_1/checkpoint.model.keras\n", - "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 2ms/step - loss: 0.4276 - sparse_categorical_accuracy: 0.8935 - val_loss: 0.5268 - val_sparse_categorical_accuracy: 0.8370\n", - "Epoch 3/10\n", - "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 20ms/step - loss: 0.1458 - sparse_categorical_accuracy: 0.9688\n", - "Epoch 3: val_sparse_categorical_accuracy improved from 0.83700 to 0.85600, saving model to training_1/checkpoint.model.keras\n", - "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.2721 - sparse_categorical_accuracy: 0.9236 - val_loss: 0.4716 - val_sparse_categorical_accuracy: 0.8560\n", - "Epoch 4/10\n", - "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - loss: 0.2223 - sparse_categorical_accuracy: 0.9375\n", - "Epoch 4: val_sparse_categorical_accuracy did not improve from 0.85600\n", - "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.2159 - sparse_categorical_accuracy: 0.9547 - val_loss: 0.4682 - val_sparse_categorical_accuracy: 0.8540\n", - "Epoch 5/10\n", - "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 16ms/step - loss: 0.1483 - sparse_categorical_accuracy: 0.9688\n", - "Epoch 5: val_sparse_categorical_accuracy improved from 0.85600 to 0.86900, saving model to training_1/checkpoint.model.keras\n", - "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 2ms/step - loss: 0.1457 - sparse_categorical_accuracy: 0.9716 - val_loss: 0.4285 - val_sparse_categorical_accuracy: 0.8690\n", - "Epoch 6/10\n", - "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - loss: 0.0836 - sparse_categorical_accuracy: 0.9688\n", - "Epoch 6: val_sparse_categorical_accuracy did not improve from 0.86900\n", - "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.1292 - sparse_categorical_accuracy: 0.9712 - val_loss: 0.4551 - val_sparse_categorical_accuracy: 0.8580\n", - "Epoch 7/10\n", - "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 12ms/step - loss: 0.0920 - sparse_categorical_accuracy: 0.9688\n", - "Epoch 7: val_sparse_categorical_accuracy did not improve from 0.86900\n", - "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.0974 - sparse_categorical_accuracy: 0.9822 - val_loss: 0.4016 - val_sparse_categorical_accuracy: 0.8670\n", - "Epoch 8/10\n", - "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 12ms/step - loss: 0.0993 - sparse_categorical_accuracy: 0.9688\n", - "Epoch 8: val_sparse_categorical_accuracy did not improve from 0.86900\n", - "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.0702 - sparse_categorical_accuracy: 0.9920 - val_loss: 0.3999 - val_sparse_categorical_accuracy: 0.8650\n", - "Epoch 9/10\n", - "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 12ms/step - loss: 0.0599 - sparse_categorical_accuracy: 1.0000\n", - "Epoch 9: val_sparse_categorical_accuracy improved from 0.86900 to 0.87800, saving model to training_1/checkpoint.model.keras\n", - "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.0457 - sparse_categorical_accuracy: 0.9974 - val_loss: 0.4145 - val_sparse_categorical_accuracy: 0.8780\n", - "Epoch 10/10\n", - "\u001b[1m 1/32\u001b[0m \u001b[37m━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m0s\u001b[0m 13ms/step - loss: 0.0286 - sparse_categorical_accuracy: 1.0000\n", - "Epoch 10: val_sparse_categorical_accuracy did not improve from 0.87800\n", - "\u001b[1m32/32\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1ms/step - loss: 0.0351 - sparse_categorical_accuracy: 0.9987 - val_loss: 0.4200 - val_sparse_categorical_accuracy: 0.8720\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "checkpoint_path = \"training_1/checkpoint.model.keras\"\n", - "checkpoint_dir = os.path.dirname(checkpoint_path)\n", - "\n", - "# Create a callback that saves the model's weights\n", - "cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,\n", - " monitor='val_sparse_categorical_accuracy',\n", - " mode='max',\n", - " save_best_only=True,\n", - " verbose=1)\n", - "\n", - "# Train the model with the new callback\n", - "model.fit(train_images, \n", - " train_labels, \n", - " epochs=10,\n", - " validation_data=(test_images, test_labels),\n", - " callbacks=[cp_callback]) # Pass callback to training\n", - "\n", - "# This may generate warnings related to saving the state of the optimizer.\n", - "# These warnings (and similar warnings throughout this notebook)\n", - "# are in place to discourage outdated usage, and can be ignored." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "310eae08", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['checkpoint.model.keras']" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "os.listdir(checkpoint_dir)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "50eeb6e5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "INFO:tensorflow:Assets written to: mnist_model/assets\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:tensorflow:Assets written to: mnist_model/assets\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Saved artifact at 'mnist_model'. The following endpoints are available:\n", - "\n", - "* Endpoint 'serve'\n", - " args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 784), dtype=tf.float32, name='keras_tensor')\n", - "Output Type:\n", - " TensorSpec(shape=(None, 10), dtype=tf.float32, name=None)\n", - "Captures:\n", - " 139403584120848: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", - " 139403240100240: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", - " 139403240100048: TensorSpec(shape=(), dtype=tf.resource, name=None)\n", - " 139403240099856: TensorSpec(shape=(), dtype=tf.resource, name=None)\n" - ] - } - ], - "source": [ - "# Export model in saved_model format\n", - "model.export(\"mnist_model\")" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "6d3bba9e", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/rishic/anaconda3/envs/spark-dl-tf/lib/python3.11/site-packages/keras/src/layers/core/dense.py:87: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.\n", - " super().__init__(activity_regularizer=activity_regularizer, **kwargs)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "32/32 - 0s - 10ms/step - loss: 2.4196 - sparse_categorical_accuracy: 0.0590\n", - "Untrained model, accuracy: 5.90%\n" - ] - } - ], - "source": [ - "# Create a basic model instance\n", - "model = create_model()\n", - "\n", - "# Evaluate the model\n", - "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", - "print(\"Untrained model, accuracy: {:5.2f}%\".format(100 * acc))" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "22ad1708", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "32/32 - 0s - 713us/step - loss: 0.4145 - sparse_categorical_accuracy: 0.8780\n", - "Restored model, accuracy: 87.80%\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/rishic/anaconda3/envs/spark-dl-tf/lib/python3.11/site-packages/keras/src/saving/saving_lib.py:713: UserWarning: Skipping variable loading for optimizer 'adam', because it has 2 variables whereas the saved optimizer has 10 variables. \n", - " saveable.load_own_variables(weights_store.get(inner_path))\n" - ] - } - ], - "source": [ - "# Load the weights from the checkpoint\n", - "model.load_weights(checkpoint_path)\n", - "\n", - "# Re-evaluate the model\n", - "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", - "print(\"Restored model, accuracy: {:5.2f}%\".format(100 * acc))" - ] - }, - { - "cell_type": "markdown", - "id": "1c097d63", - "metadata": {}, - "source": [ - "### Checkpoint callback options" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "cb336e89", - "metadata": {}, - "outputs": [], - "source": [ - "!rm -rf training_2\n", - "!mkdir training_2" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "750b6deb", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Epoch 5: saving model to training_2/cp-0005.weights.h5\n", - "\n", - "Epoch 10: saving model to training_2/cp-0010.weights.h5\n", - "\n", - "Epoch 15: saving model to training_2/cp-0015.weights.h5\n", - "\n", - "Epoch 20: saving model to training_2/cp-0020.weights.h5\n", - "\n", - "Epoch 25: saving model to training_2/cp-0025.weights.h5\n", - "\n", - "Epoch 30: saving model to training_2/cp-0030.weights.h5\n", - "\n", - "Epoch 35: saving model to training_2/cp-0035.weights.h5\n", - "\n", - "Epoch 40: saving model to training_2/cp-0040.weights.h5\n", - "\n", - "Epoch 45: saving model to training_2/cp-0045.weights.h5\n", - "\n", - "Epoch 50: saving model to training_2/cp-0050.weights.h5\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Include the epoch in the file name (uses `str.format`)\n", - "checkpoint_path = \"training_2/cp-{epoch:04d}.weights.h5\"\n", - "checkpoint_dir = os.path.dirname(checkpoint_path)\n", - "\n", - "batch_size = 32\n", - "\n", - "# Calculate the number of batches per epoch\n", - "import math\n", - "n_batches = len(train_images) / batch_size\n", - "n_batches = math.ceil(n_batches) # round up the number of batches to the nearest whole integer\n", - "\n", - "# Create a callback that saves the model's weights every 5 epochs\n", - "cp_callback = tf.keras.callbacks.ModelCheckpoint(\n", - " filepath=checkpoint_path, \n", - " verbose=1, \n", - " save_weights_only=True,\n", - " save_freq=5*n_batches)\n", - "\n", - "# Create a new model instance\n", - "model = create_model()\n", - "\n", - "# Save the weights using the `checkpoint_path` format\n", - "model.save_weights(checkpoint_path.format(epoch=0))\n", - "\n", - "# Train the model with the new callback\n", - "model.fit(train_images, \n", - " train_labels,\n", - " epochs=50, \n", - " batch_size=batch_size, \n", - " callbacks=[cp_callback],\n", - " validation_data=(test_images, test_labels),\n", - " verbose=0)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "1c43fd3d", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['cp-0000.weights.h5',\n", - " 'cp-0015.weights.h5',\n", - " 'cp-0010.weights.h5',\n", - " 'cp-0035.weights.h5',\n", - " 'cp-0020.weights.h5',\n", - " 'cp-0040.weights.h5',\n", - " 'cp-0050.weights.h5',\n", - " 'cp-0005.weights.h5',\n", - " 'cp-0045.weights.h5',\n", - " 'cp-0025.weights.h5',\n", - " 'cp-0030.weights.h5']" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "os.listdir(checkpoint_dir)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "0d7ae715", - "metadata": {}, - "outputs": [], - "source": [ - "latest = \"training_2/cp-0030.weights.h5\"" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "d345c6f7", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "32/32 - 0s - 9ms/step - loss: 0.4501 - sparse_categorical_accuracy: 0.8720\n", - "Restored model, accuracy: 87.20%\n" - ] - } - ], - "source": [ - "# Create a new model instance\n", - "model = create_model()\n", - "\n", - "# Load the previously saved weights\n", - "model.load_weights(latest)\n", - "\n", - "# Re-evaluate the model from the latest checkpoint\n", - "loss, acc = model.evaluate(test_images, test_labels, verbose=2)\n", - "print(\"Restored model, accuracy: {:5.2f}%\".format(100 * acc))" - ] - }, - { - "cell_type": "markdown", - "id": "a86f4700", - "metadata": {}, - "source": [ - "## PySpark" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "7fcf07bb", - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "from pyspark.sql import SparkSession\n", - "from pyspark import SparkConf" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c022c24", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "conda_env = os.environ.get(\"CONDA_PREFIX\")\n", - "\n", - "conf = SparkConf()\n", - "if 'spark' not in globals():\n", - " # If Spark is not already started with Jupyter, attach to Spark Standalone\n", - " import socket\n", - " hostname = socket.gethostname()\n", - " conf.setMaster(f\"spark://{hostname}:7077\") # assuming Master is on default port 7077\n", - "conf.set(\"spark.task.maxFailures\", \"1\")\n", - "conf.set(\"spark.driver.memory\", \"8g\")\n", - "conf.set(\"spark.executor.memory\", \"8g\")\n", - "conf.set(\"spark.pyspark.python\", f\"{conda_env}/bin/python\")\n", - "conf.set(\"spark.pyspark.driver.python\", f\"{conda_env}/bin/python\")\n", - "conf.set(\"spark.sql.execution.pyspark.udf.simplifiedTraceback.enabled\", \"false\")\n", - "conf.set(\"spark.sql.pyspark.jvmStacktrace.enabled\", \"true\")\n", - "conf.set(\"spark.sql.execution.arrow.pyspark.enabled\", \"true\")\n", - "conf.set(\"spark.python.worker.reuse\", \"true\")\n", - "# Create Spark Session\n", - "spark = SparkSession.builder.appName(\"spark-dl-examples\").config(conf=conf).getOrCreate()\n", - "sc = spark.sparkContext" - ] - }, - { - "cell_type": "markdown", - "id": "c81d0b1b", - "metadata": {}, - "source": [ - "### Convert numpy array to Spark DataFrame (via Pandas DataFrame)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "49ff5203", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(1000, 784)" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# numpy array to pandas DataFrame\n", - "test_pdf = pd.DataFrame(test_images)\n", - "test_pdf.shape" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "182ee0c7", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 134 ms, sys: 15.5 ms, total: 149 ms\n", - "Wall time: 1.36 s\n" - ] - } - ], - "source": [ - "%%time\n", - "df = spark.createDataFrame(test_pdf).repartition(8)" - ] - }, - { - "cell_type": "markdown", - "id": "d4e1c7ec-64fa-43c4-9bcf-0868a401d1f2", - "metadata": {}, - "source": [ - "### Save as Parquet (784 columns of float)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "0061c39a-0871-429e-a4ff-751d26bf4b04", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "24/10/03 17:40:32 WARN SparkStringUtils: Truncated the string representation of a plan since it was too large. This behavior can be adjusted by setting 'spark.sql.debug.maxToStringFields'.\n", - "[Stage 0:> (0 + 8) / 8]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 2.49 ms, sys: 1.65 ms, total: 4.13 ms\n", - "Wall time: 1.66 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "%%time\n", - "df.write.mode(\"overwrite\").parquet(\"mnist_784\")" - ] - }, - { - "cell_type": "markdown", - "id": "18315afb-3fa2-4953-9297-52c04dd70c32", - "metadata": {}, - "source": [ - "### Save as Parquet (1 column of 784 float)" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "id": "302c73ec", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 6.71 ms, sys: 4.92 ms, total: 11.6 ms\n", - "Wall time: 11.4 ms\n" - ] - }, - { - "data": { - "text/plain": [ - "(1000, 1)" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "test_pdf['data'] = test_pdf.values.tolist()\n", - "pdf = test_pdf[['data']]\n", - "pdf.shape" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "5495901b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 46.6 ms, sys: 4.71 ms, total: 51.3 ms\n", - "Wall time: 91.7 ms\n" - ] - } - ], - "source": [ - "%%time\n", - "df = spark.createDataFrame(pdf)" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "5fa7faa8-c6bd-41b0-b5f7-fb121f0332e6", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 807 μs, sys: 724 μs, total: 1.53 ms\n", - "Wall time: 211 ms\n" - ] - } - ], - "source": [ - "%%time\n", - "df.write.mode(\"overwrite\").parquet(\"mnist_1\")" - ] - }, - { - "cell_type": "markdown", - "id": "c87b444e", - "metadata": {}, - "source": [ - "### Check arrow memory configuration" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "3d4ca414", - "metadata": {}, - "outputs": [], - "source": [ - "spark.conf.set(\"spark.sql.execution.arrow.maxRecordsPerBatch\", \"128\")\n", - "# This line will fail if the vectorized reader runs out of memory\n", - "assert len(df.head()) > 0, \"`df` should not be empty\" " - ] - }, - { - "cell_type": "markdown", - "id": "9b6dde30-98a9-45db-ab3a-d4546f9bed99", - "metadata": {}, - "source": [ - "## Inference using Spark DL API" - ] - }, - { - "cell_type": "markdown", - "id": "4238fb28-d002-4b4d-9aa1-8af1fbd5d569", - "metadata": {}, - "source": [ - "### 1 column of 784 float" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "id": "db30fba6-24d0-4c00-8502-04f9b10e7e16", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import os\n", - "import pandas as pd\n", - "\n", - "from pyspark.ml.functions import predict_batch_udf\n", - "from pyspark.sql.functions import array, col, struct\n", - "from pyspark.sql.types import ArrayType, FloatType, Union, Dict" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "b9cf62f8-96b2-4716-80bd-bb93d5f939bd", - "metadata": {}, - "outputs": [], - "source": [ - "# get absolute path to model\n", - "model_dir = \"{}/training_1/checkpoint.model.keras\".format(os.getcwd())" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "id": "b81fa297-d9d0-4600-880d-dbdcdf8bccc6", - "metadata": {}, - "outputs": [], - "source": [ - "def predict_batch_fn():\n", - " import tensorflow as tf\n", - "\n", - " # Enable GPU memory growth to avoid CUDA OOM\n", - " gpus = tf.config.experimental.list_physical_devices('GPU')\n", - " if gpus:\n", - " try:\n", - " for gpu in gpus:\n", - " tf.config.experimental.set_memory_growth(gpu, True)\n", - " except RuntimeError as e:\n", - " print(e)\n", - "\n", - " model = tf.keras.models.load_model(model_dir)\n", - " def predict(inputs: np.ndarray) -> np.ndarray:\n", - " return model.predict(inputs)\n", - " \n", - " return predict" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "72a689bd-dd82-492e-8740-1738a215325f", - "metadata": {}, - "outputs": [], - "source": [ - "mnist = predict_batch_udf(predict_batch_fn,\n", - " return_type=ArrayType(FloatType()),\n", - " batch_size=1024,\n", - " input_tensor_shapes=[[784]])" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "id": "60a70150-26b1-4145-9e7d-6e17389216b7", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = spark.read.parquet(\"mnist_1\")\n", - "len(df.columns)" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "id": "e027f0d2-0f65-47b7-a562-2f0965faceec", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "+--------------------+\n", - "| data|\n", - "+--------------------+\n", - "|[0.0, 0.0, 0.0, 0...|\n", - "|[0.0, 0.0, 0.0, 0...|\n", - "|[0.0, 0.0, 0.0, 0...|\n", - "|[0.0, 0.0, 0.0, 0...|\n", - "|[0.0, 0.0, 0.0, 0...|\n", - "+--------------------+\n", - "only showing top 5 rows\n", - "\n" - ] - } - ], - "source": [ - "df.show(5)" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "id": "f0c3fb2e-469e-47bc-b948-8f6b0d7f6513", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 4:===================================================> (7 + 1) / 8]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 18.5 ms, sys: 13.3 ms, total: 31.8 ms\n", - "Wall time: 5.03 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "%%time\n", - "# first pass caches model/fn\n", - "preds = df.withColumn(\"preds\", mnist(struct(df.columns))).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "id": "cdfa229a-f4a9-4c11-a410-de4a21c02c82", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 37.3 ms, sys: 12.4 ms, total: 49.8 ms\n", - "Wall time: 259 ms\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", mnist(*df.columns)).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "id": "5586ce49-6f93-4343-9b66-0dbb64972179", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 22.9 ms, sys: 5.96 ms, total: 28.8 ms\n", - "Wall time: 237 ms\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", mnist(*[col(c) for c in df.columns])).collect()" - ] - }, - { - "cell_type": "markdown", - "id": "004f1599-3c62-499e-9fd8-ed5cb0c90de4", - "metadata": { - "tags": [] - }, - "source": [ - "#### Check predictions" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "id": "4f947dc0-6b18-4605-810b-e83250a161db", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "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", - "
datapreds
0[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-5.88436, -3.1058547, 0.10873719, 12.67319, -...
1[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-3.273286, -8.362554, 1.8936121, -3.8881433, ...
2[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-3.3856308, 0.6785604, 1.3146863, 0.9275978, ...
3[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-2.7754688, -7.3659225, 11.768427, 1.3434286,...
4[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-4.9426627, 4.0774136, -0.4529277, -0.9312789...
5[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-5.226616, -3.1389174, 2.6100307, 3.695045, -...
6[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-4.3006196, 5.1169925, 0.5850615, -0.76248693...
7[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-2.3985956, -1.4814724, -4.884057, -0.2391600...
8[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[0.82160115, -2.8640625, -1.6951559, -4.489290...
9[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-1.2338604, -2.151981, -4.171742, 1.6106845, ...
\n", - "
" - ], - "text/plain": [ - " data \\\n", - "0 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "1 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "2 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "3 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "4 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "5 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "6 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "7 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "8 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "9 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "\n", - " preds \n", - "0 [-5.88436, -3.1058547, 0.10873719, 12.67319, -... \n", - "1 [-3.273286, -8.362554, 1.8936121, -3.8881433, ... \n", - "2 [-3.3856308, 0.6785604, 1.3146863, 0.9275978, ... \n", - "3 [-2.7754688, -7.3659225, 11.768427, 1.3434286,... \n", - "4 [-4.9426627, 4.0774136, -0.4529277, -0.9312789... \n", - "5 [-5.226616, -3.1389174, 2.6100307, 3.695045, -... \n", - "6 [-4.3006196, 5.1169925, 0.5850615, -0.76248693... \n", - "7 [-2.3985956, -1.4814724, -4.884057, -0.2391600... \n", - "8 [0.82160115, -2.8640625, -1.6951559, -4.489290... \n", - "9 [-1.2338604, -2.151981, -4.171742, 1.6106845, ... " - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "preds = df.withColumn(\"preds\", mnist(*df.columns)).limit(10).toPandas()\n", - "preds" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "id": "de4964e0-d1f8-4753-afa1-a8f95ca3f151", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ -5.88436 , -3.1058547 , 0.10873719, 12.67319 ,\n", - " -5.143787 , 4.0859914 , -10.203137 , -1.4333997 ,\n", - " -3.3865087 , -3.8473575 ], dtype=float32)" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sample = preds.iloc[0]\n", - "sample.preds" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "id": "44e9a874-e301-4b72-8df7-bf1c5133c287", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "id": "c60e5af4-fc1e-4575-a717-f304664235be", - "metadata": {}, - "outputs": [], - "source": [ - "prediction = np.argmax(sample.preds)\n", - "img = np.array(sample.data).reshape(28,28)" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "id": "eb45ecc9-d376-40c4-ad7b-2bd08ca5aaf6", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGzCAYAAABpdMNsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAkfElEQVR4nO3dfXQUdZ7v8U/nqSEkaR7yLAFCFHRAcAYly/AgSiQEZUCYGUG9F7gziJiggI6KR0Udzsksrg7qIHjcHVhHEGWOyMoiDg9JGBRwwTCIM2QhJ0g4kIBcSYcAIaR/9w+uvbQkQDUdfkl4v86pc+iq37fqm6Lgk+qqrnYZY4wAALjKwmw3AAC4NhFAAAArCCAAgBUEEADACgIIAGAFAQQAsIIAAgBYQQABAKwggAAAVhBAgAPdunXTpEmT/K8LCwvlcrlUWFgYsm24XC698MILIVsf0FwRQGgxlixZIpfL5Z/atGmjHj16KC8vT5WVlbbbc2TNmjUtJmTefvtt3X777UpKSpLb7VZ6eromT56s/fv3224NLVyE7QYAp1566SWlp6fr9OnT2rx5sxYuXKg1a9Zo9+7dio6Ovqq9DBkyRKdOnVJUVJSjujVr1mjBggUNhtCpU6cUEdF8/mkWFxcrPT1dP/vZz9ShQweVlZXp7bff1urVq/W3v/1NqamptltEC9V8jnLgMuXk5OjWW2+VJP36179Wp06d9Oqrr2rVqlWaMGFCgzU1NTVq165dyHsJCwtTmzZtQrrOUK/vSr355psXzBszZoxuvfVWvfPOO3r66actdIXWgLfg0OLdeeedkqSysjJJ0qRJkxQTE6PS0lKNHDlSsbGxeuCBByRJPp9P8+fPV69evdSmTRslJSVp6tSp+u677wLWaYzR3Llz1blzZ0VHR+uOO+7Q119/fcG2G7sGtG3bNo0cOVIdOnRQu3bt1KdPH7322mv+/hYsWCBJAW8pfq+ha0DFxcXKyclRXFycYmJiNGzYMG3dujVgzPdvUX722WeaNWuWEhIS1K5dO9177706evRowNiqqirt2bNHVVVVl7OLL9CtWzdJ0vHjx4OqByTOgNAKlJaWSpI6derkn3f27FllZ2dr0KBB+pd/+Rf/W3NTp07VkiVLNHnyZD366KMqKyvTH/7wBxUXF+uzzz5TZGSkJOn555/X3LlzNXLkSI0cOVJffvmlhg8frjNnzlyyn3Xr1umee+5RSkqKHnvsMSUnJ+sf//iHVq9erccee0xTp07VoUOHtG7dOv3pT3+65Pq+/vprDR48WHFxcXryyScVGRmpt956S0OHDlVRUZEyMzMDxk+fPl0dOnTQnDlztH//fs2fP195eXl6//33/WNWrlypyZMna/HixQE3VVzMsWPHVF9frwMHDuill16SJA0bNuyyaoEGGaCFWLx4sZFk1q9fb44ePWrKy8vN8uXLTadOnUzbtm3NwYMHjTHGTJw40UgyTz/9dED9X//6VyPJLF26NGD+2rVrA+YfOXLEREVFmbvvvtv4fD7/uGeeecZIMhMnTvTPKygoMJJMQUGBMcaYs2fPmvT0dNO1a1fz3XffBWzn/HXl5uaaxv75STJz5szxvx4zZoyJiooypaWl/nmHDh0ysbGxZsiQIRfsn6ysrIBtzZw504SHh5vjx49fMHbx4sUN9tAQt9ttJBlJplOnTub111+/7FqgIbwFhxYnKytLCQkJSktL0/jx4xUTE6OVK1fquuuuCxg3bdq0gNcrVqyQx+PRXXfdpW+//dY/9evXTzExMSooKJAkrV+/XmfOnNH06dMD3hqbMWPGJXsrLi5WWVmZZsyYofbt2wcsO39dl6u+vl5/+ctfNGbMGHXv3t0/PyUlRffff782b94sr9cbUPPQQw8FbGvw4MGqr6/XN9984583adIkGWMu++xHkj755BOtWbNGr7zyirp06aKamhrHPw9wPt6CQ4uzYMEC9ejRQxEREUpKSlLPnj0VFhb4u1RERIQ6d+4cMG/v3r2qqqpSYmJig+s9cuSIJPn/o77hhhsClickJKhDhw4X7e37twN79+59+T/QRRw9elQnT55Uz549L1h20003yefzqby8XL169fLP79KlS8C473v+4XUup+644w5J524CGT16tHr37q2YmBjl5eVd0Xpx7SKA0OL079/ffxdcY9xu9wWh5PP5lJiYqKVLlzZYk5CQELIebQoPD29wvjEmZNvIyMjQj3/8Yy1dupQAQtAIIFwzMjIytH79eg0cOFBt27ZtdFzXrl0lnTtjOv9tr6NHj17yLCIjI0OStHv3bmVlZTU67nLfjktISFB0dLRKSkouWLZnzx6FhYUpLS3tstYVaqdOnVJtba2VbaN14BoQrhm//OUvVV9fr9/+9rcXLDt79qz/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YWGhKSsrM5999pnJysoy8fHx5siRI7Zba1LV1dWmuLjYFBcXG0nm1VdfNcXFxeabb74xxhjzu9/9zrRv396sWrXK7Nq1y4wePdqkp6ebU6dOWe48tC62H6qrq80TTzxhtmzZYsrKysz69evNT37yE3PDDTeY06dP2249ZKZNm2Y8Ho8pLCw0hw8f9k8nT570j3n44YdNly5dzMaNG8327dvNgAEDzIABAyx2HXqX2g/79u0zL730ktm+fbspKyszq1atMt27dzdDhgyx3HmgFhFAxhjzxhtvmC5dupioqCjTv39/s3XrVtstXXX33XefSUlJMVFRUea6664z9913n9m3b5/ttppcQUGBkXTBNHHiRGPMuVuxn3vuOZOUlGTcbrcZNmyYKSkpsdt0E7jYfjh58qQZPny4SUhIMJGRkaZr165mypQpre6XtIZ+fklm8eLF/jGnTp0yjzzyiOnQoYOJjo429957rzl8+LC9ppvApfbDgQMHzJAhQ0zHjh2N2+02119/vfnNb35jqqqq7Db+A3wfEADAimZ/DQgA0DoRQAAAKwggAIAVBBAAwAoCCABgBQEEALCCAAIAWEEAAQCsIIAAAFYQQAAAKwggAIAV/w/hgVLrpVGHsAAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure()\n", - "plt.title(\"Prediction: {}\".format(prediction))\n", - "plt.imshow(img)\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "39167347-0b99-4972-998c-e1230bf1d4d5", - "metadata": {}, - "source": [ - "### 784 columns of float" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "id": "f1285e8b-1b96-437b-973a-eb868e33afb7", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "\n", - "from pyspark.ml.functions import predict_batch_udf\n", - "from pyspark.sql.functions import array, col, struct\n", - "from pyspark.sql.types import ArrayType, FloatType, Union, Dict" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "id": "6bea332e-f6de-494f-a0db-795d9fe3e134", - "metadata": {}, - "outputs": [], - "source": [ - "def predict_batch_fn():\n", - " import tensorflow as tf\n", - " # Enable GPU memory growth\n", - " gpus = tf.config.experimental.list_physical_devices('GPU')\n", - " if gpus:\n", - " try:\n", - " for gpu in gpus:\n", - " tf.config.experimental.set_memory_growth(gpu, True)\n", - " except RuntimeError as e:\n", - " print(e)\n", - " \n", - " model = tf.keras.models.load_model(model_dir)\n", - " def predict(inputs: np.ndarray) -> np.ndarray:\n", - " return model.predict(inputs)\n", - " \n", - " return predict" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "id": "731d234c-549f-4df3-8a2b-312e63195396", - "metadata": {}, - "outputs": [], - "source": [ - "mnist = predict_batch_udf(predict_batch_fn,\n", - " return_type=ArrayType(FloatType()),\n", - " batch_size=1024,\n", - " input_tensor_shapes=[[784]])" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "id": "a40fe207-6246-4b0e-abde-823979878d97", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "784" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = spark.read.parquet(\"mnist_784\")\n", - "len(df.columns)" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "id": "10904f12-03e7-4518-8f12-2aa11989ddf5", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "[Stage 10:=======> (1 + 7) / 8]\r" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 45.6 ms, sys: 26 ms, total: 71.6 ms\n", - "Wall time: 5.51 s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", mnist(struct(*df.columns))).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "id": "671128df-f0f4-4f54-b35c-d63a78c7f89a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 46.5 ms, sys: 34 ms, total: 80.5 ms\n", - "Wall time: 884 ms\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", mnist(array(*df.columns))).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "id": "ce35deaf-7d49-4f34-9bf9-b4e6fc5761f4", - "metadata": {}, - "outputs": [], - "source": [ - "# should raise ValueError\n", - "# preds = df.withColumn(\"preds\", mnist(*df.columns)).collect()" - ] - }, - { - "cell_type": "markdown", - "id": "01709833-484b-451f-9aa8-37be5b7baf14", - "metadata": {}, - "source": [ - "### Check prediction" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "id": "f9119632-b284-45d7-a262-c262e034c15c", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "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", - " \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", - " \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", - "
0123456789...775776777778779780781782783preds
00.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-5.88436, -3.1058552, 0.108737305, 12.67319, ...
10.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-3.2732859, -8.362555, 1.893612, -3.888143, 0...
20.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-3.3856308, 0.6785604, 1.3146865, 0.9275978, ...
30.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-2.775469, -7.3659234, 11.768431, 1.3434289, ...
40.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-4.942663, 4.0774136, -0.45292768, -0.9312788...
50.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-5.226616, -3.1389174, 2.6100307, 3.695045, -...
60.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-4.3006196, 5.116993, 0.5850617, -0.7624871, ...
70.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-2.398596, -1.4814726, -4.8840575, -0.2391601...
80.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[0.82160157, -2.8640628, -1.6951559, -4.489291...
90.00.00.00.00.00.00.00.00.00.0...0.00.00.00.00.00.00.00.00.0[-1.2338604, -2.151981, -4.1717424, 1.6106843,...
\n", - "

10 rows × 785 columns

\n", - "
" - ], - "text/plain": [ - " 0 1 2 3 4 5 6 7 8 9 ... 775 776 777 778 \\\n", - "0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", - "1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", - "2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", - "3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", - "4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", - "5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", - "6 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", - "7 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", - "8 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", - "9 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0 \n", - "\n", - " 779 780 781 782 783 preds \n", - "0 0.0 0.0 0.0 0.0 0.0 [-5.88436, -3.1058552, 0.108737305, 12.67319, ... \n", - "1 0.0 0.0 0.0 0.0 0.0 [-3.2732859, -8.362555, 1.893612, -3.888143, 0... \n", - "2 0.0 0.0 0.0 0.0 0.0 [-3.3856308, 0.6785604, 1.3146865, 0.9275978, ... \n", - "3 0.0 0.0 0.0 0.0 0.0 [-2.775469, -7.3659234, 11.768431, 1.3434289, ... \n", - "4 0.0 0.0 0.0 0.0 0.0 [-4.942663, 4.0774136, -0.45292768, -0.9312788... \n", - "5 0.0 0.0 0.0 0.0 0.0 [-5.226616, -3.1389174, 2.6100307, 3.695045, -... \n", - "6 0.0 0.0 0.0 0.0 0.0 [-4.3006196, 5.116993, 0.5850617, -0.7624871, ... \n", - "7 0.0 0.0 0.0 0.0 0.0 [-2.398596, -1.4814726, -4.8840575, -0.2391601... \n", - "8 0.0 0.0 0.0 0.0 0.0 [0.82160157, -2.8640628, -1.6951559, -4.489291... \n", - "9 0.0 0.0 0.0 0.0 0.0 [-1.2338604, -2.151981, -4.1717424, 1.6106843,... \n", - "\n", - "[10 rows x 785 columns]" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "preds = df.withColumn(\"preds\", mnist(struct(df.columns))).limit(10).toPandas()\n", - "preds" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "id": "7c067c62-03a6-461e-a1ff-4653276fbea1", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "id": "a7084ad0-c021-4296-bad0-7a238971f53b", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ -5.88436 , -3.1058552, 0.1087373, 12.67319 , -5.1437874,\n", - " 4.085992 , -10.203137 , -1.4333997, -3.3865087, -3.8473575],\n", - " dtype=float32)" - ] - }, - "execution_count": 49, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sample = preds.iloc[0]\n", - "sample.preds" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "id": "8167c832-93ef-4f50-873b-07b67c19ef53", - "metadata": {}, - "outputs": [], - "source": [ - "prediction = np.argmax(sample.preds)\n", - "img = sample.drop('preds').to_numpy(dtype=float)\n", - "img = np.array(img).reshape(28,28)" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "id": "297811e1-aecb-4afd-9a6a-30c49e8881cc", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGzCAYAAABpdMNsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAkfElEQVR4nO3dfXQUdZ7v8U/nqSEkaR7yLAFCFHRAcAYly/AgSiQEZUCYGUG9F7gziJiggI6KR0Udzsksrg7qIHjcHVhHEGWOyMoiDg9JGBRwwTCIM2QhJ0g4kIBcSYcAIaR/9w+uvbQkQDUdfkl4v86pc+iq37fqm6Lgk+qqrnYZY4wAALjKwmw3AAC4NhFAAAArCCAAgBUEEADACgIIAGAFAQQAsIIAAgBYQQABAKwggAAAVhBAgAPdunXTpEmT/K8LCwvlcrlUWFgYsm24XC698MILIVsf0FwRQGgxlixZIpfL5Z/atGmjHj16KC8vT5WVlbbbc2TNmjUtJmTefvtt3X777UpKSpLb7VZ6eromT56s/fv3224NLVyE7QYAp1566SWlp6fr9OnT2rx5sxYuXKg1a9Zo9+7dio6Ovqq9DBkyRKdOnVJUVJSjujVr1mjBggUNhtCpU6cUEdF8/mkWFxcrPT1dP/vZz9ShQweVlZXp7bff1urVq/W3v/1NqamptltEC9V8jnLgMuXk5OjWW2+VJP36179Wp06d9Oqrr2rVqlWaMGFCgzU1NTVq165dyHsJCwtTmzZtQrrOUK/vSr355psXzBszZoxuvfVWvfPOO3r66actdIXWgLfg0OLdeeedkqSysjJJ0qRJkxQTE6PS0lKNHDlSsbGxeuCBByRJPp9P8+fPV69evdSmTRslJSVp6tSp+u677wLWaYzR3Llz1blzZ0VHR+uOO+7Q119/fcG2G7sGtG3bNo0cOVIdOnRQu3bt1KdPH7322mv+/hYsWCBJAW8pfq+ha0DFxcXKyclRXFycYmJiNGzYMG3dujVgzPdvUX722WeaNWuWEhIS1K5dO9177706evRowNiqqirt2bNHVVVVl7OLL9CtWzdJ0vHjx4OqByTOgNAKlJaWSpI6derkn3f27FllZ2dr0KBB+pd/+Rf/W3NTp07VkiVLNHnyZD366KMqKyvTH/7wBxUXF+uzzz5TZGSkJOn555/X3LlzNXLkSI0cOVJffvmlhg8frjNnzlyyn3Xr1umee+5RSkqKHnvsMSUnJ+sf//iHVq9erccee0xTp07VoUOHtG7dOv3pT3+65Pq+/vprDR48WHFxcXryyScVGRmpt956S0OHDlVRUZEyMzMDxk+fPl0dOnTQnDlztH//fs2fP195eXl6//33/WNWrlypyZMna/HixQE3VVzMsWPHVF9frwMHDuill16SJA0bNuyyaoEGGaCFWLx4sZFk1q9fb44ePWrKy8vN8uXLTadOnUzbtm3NwYMHjTHGTJw40UgyTz/9dED9X//6VyPJLF26NGD+2rVrA+YfOXLEREVFmbvvvtv4fD7/uGeeecZIMhMnTvTPKygoMJJMQUGBMcaYs2fPmvT0dNO1a1fz3XffBWzn/HXl5uaaxv75STJz5szxvx4zZoyJiooypaWl/nmHDh0ysbGxZsiQIRfsn6ysrIBtzZw504SHh5vjx49fMHbx4sUN9tAQt9ttJBlJplOnTub111+/7FqgIbwFhxYnKytLCQkJSktL0/jx4xUTE6OVK1fquuuuCxg3bdq0gNcrVqyQx+PRXXfdpW+//dY/9evXTzExMSooKJAkrV+/XmfOnNH06dMD3hqbMWPGJXsrLi5WWVmZZsyYofbt2wcsO39dl6u+vl5/+ctfNGbMGHXv3t0/PyUlRffff782b94sr9cbUPPQQw8FbGvw4MGqr6/XN9984583adIkGWMu++xHkj755BOtWbNGr7zyirp06aKamhrHPw9wPt6CQ4uzYMEC9ejRQxEREUpKSlLPnj0VFhb4u1RERIQ6d+4cMG/v3r2qqqpSYmJig+s9cuSIJPn/o77hhhsClickJKhDhw4X7e37twN79+59+T/QRRw9elQnT55Uz549L1h20003yefzqby8XL169fLP79KlS8C473v+4XUup+644w5J524CGT16tHr37q2YmBjl5eVd0Xpx7SKA0OL079/ffxdcY9xu9wWh5PP5lJiYqKVLlzZYk5CQELIebQoPD29wvjEmZNvIyMjQj3/8Yy1dupQAQtAIIFwzMjIytH79eg0cOFBt27ZtdFzXrl0lnTtjOv9tr6NHj17yLCIjI0OStHv3bmVlZTU67nLfjktISFB0dLRKSkouWLZnzx6FhYUpLS3tstYVaqdOnVJtba2VbaN14BoQrhm//OUvVV9fr9/+9rcXLDt79qz/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YWGhKSsrM5999pnJysoy8fHx5siRI7Zba1LV1dWmuLjYFBcXG0nm1VdfNcXFxeabb74xxhjzu9/9zrRv396sWrXK7Nq1y4wePdqkp6ebU6dOWe48tC62H6qrq80TTzxhtmzZYsrKysz69evNT37yE3PDDTeY06dP2249ZKZNm2Y8Ho8pLCw0hw8f9k8nT570j3n44YdNly5dzMaNG8327dvNgAEDzIABAyx2HXqX2g/79u0zL730ktm+fbspKyszq1atMt27dzdDhgyx3HmgFhFAxhjzxhtvmC5dupioqCjTv39/s3XrVtstXXX33XefSUlJMVFRUea6664z9913n9m3b5/ttppcQUGBkXTBNHHiRGPMuVuxn3vuOZOUlGTcbrcZNmyYKSkpsdt0E7jYfjh58qQZPny4SUhIMJGRkaZr165mypQpre6XtIZ+fklm8eLF/jGnTp0yjzzyiOnQoYOJjo429957rzl8+LC9ppvApfbDgQMHzJAhQ0zHjh2N2+02119/vfnNb35jqqqq7Db+A3wfEADAimZ/DQgA0DoRQAAAKwggAIAVBBAAwAoCCABgBQEEALCCAAIAWEEAAQCsIIAAAFYQQAAAKwggAIAV/w/hgVLrpVGHsAAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure()\n", - "plt.title(\"Prediction: {}\".format(prediction))\n", - "plt.imshow(img)\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "5961593d-182e-4620-9a5e-f98ba3d2534d", - "metadata": {}, - "source": [ - "### Using Triton Inference Server\n", - "\n", - "Note: you can restart the kernel and run from this point to simulate running in a different node or environment." - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "id": "a64d19b1-ba4a-4dc7-b3a9-368dc47d0fd8", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "from pyspark.ml.functions import predict_batch_udf\n", - "from pyspark.sql.functions import col, struct\n", - "from pyspark.sql.types import ArrayType, FloatType" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "id": "8fa92fe4-2e04-4d82-a357-bfdfca38bd8c", - "metadata": {}, - "outputs": [], - "source": [ - "%%bash\n", - "# copy model to expected layout for Triton\n", - "rm -rf models\n", - "mkdir -p models/mnist_model/1\n", - "cp -r mnist_model models/mnist_model/1/model.savedmodel\n", - "\n", - "# add config.pbtxt\n", - "cp models_config/mnist_model/config.pbtxt models/mnist_model/config.pbtxt" - ] - }, - { - "cell_type": "markdown", - "id": "f1673e0e-5c75-44e1-88c6-5f5cf1275e4b", - "metadata": {}, - "source": [ - "#### Start Triton Server on each executor" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "id": "0f7ecb25-be16-40c4-bdbb-441e2f537000", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/plain": [ - "[True]" - ] - }, - "execution_count": 54, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "num_executors = 1\n", - "triton_models_dir = \"{}/models\".format(os.getcwd())\n", - "nodeRDD = sc.parallelize(list(range(num_executors)), num_executors)\n", - "\n", - "def start_triton(it):\n", - " import docker\n", - " import time\n", - " import tritonclient.grpc as grpcclient\n", - " \n", - " client=docker.from_env()\n", - " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", - " if containers:\n", - " \n", - " print(\">>>> containers: {}\".format([c.short_id for c in containers]))\n", - " else:\n", - " container=client.containers.run(\n", - " \"nvcr.io/nvidia/tritonserver:24.08-py3\", \"tritonserver --model-repository=/models\",\n", - " detach=True,\n", - " device_requests=[docker.types.DeviceRequest(device_ids=[\"0\"], capabilities=[['gpu']])],\n", - " name=\"spark-triton\",\n", - " network_mode=\"host\",\n", - " remove=True,\n", - " shm_size=\"64M\",\n", - " volumes={triton_models_dir: {\"bind\": \"/models\", \"mode\": \"ro\"}}\n", - " )\n", - " print(\">>>> starting triton: {}\".format(container.short_id))\n", - "\n", - " # wait for triton to be running\n", - " time.sleep(15)\n", - " client = grpcclient.InferenceServerClient(\"localhost:8001\")\n", - " ready = False\n", - " while not ready:\n", - " try:\n", - " ready = client.is_server_ready()\n", - " except Exception as e:\n", - " time.sleep(5)\n", - " \n", - " return [True]\n", - "\n", - "nodeRDD.barrier().mapPartitions(start_triton).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "id": "43b93753-1d52-4060-9986-f24c30a67528", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "StructType([StructField('data', ArrayType(DoubleType(), True), True)])" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = spark.read.parquet(\"mnist_1\")\n", - "df.schema" - ] - }, - { - "cell_type": "markdown", - "id": "036680eb-babd-4b07-8b2c-ce6e724f4e85", - "metadata": {}, - "source": [ - "#### Run inference" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "id": "3af08bd0-3838-4769-a8de-2643db4101c6", - "metadata": {}, - "outputs": [], - "source": [ - "def triton_fn(triton_uri, model_name):\n", - " import numpy as np\n", - " import tritonclient.grpc as grpcclient\n", - "\n", - " np_types = {\n", - " \"BOOL\": np.dtype(np.bool_),\n", - " \"INT8\": np.dtype(np.int8),\n", - " \"INT16\": np.dtype(np.int16),\n", - " \"INT32\": np.dtype(np.int32),\n", - " \"INT64\": np.dtype(np.int64),\n", - " \"FP16\": np.dtype(np.float16),\n", - " \"FP32\": np.dtype(np.float32),\n", - " \"FP64\": np.dtype(np.float64),\n", - " \"FP64\": np.dtype(np.double),\n", - " \"BYTES\": np.dtype(object)\n", - " }\n", - "\n", - " client = grpcclient.InferenceServerClient(triton_uri)\n", - " model_meta = client.get_model_metadata(model_name)\n", - "\n", - " def predict(inputs):\n", - " if isinstance(inputs, np.ndarray):\n", - " # single ndarray input\n", - " request = [grpcclient.InferInput(model_meta.inputs[0].name, inputs.shape, model_meta.inputs[0].datatype)]\n", - " request[0].set_data_from_numpy(inputs.astype(np_types[model_meta.inputs[0].datatype]))\n", - " else:\n", - " # dict of multiple ndarray inputs\n", - " request = [grpcclient.InferInput(i.name, inputs[i.name].shape, i.datatype) for i in model_meta.inputs]\n", - " for i in request:\n", - " i.set_data_from_numpy(inputs[i.name()].astype(np_types[i.datatype()]))\n", - "\n", - " response = client.infer(model_name, inputs=request)\n", - "\n", - " if len(model_meta.outputs) > 1:\n", - " # return dictionary of numpy arrays\n", - " return {o.name: response.as_numpy(o.name) for o in model_meta.outputs}\n", - " else:\n", - " # return single numpy array\n", - " return response.as_numpy(model_meta.outputs[0].name)\n", - "\n", - " return predict" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "id": "6658d2a1-ef7b-4ca1-9fb6-f2ac9050f3e5", - "metadata": {}, - "outputs": [], - "source": [ - "from functools import partial\n", - "\n", - "predict = predict_batch_udf(partial(triton_fn, \"localhost:8001\", \"mnist_model\"),\n", - " return_type=ArrayType(FloatType()),\n", - " input_tensor_shapes=[[784]],\n", - " batch_size=8192)" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "id": "8397aa14-82fd-4351-a477-dc8e8b321fa2", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 20.1 ms, sys: 3.41 ms, total: 23.5 ms\n", - "Wall time: 625 ms\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", predict(struct(\"data\"))).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "id": "82698bd9-377a-4415-8971-835487f876cc", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 30.3 ms, sys: 8.81 ms, total: 39.2 ms\n", - "Wall time: 154 ms\n" - ] - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", predict(\"data\")).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "id": "419ad7bd-fa28-49d3-b98d-db9fba5aeaef", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "CPU times: user 2.67 ms, sys: 4.2 ms, total: 6.87 ms\n", - "Wall time: 131 ms\n" - ] - }, - { - "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", - "
datapreds
0[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-5.7614846, -3.52228, -1.1202906, 13.053683, ...
1[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-3.1390061, -8.71185, 0.82955813, -4.034869, ...
2[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-3.046528, 0.3521706, 0.6788677, 0.72303534, ...
3[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-2.401024, -7.6780066, 11.145876, 1.2857256, ...
4[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-5.0012593, 3.806796, -0.8154834, -0.9550028,...
5[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-5.0425925, -3.4815094, 1.641246, 3.608149, -...
6[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-4.288771, 5.0072904, 0.27649477, -0.797148, ...
7[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-2.2032878, -1.6879876, -5.874276, -0.5945335...
8[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[1.1337761, -3.1751056, -2.5246286, -5.028277,...
9[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ...[-0.92484117, -2.4703276, -5.023897, 1.46669, ...
\n", - "
" - ], - "text/plain": [ - " data \\\n", - "0 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "1 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "2 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "3 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "4 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "5 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "6 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "7 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "8 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "9 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... \n", - "\n", - " preds \n", - "0 [-5.7614846, -3.52228, -1.1202906, 13.053683, ... \n", - "1 [-3.1390061, -8.71185, 0.82955813, -4.034869, ... \n", - "2 [-3.046528, 0.3521706, 0.6788677, 0.72303534, ... \n", - "3 [-2.401024, -7.6780066, 11.145876, 1.2857256, ... \n", - "4 [-5.0012593, 3.806796, -0.8154834, -0.9550028,... \n", - "5 [-5.0425925, -3.4815094, 1.641246, 3.608149, -... \n", - "6 [-4.288771, 5.0072904, 0.27649477, -0.797148, ... \n", - "7 [-2.2032878, -1.6879876, -5.874276, -0.5945335... \n", - "8 [1.1337761, -3.1751056, -2.5246286, -5.028277,... \n", - "9 [-0.92484117, -2.4703276, -5.023897, 1.46669, ... " - ] - }, - "execution_count": 60, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "%%time\n", - "preds = df.withColumn(\"preds\", predict(col(\"data\"))).limit(10).toPandas()\n", - "preds" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "id": "79d90a26", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "id": "4ca495f5", - "metadata": {}, - "outputs": [], - "source": [ - "sample = preds.iloc[0]\n", - "sample.preds\n", - "\n", - "prediction = np.argmax(sample.preds)\n", - "img = np.array(sample.data).reshape(28,28)" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "id": "a5d10903", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGzCAYAAABpdMNsAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAkfElEQVR4nO3dfXQUdZ7v8U/nqSEkaR7yLAFCFHRAcAYly/AgSiQEZUCYGUG9F7gziJiggI6KR0Udzsksrg7qIHjcHVhHEGWOyMoiDg9JGBRwwTCIM2QhJ0g4kIBcSYcAIaR/9w+uvbQkQDUdfkl4v86pc+iq37fqm6Lgk+qqrnYZY4wAALjKwmw3AAC4NhFAAAArCCAAgBUEEADACgIIAGAFAQQAsIIAAgBYQQABAKwggAAAVhBAgAPdunXTpEmT/K8LCwvlcrlUWFgYsm24XC698MILIVsf0FwRQGgxlixZIpfL5Z/atGmjHj16KC8vT5WVlbbbc2TNmjUtJmTefvtt3X777UpKSpLb7VZ6eromT56s/fv3224NLVyE7QYAp1566SWlp6fr9OnT2rx5sxYuXKg1a9Zo9+7dio6Ovqq9DBkyRKdOnVJUVJSjujVr1mjBggUNhtCpU6cUEdF8/mkWFxcrPT1dP/vZz9ShQweVlZXp7bff1urVq/W3v/1NqamptltEC9V8jnLgMuXk5OjWW2+VJP36179Wp06d9Oqrr2rVqlWaMGFCgzU1NTVq165dyHsJCwtTmzZtQrrOUK/vSr355psXzBszZoxuvfVWvfPOO3r66actdIXWgLfg0OLdeeedkqSysjJJ0qRJkxQTE6PS0lKNHDlSsbGxeuCBByRJPp9P8+fPV69evdSmTRslJSVp6tSp+u677wLWaYzR3Llz1blzZ0VHR+uOO+7Q119/fcG2G7sGtG3bNo0cOVIdOnRQu3bt1KdPH7322mv+/hYsWCBJAW8pfq+ha0DFxcXKyclRXFycYmJiNGzYMG3dujVgzPdvUX722WeaNWuWEhIS1K5dO9177706evRowNiqqirt2bNHVVVVl7OLL9CtWzdJ0vHjx4OqByTOgNAKlJaWSpI6derkn3f27FllZ2dr0KBB+pd/+Rf/W3NTp07VkiVLNHnyZD366KMqKyvTH/7wBxUXF+uzzz5TZGSkJOn555/X3LlzNXLkSI0cOVJffvmlhg8frjNnzlyyn3Xr1umee+5RSkqKHnvsMSUnJ+sf//iHVq9erccee0xTp07VoUOHtG7dOv3pT3+65Pq+/vprDR48WHFxcXryyScVGRmpt956S0OHDlVRUZEyMzMDxk+fPl0dOnTQnDlztH//fs2fP195eXl6//33/WNWrlypyZMna/HixQE3VVzMsWPHVF9frwMHDuill16SJA0bNuyyaoEGGaCFWLx4sZFk1q9fb44ePWrKy8vN8uXLTadOnUzbtm3NwYMHjTHGTJw40UgyTz/9dED9X//6VyPJLF26NGD+2rVrA+YfOXLEREVFmbvvvtv4fD7/uGeeecZIMhMnTvTPKygoMJJMQUGBMcaYs2fPmvT0dNO1a1fz3XffBWzn/HXl5uaaxv75STJz5szxvx4zZoyJiooypaWl/nmHDh0ysbGxZsiQIRfsn6ysrIBtzZw504SHh5vjx49fMHbx4sUN9tAQt9ttJBlJplOnTub111+/7FqgIbwFhxYnKytLCQkJSktL0/jx4xUTE6OVK1fquuuuCxg3bdq0gNcrVqyQx+PRXXfdpW+//dY/9evXTzExMSooKJAkrV+/XmfOnNH06dMD3hqbMWPGJXsrLi5WWVmZZsyYofbt2wcsO39dl6u+vl5/+ctfNGbMGHXv3t0/PyUlRffff782b94sr9cbUPPQQw8FbGvw4MGqr6/XN9984583adIkGWMu++xHkj755BOtWbNGr7zyirp06aKamhrHPw9wPt6CQ4uzYMEC9ejRQxEREUpKSlLPnj0VFhb4u1RERIQ6d+4cMG/v3r2qqqpSYmJig+s9cuSIJPn/o77hhhsClickJKhDhw4X7e37twN79+59+T/QRRw9elQnT55Uz549L1h20003yefzqby8XL169fLP79KlS8C473v+4XUup+644w5J524CGT16tHr37q2YmBjl5eVd0Xpx7SKA0OL079/ffxdcY9xu9wWh5PP5lJiYqKVLlzZYk5CQELIebQoPD29wvjEmZNvIyMjQj3/8Yy1dupQAQtAIIFwzMjIytH79eg0cOFBt27ZtdFzXrl0lnTtjOv9tr6NHj17yLCIjI0OStHv3bmVlZTU67nLfjktISFB0dLRKSkouWLZnzx6FhYUpLS3tstYVaqdOnVJtba2VbaN14BoQrhm//OUvVV9fr9/+9rcXLDt79qz/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YWGhKSsrM5999pnJysoy8fHx5siRI7Zba1LV1dWmuLjYFBcXG0nm1VdfNcXFxeabb74xxhjzu9/9zrRv396sWrXK7Nq1y4wePdqkp6ebU6dOWe48tC62H6qrq80TTzxhtmzZYsrKysz69evNT37yE3PDDTeY06dP2249ZKZNm2Y8Ho8pLCw0hw8f9k8nT570j3n44YdNly5dzMaNG8327dvNgAEDzIABAyx2HXqX2g/79u0zL730ktm+fbspKyszq1atMt27dzdDhgyx3HmgFhFAxhjzxhtvmC5dupioqCjTv39/s3XrVtstXXX33XefSUlJMVFRUea6664z9913n9m3b5/ttppcQUGBkXTBNHHiRGPMuVuxn3vuOZOUlGTcbrcZNmyYKSkpsdt0E7jYfjh58qQZPny4SUhIMJGRkaZr165mypQpre6XtIZ+fklm8eLF/jGnTp0yjzzyiOnQoYOJjo429957rzl8+LC9ppvApfbDgQMHzJAhQ0zHjh2N2+02119/vfnNb35jqqqq7Db+A3wfEADAimZ/DQgA0DoRQAAAKwggAIAVBBAAwAoCCABgBQEEALCCAAIAWEEAAQCsIIAAAFYQQAAAKwggAIAV/w/hgVLrpVGHsAAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure()\n", - "plt.title(\"Prediction: {}\".format(prediction))\n", - "plt.imshow(img)\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "6377f41a-5654-410b-8bad-d392e9dce7b8", - "metadata": { - "tags": [] - }, - "source": [ - "#### Stop Triton Server on each executor" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "id": "9c9fd967-5cd9-4265-add9-db5c1ccf9893", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/plain": [ - "[True]" - ] - }, - "execution_count": 64, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def stop_triton(it):\n", - " import docker\n", - " import time\n", - " \n", - " client=docker.from_env()\n", - " containers=client.containers.list(filters={\"name\": \"spark-triton\"})\n", - " print(\">>>> stopping containers: {}\".format([c.short_id for c in containers]))\n", - " if containers:\n", - " container=containers[0]\n", - " container.stop(timeout=120)\n", - "\n", - " return [True]\n", - "\n", - "nodeRDD.barrier().mapPartitions(stop_triton).collect()" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "id": "f612dc0b-538f-4ecf-81f7-ef6b58c493ab", - "metadata": {}, - "outputs": [], - "source": [ - "spark.stop()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "490fc849-e47a-48d7-accc-429ff1cced6b", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "spark-dl-tf", - "language": "python", - "name": "python3" - }, - "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.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md index 2879b94a8..4b5fd5675 100644 --- a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md +++ b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md @@ -5,12 +5,12 @@ The notebook uses PCA to reduce a random dataset with 2048 feature dimensions to ## Build -Please refer to the Spark-Rapids-ML [README](https://github.com/NVIDIA/spark-rapids-ml/blob/HEAD/python) for environment setup instructions and API usage. +Please refer to the Spark-Rapids-ML [README](https://github.com/NVIDIA/spark-rapids-ml/blob/HEAD/python) to setup the RAPIDS conda environment and install Spark-Rapids-ML dependencies. ## Download RAPIDS Jar from Maven Central -Download the RAPIDS jar from Maven Central: [rapids-4-spark_2.12-24.08.1.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar) -Alternatively, see the Spark-Rapids [download page](https://nvidia.github.io/spark-rapids/docs/download.html#download-rapids-accelerator-for-apache-spark-v24081) for version selection. +Download the [Spark-Rapids plugin](https://nvidia.github.io/spark-rapids/docs/download.html#download-rapids-accelerator-for-apache-spark-v24081). +For Spark-RAPIDS-ML version 24.08, download the RAPIDS jar from Maven Central: [rapids-4-spark_2.12-24.08.1.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar). ## Running the Notebooks diff --git a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb index 3bf570feb..37a11238a 100644 --- a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb +++ b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb @@ -17,7 +17,8 @@ "source": [ "import numpy as np\n", "import pandas as pd\n", - "import time" + "import time\n", + "import os" ] }, { @@ -58,7 +59,6 @@ "\n", " SPARK_RAPIDS_VERSION = \"24.08.1\"\n", " rapids_jar = f\"rapids-4-spark_2.12-{SPARK_RAPIDS_VERSION}.jar\"\n", - "\n", " if not os.path.exists(rapids_jar):\n", " print(\"Downloading spark rapids jar\")\n", " url = f\"https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/{SPARK_RAPIDS_VERSION}/{rapids_jar}\"\n", @@ -71,7 +71,6 @@ " print(f\"Failed to download the file. Status code: {response.status_code}\")\n", " else:\n", " print(\"File already exists. Skipping download.\")\n", - " \n", " return rapids_jar\n", "\n", "def initialize_spark(rapids_jar: str):\n", @@ -119,7 +118,9 @@ "# Check if Spark session is already active, if not, initialize it\n", "if 'spark' not in globals():\n", " print(\"No active Spark session found, initializing manually.\")\n", - " rapids_jar = get_rapids_jar()\n", + " rapids_jar = os.environ.get('RAPIDS_JAR')\n", + " if rapids_jar is None:\n", + " rapids_jar = get_rapids_jar()\n", " spark = initialize_spark(rapids_jar)\n", "else:\n", " print(\"Using existing Spark session.\")" From b8e31fda884ac6a0a02757780078b343a8d05eec Mon Sep 17 00:00:00 2001 From: liyuan <84758614+nvliyuan@users.noreply.github.com> Date: Fri, 25 Oct 2024 09:57:34 +0800 Subject: [PATCH 09/10] [Doc] Update plugin versions for 24.10.0 [skip ci] (#449) * update versions for 2410 release Signed-off-by: liyuan * update the versions Signed-off-by: liyuan * update the env requirement for the latest plugin Signed-off-by: liyuan --------- Signed-off-by: liyuan --- .../xgboost-examples/csp/databricks/databricks.md | 4 ++-- docs/get-started/xgboost-examples/csp/databricks/init.sh | 2 +- .../xgboost-examples/on-prem-cluster/kubernetes-scala.md | 6 +++--- .../xgboost-examples/on-prem-cluster/standalone-python.md | 8 ++++---- .../xgboost-examples/on-prem-cluster/standalone-scala.md | 8 ++++---- .../xgboost-examples/on-prem-cluster/yarn-python.md | 4 ++-- .../xgboost-examples/on-prem-cluster/yarn-scala.md | 4 ++-- .../prepare-package-data/preparation-python.md | 2 +- .../prepare-package-data/preparation-scala.md | 2 +- examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md | 2 +- .../Spark-Rapids-ML/pca/notebooks/pca.ipynb | 6 +++--- .../micro-benchmarks/notebooks/micro-benchmarks-gpu.ipynb | 2 +- examples/UDF-Examples/RAPIDS-accelerated-UDFs/README.md | 2 +- examples/UDF-Examples/RAPIDS-accelerated-UDFs/pom.xml | 2 +- .../agaricus/notebooks/python/agaricus-gpu.ipynb | 2 +- .../mortgage/notebooks/python/MortgageETL.ipynb | 6 +++--- .../mortgage/notebooks/python/cv-mortgage-gpu.ipynb | 2 +- .../mortgage/notebooks/python/mortgage-gpu.ipynb | 2 +- .../mortgage/notebooks/scala/mortgage-ETL.ipynb | 4 ++-- .../taxi/notebooks/python/cv-taxi-gpu.ipynb | 2 +- .../XGBoost-Examples/taxi/notebooks/python/taxi-ETL.ipynb | 4 ++-- .../XGBoost-Examples/taxi/notebooks/python/taxi-gpu.ipynb | 4 ++-- .../XGBoost-Examples/taxi/notebooks/scala/taxi-ETL.ipynb | 4 ++-- tools/databricks/README.md | 2 +- ...r Apache Spark] Profiling Tool Notebook Template.ipynb | 2 +- ...ache Spark] Qualification Tool Notebook Template.ipynb | 2 +- 26 files changed, 45 insertions(+), 45 deletions(-) diff --git a/docs/get-started/xgboost-examples/csp/databricks/databricks.md b/docs/get-started/xgboost-examples/csp/databricks/databricks.md index d56f8ca84..8bb7fe7fb 100644 --- a/docs/get-started/xgboost-examples/csp/databricks/databricks.md +++ b/docs/get-started/xgboost-examples/csp/databricks/databricks.md @@ -21,7 +21,7 @@ Navigate to your home directory in the UI and select **Create** > **File** from create an `init.sh` scripts with contents: ```bash #!/bin/bash - sudo wget -O /databricks/jars/rapids-4-spark_2.12-24.08.1.jar https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar + sudo wget -O /databricks/jars/rapids-4-spark_2.12-24.10.0.jar https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.10.0/rapids-4-spark_2.12-24.10.0.jar ``` 1. Select the Databricks Runtime Version from one of the supported runtimes specified in the Prerequisites section. @@ -68,7 +68,7 @@ create an `init.sh` scripts with contents: ```bash spark.rapids.sql.python.gpu.enabled true spark.python.daemon.module rapids.daemon_databricks - spark.executorEnv.PYTHONPATH /databricks/jars/rapids-4-spark_2.12-24.08.1.jar:/databricks/spark/python + spark.executorEnv.PYTHONPATH /databricks/jars/rapids-4-spark_2.12-24.10.0.jar:/databricks/spark/python ``` Note that since python memory pool require installing the cudf library, so you need to install cudf library in each worker nodes `pip install cudf-cu11 --extra-index-url=https://pypi.nvidia.com` or disable python memory pool diff --git a/docs/get-started/xgboost-examples/csp/databricks/init.sh b/docs/get-started/xgboost-examples/csp/databricks/init.sh index 750a07335..fc415b2dd 100644 --- a/docs/get-started/xgboost-examples/csp/databricks/init.sh +++ b/docs/get-started/xgboost-examples/csp/databricks/init.sh @@ -1,7 +1,7 @@ sudo rm -f /databricks/jars/spark--maven-trees--ml--10.x--xgboost-gpu--ml.dmlc--xgboost4j-gpu_2.12--ml.dmlc__xgboost4j-gpu_2.12__1.5.2.jar sudo rm -f /databricks/jars/spark--maven-trees--ml--10.x--xgboost-gpu--ml.dmlc--xgboost4j-spark-gpu_2.12--ml.dmlc__xgboost4j-spark-gpu_2.12__1.5.2.jar -sudo wget -O /databricks/jars/rapids-4-spark_2.12-24.08.1.jar https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar +sudo wget -O /databricks/jars/rapids-4-spark_2.12-24.10.0.jar https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.10.0/rapids-4-spark_2.12-24.10.0.jar sudo wget -O /databricks/jars/xgboost4j-gpu_2.12-1.7.1.jar https://repo1.maven.org/maven2/ml/dmlc/xgboost4j-gpu_2.12/1.7.1/xgboost4j-gpu_2.12-1.7.1.jar sudo wget -O /databricks/jars/xgboost4j-spark-gpu_2.12-1.7.1.jar https://repo1.maven.org/maven2/ml/dmlc/xgboost4j-spark-gpu_2.12/1.7.1/xgboost4j-spark-gpu_2.12-1.7.1.jar ls -ltr diff --git a/docs/get-started/xgboost-examples/on-prem-cluster/kubernetes-scala.md b/docs/get-started/xgboost-examples/on-prem-cluster/kubernetes-scala.md index 2d685ef54..a0b5fe309 100644 --- a/docs/get-started/xgboost-examples/on-prem-cluster/kubernetes-scala.md +++ b/docs/get-started/xgboost-examples/on-prem-cluster/kubernetes-scala.md @@ -6,12 +6,12 @@ the reader will be able to run a sample Apache Spark XGBoost application on NVID Prerequisites ------------- -* Apache Spark 3.1.1+ (e.g.: Spark 3.1.1) +* Apache Spark 3.2.0+ (e.g.: Spark 3.2.0) * Hardware Requirements * NVIDIA Pascal™ GPU architecture or better * Multi-node clusters with homogenous GPU configuration * Software Requirements - * Ubuntu 18.04, 20.04/CentOS7, Rocky Linux 8 + * Ubuntu 20.04, 22.04/CentOS7, Rocky Linux 8 * CUDA 11.0+ * NVIDIA driver compatible with your CUDA * NCCL 2.7.8+ @@ -40,7 +40,7 @@ export SPARK_DOCKER_IMAGE= export SPARK_DOCKER_TAG= pushd ${SPARK_HOME} -wget https://github.com/NVIDIA/spark-rapids-examples/raw/branch-24.08/dockerfile/Dockerfile +wget https://github.com/NVIDIA/spark-rapids-examples/raw/branch-24.10/dockerfile/Dockerfile # Optionally install additional jars into ${SPARK_HOME}/jars/ diff --git a/docs/get-started/xgboost-examples/on-prem-cluster/standalone-python.md b/docs/get-started/xgboost-examples/on-prem-cluster/standalone-python.md index 70de42c19..b271f03d6 100644 --- a/docs/get-started/xgboost-examples/on-prem-cluster/standalone-python.md +++ b/docs/get-started/xgboost-examples/on-prem-cluster/standalone-python.md @@ -1,17 +1,17 @@ Get Started with XGBoost4J-Spark on an Apache Spark Standalone Cluster ====================================================================== -This is a getting started guide to XGBoost4J-Spark on an Apache Spark 3.1+ Standalone Cluster. +This is a getting started guide to XGBoost4J-Spark on an Apache Spark 3.2+ Standalone Cluster. At the end of this guide, the user can run a sample Apache Spark Python application that runs on NVIDIA GPUs. Prerequisites ------------- -* Apache Spark 3.1.1+ Standalone Cluster (e.g.: Spark 3.1.1) +* Apache Spark 3.2.0+ (e.g.: Spark 3.2.0) * Hardware Requirements * NVIDIA Pascal™ GPU architecture or better * Multi-node clusters with homogenous GPU configuration * Software Requirements - * Ubuntu 18.04, 20.04/CentOS7, Rocky Linux 8 + * Ubuntu 20.04, 22.04/CentOS7, Rocky Linux 8 * CUDA 11.5+ * NVIDIA driver compatible with your CUDA * NCCL 2.7.8+ @@ -31,7 +31,7 @@ In this example, we will limit the number of cores to 1, to match our dataset. Please see https://spark.apache.org/docs/latest/spark-standalone.html for more documentation regarding Standalone configuration. We use `SPARK_HOME` environment variable to point to the Apache Spark cluster. -And here are the steps to enable the GPU resources discovery for Spark 3.1+. +And here are the steps to enable the GPU resources discovery for Spark 3.2+. 1. Copy the spark config file from template diff --git a/docs/get-started/xgboost-examples/on-prem-cluster/standalone-scala.md b/docs/get-started/xgboost-examples/on-prem-cluster/standalone-scala.md index c94df4085..9910d45d3 100644 --- a/docs/get-started/xgboost-examples/on-prem-cluster/standalone-scala.md +++ b/docs/get-started/xgboost-examples/on-prem-cluster/standalone-scala.md @@ -1,18 +1,18 @@ Get Started with XGBoost4J-Spark on an Apache Spark Standalone Cluster ====================================================================== -This is a getting-started guide to XGBoost on an Apache Spark 3.1+ Standalone Cluster. At the end of this guide, +This is a getting-started guide to XGBoost on an Apache Spark 3.2+ Standalone Cluster. At the end of this guide, the user can run a sample Apache Spark application that runs on NVIDIA GPUs. Prerequisites ------------- -* Apache Spark 3.1.1+ Standalone Cluster (e.g.: Spark 3.1.1) +* Apache Spark 3.2.0+ Standalone Cluster (e.g.: Spark 3.2.0) * Hardware Requirements * NVIDIA Pascal™ GPU architecture or better * Multi-node clusters with homogenous GPU configuration * Software Requirements - * Ubuntu 18.04, 20.04/CentOS7, Rocky Linux 8 + * Ubuntu 20.04, 22.04/CentOS7, Rocky Linux 8 * CUDA 11.0+ * NVIDIA driver compatible with your CUDA * NCCL 2.7.8+ @@ -28,7 +28,7 @@ In this example, we will limit the number of cores to 1, to match our dataset. Please see https://spark.apache.org/docs/latest/spark-standalone.html for more documentation regarding Standalone configuration. We use `SPARK_HOME` environment variable to point to the Apache Spark cluster. -And here are steps to enable the GPU resources discovery for Spark 3.1+. +And here are steps to enable the GPU resources discovery for Spark 3.2+. 1. Copy the spark configure file from template. diff --git a/docs/get-started/xgboost-examples/on-prem-cluster/yarn-python.md b/docs/get-started/xgboost-examples/on-prem-cluster/yarn-python.md index b5565d023..89105d492 100644 --- a/docs/get-started/xgboost-examples/on-prem-cluster/yarn-python.md +++ b/docs/get-started/xgboost-examples/on-prem-cluster/yarn-python.md @@ -6,12 +6,12 @@ At the end of this guide, the reader will be able to run a sample Apache Spark P Prerequisites ------------- -* Apache Spark 3.1.1+ running on YARN supporting GPU scheduling. (e.g.: Spark 3.1.1, Hadoop-Yarn 3.3.0) +* Apache Spark 3.2.0+ running on YARN supporting GPU scheduling. (e.g.: Spark 3.2.0, Hadoop-Yarn 3.3.0) * Hardware Requirements * NVIDIA Pascal™ GPU architecture or better * Multi-node clusters with homogenous GPU configuration * Software Requirements - * Ubuntu 18.04, 20.04/CentOS7, Rocky Linux 8 + * Ubuntu 20.04, 22.04/CentOS7, Rocky Linux 8 * CUDA 11.5+ * NVIDIA driver compatible with your CUDA * NCCL 2.7.8+ diff --git a/docs/get-started/xgboost-examples/on-prem-cluster/yarn-scala.md b/docs/get-started/xgboost-examples/on-prem-cluster/yarn-scala.md index 97c60d562..f0387aaa2 100644 --- a/docs/get-started/xgboost-examples/on-prem-cluster/yarn-scala.md +++ b/docs/get-started/xgboost-examples/on-prem-cluster/yarn-scala.md @@ -7,12 +7,12 @@ At the end of this guide, the reader will be able to run a sample Apache Spark a Prerequisites ------------- -* Apache Spark 3.1.1+ running on YARN supporting GPU scheduling. (e.g.: Spark 3.1.1, Hadoop-Yarn 3.3.0) +* Apache Spark 3.2.0+ running on YARN supporting GPU scheduling. (e.g.: Spark 3.2.0, Hadoop-Yarn 3.3.0) * Hardware Requirements * NVIDIA Pascal™ GPU architecture or better * Multi-node clusters with homogenous GPU configuration * Software Requirements - * Ubuntu 18.04, 20.04/CentOS7, Rocky Linux 8 + * Ubuntu 20.04, 22.04/CentOS7, Rocky Linux 8 * CUDA 11.0+ * NVIDIA driver compatible with your CUDA * NCCL 2.7.8+ diff --git a/docs/get-started/xgboost-examples/prepare-package-data/preparation-python.md b/docs/get-started/xgboost-examples/prepare-package-data/preparation-python.md index 61df8def3..d8534cb1e 100644 --- a/docs/get-started/xgboost-examples/prepare-package-data/preparation-python.md +++ b/docs/get-started/xgboost-examples/prepare-package-data/preparation-python.md @@ -5,7 +5,7 @@ For simplicity export the location to these jars. All examples assume the packag ### Download the jars Download the RAPIDS Accelerator for Apache Spark plugin jar - * [RAPIDS Spark Package](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar) + * [RAPIDS Spark Package](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.10.0/rapids-4-spark_2.12-24.10.0.jar) ### Build XGBoost Python Examples diff --git a/docs/get-started/xgboost-examples/prepare-package-data/preparation-scala.md b/docs/get-started/xgboost-examples/prepare-package-data/preparation-scala.md index ba4ab38d7..8cbfa0dbe 100644 --- a/docs/get-started/xgboost-examples/prepare-package-data/preparation-scala.md +++ b/docs/get-started/xgboost-examples/prepare-package-data/preparation-scala.md @@ -5,7 +5,7 @@ For simplicity export the location to these jars. All examples assume the packag ### Download the jars 1. Download the RAPIDS Accelerator for Apache Spark plugin jar - * [RAPIDS Spark Package](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar) + * [RAPIDS Spark Package](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.10.0/rapids-4-spark_2.12-24.10.0.jar) ### Build XGBoost Scala Examples diff --git a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md index 4b5fd5675..9de395c0e 100644 --- a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md +++ b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/README.md @@ -10,7 +10,7 @@ Please refer to the Spark-Rapids-ML [README](https://github.com/NVIDIA/spark-rap ## Download RAPIDS Jar from Maven Central Download the [Spark-Rapids plugin](https://nvidia.github.io/spark-rapids/docs/download.html#download-rapids-accelerator-for-apache-spark-v24081). -For Spark-RAPIDS-ML version 24.08, download the RAPIDS jar from Maven Central: [rapids-4-spark_2.12-24.08.1.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar). +For Spark-RAPIDS-ML version 24.10, download the RAPIDS jar from Maven Central: [rapids-4-spark_2.12-24.10.0.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.10.0/rapids-4-spark_2.12-24.10.0.jar). ## Running the Notebooks diff --git a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb index 37a11238a..9af1f9c31 100644 --- a/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb +++ b/examples/ML+DL-Examples/Spark-Rapids-ML/pca/notebooks/pca.ipynb @@ -43,7 +43,7 @@ "24/10/04 18:04:27 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable\n", "Setting default log level to \"WARN\".\n", "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", - "24/10/04 18:04:27 WARN RapidsPluginUtils: RAPIDS Accelerator 24.08.1 using cudf 24.08.0, private revision 9fac64da220ddd6bf5626bd7bd1dd74c08603eac\n", + "24/10/04 18:04:27 WARN RapidsPluginUtils: RAPIDS Accelerator 24.10.0 using cudf 24.10.0, private revision 9fac64da220ddd6bf5626bd7bd1dd74c08603eac\n", "24/10/04 18:04:27 WARN RapidsPluginUtils: RAPIDS Accelerator is enabled, to disable GPU support set `spark.rapids.sql.enabled` to false.\n", "24/10/04 18:04:31 WARN GpuDeviceManager: RMM pool is disabled since spark.rapids.memory.gpu.pooling.enabled is set to false; however, this configuration is deprecated and the behavior may change in a future release.\n" ] @@ -57,7 +57,7 @@ " import os\n", " import requests\n", "\n", - " SPARK_RAPIDS_VERSION = \"24.08.1\"\n", + " SPARK_RAPIDS_VERSION = \"24.10.0\"\n", " rapids_jar = f\"rapids-4-spark_2.12-{SPARK_RAPIDS_VERSION}.jar\"\n", " if not os.path.exists(rapids_jar):\n", " print(\"Downloading spark rapids jar\")\n", @@ -539,7 +539,7 @@ ], "metadata": { "kernelspec": { - "display_name": "rapids-24.08", + "display_name": "rapids-24.10", "language": "python", "name": "python3" }, diff --git a/examples/SQL+DF-Examples/micro-benchmarks/notebooks/micro-benchmarks-gpu.ipynb b/examples/SQL+DF-Examples/micro-benchmarks/notebooks/micro-benchmarks-gpu.ipynb index e2c2b4a6f..a7f9780d3 100644 --- a/examples/SQL+DF-Examples/micro-benchmarks/notebooks/micro-benchmarks-gpu.ipynb +++ b/examples/SQL+DF-Examples/micro-benchmarks/notebooks/micro-benchmarks-gpu.ipynb @@ -22,7 +22,7 @@ "import os\n", "# Change to your cluster ip:port and directories\n", "SPARK_MASTER_URL = os.getenv(\"SPARK_MASTER_URL\", \"spark:your-ip:port\")\n", - "RAPIDS_JAR = os.getenv(\"RAPIDS_JAR\", \"/your-path/rapids-4-spark_2.12-24.08.1.jar\")\n" + "RAPIDS_JAR = os.getenv(\"RAPIDS_JAR\", \"/your-path/rapids-4-spark_2.12-24.10.0.jar\")\n" ] }, { diff --git a/examples/UDF-Examples/RAPIDS-accelerated-UDFs/README.md b/examples/UDF-Examples/RAPIDS-accelerated-UDFs/README.md index 2a9fcf6cf..67d9a618d 100644 --- a/examples/UDF-Examples/RAPIDS-accelerated-UDFs/README.md +++ b/examples/UDF-Examples/RAPIDS-accelerated-UDFs/README.md @@ -186,7 +186,7 @@ then do the following inside the Docker container. ### Get jars from Maven Central -[rapids-4-spark_2.12-24.08.1.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar) +[rapids-4-spark_2.12-24.10.0.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.10.0/rapids-4-spark_2.12-24.10.0.jar) ### Launch a local mode Spark diff --git a/examples/UDF-Examples/RAPIDS-accelerated-UDFs/pom.xml b/examples/UDF-Examples/RAPIDS-accelerated-UDFs/pom.xml index 0a238f7d7..80f9c6de0 100644 --- a/examples/UDF-Examples/RAPIDS-accelerated-UDFs/pom.xml +++ b/examples/UDF-Examples/RAPIDS-accelerated-UDFs/pom.xml @@ -37,7 +37,7 @@ cuda11 2.12 - 24.06.0 + 24.10.0 3.1.1 2.12.15 ${project.build.directory}/cpp-build diff --git a/examples/XGBoost-Examples/agaricus/notebooks/python/agaricus-gpu.ipynb b/examples/XGBoost-Examples/agaricus/notebooks/python/agaricus-gpu.ipynb index 7be0e60f4..d997ca123 100644 --- a/examples/XGBoost-Examples/agaricus/notebooks/python/agaricus-gpu.ipynb +++ b/examples/XGBoost-Examples/agaricus/notebooks/python/agaricus-gpu.ipynb @@ -73,7 +73,7 @@ "Setting default log level to \"WARN\".\n", "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", "2022-11-30 06:57:40,550 WARN resource.ResourceUtils: The configuration of cores (exec = 2 task = 1, runnable tasks = 2) will result in wasted resources due to resource gpu limiting the number of runnable tasks per executor to: 1. Please adjust your configuration.\n", - "2022-11-30 06:57:54,195 WARN rapids.RapidsPluginUtils: RAPIDS Accelerator 24.08.1 using cudf 24.08.1.\n", + "2022-11-30 06:57:54,195 WARN rapids.RapidsPluginUtils: RAPIDS Accelerator 24.10.0 using cudf 24.10.0.\n", "2022-11-30 06:57:54,210 WARN rapids.RapidsPluginUtils: spark.rapids.sql.multiThreadedRead.numThreads is set to 20.\n", "2022-11-30 06:57:54,214 WARN rapids.RapidsPluginUtils: RAPIDS Accelerator is enabled, to disable GPU support set `spark.rapids.sql.enabled` to false.\n", "2022-11-30 06:57:54,214 WARN rapids.RapidsPluginUtils: spark.rapids.sql.explain is set to `NOT_ON_GPU`. Set it to 'NONE' to suppress the diagnostics logging about the query placement on the GPU.\n", diff --git a/examples/XGBoost-Examples/mortgage/notebooks/python/MortgageETL.ipynb b/examples/XGBoost-Examples/mortgage/notebooks/python/MortgageETL.ipynb index 02875a23a..edb88183f 100644 --- a/examples/XGBoost-Examples/mortgage/notebooks/python/MortgageETL.ipynb +++ b/examples/XGBoost-Examples/mortgage/notebooks/python/MortgageETL.ipynb @@ -6,10 +6,10 @@ "source": [ "## Prerequirement\n", "### 1. Download data\n", - "Dataset is derived from Fannie Mae’s [Single-Family Loan Performance Data](http://www.fanniemae.com/portal/funding-the-market/data/loan-performance-data.html) with all rights reserved by Fannie Mae. Refer to these [instructions](https://github.com/NVIDIA/spark-rapids-examples/blob/branch-24.08/docs/get-started/xgboost-examples/dataset/mortgage.md) to download the dataset.\n", + "Dataset is derived from Fannie Mae’s [Single-Family Loan Performance Data](http://www.fanniemae.com/portal/funding-the-market/data/loan-performance-data.html) with all rights reserved by Fannie Mae. Refer to these [instructions](https://github.com/NVIDIA/spark-rapids-examples/blob/branch-24.10/docs/get-started/xgboost-examples/dataset/mortgage.md) to download the dataset.\n", "\n", "### 2. Download needed jars\n", - "* [rapids-4-spark_2.12-24.08.1.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar)\n", + "* [rapids-4-spark_2.12-24.10.0.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.10.0/rapids-4-spark_2.12-24.10.0.jar)\n", "\n", "\n", "### 3. Start Spark Standalone\n", @@ -17,7 +17,7 @@ "\n", "### 4. Add ENV\n", "```\n", - "$ export SPARK_JARS=rapids-4-spark_2.12-24.08.1.jar\n", + "$ export SPARK_JARS=rapids-4-spark_2.12-24.10.0.jar\n", "$ export PYSPARK_DRIVER_PYTHON=jupyter \n", "$ export PYSPARK_DRIVER_PYTHON_OPTS=notebook\n", "```\n", diff --git a/examples/XGBoost-Examples/mortgage/notebooks/python/cv-mortgage-gpu.ipynb b/examples/XGBoost-Examples/mortgage/notebooks/python/cv-mortgage-gpu.ipynb index fd1526467..663efeef7 100644 --- a/examples/XGBoost-Examples/mortgage/notebooks/python/cv-mortgage-gpu.ipynb +++ b/examples/XGBoost-Examples/mortgage/notebooks/python/cv-mortgage-gpu.ipynb @@ -63,7 +63,7 @@ "Setting default log level to \"WARN\".\n", "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", "2022-11-25 09:34:43,952 WARN resource.ResourceUtils: The configuration of cores (exec = 4 task = 1, runnable tasks = 4) will result in wasted resources due to resource gpu limiting the number of runnable tasks per executor to: 1. Please adjust your configuration.\n", - "2022-11-25 09:34:58,155 WARN rapids.RapidsPluginUtils: RAPIDS Accelerator 24.08.1 using cudf 24.08.1.\n", + "2022-11-25 09:34:58,155 WARN rapids.RapidsPluginUtils: RAPIDS Accelerator 24.10.0 using cudf 24.10.0.\n", "2022-11-25 09:34:58,171 WARN rapids.RapidsPluginUtils: spark.rapids.sql.multiThreadedRead.numThreads is set to 20.\n", "2022-11-25 09:34:58,175 WARN rapids.RapidsPluginUtils: RAPIDS Accelerator is enabled, to disable GPU support set `spark.rapids.sql.enabled` to false.\n", "2022-11-25 09:34:58,175 WARN rapids.RapidsPluginUtils: spark.rapids.sql.explain is set to `NOT_ON_GPU`. Set it to 'NONE' to suppress the diagnostics logging about the query placement on the GPU.\n" diff --git a/examples/XGBoost-Examples/mortgage/notebooks/python/mortgage-gpu.ipynb b/examples/XGBoost-Examples/mortgage/notebooks/python/mortgage-gpu.ipynb index f3f8ab047..e0b2ba339 100644 --- a/examples/XGBoost-Examples/mortgage/notebooks/python/mortgage-gpu.ipynb +++ b/examples/XGBoost-Examples/mortgage/notebooks/python/mortgage-gpu.ipynb @@ -84,7 +84,7 @@ "22/11/24 06:14:06 INFO org.apache.spark.SparkEnv: Registering BlockManagerMaster\n", "22/11/24 06:14:06 INFO org.apache.spark.SparkEnv: Registering BlockManagerMasterHeartbeat\n", "22/11/24 06:14:06 INFO org.apache.spark.SparkEnv: Registering OutputCommitCoordinator\n", - "22/11/24 06:14:07 WARN com.nvidia.spark.rapids.RapidsPluginUtils: RAPIDS Accelerator 24.08.1 using cudf 24.08.1.\n", + "22/11/24 06:14:07 WARN com.nvidia.spark.rapids.RapidsPluginUtils: RAPIDS Accelerator 24.10.0 using cudf 24.10.0.\n", "22/11/24 06:14:07 WARN com.nvidia.spark.rapids.RapidsPluginUtils: spark.rapids.sql.multiThreadedRead.numThreads is set to 20.\n", "22/11/24 06:14:07 WARN com.nvidia.spark.rapids.RapidsPluginUtils: RAPIDS Accelerator is enabled, to disable GPU support set `spark.rapids.sql.enabled` to false.\n", "22/11/24 06:14:07 WARN com.nvidia.spark.rapids.RapidsPluginUtils: spark.rapids.sql.explain is set to `NOT_ON_GPU`. Set it to 'NONE' to suppress the diagnostics logging about the query placement on the GPU.\n" diff --git a/examples/XGBoost-Examples/mortgage/notebooks/scala/mortgage-ETL.ipynb b/examples/XGBoost-Examples/mortgage/notebooks/scala/mortgage-ETL.ipynb index a2725240c..a55d07872 100644 --- a/examples/XGBoost-Examples/mortgage/notebooks/scala/mortgage-ETL.ipynb +++ b/examples/XGBoost-Examples/mortgage/notebooks/scala/mortgage-ETL.ipynb @@ -20,14 +20,14 @@ "Refer to these [instructions](https://github.com/NVIDIA/spark-rapids-examples/blob/branch-23.12/docs/get-started/xgboost-examples/dataset/mortgage.md) to download the dataset.\n", "\n", "### 2. Download needed jars\n", - "* [rapids-4-spark_2.12-24.08.1.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar)\n", + "* [rapids-4-spark_2.12-24.10.0.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.10.0/rapids-4-spark_2.12-24.10.0.jar)\n", "\n", "### 3. Start Spark Standalone\n", "Before Running the script, please setup Spark standalone mode\n", "\n", "### 4. Add ENV\n", "```\n", - "$ export SPARK_JARS=rapids-4-spark_2.12-24.08.1.jar\n", + "$ export SPARK_JARS=rapids-4-spark_2.12-24.10.0.jar\n", "\n", "```\n", "\n", diff --git a/examples/XGBoost-Examples/taxi/notebooks/python/cv-taxi-gpu.ipynb b/examples/XGBoost-Examples/taxi/notebooks/python/cv-taxi-gpu.ipynb index 35dc78f29..5a45fe466 100644 --- a/examples/XGBoost-Examples/taxi/notebooks/python/cv-taxi-gpu.ipynb +++ b/examples/XGBoost-Examples/taxi/notebooks/python/cv-taxi-gpu.ipynb @@ -62,7 +62,7 @@ "Setting default log level to \"WARN\".\n", "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", "2022-11-30 08:02:10,103 WARN resource.ResourceUtils: The configuration of cores (exec = 2 task = 1, runnable tasks = 2) will result in wasted resources due to resource gpu limiting the number of runnable tasks per executor to: 1. Please adjust your configuration.\n", - "2022-11-30 08:02:23,737 WARN rapids.RapidsPluginUtils: RAPIDS Accelerator 24.08.1 using cudf 24.08.1.\n", + "2022-11-30 08:02:23,737 WARN rapids.RapidsPluginUtils: RAPIDS Accelerator 24.10.0 using cudf 24.10.0.\n", "2022-11-30 08:02:23,752 WARN rapids.RapidsPluginUtils: spark.rapids.sql.multiThreadedRead.numThreads is set to 20.\n", "2022-11-30 08:02:23,756 WARN rapids.RapidsPluginUtils: RAPIDS Accelerator is enabled, to disable GPU support set `spark.rapids.sql.enabled` to false.\n", "2022-11-30 08:02:23,757 WARN rapids.RapidsPluginUtils: spark.rapids.sql.explain is set to `NOT_ON_GPU`. Set it to 'NONE' to suppress the diagnostics logging about the query placement on the GPU.\n", diff --git a/examples/XGBoost-Examples/taxi/notebooks/python/taxi-ETL.ipynb b/examples/XGBoost-Examples/taxi/notebooks/python/taxi-ETL.ipynb index b00765d46..f10937fed 100644 --- a/examples/XGBoost-Examples/taxi/notebooks/python/taxi-ETL.ipynb +++ b/examples/XGBoost-Examples/taxi/notebooks/python/taxi-ETL.ipynb @@ -19,14 +19,14 @@ "All data could be found at https://www1.nyc.gov/site/tlc/about/tlc-trip-record-data.page\n", "\n", "### 2. Download needed jars\n", - "* [rapids-4-spark_2.12-24.08.1.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar)\n", + "* [rapids-4-spark_2.12-24.10.0.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.10.0/rapids-4-spark_2.12-24.10.0.jar)\n", "\n", "### 3. Start Spark Standalone\n", "Before running the script, please setup Spark standalone mode\n", "\n", "### 4. Add ENV\n", "```\n", - "$ export SPARK_JARS=rapids-4-spark_2.12-24.08.1.jar\n", + "$ export SPARK_JARS=rapids-4-spark_2.12-24.10.0.jar\n", "$ export PYSPARK_DRIVER_PYTHON=jupyter \n", "$ export PYSPARK_DRIVER_PYTHON_OPTS=notebook\n", "```\n", diff --git a/examples/XGBoost-Examples/taxi/notebooks/python/taxi-gpu.ipynb b/examples/XGBoost-Examples/taxi/notebooks/python/taxi-gpu.ipynb index 078d3ad5c..1a1eb829c 100644 --- a/examples/XGBoost-Examples/taxi/notebooks/python/taxi-gpu.ipynb +++ b/examples/XGBoost-Examples/taxi/notebooks/python/taxi-gpu.ipynb @@ -73,7 +73,7 @@ "Setting default log level to \"WARN\".\n", "To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).\n", "2022-11-30 07:51:19,480 WARN resource.ResourceUtils: The configuration of cores (exec = 2 task = 1, runnable tasks = 2) will result in wasted resources due to resource gpu limiting the number of runnable tasks per executor to: 1. Please adjust your configuration.\n", - "2022-11-30 07:51:33,277 WARN rapids.RapidsPluginUtils: RAPIDS Accelerator 24.08.1 using cudf 24.08.1.\n", + "2022-11-30 07:51:33,277 WARN rapids.RapidsPluginUtils: RAPIDS Accelerator 24.10.0 using cudf 24.10.0.\n", "2022-11-30 07:51:33,292 WARN rapids.RapidsPluginUtils: spark.rapids.sql.multiThreadedRead.numThreads is set to 20.\n", "2022-11-30 07:51:33,295 WARN rapids.RapidsPluginUtils: RAPIDS Accelerator is enabled, to disable GPU support set `spark.rapids.sql.enabled` to false.\n", "2022-11-30 07:51:33,295 WARN rapids.RapidsPluginUtils: spark.rapids.sql.explain is set to `NOT_ON_GPU`. Set it to 'NONE' to suppress the diagnostics logging about the query placement on the GPU.\n", @@ -266,7 +266,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Training takes 24.08 seconds\n" + "Training takes 24.10 seconds\n" ] }, { diff --git a/examples/XGBoost-Examples/taxi/notebooks/scala/taxi-ETL.ipynb b/examples/XGBoost-Examples/taxi/notebooks/scala/taxi-ETL.ipynb index 979d2f9a9..02f38b99b 100644 --- a/examples/XGBoost-Examples/taxi/notebooks/scala/taxi-ETL.ipynb +++ b/examples/XGBoost-Examples/taxi/notebooks/scala/taxi-ETL.ipynb @@ -19,14 +19,14 @@ "All data could be found at https://www1.nyc.gov/site/tlc/about/tlc-trip-record-data.page\n", "\n", "### 2. Download needed jar\n", - "* [rapids-4-spark_2.12-24.08.1.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.08.1/rapids-4-spark_2.12-24.08.1.jar)\n", + "* [rapids-4-spark_2.12-24.10.0.jar](https://repo1.maven.org/maven2/com/nvidia/rapids-4-spark_2.12/24.10.0/rapids-4-spark_2.12-24.10.0.jar)\n", "\n", "### 3. Start Spark Standalone\n", "Before running the script, please setup Spark standalone mode\n", "\n", "### 4. Add ENV\n", "```\n", - "$ export SPARK_JARS=rapids-4-spark_2.12-24.08.1.jar\n", + "$ export SPARK_JARS=rapids-4-spark_2.12-24.10.0.jar\n", "\n", "```\n", "\n", diff --git a/tools/databricks/README.md b/tools/databricks/README.md index 7691e2508..540c41f66 100644 --- a/tools/databricks/README.md +++ b/tools/databricks/README.md @@ -20,4 +20,4 @@ top of the notebook. After that, select *Run all* to execute the tools for the 1. Multiple event logs must be comma-separated. - For example: `/dbfs/path/to/eventlog1,/dbfs/path/to/eventlog2` -**Latest Tools Version Supported** 24.08.0 \ No newline at end of file +**Latest Tools Version Supported** 24.10.0 \ No newline at end of file diff --git a/tools/databricks/[RAPIDS Accelerator for Apache Spark] Profiling Tool Notebook Template.ipynb b/tools/databricks/[RAPIDS Accelerator for Apache Spark] Profiling Tool Notebook Template.ipynb index 503b18ffb..f59953a13 100644 --- a/tools/databricks/[RAPIDS Accelerator for Apache Spark] Profiling Tool Notebook Template.ipynb +++ b/tools/databricks/[RAPIDS Accelerator for Apache Spark] Profiling Tool Notebook Template.ipynb @@ -53,7 +53,7 @@ }, "outputs": [], "source": [ - "TOOLS_VER = \"24.08.0\"\n", + "TOOLS_VER = \"24.10.0\"\n", "print(f\"Using Tools Version: {TOOLS_VER}\")" ] }, diff --git a/tools/databricks/[RAPIDS Accelerator for Apache Spark] Qualification Tool Notebook Template.ipynb b/tools/databricks/[RAPIDS Accelerator for Apache Spark] Qualification Tool Notebook Template.ipynb index 898a4846f..b27f2f919 100644 --- a/tools/databricks/[RAPIDS Accelerator for Apache Spark] Qualification Tool Notebook Template.ipynb +++ b/tools/databricks/[RAPIDS Accelerator for Apache Spark] Qualification Tool Notebook Template.ipynb @@ -49,7 +49,7 @@ }, "outputs": [], "source": [ - "TOOLS_VER = \"24.08.0\"\n", + "TOOLS_VER = \"24.10.0\"\n", "print(f\"Using Tools Version: {TOOLS_VER}\")" ] }, From 4a175362f57e7c4222abb55b93f0e572ddcb824d Mon Sep 17 00:00:00 2001 From: "Rishi C." <77904151+rishic3@users.noreply.github.com> Date: Fri, 25 Oct 2024 13:59:13 -0400 Subject: [PATCH 10/10] Add tags to skip Triton cells for CI/CD (#451) * Add Triton cell tags Signed-off-by: Rishi Chandra * Avoid relative paths in tf notebooks * Use pathlib for relative dirs * Account for tensorflow extraction path bug --------- Signed-off-by: Rishi Chandra --- .../conditional_generation_tf.ipynb | 124 +++++++++++++--- .../conditional_generation_torch.ipynb | 124 +++++++++++++--- .../huggingface/pipelines_tf.ipynb | 66 +++++++-- .../huggingface/pipelines_torch.ipynb | 66 +++++++-- .../sentence_transformers_torch.ipynb | 72 +++++++-- .../pytorch/image_classification_torch.ipynb | 71 +++++++-- .../pytorch/regression_torch.ipynb | 67 +++++++-- .../tensorflow/feature_columns_tf.ipynb | 124 ++++++++++++---- .../tensorflow/image_classification_tf.ipynb | 78 ++++++++-- .../tensorflow/keras-metadata_tf.ipynb | 64 ++++++-- .../tensorflow/text_classification_tf.ipynb | 138 +++++++++++++----- 11 files changed, 800 insertions(+), 194 deletions(-) diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_tf.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_tf.ipynb index e2c67eb98..3105e0661 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_tf.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_tf.ipynb @@ -1039,7 +1039,11 @@ "cell_type": "code", "execution_count": 35, "id": "b858cf85-82e6-41ef-905b-d8c5d6fea492", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import os" @@ -1049,7 +1053,11 @@ "cell_type": "code", "execution_count": 36, "id": "05ce7c77-d562-45e8-89bb-cd656aba5a5f", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "%%bash\n", @@ -1076,7 +1084,11 @@ "cell_type": "code", "execution_count": 37, "id": "afd00b7e-8150-4c95-a2e4-037e9c90f92a", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1160,7 +1172,9 @@ "execution_count": 38, "id": "1a997c33-5202-466d-8304-b8c30f32978f", "metadata": { - "tags": [] + "tags": [ + "TRITON" + ] }, "outputs": [], "source": [ @@ -1175,7 +1189,11 @@ "cell_type": "code", "execution_count": 39, "id": "9dea1875-6b95-4fc0-926d-a625a441b33d", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "# only use first N examples, since this is slow\n", @@ -1186,7 +1204,11 @@ "cell_type": "code", "execution_count": 40, "id": "5d6c54e7-534d-406f-b8e6-fd592efd0ab2", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "# only use first sentence and add prefix for conditional generation\n", @@ -1201,7 +1223,11 @@ "cell_type": "code", "execution_count": 41, "id": "dc1bbbe3-4232-49e5-80f6-99976524b73b", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "# only use first 100 rows, since generation takes a while\n", @@ -1212,7 +1238,11 @@ "cell_type": "code", "execution_count": 42, "id": "5d10c61c-6102-4d19-8dd6-0c7b5b65343e", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1255,7 +1285,11 @@ "cell_type": "code", "execution_count": 43, "id": "2e0907da-a5d9-4c3b-9db4-ce5e70ca9bb4", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "def triton_fn(triton_uri, model_name):\n", @@ -1305,7 +1339,11 @@ "cell_type": "code", "execution_count": 44, "id": "9308bdd7-6f67-484d-8b51-dd1e1b2960ba", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "generate = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"hf_generation_tf\"),\n", @@ -1318,7 +1356,11 @@ "cell_type": "code", "execution_count": 45, "id": "38484ffd-370d-492b-8ca4-9eff9f242a9f", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1354,7 +1396,11 @@ "cell_type": "code", "execution_count": 46, "id": "ebcb6699-3ac2-4529-ab0f-fab0a5e792da", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1389,7 +1435,11 @@ "cell_type": "code", "execution_count": 47, "id": "e2ed18ad-d00b-472c-b2c3-047932f2105d", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1424,7 +1474,11 @@ "cell_type": "code", "execution_count": 48, "id": "0cd64a1c-beb8-47d5-ac6f-e8525bb61176", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1481,7 +1535,11 @@ "cell_type": "code", "execution_count": 49, "id": "af70fed8-0f2b-4ea7-841c-476afdf9b1c0", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1500,7 +1558,11 @@ "cell_type": "code", "execution_count": 50, "id": "ef075e10-e22c-4236-9e0b-cb47cf2d3d06", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1543,7 +1605,11 @@ "cell_type": "code", "execution_count": 51, "id": "2e7e4af8-b815-4375-b851-8368309ee8e1", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1578,7 +1644,11 @@ "cell_type": "code", "execution_count": 52, "id": "7b0aefb0-a96b-4791-a23c-1ce9b24eb20c", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1613,7 +1683,11 @@ "cell_type": "code", "execution_count": 53, "id": "1214b75b-a373-4579-b4c6-0cb8627da776", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1648,7 +1722,11 @@ "cell_type": "code", "execution_count": 54, "id": "c9dbd21f-9e37-4221-b765-80ba8c80b884", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1715,7 +1793,11 @@ "cell_type": "code", "execution_count": 55, "id": "425d3b28-7705-45ba-8a18-ad34fc895219", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_torch.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_torch.ipynb index a09bede39..94cb7df19 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_torch.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/conditional_generation_torch.ipynb @@ -960,7 +960,11 @@ "cell_type": "code", "execution_count": 28, "id": "b858cf85-82e6-41ef-905b-d8c5d6fea492", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import os" @@ -970,7 +974,11 @@ "cell_type": "code", "execution_count": 29, "id": "05ce7c77-d562-45e8-89bb-cd656aba5a5f", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "%%bash\n", @@ -997,7 +1005,11 @@ "cell_type": "code", "execution_count": 30, "id": "afd00b7e-8150-4c95-a2e4-037e9c90f92a", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1079,7 +1091,9 @@ "execution_count": 31, "id": "1a997c33-5202-466d-8304-b8c30f32978f", "metadata": { - "tags": [] + "tags": [ + "TRITON" + ] }, "outputs": [], "source": [ @@ -1094,7 +1108,11 @@ "cell_type": "code", "execution_count": 32, "id": "9dea1875-6b95-4fc0-926d-a625a441b33d", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "# only use first N examples, since this is slow\n", @@ -1105,7 +1123,11 @@ "cell_type": "code", "execution_count": 33, "id": "5d6c54e7-534d-406f-b8e6-fd592efd0ab2", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "# only use first sentence and add prefix for conditional generation\n", @@ -1120,7 +1142,11 @@ "cell_type": "code", "execution_count": 34, "id": "dc1bbbe3-4232-49e5-80f6-99976524b73b", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "# only use first 100 rows, since generation takes a while\n", @@ -1131,7 +1157,11 @@ "cell_type": "code", "execution_count": 35, "id": "5d10c61c-6102-4d19-8dd6-0c7b5b65343e", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1174,7 +1204,11 @@ "cell_type": "code", "execution_count": 36, "id": "2e0907da-a5d9-4c3b-9db4-ce5e70ca9bb4", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "def triton_fn(triton_uri, model_name):\n", @@ -1224,7 +1258,11 @@ "cell_type": "code", "execution_count": 37, "id": "9308bdd7-6f67-484d-8b51-dd1e1b2960ba", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "generate = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"hf_generation_torch\"),\n", @@ -1237,7 +1275,11 @@ "cell_type": "code", "execution_count": 38, "id": "38484ffd-370d-492b-8ca4-9eff9f242a9f", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1273,7 +1315,11 @@ "cell_type": "code", "execution_count": 39, "id": "ebcb6699-3ac2-4529-ab0f-fab0a5e792da", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1308,7 +1354,11 @@ "cell_type": "code", "execution_count": 40, "id": "e2ed18ad-d00b-472c-b2c3-047932f2105d", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1343,7 +1393,11 @@ "cell_type": "code", "execution_count": 41, "id": "0cd64a1c-beb8-47d5-ac6f-e8525bb61176", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1386,7 +1440,11 @@ "cell_type": "code", "execution_count": 42, "id": "af70fed8-0f2b-4ea7-841c-476afdf9b1c0", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1405,7 +1463,11 @@ "cell_type": "code", "execution_count": 43, "id": "ef075e10-e22c-4236-9e0b-cb47cf2d3d06", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1448,7 +1510,11 @@ "cell_type": "code", "execution_count": 44, "id": "2e7e4af8-b815-4375-b851-8368309ee8e1", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1483,7 +1549,11 @@ "cell_type": "code", "execution_count": 45, "id": "7b0aefb0-a96b-4791-a23c-1ce9b24eb20c", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1518,7 +1588,11 @@ "cell_type": "code", "execution_count": 46, "id": "1214b75b-a373-4579-b4c6-0cb8627da776", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1553,7 +1627,11 @@ "cell_type": "code", "execution_count": 47, "id": "c9dbd21f-9e37-4221-b765-80ba8c80b884", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1606,7 +1684,11 @@ "cell_type": "code", "execution_count": 48, "id": "425d3b28-7705-45ba-8a18-ad34fc895219", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_tf.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_tf.ipynb index 115cfffc4..dcba0be87 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_tf.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_tf.ipynb @@ -589,7 +589,11 @@ "cell_type": "code", "execution_count": 22, "id": "4d4be844-4b8c-47df-bd09-0c280c7ff16b", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import numpy as np\n", @@ -604,7 +608,11 @@ "cell_type": "code", "execution_count": 23, "id": "7e53df9f-43cb-4c38-b8ac-dc2cbad99815", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "%%bash\n", @@ -631,7 +639,11 @@ "cell_type": "code", "execution_count": 24, "id": "144acb8e-4c08-40fc-a9ed-f721c409ee68", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -717,7 +729,11 @@ "cell_type": "code", "execution_count": 25, "id": "d53fb283-bf9e-4571-8c68-b75a41f1f067", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "# only use first sentence of IMDB reviews\n", @@ -732,7 +748,11 @@ "cell_type": "code", "execution_count": 26, "id": "29b0cc0d-c480-4e4a-bd41-207dc314cba5", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "def triton_fn(triton_uri, model_name):\n", @@ -782,7 +802,11 @@ "cell_type": "code", "execution_count": 27, "id": "3930cfcd-3284-4c6a-a9b5-36b8053fe899", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "from functools import partial\n", @@ -800,7 +824,11 @@ "cell_type": "code", "execution_count": 28, "id": "8eecbf23-4e9e-4d4c-8645-98209b25db2c", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -837,7 +865,11 @@ "cell_type": "code", "execution_count": 29, "id": "566ba28c-0ca4-4479-a24a-c8a362228b89", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -873,7 +905,11 @@ "cell_type": "code", "execution_count": 30, "id": "44c7e776-08da-484a-ba07-9d6add1a0f15", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -909,7 +945,11 @@ "cell_type": "code", "execution_count": 31, "id": "f61d79f8-661e-4d9e-a3aa-c0754b854603", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -976,7 +1016,11 @@ "cell_type": "code", "execution_count": 32, "id": "425d3b28-7705-45ba-8a18-ad34fc895219", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_torch.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_torch.ipynb index 47f45b670..1e99ed365 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_torch.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/pipelines_torch.ipynb @@ -484,7 +484,11 @@ "cell_type": "code", "execution_count": 21, "id": "4d4be844-4b8c-47df-bd09-0c280c7ff16b", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import numpy as np\n", @@ -499,7 +503,11 @@ "cell_type": "code", "execution_count": 22, "id": "7e53df9f-43cb-4c38-b8ac-dc2cbad99815", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "%%bash\n", @@ -526,7 +534,11 @@ "cell_type": "code", "execution_count": 23, "id": "144acb8e-4c08-40fc-a9ed-f721c409ee68", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -612,7 +624,11 @@ "cell_type": "code", "execution_count": 24, "id": "d53fb283-bf9e-4571-8c68-b75a41f1f067", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "# only use first sentence of IMDB reviews\n", @@ -627,7 +643,11 @@ "cell_type": "code", "execution_count": 25, "id": "29b0cc0d-c480-4e4a-bd41-207dc314cba5", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "def triton_fn(triton_uri, model_name):\n", @@ -677,7 +697,11 @@ "cell_type": "code", "execution_count": 26, "id": "3930cfcd-3284-4c6a-a9b5-36b8053fe899", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "from functools import partial\n", @@ -695,7 +719,11 @@ "cell_type": "code", "execution_count": 27, "id": "8eecbf23-4e9e-4d4c-8645-98209b25db2c", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -732,7 +760,11 @@ "cell_type": "code", "execution_count": 28, "id": "566ba28c-0ca4-4479-a24a-c8a362228b89", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -768,7 +800,11 @@ "cell_type": "code", "execution_count": 29, "id": "44c7e776-08da-484a-ba07-9d6add1a0f15", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -804,7 +840,11 @@ "cell_type": "code", "execution_count": 30, "id": "f61d79f8-661e-4d9e-a3aa-c0754b854603", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -857,7 +897,11 @@ "cell_type": "code", "execution_count": 31, "id": "425d3b28-7705-45ba-8a18-ad34fc895219", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/sentence_transformers_torch.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/sentence_transformers_torch.ipynb index 4a8a04078..deac314d0 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/sentence_transformers_torch.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/huggingface/sentence_transformers_torch.ipynb @@ -444,7 +444,11 @@ "cell_type": "code", "execution_count": 14, "id": "772e337e-1098-4c7b-ba81-8cb221a518e2", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import numpy as np\n", @@ -458,7 +462,11 @@ "cell_type": "code", "execution_count": 15, "id": "69d0c93a-bb0b-46c5-9d28-7b08a2e70964", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "%%bash\n", @@ -485,7 +493,11 @@ "cell_type": "code", "execution_count": 16, "id": "1654cdc1-4f9a-4fd5-b7ac-6ca4215bde5d", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -566,7 +578,11 @@ "cell_type": "code", "execution_count": 17, "id": "2969d502-e97b-49d6-bf80-7d177ae867cf", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "from functools import partial\n", @@ -579,7 +595,11 @@ "cell_type": "code", "execution_count": 18, "id": "c8f1e6d6-6519-49e7-8465-4419547633b8", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -598,7 +618,11 @@ "cell_type": "code", "execution_count": 19, "id": "29b0cc0d-c480-4e4a-bd41-207dc314cba5", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "def triton_fn(triton_uri, model_name):\n", @@ -648,7 +672,11 @@ "cell_type": "code", "execution_count": 20, "id": "9c712b8f-6eb4-4fb8-9f0a-04feef847fea", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "encode = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"hf_transformer_torch\"),\n", @@ -661,7 +689,11 @@ "cell_type": "code", "execution_count": 21, "id": "934c1a1f-b126-45b0-9c15-265236820ad3", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -683,7 +715,11 @@ "cell_type": "code", "execution_count": 22, "id": "f84cd3f6-b6a8-4142-859a-91f3c183457b", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -704,7 +740,11 @@ "cell_type": "code", "execution_count": 23, "id": "921a4c01-e296-4406-be90-86f20c8c582d", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -725,7 +765,11 @@ "cell_type": "code", "execution_count": 24, "id": "9f67584e-9c4e-474f-b6ea-7811b14d116e", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -778,7 +822,11 @@ "cell_type": "code", "execution_count": 25, "id": "d8e5466b-b5dc-4fe1-9012-0c87cdd72962", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification_torch.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification_torch.ipynb index ea07ce28a..b6d739a34 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification_torch.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/image_classification_torch.ipynb @@ -2007,7 +2007,11 @@ "cell_type": "code", "execution_count": 57, "id": "53ca290a-ccc3-4923-a292-944921bab36d", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import numpy as np\n", @@ -2022,7 +2026,11 @@ "cell_type": "code", "execution_count": 58, "id": "8fa92fe4-2e04-4d82-a357-bfdfca38bd8c", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "%%bash\n", @@ -2047,7 +2055,11 @@ "cell_type": "code", "execution_count": null, "id": "5e869730-3597-4074-bab0-f87768f8996a", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "num_executors = 1\n", @@ -2103,7 +2115,11 @@ "cell_type": "code", "execution_count": 60, "id": "ab94d4d1-dac6-4474-9eb0-59478aa98f7d", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "data": { @@ -2126,7 +2142,10 @@ "execution_count": 61, "id": "12b5f2fc-52e9-428a-b683-6ab1b639aa24", "metadata": { - "scrolled": true + "scrolled": true, + "tags": [ + "TRITON" + ] }, "outputs": [ { @@ -2148,7 +2167,11 @@ "cell_type": "code", "execution_count": 62, "id": "960657d0-31c9-4df6-8eb8-ac3d23137f7a", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "def triton_fn(triton_uri, model_name):\n", @@ -2198,7 +2221,11 @@ "cell_type": "code", "execution_count": 63, "id": "0262fd4a-9845-44b9-8c75-1c105e7deeca", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "mnist = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"fashion_mnist\"),\n", @@ -2211,7 +2238,11 @@ "cell_type": "code", "execution_count": 64, "id": "fc5f6baa-052e-4b89-94b6-4821cf01952a", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -2231,7 +2262,11 @@ "cell_type": "code", "execution_count": 65, "id": "a85dea35-e41d-482d-8a8f-52d3c108f038", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -2251,7 +2286,11 @@ "cell_type": "code", "execution_count": 66, "id": "bc3f0dbe-c52b-41d6-8097-8cebaa5ee5a8", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -2271,7 +2310,11 @@ "cell_type": "code", "execution_count": 67, "id": "99fb5e8d", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -2318,7 +2361,11 @@ "cell_type": "code", "execution_count": null, "id": "ab2fe42f-a072-4370-bac2-52fd95363530", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "def stop_triton(it):\n", diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression_torch.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression_torch.ipynb index 5ccc22ec2..3412f91a2 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression_torch.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/pytorch/regression_torch.ipynb @@ -2273,7 +2273,11 @@ "cell_type": "code", "execution_count": 73, "id": "a9ab4cdf-8103-447e-9ac8-944e2e527239", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import numpy as np\n", @@ -2288,7 +2292,11 @@ "cell_type": "code", "execution_count": 74, "id": "6632636e-67a3-406c-832c-758aac4245fd", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "%%bash\n", @@ -2313,7 +2321,10 @@ "execution_count": 75, "id": "c6fd1612-de6a-461c-a2ad-1a3fcd277d66", "metadata": { - "scrolled": true + "scrolled": true, + "tags": [ + "TRITON" + ] }, "outputs": [ { @@ -2388,7 +2399,11 @@ "cell_type": "code", "execution_count": 76, "id": "5eae04bc-75ca-421a-87c8-ac507ce1f2f5", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "df = spark.read.parquet(\"california_housing\")" @@ -2399,7 +2414,9 @@ "execution_count": 77, "id": "b350bd8e-9b8f-4511-9ddf-76d917b21b5f", "metadata": { - "tags": [] + "tags": [ + "TRITON" + ] }, "outputs": [ { @@ -2429,7 +2446,11 @@ "cell_type": "code", "execution_count": 78, "id": "69b343ec-688d-4e4d-985e-db72beaaf00c", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "def triton_fn(triton_uri, model_name):\n", @@ -2479,7 +2500,11 @@ "cell_type": "code", "execution_count": 79, "id": "d3e64fda-117b-4810-a9a2-dd498239496f", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "classify = predict_batch_udf(partial(triton_fn, triton_uri=\"localhost:8001\", model_name=\"housing_model\"),\n", @@ -2492,7 +2517,11 @@ "cell_type": "code", "execution_count": 80, "id": "a24149a5-3adc-4089-8769-13cf1e44547a", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -2514,7 +2543,11 @@ "cell_type": "code", "execution_count": 81, "id": "df2ce39f-30af-491a-8472-800fb1ce8458", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -2535,7 +2568,11 @@ "cell_type": "code", "execution_count": 82, "id": "ca6f3eaa-9569-45d0-88bf-9aa0757e1ecb", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "# should raise ValueError\n", @@ -2548,7 +2585,9 @@ "execution_count": 83, "id": "b79c62c8-e1e8-4467-8aef-8939c31833b8", "metadata": { - "tags": [] + "tags": [ + "TRITON" + ] }, "outputs": [ { @@ -2602,7 +2641,11 @@ "cell_type": "code", "execution_count": 84, "id": "15e9b3df-f3c9-46bb-bbeb-42496f7663de", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/feature_columns_tf.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/feature_columns_tf.ipynb index 17af1c934..2ff37b6c6 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/feature_columns_tf.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/feature_columns_tf.ipynb @@ -23,7 +23,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "01162f42-0637-4dfe-8d7d-b577e4ffd017", "metadata": {}, "outputs": [ @@ -31,13 +31,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "2024-10-03 17:38:52.548855: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", - "2024-10-03 17:38:52.555529: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", - "2024-10-03 17:38:52.563119: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", - "2024-10-03 17:38:52.565499: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", - "2024-10-03 17:38:52.571252: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "2024-10-24 16:04:17.711230: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2024-10-24 16:04:17.719701: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", + "2024-10-24 16:04:17.728758: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", + "2024-10-24 16:04:17.731459: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", + "2024-10-24 16:04:17.738797: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", "To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", - "2024-10-03 17:38:52.894224: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" + "2024-10-24 16:04:18.115892: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" ] } ], @@ -51,7 +51,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "id": "9fa3e1b7-58cd-45f9-9fee-85f25a31c3c6", "metadata": {}, "outputs": [ @@ -78,22 +78,29 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 7, "id": "9326b072-a53c-40c4-a6cb-bd4d3d644d03", "metadata": {}, "outputs": [], "source": [ + "import pathlib\n", + "import os\n", "dataset_url = 'http://storage.googleapis.com/download.tensorflow.org/data/petfinder-mini.zip'\n", - "csv_file = 'datasets/petfinder-mini/petfinder-mini.csv'\n", "\n", - "tf.keras.utils.get_file('petfinder_mini.zip', dataset_url,\n", - " extract=True, cache_dir='.')\n", - "dataframe = pd.read_csv(csv_file)" + "data_dir = tf.keras.utils.get_file('petfinder_mini.zip', dataset_url, extract=True, cache_dir='.')\n", + "data_dir = pathlib.Path(data_dir)\n", + "try:\n", + " # pet-finder-mini might be under a parent a directory petfinder_mini_extracted. Check if this is the case:\n", + " dataset = os.path.join(os.path.dirname(data_dir), 'petfinder_mini_extracted/petfinder-mini/petfinder-mini.csv')\n", + " dataframe = pd.read_csv(dataset)\n", + "except:\n", + " dataset = os.path.join(os.path.dirname(data_dir), 'petfinder-mini/petfinder-mini.csv')\n", + " dataframe = pd.read_csv(dataset)" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 11, "id": "e98480ef-d13d-44c0-a227-e9a22f9bf2b0", "metadata": {}, "outputs": [ @@ -253,7 +260,7 @@ "4 This handsome yet cute boy is up for adoption.... 3 2 " ] }, - "execution_count": 5, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -1267,7 +1274,11 @@ "cell_type": "code", "execution_count": 45, "id": "2605d134-ef75-4d94-9b16-2c6d85f29bef", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import numpy as np\n", @@ -1281,7 +1292,11 @@ "cell_type": "code", "execution_count": 46, "id": "4666e618-8038-4dc5-9be7-793aedbf4500", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1316,7 +1331,10 @@ "execution_count": 47, "id": "a7fb146c-5319-4831-85f7-f2f3c084b042", "metadata": { - "scrolled": true + "scrolled": true, + "tags": [ + "TRITON" + ] }, "outputs": [ { @@ -1395,7 +1413,11 @@ "cell_type": "code", "execution_count": 48, "id": "fe8dc3e6-f1b1-4a24-85f4-0a5ecabef4c5", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "df = spark.read.parquet(\"datasets/petfinder-mini\")" @@ -1405,7 +1427,11 @@ "cell_type": "code", "execution_count": 49, "id": "ce92f041-930f-48ed-9a03-19f6c249ca27", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1433,7 +1459,11 @@ "cell_type": "code", "execution_count": 50, "id": "4cfb3f34-a215-4781-91bf-2bec85e15633", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1454,7 +1484,9 @@ "id": "b315ee72-62af-476b-a994-0dba72d5f96e", "metadata": { "scrolled": true, - "tags": [] + "tags": [ + "TRITON" + ] }, "outputs": [ { @@ -1475,7 +1507,11 @@ "cell_type": "code", "execution_count": 52, "id": "da004eca-f7ad-4ee3-aa88-a6a20c1b72e5", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "def triton_fn(triton_uri, model_name):\n", @@ -1545,7 +1581,11 @@ "cell_type": "code", "execution_count": 53, "id": "2ffb020e-dc93-456b-bee6-405611eee1e1", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "from functools import partial\n", @@ -1561,7 +1601,11 @@ "cell_type": "code", "execution_count": 54, "id": "7657f820-5ec2-4ac8-a107-4b58773d204a", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1597,7 +1641,7 @@ } ], "source": [ - "# FAILS: Op type not registered 'DenseBincount' WITHOUT custom python backend\n", + "# WITHOUT custom python backend, FAILS with: Op type not registered 'DenseBincount' \n", "df.withColumn(\"preds\", classify(struct(*columns))).show(truncate=10)" ] }, @@ -1605,7 +1649,11 @@ "cell_type": "code", "execution_count": 55, "id": "e6ff0356-becd-421f-aebb-272497d5ad6a", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1633,7 +1681,11 @@ "cell_type": "code", "execution_count": 56, "id": "ce18ee7c-5958-4986-b200-6d986fcc6243", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1669,7 +1721,9 @@ "execution_count": 57, "id": "0888ce40-b2c4-4aed-8ccb-6a8bcd00abc8", "metadata": { - "tags": [] + "tags": [ + "TRITON" + ] }, "outputs": [ { @@ -1698,7 +1752,11 @@ "cell_type": "code", "execution_count": 58, "id": "d45812b5-f584-41a4-a821-2b59e065671c", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1751,7 +1809,11 @@ "cell_type": "code", "execution_count": 59, "id": "6914f44f-677f-4db3-be09-783df8d11b8a", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification_tf.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification_tf.ipynb index 5add2686b..f7df9f513 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification_tf.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/image_classification_tf.ipynb @@ -1950,7 +1950,11 @@ "cell_type": "code", "execution_count": 52, "id": "a64d19b1-ba4a-4dc7-b3a9-368dc47d0fd8", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import os\n", @@ -1963,7 +1967,11 @@ "cell_type": "code", "execution_count": 53, "id": "8fa92fe4-2e04-4d82-a357-bfdfca38bd8c", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "%%bash\n", @@ -1988,7 +1996,11 @@ "cell_type": "code", "execution_count": 54, "id": "0f7ecb25-be16-40c4-bdbb-441e2f537000", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -2055,7 +2067,11 @@ "cell_type": "code", "execution_count": 55, "id": "43b93753-1d52-4060-9986-f24c30a67528", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "data": { @@ -2085,7 +2101,11 @@ "cell_type": "code", "execution_count": 56, "id": "3af08bd0-3838-4769-a8de-2643db4101c6", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "def triton_fn(triton_uri, model_name):\n", @@ -2135,7 +2155,11 @@ "cell_type": "code", "execution_count": 57, "id": "6658d2a1-ef7b-4ca1-9fb6-f2ac9050f3e5", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "from functools import partial\n", @@ -2150,7 +2174,11 @@ "cell_type": "code", "execution_count": 58, "id": "8397aa14-82fd-4351-a477-dc8e8b321fa2", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -2170,7 +2198,11 @@ "cell_type": "code", "execution_count": 59, "id": "82698bd9-377a-4415-8971-835487f876cc", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -2190,7 +2222,11 @@ "cell_type": "code", "execution_count": 60, "id": "419ad7bd-fa28-49d3-b98d-db9fba5aeaef", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -2321,7 +2357,11 @@ "cell_type": "code", "execution_count": 61, "id": "79d90a26", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", @@ -2332,7 +2372,11 @@ "cell_type": "code", "execution_count": 62, "id": "4ca495f5", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "sample = preds.iloc[0]\n", @@ -2346,7 +2390,11 @@ "cell_type": "code", "execution_count": 63, "id": "a5d10903", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "data": { @@ -2380,7 +2428,11 @@ "cell_type": "code", "execution_count": 64, "id": "9c9fd967-5cd9-4265-add9-db5c1ccf9893", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/keras-metadata_tf.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/keras-metadata_tf.ipynb index e0683e388..007f6d8ae 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/keras-metadata_tf.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/keras-metadata_tf.ipynb @@ -768,7 +768,11 @@ "cell_type": "code", "execution_count": 29, "id": "2605d134-ef75-4d94-9b16-2c6d85f29bef", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import os\n", @@ -781,7 +785,11 @@ "cell_type": "code", "execution_count": 30, "id": "4666e618-8038-4dc5-9be7-793aedbf4500", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "%%bash\n", @@ -806,7 +814,11 @@ "cell_type": "code", "execution_count": 31, "id": "8c8c0744-0558-4dac-bbfe-8bdde4b2af2d", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -880,7 +892,11 @@ "cell_type": "code", "execution_count": 32, "id": "bcd46360-6851-4a9d-8590-c086e001242a", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "def triton_fn(triton_uri, model_name):\n", @@ -931,7 +947,11 @@ "cell_type": "code", "execution_count": 33, "id": "9fabcaeb-5a44-42bb-8097-5dbc2d0cee3e", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "from functools import partial\n", @@ -946,7 +966,11 @@ "cell_type": "code", "execution_count": 34, "id": "b17f33c8-a0f0-4bce-91f8-5838ba9b12a7", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "# spark.conf.set(\"spark.sql.execution.arrow.maxRecordsPerBatch\", \"1024\")\n", @@ -957,7 +981,11 @@ "cell_type": "code", "execution_count": 35, "id": "8e5b9e99-a1cf-43d3-a795-c7271a917057", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "df = spark.read.parquet(\"image_data.parquet\")" @@ -968,7 +996,9 @@ "execution_count": 36, "id": "e595473d-1a5d-46a6-a6ba-89d2ea903de9", "metadata": { - "tags": [] + "tags": [ + "TRITON" + ] }, "outputs": [ { @@ -1031,7 +1061,11 @@ "cell_type": "code", "execution_count": 37, "id": "5f66d468-e0b1-4589-8606-b3848063a823", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1092,7 +1126,11 @@ "cell_type": "code", "execution_count": 38, "id": "632c4c3a-fa52-4c3d-b71e-7526286e353a", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1137,7 +1175,11 @@ "cell_type": "code", "execution_count": 39, "id": "bbfcaa51-3b9f-43ff-a4a8-4b46766115b8", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", diff --git a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/text_classification_tf.ipynb b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/text_classification_tf.ipynb index 971bf393d..63499611c 100644 --- a/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/text_classification_tf.ipynb +++ b/examples/ML+DL-Examples/Spark-DL/dl_inference/tensorflow/text_classification_tf.ipynb @@ -23,7 +23,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "id": "76f0f5df-502f-444e-b2ee-1122e1dea870", "metadata": {}, "outputs": [ @@ -31,13 +31,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "2024-10-03 17:43:56.140645: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", - "2024-10-03 17:43:56.147227: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", - "2024-10-03 17:43:56.154601: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", - "2024-10-03 17:43:56.156763: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", - "2024-10-03 17:43:56.162424: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "2024-10-24 16:15:43.020721: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2024-10-24 16:15:43.028070: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:485] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", + "2024-10-24 16:15:43.035674: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:8454] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", + "2024-10-24 16:15:43.037910: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1452] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", + "2024-10-24 16:15:43.044256: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", "To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", - "2024-10-03 17:43:56.485452: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" + "2024-10-24 16:15:43.368732: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" ] } ], @@ -54,7 +54,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "id": "a364ad5f-b269-45b5-ab8b-d8f34fb642b7", "metadata": {}, "outputs": [ @@ -72,7 +72,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "id": "57b1d71f", "metadata": {}, "outputs": [], @@ -89,27 +89,42 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 10, "id": "d229c1b6-3967-46b5-9ea8-68f4b42dd211", "metadata": {}, + "outputs": [], + "source": [ + "import pathlib\n", + "url = \"https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz\"\n", + "\n", + "dataset = tf.keras.utils.get_file(\n", + " fname=\"aclImdb\", origin=url, untar=True,\n", + ")\n", + "\n", + "dataset_dir = pathlib.Path(dataset)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "bfa5177f", + "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Downloading data from https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz\n", - "\u001b[1m84125825/84125825\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m4s\u001b[0m 0us/step\n" + "/home/rishic/.keras/datasets/aclImdb\n", + "/home/rishic/.keras/datasets/aclImdb\n" ] } ], "source": [ - "url = \"https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz\"\n", - "\n", - "dataset = tf.keras.utils.get_file(\n", - " \"aclImdb_v1\", url, untar=True, cache_dir=\".\", cache_subdir=\"\"\n", - ")\n", - "\n", - "dataset_dir = os.path.join(os.path.dirname(dataset), \"aclImdb\")" + "print(dataset_dir)\n", + "# aclImdb might be created as a directory containing a single directory aclImdb. Check if this is the case:\n", + "if os.path.exists(dataset_dir / \"aclImdb\"):\n", + " dataset_dir = dataset_dir / \"aclImdb\"\n", + "print(dataset_dir)" ] }, { @@ -135,7 +150,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 13, "id": "12faaa3f-3441-4361-b9eb-4317e8c2c2f7", "metadata": {}, "outputs": [ @@ -152,19 +167,20 @@ " 'unsup']" ] }, - "execution_count": 7, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "train_dir = os.path.join(dataset_dir, \"train\")\n", + "test_dir = os.path.join(dataset_dir, \"test\")\n", "os.listdir(train_dir)" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 14, "id": "152cc0cc-65d0-4e17-9ee8-222390df45b5", "metadata": {}, "outputs": [ @@ -184,7 +200,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 15, "id": "b2277f58-78c8-4a12-bc98-5103e7c81a35", "metadata": {}, "outputs": [], @@ -195,7 +211,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 17, "id": "ed83de92-ebb3-4170-b2bf-25265c6a6942", "metadata": {}, "outputs": [ @@ -211,7 +227,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "2024-10-03 17:44:07.678162: I tensorflow/core/common_runtime/gpu/gpu_device.cc:2021] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 44790 MB memory: -> device: 0, name: NVIDIA RTX A6000, pci bus id: 0000:01:00.0, compute capability: 8.6\n" + "2024-10-24 02:18:45.343343: I tensorflow/core/common_runtime/gpu/gpu_device.cc:2021] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 46446 MB memory: -> device: 0, name: NVIDIA RTX A6000, pci bus id: 0000:01:00.0, compute capability: 8.6\n" ] } ], @@ -220,7 +236,7 @@ "seed = 42\n", "\n", "raw_train_ds = tf.keras.utils.text_dataset_from_directory(\n", - " \"aclImdb/train\",\n", + " train_dir,\n", " batch_size=batch_size,\n", " validation_split=0.2,\n", " subset=\"training\",\n", @@ -298,7 +314,7 @@ ], "source": [ "raw_val_ds = tf.keras.utils.text_dataset_from_directory(\n", - " \"aclImdb/train\",\n", + " train_dir,\n", " batch_size=batch_size,\n", " validation_split=0.2,\n", " subset=\"validation\",\n", @@ -322,7 +338,7 @@ ], "source": [ "raw_test_ds = tf.keras.utils.text_dataset_from_directory(\n", - " \"aclImdb/test\", batch_size=batch_size\n", + " test_dir, batch_size=batch_size\n", ")" ] }, @@ -1374,7 +1390,11 @@ "cell_type": "code", "execution_count": 47, "id": "772e337e-1098-4c7b-ba81-8cb221a518e2", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import numpy as np\n", @@ -1388,7 +1408,11 @@ "cell_type": "code", "execution_count": 48, "id": "69d0c93a-bb0b-46c5-9d28-7b08a2e70964", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "%%bash\n", @@ -1405,7 +1429,11 @@ "cell_type": "code", "execution_count": 49, "id": "f4f14c8f", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "import unicodedata\n", @@ -1444,7 +1472,11 @@ "cell_type": "code", "execution_count": 50, "id": "a7fb146c-5319-4831-85f7-f2f3c084b042", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr", @@ -1522,7 +1554,11 @@ "cell_type": "code", "execution_count": 51, "id": "41106a02-236e-4cb3-ac51-76aa64b663c2", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1574,7 +1610,11 @@ "cell_type": "code", "execution_count": 52, "id": "8b763167-7f50-4278-9bc9-6c3433b62294", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "data": { @@ -1596,7 +1636,11 @@ "cell_type": "code", "execution_count": 53, "id": "29b0cc0d-c480-4e4a-bd41-207dc314cba5", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "def triton_fn(triton_uri, model_name):\n", @@ -1646,7 +1690,11 @@ "cell_type": "code", "execution_count": 54, "id": "8e06d33f-5cef-4a48-afc3-5d468f8ec2b4", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [], "source": [ "from functools import partial\n", @@ -1661,7 +1709,11 @@ "cell_type": "code", "execution_count": 55, "id": "d89e74ad-e551-4bfa-ad08-98725878630a", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1714,7 +1766,11 @@ "cell_type": "code", "execution_count": 56, "id": "b4fa7fc9-341c-49a6-9af2-e316f2355d67", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stdout", @@ -1770,7 +1826,11 @@ "cell_type": "code", "execution_count": 57, "id": "a71ac9b6-47a2-4306-bc40-9ce7b4e968ec", - "metadata": {}, + "metadata": { + "tags": [ + "TRITON" + ] + }, "outputs": [ { "name": "stderr",