├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .github └── workflows │ ├── cicd.yml │ ├── docker-image.yml │ └── static.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── bentoml ├── README.md └── hello.py ├── examples └── quickstart │ ├── .bentoignore │ ├── BENCHMARK.md │ ├── README.md │ ├── bentofile.yaml │ ├── iris_classifier.ipynb │ ├── locustfile.py │ ├── query.py │ ├── query.sh │ ├── requirements.txt │ ├── service.py │ └── train.py ├── four-score.m4a.srt ├── four-score.m4a.txt ├── four-score.m4a.vtt ├── hugging-face ├── download_hf_model.py ├── hf_fine_tune_hello_world.py ├── hf_whisper.py ├── load_model.py └── zero_shot_classification.py ├── input.txt ├── keywords.txt ├── main.py ├── mylib ├── __init__.py └── calculator.py ├── repeat.sh ├── requirements.txt ├── setup.sh ├── test_main.py ├── tf-requirements.txt └── utils ├── README.md ├── four-score.m4a ├── four-score.wav ├── install-nvidia-container-toolkit.sh ├── kw_extract.py ├── quickstart_pytorch.py ├── quickstart_tf2.py ├── transcribe-whisper.sh ├── verify_pytorch.py └── verify_tf.py /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/codespaces-linux/.devcontainer/base.Dockerfile 2 | FROM mcr.microsoft.com/vscode/devcontainers/universal:2-focal 3 | 4 | RUN apt-get update && apt-get -y install --no-install-recommends \ 5 | ffmpeg \ 6 | python3.8-venv \ 7 | gcc \ 8 | pciutils 9 | 10 | # https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#install-guide 11 | RUN distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \ 12 | && curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ 13 | && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \ 14 | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ 15 | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list 16 | 17 | RUN apt-get update \ 18 | && apt-get install -y nvidia-docker2 \ 19 | && systemctl restart docker 20 | 21 | #create global virtual environment using python standard library tools of virtualenv 22 | ARG USER="codespace" 23 | ARG VENV_PATH="/home/${USER}/venv" 24 | COPY requirements.txt /tmp/ 25 | COPY Makefile /tmp/ 26 | RUN su $USER -c "/usr/bin/python3 -m venv /home/${USER}/venv" \ 27 | && su $USER -c "${VENV_PATH}/bin/pip --disable-pip-version-check --no-cache-dir install -r /tmp/requirements.txt" \ 28 | && rm -rf /tmp/requirements.txt 29 | 30 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/codespaces-linux 3 | { 4 | "name": "GitHub Codespaces (Default)", 5 | 6 | "build": { 7 | "dockerfile": "Dockerfile", 8 | "context": ".." 9 | }, 10 | "features": { 11 | "ghcr.io/devcontainers/features/nvidia-cuda:1": { 12 | "installCudnn": true 13 | }, 14 | "ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {} 15 | }, 16 | 17 | // Configure tool-specific properties. 18 | "customizations": { 19 | // Configure properties specific to VS Code. 20 | "vscode": { 21 | // Set *default* container specific settings.json values on container create. 22 | "settings": { 23 | "go.toolsManagement.checkForUpdates": "local", 24 | "go.useLanguageServer": true, 25 | "go.gopath": "/go", 26 | "python.defaultInterpreterPath": "/home/codespace/venv/bin/python", 27 | "python.linting.enabled": true, 28 | "python.linting.pylintEnabled": true, 29 | "python.formatting.autopep8Path": "/home/codespace/venv/bin/autopep8", 30 | "python.formatting.blackPath": "/home/codespace/venv/bin/black", 31 | "python.formatting.yapfPath": "/home/codespace/venv/bin/yapf", 32 | "python.linting.banditPath": "/home/codespace/venv/bin/bandit", 33 | "python.linting.flake8Path": "/home/codespace/venv/bin/flake8", 34 | "python.linting.mypyPath": "/home/codespace/venv/bin/mypy", 35 | "python.linting.pycodestylePath": "/home/codespace/venv/bin/pycodestyle", 36 | "python.linting.pydocstylePath": "/home/codespace/venv/bin/pydocstyle", 37 | "python.linting.pylintPath": "/home/codespace/venv/bin/pylint", 38 | "lldb.executable": "/usr/bin/lldb", 39 | "files.watcherExclude": { 40 | "**/target/**": true 41 | } 42 | }, 43 | 44 | // Add the IDs of extensions you want installed when the container is created. 45 | "extensions": [ 46 | "GitHub.vscode-pull-request-github", 47 | "GitHub.copilot-nightly", 48 | "GitHub.copilot-labs", 49 | "ms-azuretools.vscode-docker", 50 | "ms-toolsai.jupyter", 51 | "ms-toolsai.jupyter-keymap", 52 | "ms-toolsai.jupyter-renderers", 53 | "ms-python.vscode-pylance", 54 | "ms-python.python", 55 | "ms-vscode.makefile-tools" 56 | ] 57 | } 58 | }, 59 | 60 | "remoteUser": "codespace", 61 | 62 | "overrideCommand": false, 63 | 64 | "mounts": ["source=codespaces-linux-var-lib-docker,target=/var/lib/docker,type=volume"], 65 | 66 | "runArgs": [ 67 | "--cap-add=SYS_PTRACE", 68 | "--security-opt", 69 | "seccomp=unconfined", 70 | "--privileged", 71 | "--init", 72 | //"--gpus", "all" 73 | ], 74 | 75 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 76 | // "forwardPorts": [], 77 | 78 | // "oryx build" will automatically install your dependencies and attempt to build your project 79 | //"postCreateCommand": "oryx build -p virtualenv_name=.venv --log-file /tmp/oryx-build.log --manifest-dir /tmp || echo 'Could not auto-build. Skipping.'" 80 | "postCreateCommand": "bash setup.sh" 81 | } 82 | -------------------------------------------------------------------------------- /.github/workflows/cicd.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [ "GPU" ] 5 | pull_request: 6 | branches: [ "GPU" ] 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - name: install packages 15 | run: make install 16 | - name: lint 17 | run: make lint 18 | - name: test 19 | run: make test 20 | - name: format 21 | run: make format 22 | - name: deploy 23 | run: make deploy 24 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | pull_request: 5 | branches: [ "main" ] 6 | # Allow mannually trigger 7 | workflow_dispatch: 8 | 9 | jobs: 10 | 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Build the Codespaces container image 18 | run: docker build . --file .devcontainer/Dockerfile 19 | -------------------------------------------------------------------------------- /.github/workflows/static.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy static content to Pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["GPU"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow one concurrent deployment 19 | concurrency: 20 | group: "pages" 21 | cancel-in-progress: true 22 | 23 | jobs: 24 | # Single deploy job since we're just deploying 25 | deploy: 26 | environment: 27 | name: github-pages 28 | url: ${{ steps.deployment.outputs.page_url }} 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v3 33 | - name: Setup Pages 34 | uses: actions/configure-pages@v2 35 | - name: Upload artifact 36 | uses: actions/upload-pages-artifact@v1 37 | with: 38 | # Upload entire repository 39 | path: '.' 40 | - name: Deploy to GitHub Pages 41 | id: deployment 42 | uses: actions/deploy-pages@v1 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #ignore big media files 2 | media 3 | #ignore transcript changes from whisper tests:wq 4 | four-score.m4a.* 5 | 6 | #ignore huggingface 7 | summarizeApp 8 | #ignore fine-tuning 9 | test_trainer/ 10 | 11 | #ignore pytorch artifacts 12 | data 13 | model.pth 14 | 15 | # Byte-compiled / optimized / DLL files 16 | __pycache__/ 17 | *.py[cod] 18 | *$py.class 19 | 20 | # C extensions 21 | *.so 22 | 23 | # Distribution / packaging 24 | .Python 25 | build/ 26 | develop-eggs/ 27 | dist/ 28 | downloads/ 29 | eggs/ 30 | .eggs/ 31 | lib/ 32 | lib64/ 33 | parts/ 34 | sdist/ 35 | var/ 36 | wheels/ 37 | pip-wheel-metadata/ 38 | share/python-wheels/ 39 | *.egg-info/ 40 | .installed.cfg 41 | *.egg 42 | MANIFEST 43 | 44 | # PyInstaller 45 | # Usually these files are written by a python script from a template 46 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 47 | *.manifest 48 | *.spec 49 | 50 | # Installer logs 51 | pip-log.txt 52 | pip-delete-this-directory.txt 53 | 54 | # Unit test / coverage reports 55 | htmlcov/ 56 | .tox/ 57 | .nox/ 58 | .coverage 59 | .coverage.* 60 | .cache 61 | nosetests.xml 62 | coverage.xml 63 | *.cover 64 | *.py,cover 65 | .hypothesis/ 66 | .pytest_cache/ 67 | 68 | # Translations 69 | *.mo 70 | *.pot 71 | 72 | # Django stuff: 73 | *.log 74 | local_settings.py 75 | db.sqlite3 76 | db.sqlite3-journal 77 | 78 | # Flask stuff: 79 | instance/ 80 | .webassets-cache 81 | 82 | # Scrapy stuff: 83 | .scrapy 84 | 85 | # Sphinx documentation 86 | docs/_build/ 87 | 88 | # PyBuilder 89 | target/ 90 | 91 | # Jupyter Notebook 92 | .ipynb_checkpoints 93 | 94 | # IPython 95 | profile_default/ 96 | ipython_config.py 97 | 98 | # pyenv 99 | .python-version 100 | 101 | # pipenv 102 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 103 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 104 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 105 | # install all needed dependencies. 106 | #Pipfile.lock 107 | 108 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 109 | __pypackages__/ 110 | 111 | # Celery stuff 112 | celerybeat-schedule 113 | celerybeat.pid 114 | 115 | # SageMath parsed files 116 | *.sage.py 117 | 118 | # Environments 119 | .env 120 | .venv 121 | env/ 122 | venv/ 123 | ENV/ 124 | env.bak/ 125 | venv.bak/ 126 | 127 | # Spyder project settings 128 | .spyderproject 129 | .spyproject 130 | 131 | # Rope project settings 132 | .ropeproject 133 | 134 | # mkdocs documentation 135 | /site 136 | 137 | # mypy 138 | .mypy_cache/ 139 | .dmypy.json 140 | dmypy.json 141 | 142 | # Pyre type checker 143 | .pyre/ 144 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | RUN apk update && apk add bash 3 | 4 | WORKDIR /app 5 | COPY repeat.sh /app -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | pip install --upgrade pip &&\ 3 | pip install -r requirements.txt 4 | #force install latest whisper 5 | pip install --upgrade --no-deps --force-reinstall git+https://github.com/openai/whisper.git 6 | test: 7 | python -m pytest -vv --cov=main --cov=mylib test_*.py 8 | 9 | format: 10 | black *.py hugging-face/zero_shot_classification.py hugging-face/hf_whisper.py 11 | 12 | lint: 13 | pylint --disable=R,C --ignore-patterns=test_.*?py *.py mylib/*.py\ 14 | hugging-face/zero_shot_classification.py hugging-face/hf_whisper.py 15 | 16 | container-lint: 17 | docker run --rm -i hadolint/hadolint < Dockerfile 18 | 19 | checkgpu: 20 | echo "Checking GPU for PyTorch" 21 | python utils/verify_pytorch.py 22 | echo "Checking GPU for Tensorflow" 23 | python utils/verify_tf.py 24 | 25 | refactor: format lint 26 | 27 | deploy: 28 | #deploy goes here 29 | 30 | all: install lint test format deploy 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 🎓 Pragmatic AI Labs | Join 1M+ ML Engineers 2 | 3 | ### 🔥 Hot Course Offers: 4 | * 🤖 [Master GenAI Engineering](https://ds500.paiml.com/learn/course/0bbb5/) - Build Production AI Systems 5 | * 🦀 [Learn Professional Rust](https://ds500.paiml.com/learn/course/g6u1k/) - Industry-Grade Development 6 | * 📊 [AWS AI & Analytics](https://ds500.paiml.com/learn/course/31si1/) - Scale Your ML in Cloud 7 | * ⚡ [Production GenAI on AWS](https://ds500.paiml.com/learn/course/ehks1/) - Deploy at Enterprise Scale 8 | * 🛠️ [Rust DevOps Mastery](https://ds500.paiml.com/learn/course/ex8eu/) - Automate Everything 9 | 10 | ### 🚀 Level Up Your Career: 11 | * 💼 [Production ML Program](https://paiml.com) - Complete MLOps & Cloud Mastery 12 | * 🎯 [Start Learning Now](https://ds500.paiml.com) - Fast-Track Your ML Career 13 | * 🏢 Trusted by Fortune 500 Teams 14 | 15 | Learn end-to-end ML engineering from industry veterans at [PAIML.COM](https://paiml.com) 16 | 17 | 18 | [![CI](https://github.com/nogibjj/mlops-template/actions/workflows/cicd.yml/badge.svg?branch=GPU)](https://github.com/nogibjj/mlops-template/actions/workflows/cicd.yml) 19 | [![Codespaces Prebuilds](https://github.com/nogibjj/mlops-template/actions/workflows/codespaces/create_codespaces_prebuilds/badge.svg?branch=GPU)](https://github.com/nogibjj/mlops-template/actions/workflows/codespaces/create_codespaces_prebuilds) 20 | 21 | ## Template for MLOPs projects with GPU 22 | 23 | **CONDA IS NOT NEEDED AS A PACKAGE MANAGER. All setup is done using the Python Software Foundation recommended tools: virtualenv and pip and mainstream production tools Docker. Please see [PEP 453](https://peps.python.org/pep-0453/) "officially recommend the use of pip as the default installer for Python packages"** 24 | 25 | *GitHub Codespaces are FREE for education and as are GPU Codespaces as of this writing in December 2022* 26 | 27 | 1. First thing to do on launch is to open a new shell and verify virtualenv is sourced. 28 | 29 | Things included are: 30 | 31 | * `Makefile` 32 | 33 | * `Pytest` 34 | 35 | * `pandas` 36 | 37 | * `Pylint` or `ruff` 38 | 39 | * `Dockerfile` 40 | 41 | * `GitHub copilot` 42 | 43 | * `jupyter` and `ipython` 44 | 45 | * Most common Python libraries for ML/DL and Hugging Face 46 | 47 | * `githubactions` 48 | 49 | ## Two fun tools to explore: 50 | 51 | * Zero-shot classification: ./hugging-face/zero_shot_classification.py classify 52 | * Yake for candidate label creation: ./utils/kw_extract.py 53 | 54 | ## Try out Bento 55 | 56 | * [tutorial bento](https://docs.bentoml.org/en/latest/tutorial.html) 57 | 58 | `docker run -it --rm -p 8888:8888 -p 3000:3000 -p 3001:3001 bentoml/quickstart:latest` 59 | 60 | ### Verify GPU works 61 | 62 | The following examples test out the GPU (including Docker GPU) 63 | 64 | * run pytorch training test: `python utils/quickstart_pytorch.py` 65 | * run pytorch CUDA test: `python utils/verify_cuda_pytorch.py` 66 | * run tensorflow training test: `python utils/quickstart_tf2.py` 67 | * run nvidia monitoring test: `nvidia-smi -l 1` it should show a GPU 68 | * run whisper transcribe test `./utils/transcribe-whisper.sh` and verify GPU is working with `nvidia-smi -l 1` 69 | * run `lspci | grep -i nvidia` you should see something like: `0001:00:00.0 3D controller: NVIDIA Corporation GV100GL [Tesla V100 PCIe 16GB] (rev a1)` 70 | 71 | 72 | Additionally, this workspace is setup to fine-tune Hugging Face 73 | 74 | ![fine-tune](https://user-images.githubusercontent.com/58792/195709866-121f994e-3531-493b-99af-c3266c4e28ea.jpg) 75 | 76 | 77 | `python hugging-face/hf_fine_tune_hello_world.py` 78 | 79 | #### Verify containerized GPU works for Tensorflow 80 | 81 | *Because of potential versioning conflicts between PyTorch and Tensorflow it is recommended to run Tensorflow via GPU Container and PyTorch via default environment.* 82 | 83 | See [TensorFlow GPU documentation](https://www.tensorflow.org/install/docker) 84 | * Run `docker run --gpus all -it --rm tensorflow/tensorflow:latest-gpu \ 85 | python -c "import tensorflow as tf; print(tf.reduce_sum(tf.random.normal([1000, 1000])))"` 86 | 87 | * Also interactively explore: `docker run --gpus all -it --rm tensorflow/tensorflow:latest-gpu`, then when inside run: 88 | `apt-get update && apt-get install pciutils` then `lspci | grep -i nvidia` 89 | 90 | * To mount the code into your container: `docker run --gpus all -it --rm -v $(pwd):/tmp tensorflow/tensorflow:latest-gpu /bin/bash`. Then do `apt-get install -y git && cd /tmp`. Then all you need to do is run `make install`. Now you can verify you can train deep learning models by doing `python utils/quickstart_tf2.py` 91 | 92 | ##### More Tensorflow GPU Ideas 93 | 94 | https://www.tensorflow.org/resources/recommendation-systems 95 | 96 | ```bash 97 | # Deploy the retrieval model with TensorFlow Serving 98 | docker run -t --rm -p 8501:8501 \ 99 | -v "RETRIEVAL/MODEL/PATH:/models/retrieval" \ 100 | -e MODEL_NAME=retrieval tensorflow/serving & 101 | ``` 102 | 103 | ### Setup Docker Toolkit NVidia 104 | 105 | * [reference docs](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#install-guide) 106 | 107 | ![mlops-tensorflow-gpu](https://user-images.githubusercontent.com/58792/206875904-114b4cf0-879d-497b-8690-267dac8b222d.jpg) 108 | 109 | 110 | ### Used in Following Projects 111 | 112 | Used as the base and customized in the following Duke MLOps and Applied Data Engineering Coursera Labs: 113 | 114 | * [MLOPs-C2-Lab1-CICD](https://github.com/nogibjj/Coursera-MLOPs-Foundations-Lab-1-CICD) 115 | * [MLOps-C2-Lab2-PokerSimulator](https://github.com/nogibjj/Coursera-MLOPs-Foundations-Lab-2-poker-simulator) 116 | * [MLOps-C2-Final-HuggingFace](https://github.com/nogibjj/Coursera-MLOps-C2-Final-HuggingFace) 117 | * [Coursera-MLOps-C2-lab3-probability-simulations](Coursera-MLOps-C2-lab3-probability-simulations) 118 | * [Coursera-MLOps-C2-lab4-greedy-optimization](https://github.com/nogibjj/Coursera-MLOps-C2-lab4-greedy-optimization) 119 | ### References 120 | 121 | * [Docker "one-liners" for Tensorflow recommenders](https://www.tensorflow.org/resources/recommendation-systems) 122 | * [Watch GitHub Universe Talk: Teaching MLOps at scale with Github](https://watch.githubuniverse.com/on-demand/ec17cbb3-0a89-4764-90a5-9debb58515f8) 123 | * [Building Cloud Computing Solutions at Scale Specialization](https://www.coursera.org/specializations/building-cloud-computing-solutions-at-scale) 124 | * [Python, Bash and SQL Essentials for Data Engineering Specialization](https://www.coursera.org/learn/web-app-command-line-tools-for-data-engineering-duke) 125 | * [Implementing MLOps in the Enterprise](https://learning.oreilly.com/library/view/implementing-mlops-in/9781098136574/) 126 | * [Practical MLOps: Operationalizing Machine Learning Models](https://www.amazon.com/Practical-MLOps-Operationalizing-Machine-Learning/dp/1098103017) 127 | * [Coursera-Dockerfile](https://gist.github.com/noahgift/82a34d56f0a8f347865baaa685d5e98d) 128 | -------------------------------------------------------------------------------- /bentoml/README.md: -------------------------------------------------------------------------------- 1 | ## Bento Exploration 2 | 3 | `bentoml models list` 4 | 5 | ### Very clean format for dealing with models 6 | 7 | `ls /home/codespace/bentoml/models/iris_clf/ecde3adktowieaan/` 8 | `model.yaml` and `saved_model.pkl` 9 | 10 | ### Export the model 11 | 12 | `bentoml models export iris_clf:latest .` 13 | 14 | ### Try out Yatai 15 | 16 | * Must install minikube 17 | 18 | https://github.com/bentoml/Yatai 19 | 20 | `minikube start --cpus 4 --memory 4096` 21 | 22 | Check if it is running: 23 | 24 | `minikube status` 25 | 26 | Double check context: 27 | 28 | `kubectl config current-context` 29 | 30 | Enable ingress 31 | 32 | `minikube addons enable ingress` 33 | 34 | Then install: 35 | 36 | `bash <(curl -s "https://raw.githubusercontent.com/bentoml/yatai/main/scripts/quick-install-yatai.sh")` -------------------------------------------------------------------------------- /bentoml/hello.py: -------------------------------------------------------------------------------- 1 | import bentoml 2 | 3 | from sklearn import svm 4 | from sklearn import datasets 5 | 6 | # Load training data set 7 | iris = datasets.load_iris() 8 | X, y = iris.data, iris.target 9 | 10 | # Train the model 11 | clf = svm.SVC(gamma='scale') 12 | clf.fit(X, y) 13 | 14 | # Save model to the BentoML local model store 15 | saved_model = bentoml.sklearn.save_model("iris_clf", clf) 16 | print(f"Model saved: {saved_model}") 17 | -------------------------------------------------------------------------------- /examples/quickstart/.bentoignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.py[cod] 3 | *$py.class 4 | .ipynb_checkpoints 5 | -------------------------------------------------------------------------------- /examples/quickstart/BENCHMARK.md: -------------------------------------------------------------------------------- 1 | Run the iris_classifier service in production mode: 2 | 3 | | Protocol | Command | 4 | | -------- | -------------------------------------------------------- | 5 | | HTTP | `bentoml serve-http iris_classifier:latest --production` | 6 | | gRPC | `bentoml serve-grpc iris_classifier:latest --production` | 7 | 8 | Start locust testing client: 9 | 10 | ```bash 11 | locust --class-picker -H http://localhost:3000 12 | ``` 13 | -------------------------------------------------------------------------------- /examples/quickstart/README.md: -------------------------------------------------------------------------------- 1 | # BentoML Scikit-Learn Tutorial 2 | 3 | This is a sample project demonstrating basic usage of [BentoML](https://github.com/bentoml) with 4 | Scikit-learn. 5 | 6 | In this project, we will train a classifier model using Scikit-learn and the Iris dataset, build 7 | an prediction service for serving the trained model via an HTTP server, and containerize the 8 | model server as a docker image for production deployment. 9 | 10 | This project is also available to run from a notebook: https://github.com/bentoml/BentoML/blob/main/examples/quickstart/iris_classifier.ipynb 11 | 12 | ### Install Dependencies 13 | 14 | Install python packages required for running this project: 15 | ```bash 16 | pip install -r ./requirements.txt 17 | ``` 18 | 19 | ### Model Training 20 | 21 | First step, train a classification model with sklearn's built-in iris dataset and save the model 22 | with BentoML: 23 | 24 | ```bash 25 | import bentoml 26 | from sklearn import svm, datasets 27 | 28 | # Load training data 29 | iris = datasets.load_iris() 30 | X, y = iris.data, iris.target 31 | 32 | # Model Training 33 | clf = svm.SVC() 34 | clf.fit(X, y) 35 | 36 | # Save model to BentoML local model store 37 | bentoml.sklearn.save_model("iris_clf", clf) 38 | ``` 39 | 40 | This will save a new model in the BentoML local model store, a new version tag is automatically 41 | generated when the model is saved. You can see all model revisions from CLI via `bentoml models` 42 | commands: 43 | 44 | ```bash 45 | bentoml models get iris_clf:latest 46 | 47 | bentoml models list 48 | 49 | bentoml models --help 50 | ``` 51 | 52 | To verify that the saved model can be loaded correctly, run the following: 53 | 54 | ```python 55 | import bentoml 56 | 57 | loaded_model = bentoml.sklearn.load_model("iris_clf:latest") 58 | 59 | loaded_model.predict([[5.9, 3. , 5.1, 1.8]]) # => array(2) 60 | ``` 61 | 62 | In BentoML, the recommended way of running ML model inference in serving is via Runner, which 63 | gives BentoML more flexibility in terms of how to schedule the inference computation, how to 64 | batch inference requests and take advantage of hardware resoureces available. Saved models can 65 | be loaded as Runner instance as shown below: 66 | 67 | ```python 68 | import bentoml 69 | 70 | # Create a Runner instance: 71 | iris_clf_runner = bentoml.sklearn.get("iris_clf:latest").to_runner() 72 | 73 | # Runner#init_local initializes the model in current process, this is meant for development and testing only: 74 | iris_clf_runner.init_local() 75 | 76 | # This should yield the same result as the loaded model: 77 | iris_clf_runner.predict.run([[5.9, 3., 5.1, 1.8]]) 78 | ``` 79 | 80 | 81 | ### Serving the model 82 | 83 | A simple BentoML Service that serves the model saved above look like this: 84 | 85 | ```python 86 | import numpy as np 87 | import bentoml 88 | from bentoml.io import NumpyNdarray 89 | 90 | iris_clf_runner = bentoml.sklearn.get("iris_clf:latest").to_runner() 91 | 92 | svc = bentoml.Service("iris_classifier", runners=[iris_clf_runner]) 93 | 94 | @svc.api(input=NumpyNdarray(), output=NumpyNdarray()) 95 | async def classify(input_series: np.ndarray) -> np.ndarray: 96 | return await iris_clf_runner.predict.async_run(input_series) 97 | ``` 98 | 99 | Copy this to a `service.py` file, and run your service with Bento Server locally: 100 | 101 | ```bash 102 | bentoml serve service.py:svc --reload 103 | ``` 104 | 105 | Open your web browser at http://127.0.0.1:3000 to view the Bento UI for sending test requests. 106 | 107 | You may also send request with `curl` command or any HTTP client, e.g.: 108 | 109 | ```bash 110 | curl -X POST -H "content-type: application/json" --data "[[5.9, 3, 5.1, 1.8]]" http://127.0.0.1:3000/classify 111 | ``` 112 | 113 | 114 | ### Build Bento for deployment 115 | 116 | Bento is the distribution format in BentoML which captures all the source code, model files, config 117 | files and dependency specifications required for running the service for production deployment. Think 118 | of it as Docker/Container designed for machine learning models. 119 | 120 | To begin with building Bento, create a `bentofile.yaml` under your project directory: 121 | 122 | ```yaml 123 | service: "service.py:svc" 124 | labels: 125 | owner: bentoml-team 126 | project: gallery 127 | include: 128 | - "*.py" 129 | python: 130 | packages: 131 | - scikit-learn 132 | - pandas 133 | ``` 134 | 135 | Next, run `bentoml build` from current directory to start the Bento build: 136 | 137 | ``` 138 | > bentoml build 139 | 140 | 05/05/2022 19:19:16 INFO [cli] Building BentoML service "iris_classifier:5wtigdwm4kwzduqj" from build context "/Users/bentoml/workspace/gallery/quickstart" 141 | 05/05/2022 19:19:16 INFO [cli] Packing model "iris_clf:4i7wbngm4crhpuqj" from "/Users/bentoml/bentoml/models/iris_clf/4i7wbngm4crhpuqj" 142 | 05/05/2022 19:19:16 INFO [cli] Successfully saved Model(tag="iris_clf:4i7wbngm4crhpuqj", 143 | path="/var/folders/bq/gdsf0kmn2k1bf880r_l238600000gn/T/tmp26dx354ubentoml_bento_iris_classifier/models/iris_clf/4i7wbngm4crhpuqj/") 144 | 05/05/2022 19:19:16 INFO [cli] Locking PyPI package versions.. 145 | 05/05/2022 19:19:17 INFO [cli] 146 | ██████╗░███████╗███╗░░██╗████████╗░█████╗░███╗░░░███╗██╗░░░░░ 147 | ██╔══██╗██╔════╝████╗░██║╚══██╔══╝██╔══██╗████╗░████║██║░░░░░ 148 | ██████╦╝█████╗░░██╔██╗██║░░░██║░░░██║░░██║██╔████╔██║██║░░░░░ 149 | ██╔══██╗██╔══╝░░██║╚████║░░░██║░░░██║░░██║██║╚██╔╝██║██║░░░░░ 150 | ██████╦╝███████╗██║░╚███║░░░██║░░░╚█████╔╝██║░╚═╝░██║███████╗ 151 | ╚═════╝░╚══════╝╚═╝░░╚══╝░░░╚═╝░░░░╚════╝░╚═╝░░░░░╚═╝╚══════╝ 152 | 153 | 05/05/2022 19:19:17 INFO [cli] Successfully built Bento(tag="iris_classifier:5wtigdwm4kwzduqj") at "/Users/bentoml/bentoml/bentos/iris_classifier/5wtigdwm4kwzduqj/" 154 | ``` 155 | 156 | A new Bento is now built and saved to local Bento store. You can view and manage it via 157 | `bentoml list`,`bentoml get` and `bentoml delete` CLI command. 158 | 159 | 160 | ### Containerize and Deployment 161 | 162 | Bento is designed to be deployed to run efficiently in a variety of different environments. 163 | And there are lots of deployment options and tools as part of the BentoML eco-system, such as 164 | [Yatai](https://github.com/bentoml/Yatai) and [bentoctl](https://github.com/bentoml/bentoctl) for 165 | direct deployment to cloud platforms. 166 | 167 | In this guide, we will show you the most basic way of deploying a Bento, which is converting a Bento 168 | into a Docker image containing the HTTP model server. 169 | 170 | Make sure you have docker installed and docker deamon running, and run the following commnand: 171 | 172 | ```bash 173 | bentoml containerize iris_classifier:latest 174 | ``` 175 | 176 | This will build a new docker image with all source code, model files and dependencies in place, 177 | and ready for production deployment. To start a container with this docker image locally, run: 178 | 179 | ```bash 180 | docker run -p 3000:3000 iris_classifier:invwzzsw7li6zckb2ie5eubhd 181 | ``` 182 | 183 | ## What's Next? 184 | 185 | - 👉 [Pop into our Slack community!](https://l.linklyhq.com/l/ktO8) We're happy to help with any issue you face or even just to meet you and hear what you're working on. 186 | - Dive deeper into the [Core Concepts](https://docs.bentoml.org/en/latest/concepts/index.html) in BentoML 187 | - Learn how to use BentoML with other ML Frameworks at [Frameworks Guide](https://docs.bentoml.org/en/latest/frameworks/index.html) or check out other [gallery projects](https://github.com/bentoml/BentoML/tree/main/examples) 188 | - Learn more about model deployment options for Bento: 189 | - [🦄️ Yatai](https://github.com/bentoml/Yatai): Model Deployment at scale on Kubernetes 190 | - [🚀 bentoctl](https://github.com/bentoml/bentoctl): Fast model deployment on any cloud platform 191 | 192 | -------------------------------------------------------------------------------- /examples/quickstart/bentofile.yaml: -------------------------------------------------------------------------------- 1 | service: "service.py:svc" 2 | labels: 3 | owner: bentoml-team 4 | project: gallery 5 | include: 6 | - "*.py" 7 | python: 8 | packages: 9 | - scikit-learn 10 | - pandas 11 | -------------------------------------------------------------------------------- /examples/quickstart/iris_classifier.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "747e0e8d", 6 | "metadata": {}, 7 | "source": [ 8 | "# BentoML Scikit-learn Tutorial\n", 9 | "\n", 10 | "\n", 11 | "This is a sample project demonstrating basic usage of [BentoML](https://github.com/bentoml) with\n", 12 | "Scikit-learn.\n", 13 | "\n", 14 | "In this project, we will train a classifier model using Scikit-learn and the Iris dataset, build\n", 15 | "a prediction service for serving the trained model via an HTTP server, and containerize the \n", 16 | "model server as a docker image for production deployment.\n", 17 | "\n", 18 | "\n", 19 | "Link to source code: https://github.com/bentoml/BentoML/tree/main/examples/quickstart\n", 20 | "\n", 21 | "### Install Dependencies\n", 22 | "\n", 23 | "Install required python packages:" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "id": "daa3cbef", 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "!pip install -r https://raw.githubusercontent.com/bentoml/BentoML/main/examples/quickstart/requirements.txt" 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "id": "b66e31f7", 39 | "metadata": {}, 40 | "source": [ 41 | "## Model Training" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "id": "eb526488", 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [ 51 | "from sklearn import svm, datasets\n", 52 | "\n", 53 | "# Load training data\n", 54 | "iris = datasets.load_iris()\n", 55 | "X, y = iris.data, iris.target\n", 56 | "\n", 57 | "# Model Training\n", 58 | "clf = svm.SVC()\n", 59 | "clf.fit(X, y)" 60 | ] 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "id": "3c114c75", 65 | "metadata": {}, 66 | "source": [ 67 | "Save the `clf` model instance to BentoML local model store:" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": null, 73 | "id": "e94ed449", 74 | "metadata": {}, 75 | "outputs": [], 76 | "source": [ 77 | "import bentoml\n", 78 | "\n", 79 | "bentoml.sklearn.save_model(\"iris_clf\", clf)" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "id": "d613e57e", 85 | "metadata": {}, 86 | "source": [ 87 | "Models saved can be accessed via `bentoml models` CLI command:" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": null, 93 | "id": "7d771f04", 94 | "metadata": {}, 95 | "outputs": [], 96 | "source": [ 97 | "!bentoml models get iris_clf:latest" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "id": "5a876780", 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "!bentoml models list" 108 | ] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "id": "672721c4", 113 | "metadata": {}, 114 | "source": [ 115 | "To verify that the saved model can be loaded correctly:" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "id": "28ac794b", 122 | "metadata": {}, 123 | "outputs": [], 124 | "source": [ 125 | "loaded_model = bentoml.sklearn.load_model(\"iris_clf:latest\")\n", 126 | "\n", 127 | "loaded_model.predict([[5.9, 3.0, 5.1, 1.8]])" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "id": "8fd3bf97", 133 | "metadata": {}, 134 | "source": [ 135 | "In BentoML, the recommended way of running ML model inference in serving is via Runner, which \n", 136 | "gives BentoML more flexibility in terms of how to schedule the inference computation, how to \n", 137 | "batch inference requests and take advantage of hardware resources available. Saved models can\n", 138 | "be loaded as a Runner instance as shown below:\n" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": null, 144 | "id": "83205567", 145 | "metadata": {}, 146 | "outputs": [], 147 | "source": [ 148 | "# Create a Runner instance:\n", 149 | "iris_clf_runner = bentoml.sklearn.get(\"iris_clf:latest\").to_runner()\n", 150 | "\n", 151 | "# Runner#init_local initializes the model in current process, this is meant for development and testing only:\n", 152 | "iris_clf_runner.init_local()\n", 153 | "\n", 154 | "# This should yield the same result as the loaded model:\n", 155 | "iris_clf_runner.predict.run([[5.9, 3.0, 5.1, 1.8]])" 156 | ] 157 | }, 158 | { 159 | "cell_type": "markdown", 160 | "id": "3fa68254", 161 | "metadata": {}, 162 | "source": [ 163 | "## Serving the model\n", 164 | "\n", 165 | "A simple BentoML Service that serves the model saved above looks like this:" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": null, 171 | "id": "127aa3fd", 172 | "metadata": {}, 173 | "outputs": [], 174 | "source": [ 175 | "%%writefile service.py\n", 176 | "import numpy as np\n", 177 | "import bentoml\n", 178 | "from bentoml.io import NumpyNdarray\n", 179 | "\n", 180 | "iris_clf_runner = bentoml.sklearn.get(\"iris_clf:latest\").to_runner()\n", 181 | "\n", 182 | "svc = bentoml.Service(\"iris_classifier\", runners=[iris_clf_runner])\n", 183 | "\n", 184 | "@svc.api(input=NumpyNdarray(), output=NumpyNdarray())\n", 185 | "def classify(input_series: np.ndarray) -> np.ndarray:\n", 186 | " return iris_clf_runner.predict.run(input_series)\n" 187 | ] 188 | }, 189 | { 190 | "cell_type": "markdown", 191 | "id": "203beeed", 192 | "metadata": {}, 193 | "source": [ 194 | "Note: using `%%writefile` here because `bentoml.Service` definition must be created in its own `.py` file\n", 195 | "\n", 196 | "Start a dev model server to test out the service defined above:" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": null, 202 | "id": "7523b58f", 203 | "metadata": {}, 204 | "outputs": [], 205 | "source": [ 206 | "!bentoml serve service.py:svc --reload" 207 | ] 208 | }, 209 | { 210 | "cell_type": "markdown", 211 | "id": "3974e4ce", 212 | "metadata": {}, 213 | "source": [ 214 | "\n", 215 | "Open your web browser at http://127.0.0.1:3000 to view the Bento UI for sending test requests.\n", 216 | "\n", 217 | "You may also send request with `curl` command or any HTTP client, e.g.:\n", 218 | "\n", 219 | "```bash\n", 220 | "curl -X POST -H \"content-type: application/json\" --data \"[[5.9, 3, 5.1, 1.8]]\" http://127.0.0.1:3000/classify\n", 221 | "```\n" 222 | ] 223 | }, 224 | { 225 | "cell_type": "markdown", 226 | "id": "4f1a8bcc", 227 | "metadata": {}, 228 | "source": [ 229 | "### Build Bento for deployment" 230 | ] 231 | }, 232 | { 233 | "cell_type": "markdown", 234 | "id": "d6192cd5", 235 | "metadata": {}, 236 | "source": [ 237 | "Bento is the distribution format in BentoML which captures all the source code, model files, config\n", 238 | "files and dependency specifications required for running the service for production deployment. Think \n", 239 | "of it as Docker/Container designed for machine learning models.\n", 240 | "\n", 241 | "To begin with building Bento, create a `bentofile.yaml` under your project directory:" 242 | ] 243 | }, 244 | { 245 | "cell_type": "code", 246 | "execution_count": null, 247 | "id": "6458e417", 248 | "metadata": {}, 249 | "outputs": [], 250 | "source": [ 251 | "%%writefile bentofile.yaml\n", 252 | "service: \"service.py:svc\"\n", 253 | "labels:\n", 254 | " owner: bentoml-team\n", 255 | " project: gallery\n", 256 | "include:\n", 257 | "- \"*.py\"\n", 258 | "python:\n", 259 | " packages:\n", 260 | " - scikit-learn\n", 261 | " - pandas" 262 | ] 263 | }, 264 | { 265 | "cell_type": "markdown", 266 | "id": "47505e3c", 267 | "metadata": {}, 268 | "source": [ 269 | "Next, run `bentoml build` from current directory to start the Bento build:" 270 | ] 271 | }, 272 | { 273 | "cell_type": "code", 274 | "execution_count": null, 275 | "id": "b7cab8b2", 276 | "metadata": {}, 277 | "outputs": [], 278 | "source": [ 279 | "!bentoml build" 280 | ] 281 | }, 282 | { 283 | "cell_type": "markdown", 284 | "id": "4c159551", 285 | "metadata": {}, 286 | "source": [ 287 | "A new Bento is now built and saved to local Bento store. You can view and manage it via \n", 288 | "`bentoml list`,`bentoml get` and `bentoml delete` CLI command." 289 | ] 290 | }, 291 | { 292 | "cell_type": "markdown", 293 | "id": "81ed8b84", 294 | "metadata": {}, 295 | "source": [ 296 | "## Containerize and Deployment" 297 | ] 298 | }, 299 | { 300 | "cell_type": "markdown", 301 | "id": "8c215454", 302 | "metadata": {}, 303 | "source": [ 304 | "Bento is designed to be deployed to run efficiently in a variety of different environments.\n", 305 | "And there are lots of deployment options and tools as part of the BentoML eco-system, such as \n", 306 | "[Yatai](https://github.com/bentoml/Yatai) and [bentoctl](https://github.com/bentoml/bentoctl) for\n", 307 | "direct deployment to cloud platforms.\n", 308 | "\n", 309 | "In this guide, we will show you the most basic way of deploying a Bento, which is converting a Bento\n", 310 | "into a Docker image containing the HTTP model server.\n", 311 | "\n", 312 | "Make sure you have docker installed and docker deamon running, and run the following commnand:\n", 313 | "\n", 314 | "```bash\n", 315 | "bentoml containerize iris_classifier:latest\n", 316 | "```\n", 317 | "\n", 318 | "This will build a new docker image with all source code, model files and dependencies in place,\n", 319 | "and ready for production deployment. To start a container with this docker image locally, run:\n", 320 | "\n", 321 | "```bash\n", 322 | "docker run -p 3000:3000 iris_classifier:invwzzsw7li6zckb2ie5eubhd \n", 323 | "```\n", 324 | "\n", 325 | "## What's Next?\n", 326 | "\n", 327 | "- 👉 [Pop into our Slack community!](https://l.linklyhq.com/l/ktO8) We're happy to help with any issue you face or even just to meet you and hear what you're working on.\n", 328 | "\n", 329 | "- Dive deeper into the [Core Concepts](https://docs.bentoml.org/en/latest/concepts/index.html) in BentoML\n", 330 | "- Learn how to use BentoML with other ML Frameworks at [Frameworks Guide](https://docs.bentoml.org/en/latest/frameworks/index.html) or check out other [gallery projects](https://github.com/bentoml/BentoML/tree/main/examples)\n", 331 | "- Learn more about model deployment options for Bento:\n", 332 | " - [🦄️ Yatai](https://github.com/bentoml/Yatai): Model Deployment at scale on Kubernetes\n", 333 | " - [🚀 bentoctl](https://github.com/bentoml/bentoctl): Fast model deployment on any cloud platform\n" 334 | ] 335 | } 336 | ], 337 | "metadata": { 338 | "kernelspec": { 339 | "display_name": "Python 3 (ipykernel)", 340 | "language": "python", 341 | "name": "python3" 342 | }, 343 | "language_info": { 344 | "codemirror_mode": { 345 | "name": "ipython", 346 | "version": 3 347 | }, 348 | "file_extension": ".py", 349 | "mimetype": "text/x-python", 350 | "name": "python", 351 | "nbconvert_exporter": "python", 352 | "pygments_lexer": "ipython3", 353 | "version": "3.8.12" 354 | } 355 | }, 356 | "nbformat": 4, 357 | "nbformat_minor": 5 358 | } 359 | -------------------------------------------------------------------------------- /examples/quickstart/locustfile.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | import grpc 4 | import numpy as np 5 | from locust import task 6 | from locust import User 7 | from locust import between 8 | from locust import HttpUser 9 | from sklearn import datasets 10 | 11 | from bentoml.grpc.v1 import service_pb2 as pb 12 | from bentoml.grpc.v1 import service_pb2_grpc as services 13 | 14 | test_data = datasets.load_iris().data 15 | num_of_rows = test_data.shape[0] 16 | max_batch_size = 10 17 | 18 | 19 | class IrisHttpUser(HttpUser): 20 | """ 21 | Usage: 22 | Run the iris_classifier service in production mode: 23 | 24 | bentoml serve-http iris_classifier:latest --production 25 | 26 | Start locust load testing client with: 27 | 28 | locust --class-picker -H http://localhost:3000 29 | 30 | Open browser at http://0.0.0.0:8089, adjust desired number of users and spawn 31 | rate for the load test from the Web UI and start swarming. 32 | """ 33 | 34 | @task 35 | def classify(self): 36 | start = np.random.choice(num_of_rows - max_batch_size) 37 | end = start + np.random.choice(max_batch_size) + 1 38 | 39 | input_data = test_data[start:end] 40 | self.client.post("/classify", json=input_data.tolist()) 41 | 42 | wait_time = between(0.01, 2) 43 | 44 | 45 | class GrpcUser(User): 46 | abstract = True 47 | 48 | stub_class = None 49 | 50 | def __init__(self, environment): 51 | super().__init__(environment) 52 | self.environment = environment 53 | 54 | def on_start(self): 55 | self.channel = grpc.insecure_channel(self.host) 56 | self.stub = services.BentoServiceStub(self.channel) 57 | 58 | 59 | class IrisGrpcUser(GrpcUser): 60 | """ 61 | Implementation is inspired by https://docs.locust.io/en/stable/testing-other-systems.html 62 | 63 | Usage: 64 | Run the iris_classifier service in production mode: 65 | 66 | bentoml serve-grpc iris_classifier:latest --production 67 | 68 | Start locust load testing client with: 69 | 70 | locust --class-picker -H localhost:3000 71 | 72 | Open browser at http://0.0.0.0:8089, adjust desired number of users and spawn 73 | rate for the load test from the Web UI and start swarming. 74 | """ 75 | 76 | @task 77 | def classify(self): 78 | start = np.random.choice(num_of_rows - max_batch_size) 79 | end = start + np.random.choice(max_batch_size) + 1 80 | input_data = test_data[start:end] 81 | request_meta = { 82 | "request_type": "grpc", 83 | "name": "classify", 84 | "start_time": time.time(), 85 | "response_length": 0, 86 | "exception": None, 87 | "context": None, 88 | "response": None, 89 | } 90 | start_perf_counter = time.perf_counter() 91 | try: 92 | request_meta["response"] = self.stub.Call( 93 | request=pb.Request( 94 | api_name=request_meta["name"], 95 | ndarray=pb.NDArray( 96 | dtype=pb.NDArray.DTYPE_FLOAT, 97 | # shape=(1, 4), 98 | shape=(len(input_data), 4), 99 | # float_values=[5.9, 3, 5.1, 1.8], 100 | float_values=input_data.flatten(), 101 | ), 102 | ) 103 | ) 104 | except grpc.RpcError as e: 105 | request_meta["exception"] = e 106 | request_meta["response_time"] = ( 107 | time.perf_counter() - start_perf_counter 108 | ) * 1000 109 | self.environment.events.request.fire(**request_meta) 110 | 111 | wait_time = between(0.01, 2) 112 | -------------------------------------------------------------------------------- /examples/quickstart/query.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | result = requests.post( 4 | "http://127.0.0.1:3000/classify", 5 | headers={"content-type": "application/json"}, 6 | data="[[5.9, 3, 5.1, 1.8]]", 7 | ).text 8 | 9 | print(result) -------------------------------------------------------------------------------- /examples/quickstart/query.sh: -------------------------------------------------------------------------------- 1 | curl -X POST \ 2 | -H "content-type: application/json" \ 3 | --data "[[5.9, 3, 5.1, 1.8]]" \ 4 | http://127.0.0.1:3000/classify -------------------------------------------------------------------------------- /examples/quickstart/requirements.txt: -------------------------------------------------------------------------------- 1 | scikit-learn 2 | pandas 3 | bentoml>=1.0.0 4 | -------------------------------------------------------------------------------- /examples/quickstart/service.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | import bentoml 4 | from bentoml.io import NumpyNdarray 5 | 6 | iris_clf_runner = bentoml.sklearn.get("iris_clf:latest").to_runner() 7 | 8 | svc = bentoml.Service("iris_classifier", runners=[iris_clf_runner]) 9 | 10 | 11 | @svc.api( 12 | input=NumpyNdarray.from_sample( 13 | np.array([[4.9, 3.0, 1.4, 0.2]], dtype=np.double), enforce_shape=False 14 | ), 15 | output=NumpyNdarray(), 16 | ) 17 | async def classify(input_series: np.ndarray) -> np.ndarray: 18 | return await iris_clf_runner.predict.async_run(input_series) 19 | -------------------------------------------------------------------------------- /examples/quickstart/train.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from sklearn import svm 4 | from sklearn import datasets 5 | 6 | import bentoml 7 | 8 | logging.basicConfig(level=logging.WARN) 9 | 10 | if __name__ == "__main__": 11 | 12 | # Load training data 13 | iris = datasets.load_iris() 14 | X, y = iris.data, iris.target 15 | 16 | # Model Training 17 | clf = svm.SVC() 18 | clf.fit(X, y) 19 | 20 | # Save model to BentoML local model store 21 | saved_model = bentoml.sklearn.save_model( 22 | "iris_clf", clf, signatures={"predict": {"batchable": True, "batch_dim": 0}} 23 | ) 24 | print(f"Model saved: {saved_model}") 25 | -------------------------------------------------------------------------------- /four-score.m4a.srt: -------------------------------------------------------------------------------- 1 | 1 2 | 00:00:00,000 --> 00:00:08,120 3 | Four score and seven years ago our fathers brought forth on this continent a new nation 4 | 5 | 2 6 | 00:00:08,120 --> 00:00:14,800 7 | conceived in liberty and dedicated to the proposition that all men are created equal. 8 | 9 | 3 10 | 00:00:14,800 --> 00:00:21,000 11 | Now we are engaged in a great civil war testing whether that nation or any nation so conceived 12 | 13 | 4 14 | 00:00:21,000 --> 00:00:24,220 15 | and so dedicated can long endure. 16 | 17 | 5 18 | 00:00:24,220 --> 00:00:26,720 19 | We are met on a great battlefield of that war. 20 | 21 | 6 22 | 00:00:26,720 --> 00:00:33,100 23 | We have come to dedicate a portion of that field as a final resting place for those here 24 | 25 | 7 26 | 00:00:33,100 --> 00:00:36,060 27 | gave their lives that the nation might live. 28 | 29 | 8 30 | 00:00:36,060 --> 00:00:52,340 31 | It is altogether fitting and proper that we should do this. 32 | 33 | -------------------------------------------------------------------------------- /four-score.m4a.txt: -------------------------------------------------------------------------------- 1 | Four score and seven years ago our fathers brought forth on this continent a new nation 2 | conceived in liberty and dedicated to the proposition that all men are created equal. 3 | Now we are engaged in a great civil war testing whether that nation or any nation so conceived 4 | and so dedicated can long endure. 5 | We are met on a great battlefield of that war. 6 | We have come to dedicate a portion of that field as a final resting place for those here 7 | gave their lives that the nation might live. 8 | It is altogether fitting and proper that we should do this. 9 | -------------------------------------------------------------------------------- /four-score.m4a.vtt: -------------------------------------------------------------------------------- 1 | WEBVTT 2 | 3 | 00:00.000 --> 00:08.120 4 | Four score and seven years ago our fathers brought forth on this continent a new nation 5 | 6 | 00:08.120 --> 00:14.800 7 | conceived in liberty and dedicated to the proposition that all men are created equal. 8 | 9 | 00:14.800 --> 00:21.000 10 | Now we are engaged in a great civil war testing whether that nation or any nation so conceived 11 | 12 | 00:21.000 --> 00:24.220 13 | and so dedicated can long endure. 14 | 15 | 00:24.220 --> 00:26.720 16 | We are met on a great battlefield of that war. 17 | 18 | 00:26.720 --> 00:33.100 19 | We have come to dedicate a portion of that field as a final resting place for those here 20 | 21 | 00:33.100 --> 00:36.060 22 | gave their lives that the nation might live. 23 | 24 | 00:36.060 --> 00:52.340 25 | It is altogether fitting and proper that we should do this. 26 | 27 | -------------------------------------------------------------------------------- /hugging-face/download_hf_model.py: -------------------------------------------------------------------------------- 1 | """ 2 | After running zip it to save 3 | zip -r summarizeApp.zip summarizeApp 4 | """ 5 | 6 | from transformers import pipeline 7 | 8 | model = pipeline( 9 | "summarization", 10 | model="sshleifer/distilbart-cnn-12-6", 11 | revision="a4f8f3e", 12 | ) 13 | model.save_pretrained("summarizeApp") -------------------------------------------------------------------------------- /hugging-face/hf_fine_tune_hello_world.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Fine Tuning Example with HuggingFace 5 | 6 | Based on official tutorial 7 | """ 8 | 9 | from transformers import AutoTokenizer 10 | from datasets import load_dataset, load_metric 11 | from transformers import AutoModelForSequenceClassification 12 | from transformers import TrainingArguments, Trainer 13 | import numpy as np 14 | 15 | # Load the dataset 16 | dataset = load_dataset("yelp_review_full") 17 | dataset["train"][100] 18 | tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") 19 | 20 | def tokenize_function(examples): 21 | return tokenizer(examples["text"], padding="max_length", truncation=True) 22 | tokenized_datasets = dataset.map(tokenize_function, batched=True) 23 | 24 | # Load the model 25 | model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=5) 26 | 27 | metric = load_metric("accuracy") 28 | def compute_metrics(eval_pred): 29 | logits, labels = eval_pred 30 | predictions = np.argmax(logits, axis=-1) 31 | return metric.compute(predictions=predictions, references=labels) 32 | 33 | # can use if needed to reduce memory usage and training time 34 | small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000)) 35 | small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000)) 36 | 37 | 38 | training_args = TrainingArguments(output_dir="test_trainer", evaluation_strategy="epoch") 39 | trainer = Trainer( 40 | model=model, 41 | args=training_args, 42 | train_dataset=small_train_dataset, 43 | eval_dataset=small_eval_dataset, 44 | compute_metrics=compute_metrics, 45 | ) 46 | 47 | trainer.train() # train the model -------------------------------------------------------------------------------- /hugging-face/hf_whisper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # """Create OpenAI Whisper command-line tool using Hugging Face's transformers library.""" 3 | 4 | from transformers import pipeline 5 | import click 6 | 7 | 8 | # Create a function that reads a sample audio file and transcribes it using openai's whisper 9 | def traudio(filename, model="openai/whisper-tiny.en"): 10 | with open(filename, "rb") as f: 11 | _ = f.read() # this needs to be fixed 12 | print(f"Transcribing {filename}...") 13 | pipe = pipeline("automatic-speech-recognition", model=model) 14 | results = pipe(filename) 15 | return results 16 | 17 | 18 | # create click group 19 | @click.group() 20 | def cli(): 21 | """A cli for openai whisper""" 22 | 23 | 24 | # create a click command that transcribes 25 | @cli.command("transcribe") 26 | @click.option( 27 | "--model", default="openai/whisper-tiny.en", help="Model to use for transcription" 28 | ) 29 | @click.argument("filename", default="utils/four-score.m4a") 30 | def whispercli(filename, model): 31 | """Transcribe audio using openai whisper""" 32 | results = traudio(filename, model) 33 | # print out each label and its score in a tabular format with colors 34 | for result in results: 35 | click.secho(f"{result['text']}", fg="green") 36 | 37 | 38 | if __name__ == "__main__": 39 | cli() 40 | -------------------------------------------------------------------------------- /hugging-face/load_model.py: -------------------------------------------------------------------------------- 1 | """Loading a model from a file.""" 2 | 3 | from transformers import AutoModelForSeq2SeqLM, AutoTokenizer 4 | 5 | model = AutoModelForSeq2SeqLM.from_pretrained("summarizeApp") 6 | tokenizer = AutoTokenizer.from_pretrained("summarizeApp") 7 | #open the file with utf-8 encoding 8 | with open("input.txt", encoding="utf-8") as f: 9 | text = f.read() 10 | 11 | input_ids = tokenizer.encode(text, return_tensors="pt") 12 | outputs = model.generate(input_ids) 13 | decoded = tokenizer.decode(outputs[0], skip_special_tokens=True) 14 | print(decoded) -------------------------------------------------------------------------------- /hugging-face/zero_shot_classification.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Create Zero-shot classification command-line tool using Hugging Face's transformers library.""" 3 | 4 | from transformers import pipeline 5 | import click 6 | 7 | # Create a function that reads a file 8 | def read_file(filename): 9 | with open(filename, encoding="utf-8") as myfile: 10 | return myfile.read() 11 | 12 | 13 | # create a function that grabs candidate labels from a file 14 | def read_labels(kw_file): 15 | return read_file(kw_file).splitlines() 16 | 17 | 18 | # create a function that reads a file performs zero-shot classification 19 | def classify(text, labels, model="MoritzLaurer/mDeBERTa-v3-base-mnli-xnli"): 20 | classifier = pipeline("zero-shot-classification", model=model) 21 | results = classifier(text, labels, multi_label=False) 22 | return results 23 | 24 | 25 | # create click group 26 | @click.group() 27 | def cli(): 28 | """A cli for zero-shot classification""" 29 | 30 | 31 | # create a click command that performs zero-shot classification 32 | @cli.command("classify") 33 | @click.argument("filename", default="four-score.m4a.txt") 34 | @click.argument("kw_file", default="keywords.txt") 35 | def classifycli(filename, kw_file): 36 | """Classify text using zero-shot classification""" 37 | text = read_file(filename) 38 | labels = read_labels(kw_file) # needs to be a sequence 39 | results = classify(text, labels) 40 | # print out each label and its score in a tabular format with colors 41 | for label, score in zip(results["labels"], results["scores"]): 42 | click.secho(f"{label}\t{score:.2f}", fg="green") 43 | 44 | 45 | if __name__ == "__main__": 46 | cli() 47 | -------------------------------------------------------------------------------- /input.txt: -------------------------------------------------------------------------------- 1 | Fourscore and seven years ago our fathers brought forth on this continent a new nation 2 | conceived in liberty and dedicated to the proposition that all men are created equal. 3 | Now we are engaged in a great civil war testing whether that nation or any nation so conceived 4 | and so dedicated can long endure. 5 | We are met on a great battlefield of that war. 6 | We have come to dedicate a portion of that field as a final resting place for those here 7 | gave their lives that the nation might live. 8 | It is all together fitting and proper that we should do this. 9 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | created equal 2 | years ago 3 | ago our fathers 4 | fathers brought 5 | men are created 6 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | """ 2 | Main cli or app entry point 3 | """ 4 | 5 | from mylib.calculator import add 6 | import click 7 | 8 | 9 | @click.command("add") 10 | @click.argument("a", type=int) 11 | @click.argument("b", type=int) 12 | def add_cli(a, b): 13 | click.echo(add(a, b)) 14 | 15 | 16 | if __name__ == "__main__": 17 | # pylint: disable=no-value-for-parameter 18 | add_cli() 19 | -------------------------------------------------------------------------------- /mylib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nogibjj/mlops-template/e1b97de328bd7cbe84eba007f8dbd05719e3df27/mylib/__init__.py -------------------------------------------------------------------------------- /mylib/calculator.py: -------------------------------------------------------------------------------- 1 | """ 2 | Calculations library 3 | """ 4 | 5 | 6 | def add(a, b): 7 | return a + b 8 | 9 | 10 | def subtract(a, b): 11 | return a - b 12 | 13 | 14 | def multiply(a, b): 15 | return a * b 16 | 17 | 18 | def divide(a, b): 19 | return a / b -------------------------------------------------------------------------------- /repeat.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | repeat() { 4 | for i in `seq 1 $1`; do 5 | echo $2 6 | done 7 | } 8 | 9 | repeat $1 $2 -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | #wheel 2 | wheel==0.37.1 3 | #devops 4 | black==22.3.0 5 | click==8.1.3 6 | pytest==7.1.3 7 | pytest-cov==4.0.0 8 | pylint==2.15.3 9 | boto3==1.24.87 10 | #web 11 | fastapi==0.85.0 12 | uvicorn==0.18.3 13 | #datascience 14 | jupyter==1.0.0 15 | pandas==1.5.0 16 | numpy==1.23.3 17 | scikit-learn==1.1.2 18 | matplotlib==3.6.0 19 | seaborn==0.12.0 20 | dask==2022.9.2 21 | #geo 22 | geopy==2.2.0 23 | #MLOps 24 | gradio==3.4.1 25 | streamlit==1.13.0 26 | protobuf==3.16.0 27 | onnx==1.12.0 28 | databricks==0.2 29 | databricks-cli==0.17.3 30 | databricks-sql-connector==2.1.0 31 | mlflow==2.0.1 32 | ##MLOps-HuggingFace 33 | transformers==4.22.2 34 | sentencepiece==0.1.97 35 | datasets==2.5.2 36 | tokenizers==0.12.1 37 | #deep learning 38 | torch 39 | torchvision 40 | tensorflow 41 | #openai whisper 42 | git+https://github.com/openai/whisper.git 43 | #yake 44 | yake==0.4.8 45 | 46 | 47 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source /home/codespace/venv/bin/activate 3 | #append it to bash so every shell launches with it 4 | echo 'source /home/codespace/venv/bin/activate' >> ~/.bashrc 5 | -------------------------------------------------------------------------------- /test_main.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test goes here 3 | 4 | """ 5 | 6 | from mylib.calculator import add 7 | 8 | 9 | def test_add(): 10 | assert add(1, 2) == 3 11 | -------------------------------------------------------------------------------- /tf-requirements.txt: -------------------------------------------------------------------------------- 1 | #Tensorflow requirements 2 | tensorflow==2.10.0 -------------------------------------------------------------------------------- /utils/README.md: -------------------------------------------------------------------------------- 1 | Using CPP Whisper: https://github.com/ggerganov/whisper.cpp/issues/89 2 | ffmpeg -i four-score.m4a -ac 2 -ar 16000 -f wav four-score.wav 3 | #time ./main -f ../mlops-template/utils/four-score.wav 4 | time ./main -m models/ggml-medium.en.bin -f ../mlops-template/utils/four-score.wav 5 | ##fastest test 6 | time ./main -m models/ggml-medium.en.bin -f ../mlops-template/utils/four-score.wav -t 8 -p 2 7 | 8 | -------------------------------------------------------------------------------- /utils/four-score.m4a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nogibjj/mlops-template/e1b97de328bd7cbe84eba007f8dbd05719e3df27/utils/four-score.m4a -------------------------------------------------------------------------------- /utils/four-score.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nogibjj/mlops-template/e1b97de328bd7cbe84eba007f8dbd05719e3df27/utils/four-score.wav -------------------------------------------------------------------------------- /utils/install-nvidia-container-toolkit.sh: -------------------------------------------------------------------------------- 1 | #installs NVIDIA container Toolkit 2 | # https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#install-guide 3 | distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \ 4 | && curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ 5 | && curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \ 6 | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ 7 | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list 8 | 9 | sudo apt-get update 10 | sudo apt-get install -y nvidia-docker2 11 | sudo systemctl restart docker 12 | 13 | #then start 14 | #sudo docker run --rm --gpus all nvidia/cuda:11.6.2-base-ubuntu20.04 nvidia-smi -------------------------------------------------------------------------------- /utils/kw_extract.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Main cli or app entry point 5 | """ 6 | import yake 7 | import click 8 | 9 | # create a function that reads a file 10 | def read_file(filename): 11 | with open(filename, encoding="utf-8") as myfile: 12 | return myfile.read() 13 | 14 | 15 | # def extract keywords 16 | def extract_keywords(text): 17 | kw_extractor = yake.KeywordExtractor() 18 | keywords = kw_extractor.extract_keywords(text) 19 | return keywords 20 | 21 | 22 | # create a function that makes hash tags 23 | def make_hashtags(keywords): 24 | hashtags = [] 25 | for keyword in keywords: 26 | hashtags.append("#" + keyword[0].replace(" ", "")) 27 | return hashtags 28 | 29 | #create a function returns only the top N keywords 30 | def top_n_keywords(keywords, n=5): 31 | return keywords[:n] 32 | 33 | @click.group() 34 | def cli(): 35 | """A cli for keyword extraction""" 36 | 37 | #print the top N keywords 38 | @cli.command("extract") 39 | @click.argument("filename", default="text.txt") 40 | @click.option("--n", default=5, help="Number of keywords to extract") 41 | def extract(filename, n): 42 | """Extract keywords from a file""" 43 | text = read_file(filename) 44 | keywords = extract_keywords(text) 45 | top_keywords = top_n_keywords(keywords, n) 46 | for keyword in top_keywords: 47 | print(keyword[0]) 48 | 49 | 50 | @cli.command("hashtags") 51 | @click.argument("filename", default="text.txt") 52 | def hashtagscli(filename): 53 | """Extract keywords from a file and make hashtags""" 54 | text = read_file(filename) 55 | keywords = extract_keywords(text) 56 | hashtags = make_hashtags(keywords) 57 | click.echo(hashtags) 58 | 59 | 60 | if __name__ == "__main__": 61 | cli() -------------------------------------------------------------------------------- /utils/quickstart_pytorch.py: -------------------------------------------------------------------------------- 1 | """ 2 | `Learn the Basics `_ || 3 | **Quickstart** || 4 | `Tensors `_ || 5 | `Datasets & DataLoaders `_ || 6 | `Transforms `_ || 7 | `Build Model `_ || 8 | `Autograd `_ || 9 | `Optimization `_ || 10 | `Save & Load Model `_ 11 | 12 | Quickstart 13 | =================== 14 | This section runs through the API for common tasks in machine learning. Refer to the links in each section to dive deeper. 15 | 16 | Working with data 17 | ----------------- 18 | PyTorch has two `primitives to work with data `_: 19 | ``torch.utils.data.DataLoader`` and ``torch.utils.data.Dataset``. 20 | ``Dataset`` stores the samples and their corresponding labels, and ``DataLoader`` wraps an iterable around 21 | the ``Dataset``. 22 | 23 | """ 24 | 25 | import torch 26 | from torch import nn 27 | from torch.utils.data import DataLoader 28 | from torchvision import datasets 29 | from torchvision.transforms import ToTensor 30 | 31 | ###################################################################### 32 | # PyTorch offers domain-specific libraries such as `TorchText `_, 33 | # `TorchVision `_, and `TorchAudio `_, 34 | # all of which include datasets. For this tutorial, we will be using a TorchVision dataset. 35 | # 36 | # The ``torchvision.datasets`` module contains ``Dataset`` objects for many real-world vision data like 37 | # CIFAR, COCO (`full list here `_). In this tutorial, we 38 | # use the FashionMNIST dataset. Every TorchVision ``Dataset`` includes two arguments: ``transform`` and 39 | # ``target_transform`` to modify the samples and labels respectively. 40 | 41 | # Download training data from open datasets. 42 | training_data = datasets.FashionMNIST( 43 | root="data", 44 | train=True, 45 | download=True, 46 | transform=ToTensor(), 47 | ) 48 | 49 | # Download test data from open datasets. 50 | test_data = datasets.FashionMNIST( 51 | root="data", 52 | train=False, 53 | download=True, 54 | transform=ToTensor(), 55 | ) 56 | 57 | ###################################################################### 58 | # We pass the ``Dataset`` as an argument to ``DataLoader``. This wraps an iterable over our dataset, and supports 59 | # automatic batching, sampling, shuffling and multiprocess data loading. Here we define a batch size of 64, i.e. each element 60 | # in the dataloader iterable will return a batch of 64 features and labels. 61 | 62 | batch_size = 64 63 | 64 | # Create data loaders. 65 | train_dataloader = DataLoader(training_data, batch_size=batch_size) 66 | test_dataloader = DataLoader(test_data, batch_size=batch_size) 67 | 68 | for X, y in test_dataloader: 69 | print(f"Shape of X [N, C, H, W]: {X.shape}") 70 | print(f"Shape of y: {y.shape} {y.dtype}") 71 | break 72 | 73 | ###################################################################### 74 | # Read more about `loading data in PyTorch `_. 75 | # 76 | 77 | ###################################################################### 78 | # -------------- 79 | # 80 | 81 | ################################ 82 | # Creating Models 83 | # ------------------ 84 | # To define a neural network in PyTorch, we create a class that inherits 85 | # from `nn.Module `_. We define the layers of the network 86 | # in the ``__init__`` function and specify how data will pass through the network in the ``forward`` function. To accelerate 87 | # operations in the neural network, we move it to the GPU if available. 88 | 89 | # Get cpu or gpu device for training. 90 | device = "cuda" if torch.cuda.is_available() else "cpu" 91 | print(f"Using {device} device") 92 | 93 | # Define model 94 | class NeuralNetwork(nn.Module): 95 | def __init__(self): 96 | super().__init__() 97 | self.flatten = nn.Flatten() 98 | self.linear_relu_stack = nn.Sequential( 99 | nn.Linear(28*28, 512), 100 | nn.ReLU(), 101 | nn.Linear(512, 512), 102 | nn.ReLU(), 103 | nn.Linear(512, 10) 104 | ) 105 | 106 | def forward(self, x): 107 | x = self.flatten(x) 108 | logits = self.linear_relu_stack(x) 109 | return logits 110 | 111 | model = NeuralNetwork().to(device) 112 | print(model) 113 | 114 | ###################################################################### 115 | # Read more about `building neural networks in PyTorch `_. 116 | # 117 | 118 | 119 | ###################################################################### 120 | # -------------- 121 | # 122 | 123 | 124 | ##################################################################### 125 | # Optimizing the Model Parameters 126 | # ---------------------------------------- 127 | # To train a model, we need a `loss function `_ 128 | # and an `optimizer `_. 129 | 130 | loss_fn = nn.CrossEntropyLoss() 131 | optimizer = torch.optim.SGD(model.parameters(), lr=1e-3) 132 | 133 | 134 | ####################################################################### 135 | # In a single training loop, the model makes predictions on the training dataset (fed to it in batches), and 136 | # backpropagates the prediction error to adjust the model's parameters. 137 | 138 | def train(dataloader, model, loss_fn, optimizer): 139 | size = len(dataloader.dataset) 140 | model.train() 141 | for batch, (X, y) in enumerate(dataloader): 142 | X, y = X.to(device), y.to(device) 143 | 144 | # Compute prediction error 145 | pred = model(X) 146 | loss = loss_fn(pred, y) 147 | 148 | # Backpropagation 149 | optimizer.zero_grad() 150 | loss.backward() 151 | optimizer.step() 152 | 153 | if batch % 100 == 0: 154 | loss, current = loss.item(), batch * len(X) 155 | print(f"loss: {loss:>7f} [{current:>5d}/{size:>5d}]") 156 | 157 | ############################################################################## 158 | # We also check the model's performance against the test dataset to ensure it is learning. 159 | 160 | def test(dataloader, model, loss_fn): 161 | size = len(dataloader.dataset) 162 | num_batches = len(dataloader) 163 | model.eval() 164 | test_loss, correct = 0, 0 165 | with torch.no_grad(): 166 | for X, y in dataloader: 167 | X, y = X.to(device), y.to(device) 168 | pred = model(X) 169 | test_loss += loss_fn(pred, y).item() 170 | correct += (pred.argmax(1) == y).type(torch.float).sum().item() 171 | test_loss /= num_batches 172 | correct /= size 173 | print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n") 174 | 175 | ############################################################################## 176 | # The training process is conducted over several iterations (*epochs*). During each epoch, the model learns 177 | # parameters to make better predictions. We print the model's accuracy and loss at each epoch; we'd like to see the 178 | # accuracy increase and the loss decrease with every epoch. 179 | 180 | epochs = 5 181 | for t in range(epochs): 182 | print(f"Epoch {t+1}\n-------------------------------") 183 | train(train_dataloader, model, loss_fn, optimizer) 184 | test(test_dataloader, model, loss_fn) 185 | print("Done!") 186 | 187 | ###################################################################### 188 | # Read more about `Training your model `_. 189 | # 190 | 191 | ###################################################################### 192 | # -------------- 193 | # 194 | 195 | ###################################################################### 196 | # Saving Models 197 | # ------------- 198 | # A common way to save a model is to serialize the internal state dictionary (containing the model parameters). 199 | 200 | torch.save(model.state_dict(), "model.pth") 201 | print("Saved PyTorch Model State to model.pth") 202 | 203 | 204 | 205 | ###################################################################### 206 | # Loading Models 207 | # ---------------------------- 208 | # 209 | # The process for loading a model includes re-creating the model structure and loading 210 | # the state dictionary into it. 211 | 212 | model = NeuralNetwork() 213 | model.load_state_dict(torch.load("model.pth")) 214 | 215 | ############################################################# 216 | # This model can now be used to make predictions. 217 | 218 | classes = [ 219 | "T-shirt/top", 220 | "Trouser", 221 | "Pullover", 222 | "Dress", 223 | "Coat", 224 | "Sandal", 225 | "Shirt", 226 | "Sneaker", 227 | "Bag", 228 | "Ankle boot", 229 | ] 230 | 231 | model.eval() 232 | x, y = test_data[0][0], test_data[0][1] 233 | with torch.no_grad(): 234 | pred = model(x) 235 | predicted, actual = classes[pred[0].argmax(0)], classes[y] 236 | print(f'Predicted: "{predicted}", Actual: "{actual}"') 237 | 238 | 239 | ###################################################################### 240 | # Read more about `Saving & Loading your model `_. 241 | # -------------------------------------------------------------------------------- /utils/quickstart_tf2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import tensorflow as tf 4 | print("TensorFlow version:", tf.__version__) 5 | 6 | mnist = tf.keras.datasets.mnist 7 | 8 | (x_train, y_train), (x_test, y_test) = mnist.load_data() 9 | x_train, x_test = x_train / 255.0, x_test / 255.0 10 | model = tf.keras.models.Sequential([ 11 | tf.keras.layers.Flatten(input_shape=(28, 28)), 12 | tf.keras.layers.Dense(128, activation='relu'), 13 | tf.keras.layers.Dropout(0.2), 14 | tf.keras.layers.Dense(10) 15 | ]) 16 | predictions = model(x_train[:1]).numpy() 17 | predictions 18 | tf.nn.softmax(predictions).numpy() 19 | loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) 20 | loss_fn(y_train[:1], predictions).numpy() 21 | model.compile(optimizer='adam', 22 | loss=loss_fn, 23 | metrics=['accuracy']) 24 | model.fit(x_train, y_train, epochs=5) 25 | model.evaluate(x_test, y_test, verbose=2) 26 | probability_model = tf.keras.Sequential([ 27 | model, 28 | tf.keras.layers.Softmax() 29 | ]) 30 | probability_model(x_test[:5]) -------------------------------------------------------------------------------- /utils/transcribe-whisper.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | whisper utils/four-score.m4a --model large --language English -------------------------------------------------------------------------------- /utils/verify_pytorch.py: -------------------------------------------------------------------------------- 1 | import torch 2 | 3 | if torch.cuda.is_available(): 4 | print("CUDA is available") 5 | print("CUDA version: {}".format(torch.version.cuda)) 6 | print("PyTorch version: {}".format(torch.__version__)) 7 | print("cuDNN version: {}".format(torch.backends.cudnn.version())) 8 | print("Number of CUDA devices: {}".format(torch.cuda.device_count())) 9 | print("Current CUDA device: {}".format(torch.cuda.current_device())) 10 | print("Device name: {}".format(torch.cuda.get_device_name(torch.cuda.current_device()))) 11 | else: 12 | print("CUDA is not available") -------------------------------------------------------------------------------- /utils/verify_tf.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf; print(tf.config.list_physical_devices('GPU')) --------------------------------------------------------------------------------