From d2df9478270a052d7928394cc7c3fec618f8444d Mon Sep 17 00:00:00 2001 From: Daniela Plascencia Date: Tue, 7 Jan 2020 11:02:34 -0600 Subject: [PATCH 1/3] Adds handwritten digit recognition example * Python scripts for training, classifying and model serving * Docker images for all tasks mentioned above Signed-off-by: Daniela Plascencia --- handwritten_digit_recog/Makefile | 16 ++ handwritten_digit_recog/README.md | 50 ++++++ handwritten_digit_recog/docker/Dockerfile.mkl | 15 ++ handwritten_digit_recog/docker/Dockerfile.oss | 14 ++ .../docker/Dockerfile.website | 9 + handwritten_digit_recog/python/classify.py | 63 +++++++ handwritten_digit_recog/python/serve.py | 52 ++++++ handwritten_digit_recog/python/train.py | 166 ++++++++++++++++++ handwritten_digit_recog/scripts/entrypoint.sh | 78 ++++++++ handwritten_digit_recog/website/app.py | 88 ++++++++++ .../website/static/styles/mainpage.css | 27 +++ .../website/templates/homepage.html | 25 +++ 12 files changed, 603 insertions(+) create mode 100644 handwritten_digit_recog/Makefile create mode 100644 handwritten_digit_recog/README.md create mode 100644 handwritten_digit_recog/docker/Dockerfile.mkl create mode 100644 handwritten_digit_recog/docker/Dockerfile.oss create mode 100644 handwritten_digit_recog/docker/Dockerfile.website create mode 100644 handwritten_digit_recog/python/classify.py create mode 100644 handwritten_digit_recog/python/serve.py create mode 100644 handwritten_digit_recog/python/train.py create mode 100644 handwritten_digit_recog/scripts/entrypoint.sh create mode 100644 handwritten_digit_recog/website/app.py create mode 100644 handwritten_digit_recog/website/static/styles/mainpage.css create mode 100644 handwritten_digit_recog/website/templates/homepage.html diff --git a/handwritten_digit_recog/Makefile b/handwritten_digit_recog/Makefile new file mode 100644 index 0000000..53181bc --- /dev/null +++ b/handwritten_digit_recog/Makefile @@ -0,0 +1,16 @@ +MAKE := $(MAKE) -e +DOCKER_BUILD_CMD = docker build + +all: + $(MAKE) train serve website + +train: + $(DOCKER_BUILD_CMD) --build-arg stage=train -f docker/Dockerfile.$(TYPE) -t $(REGISTRY)/dlrs-train-$(TYPE) . + +serve: + $(DOCKER_BUILD_CMD) --build-arg stage=serve -f docker/Dockerfile.$(TYPE) -t $(REGISTRY)/dlrs-serve-$(TYPE) . + +website: + $(DOCKER_BUILD_CMD) -f docker/Dockerfile.website -t $(REGISTRY)/dlrs-website . + +.PHONY: all train serve website diff --git a/handwritten_digit_recog/README.md b/handwritten_digit_recog/README.md new file mode 100644 index 0000000..5253bc6 --- /dev/null +++ b/handwritten_digit_recog/README.md @@ -0,0 +1,50 @@ +# Handwritten Digit Recognition with DLRS + +The content in this directory is for running a handwritten digit recognition example using the Deep Learning Reference Stack, Pytorch and MNIST. + +#### Pre-requisites + +* Docker + +## Running on containers + +Please follow these instructions to train the model and classify random handwritten digits on DLRS based Docker containers. + +### Set up + +Set TYPE and REGISTRY env variables +TYPE options: mkl or oss +REGISTRY options: registry name + +```bash +export TYPE= +export REGISTRY= +make +``` + +### Train + +```bash +mkdir models +docker run --rm -ti -v ${PWD}/models:/workdir/models $REGISTRY/dlrs-train-$TYPE:latest "-s train" +``` + +### Serving the model for live classification + +```bash +docker run -p 5059:5059 -it -v ${PWD}/models:/workdir/models $REGISTRY/dlrs-serve-$TYPE:latest "-s serve" +curl -i -X POST -d 'Classify' http://localhost:5059/digit_recognition/classify +``` + +### Website + +We have created a simple website template for you to interact with. + +```bash +docker run --rm -p 8080:5000 -it $REGISTRY/dlrs-website:latest --website_endpoint 0.0.0.0 +Open localhost:8080 on a web browser +``` + +## Running on Kubeflow pipelines + +We have created a Kubeflow Pipeline to run this example. Please go to [Kubeflow Pipelines](https://github.com/intel/stacks-usecase/kubeflow/pipelines) for more details. diff --git a/handwritten_digit_recog/docker/Dockerfile.mkl b/handwritten_digit_recog/docker/Dockerfile.mkl new file mode 100644 index 0000000..7db4f62 --- /dev/null +++ b/handwritten_digit_recog/docker/Dockerfile.mkl @@ -0,0 +1,15 @@ +FROM clearlinux/stacks-pytorch-mkl:v0.5.0 + +ARG stage + +ENV PATH=$PATH:/opt/conda/bin/ \ + LD_LIBRARY_PATH=/usr/lib64:/opt/conda/lib \ + STAGE=$stage + +WORKDIR /workdir +COPY python/ python/ +COPY scripts/entrypoint.sh . + +RUN chmod +x entrypoint.sh + +ENTRYPOINT ["./entrypoint.sh"] diff --git a/handwritten_digit_recog/docker/Dockerfile.oss b/handwritten_digit_recog/docker/Dockerfile.oss new file mode 100644 index 0000000..f777075 --- /dev/null +++ b/handwritten_digit_recog/docker/Dockerfile.oss @@ -0,0 +1,14 @@ +FROM clearlinux/stacks-pytorch-oss:v0.5.0 + +ARG stage +ENV STAGE=$stage + +WORKDIR /workdir +COPY python/ python/ +COPY scripts/entrypoint.sh . + +RUN chmod +x entrypoint.sh + +EXPOSE 5059 + +ENTRYPOINT ["./entrypoint.sh"] diff --git a/handwritten_digit_recog/docker/Dockerfile.website b/handwritten_digit_recog/docker/Dockerfile.website new file mode 100644 index 0000000..6d1113e --- /dev/null +++ b/handwritten_digit_recog/docker/Dockerfile.website @@ -0,0 +1,9 @@ +FROM clearlinux/stacks-pytorch-oss:v0.5.0 + +WORKDIR /workdir/website +COPY website/ /workdir/website/ + +EXPOSE 5000 + +SHELL ["/bin/bash", "-c"] +ENTRYPOINT ["python", "app.py"] diff --git a/handwritten_digit_recog/python/classify.py b/handwritten_digit_recog/python/classify.py new file mode 100644 index 0000000..886c94d --- /dev/null +++ b/handwritten_digit_recog/python/classify.py @@ -0,0 +1,63 @@ +import torch +import numpy as np +import matplotlib.pyplot as plt +from torchvision import datasets, transforms + +from train import Net + +# Load pre-trained model +model_path = "/workdir/models/mnist_cnn.pt" +device = torch.device("cpu") +model = Net().to(device) +model.load_state_dict(torch.load(model_path)) + +# Use a transform to normalize data (same as in training) +transform = transforms.Compose( + [transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))] +) + +# Load training data +kwargs = {"num_workers": 1, "pin_memory": True} +test_loader = datasets.MNIST("data", download=True, train=False, transform=transform) +data_loader = torch.utils.data.DataLoader(test_loader, batch_size=64, shuffle=True) + + +def img_show(img, ps, probab): + ps = ps.data.numpy().squeeze() + fig, (ax1, ax2) = plt.subplots(figsize=(5, 3), ncols=2) + ax1.imshow(img.resize_(1, 28, 28).numpy().squeeze(), cmap="gray_r") + ax1.axis("off") + ax1.set_title("Random Test Image") + ax1.text( + 5, + 30, + "Predicted value: %s" % probab.index(max(probab)), + fontsize=10, + bbox={"facecolor": "cornsilk", "boxstyle": "round", "alpha": 0.5}, + ) + ax2.barh(np.arange(10), ps, color="gold") + ax2.set_aspect(0.1) + ax2.set_yticks(np.arange(10)) + ax2.set_yticklabels(np.arange(10)) + ax2.set_title("Probability Chart") + ax2.set_xlim(0, 1.1) + plt.grid(True) + plt.tight_layout() + plt.show() + + +# Function for classifying random handwritten numbers from the MNIST dataset +def classify(imgshow=False): + images, labels = next(iter(data_loader)) + img = images[0].view(1, 1, 28, 28) + with torch.no_grad(): + logps = model(img) + ps = torch.exp(logps) + probab = list(ps.numpy()[0]) + if imgshow: + img_show(img, ps, probab) + return img, probab + + +if __name__ == "__main__": + classify(imgshow=True) diff --git a/handwritten_digit_recog/python/serve.py b/handwritten_digit_recog/python/serve.py new file mode 100644 index 0000000..08cba1f --- /dev/null +++ b/handwritten_digit_recog/python/serve.py @@ -0,0 +1,52 @@ +#!usr/bin/env python +# +# Copyright (c) 2019 Intel 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 REST API for Pytorch MNIST Handwritten Digit Recognition""" + +import flask + +from classify import classify + +app = flask.Flask("Handwritten Digit Recognition") + +banner = { + "what": "Handwritten Digit Recognition", + "usage": { + "Client": "curl -i -X POST -d 'Classify' http://localhost:5059/digit_recognition/classify", + "Server": "docker run -d -p 5059:5059 stacks_handwritten_digit_recog", + }, +} + + +@app.route("/digit_recognition/", methods=["GET"]) +def index(): + return flask.jsonify(banner), 201 + + +@app.route("/digit_recognition/classify", methods=["POST"]) +def digit_recog(): + img, probab = classify(imgshow=False) + return flask.jsonify({"Prediction": probab.index(max(probab))}), 201 + + +@app.errorhandler(404) +def not_found(error): + return flask.make_response(flask.jsonify({"error": "Not found"}), 404) + + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5059) diff --git a/handwritten_digit_recog/python/train.py b/handwritten_digit_recog/python/train.py new file mode 100644 index 0000000..cfea271 --- /dev/null +++ b/handwritten_digit_recog/python/train.py @@ -0,0 +1,166 @@ +from __future__ import print_function +import argparse +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.optim as optim +from torchvision import datasets, transforms +from torch.optim.lr_scheduler import StepLR + + +device = torch.device("cpu") +transform = transforms.Compose( + [transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))] +) + + +class Net(nn.Module): + def __init__(self): + super(Net, self).__init__() + self.conv1 = nn.Conv2d(1, 32, 3, 1) + self.conv2 = nn.Conv2d(32, 64, 3, 1) + self.dropout1 = nn.Dropout2d(0.25) + self.dropout2 = nn.Dropout2d(0.5) + self.fc1 = nn.Linear(9216, 128) + self.fc2 = nn.Linear(128, 10) + + def forward(self, x): + x = self.conv1(x) + x = F.relu(x) + x = self.conv2(x) + x = F.max_pool2d(x, 2) + x = self.dropout1(x) + x = torch.flatten(x, 1) + x = self.fc1(x) + x = F.relu(x) + x = self.dropout2(x) + x = self.fc2(x) + output = F.log_softmax(x, dim=1) + return output + + +def train(args, model, device, train_loader, optimizer, epoch): + model.train() + for batch_idx, (data, target) in enumerate(train_loader): + data, target = data.to(device), target.to(device) + optimizer.zero_grad() + output = model(data) + loss = F.nll_loss(output, target) + loss.backward() + optimizer.step() + if batch_idx % args.log_interval == 0: + print( + "Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}".format( + epoch, + batch_idx * len(data), + len(train_loader.dataset), + 100.0 * batch_idx / len(train_loader), + loss.item(), + ) + ) + + +def test(args, model, device, test_loader): + model.eval() + test_loss = 0 + correct = 0 + with torch.no_grad(): + for data, target in test_loader: + data, target = data.to(device), target.to(device) + output = model(data) + test_loss += F.nll_loss( + output, target, reduction="sum" + ).item() # sum up batch loss + pred = output.argmax( + dim=1, keepdim=True + ) # get the index of the max log-probability + correct += pred.eq(target.view_as(pred)).sum().item() + + test_loss /= len(test_loader.dataset) + print( + "\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n".format( + test_loss, + correct, + len(test_loader.dataset), + 100.0 * correct / len(test_loader.dataset), + ) + ) + + +def main(): + # Training settings + parser = argparse.ArgumentParser(description="PyTorch MNIST Example") + parser.add_argument( + "--batch-size", + type=int, + default=64, + metavar="N", + help="input batch size for training (default: 64)", + ) + parser.add_argument( + "--test-batch-size", + type=int, + default=1000, + metavar="N", + help="input batch size for testing (default: 1000)", + ) + parser.add_argument( + "--epochs", + type=int, + default=1, + metavar="N", + help="number of epochs to train (default: 10)", + ) + parser.add_argument( + "--lr", type=float, default=0.01, metavar="LR", help="learning rate (default: 0.01)" + ) + parser.add_argument( + "--gamma", + type=float, + default=0.7, + metavar="M", + help="Learning rate step gamma (default: 0.7)", + ) + parser.add_argument( + "--seed", type=int, default=1, metavar="S", help="random seed (default: 1)" + ) + parser.add_argument( + "--log-interval", + type=int, + default=10, + metavar="N", + help="how many batches to wait before logging training status", + ) + + args = parser.parse_args() + + torch.manual_seed(args.seed) + + kwargs = {"num_workers": int(cpu_count()/2), "pin_memory": True} + train_loader = torch.utils.data.DataLoader( + datasets.MNIST("data", train=True, download=True, transform=transform), + batch_size=args.batch_size, + shuffle=True, + **kwargs, + ) + test_loader = torch.utils.data.DataLoader( + datasets.MNIST("data", train=False, transform=transform), + batch_size=args.test_batch_size, + shuffle=True, + **kwargs, + ) + + model = Net().to(device) + optimizer = optim.Adadelta(model.parameters(), lr=args.lr) + + scheduler = StepLR(optimizer, step_size=1, gamma=args.gamma) + for epoch in range(1, args.epochs + 1): + train(args, model, device, train_loader, optimizer, epoch) + test(args, model, device, test_loader) + scheduler.step() + + torch.save(model.state_dict(), "/workdir/models/mnist_cnn.pt") + + +if __name__ == "__main__": + main() diff --git a/handwritten_digit_recog/scripts/entrypoint.sh b/handwritten_digit_recog/scripts/entrypoint.sh new file mode 100644 index 0000000..6144760 --- /dev/null +++ b/handwritten_digit_recog/scripts/entrypoint.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash + +function usage() { + cat << EOF +\$ $(basename $0) OPTIONS [SERIES] + +where OPTIONS are + + -b : GCP Storage Bucket where your pretrained model will be accessed + -c : Set cloud mode + -s : Stage to deploy + -t : GCP Access token --> `gcloud auth print-access-token` + +EOF +>&2 + + exit 1 +} + +function fetch_model() { + echo "Fetching model from ${bucket}" + curl -H "Authorization: Bearer ${token}" \ + https://www.googleapis.com/storage/v1/b/${bucket}/o/mnist_cnn.pt?alt=media \ + --output /workdir/models/mnist_cnn.pt +} + +function upload_model() { + echo "Uploading model to ${bucket}" + curl -v --upload-file /workdir/models/mnist_cnn.pt \ + -H "Authorization: Bearer ${token}" \ + https://storage.googleapis.com/${bucket}/mnist_cnn.pt +} + +while getopts "cb:s:t:h" opt; do + case $opt in + b) + bucket=$OPTARG + ;; + c) + cloud=true + ;; + s) + stage=$OPTARG + ;; + t) + token=$OPTARG + ;; + h) + usage + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + usage + ;; + :) + echo "Option -$OPTARG requires an argument." >&2 + usage + ;; + esac +done + +if [[ ! -d "/workdir/models/" ]]; then + mkdir /workdir/models/ +fi + +cd python/ + +if [[ ${cloud} ]]; then + echo "Deploying ${stage} stage on cloud mode" + if [[ ${stage} == "serve" ]]; then + fetch_model && python ${stage}.py + elif [[ ${stage} == "train" ]]; then + python ${stage}.py && upload_model + fi +else + echo "Deploying ${stage} stage" + python ${stage}.py +fi diff --git a/handwritten_digit_recog/website/app.py b/handwritten_digit_recog/website/app.py new file mode 100644 index 0000000..b6028e5 --- /dev/null +++ b/handwritten_digit_recog/website/app.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019 Intel 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. +# + +import argparse + +import requests +from flask import Flask +from flask import request +from flask import render_template + +app = Flask("Website for Pytorch MNIST handwritten digit recognition example") +parser = argparse.ArgumentParser() +parser.add_argument( + "-ip", + "--endpoint", + required=False, + default="localhost", + help="Endpoint address of the inference API", +) +parser.add_argument( + "-p", + "--port", + required=False, + default="5059", + help="Endpoint port of the inference API", +) +parser.add_argument( + "-wip", + "--website_endpoint", + required=False, + default="localhost", + help="Endpoint address for the website", +) +parser.add_argument( + "-wp", + "--website_port", + required=False, + default="5000", + help="Endpoint port for the website", +) +parser.add_argument( + "-s", + "--tls", + required=False, + action="store_true", + default=False, + help="Is the inference endpoint encrypted with TLS ", +) +args = vars(parser.parse_args()) + + +@app.route("/", methods=["GET", "POST"]) +def homepage(): + args["protocol"] = "https" if args["tls"] else "http" + if request.method == "POST": + response = requests.post( + "{}://{}:{}/digit_recognition/classify".format( + args["protocol"], args["endpoint"], args["port"] + ), + json={"Prediction": "Classify"}, + ) + prediction_json = response.json() + prediction = prediction_json["Prediction"] + return render_template("homepage.html", optText=prediction,) + return render_template("homepage.html", optText=None) + + +if __name__ == "__main__": + app.run( + debug=True, + host="{}".format(args["website_endpoint"]), + port=int(args["website_port"]), + ) diff --git a/handwritten_digit_recog/website/static/styles/mainpage.css b/handwritten_digit_recog/website/static/styles/mainpage.css new file mode 100644 index 0000000..9dc2481 --- /dev/null +++ b/handwritten_digit_recog/website/static/styles/mainpage.css @@ -0,0 +1,27 @@ +.center-div +{ + margin: 0 auto; + text-align: center; +} + +div#title-box +{ + margin: auto; + text-align: center; + font-size: 24pt; + font-weight: bold; +} + +div#author +{ + margin: 0 auto; + text-align: center; + font-size: 10pt; +} + +.fill-text +{ +margin: auto; + text-align: justify; + font-size: 12pt; +} diff --git a/handwritten_digit_recog/website/templates/homepage.html b/handwritten_digit_recog/website/templates/homepage.html new file mode 100644 index 0000000..f28b084 --- /dev/null +++ b/handwritten_digit_recog/website/templates/homepage.html @@ -0,0 +1,25 @@ + + + + + + Handwritten Digit Recognition with Intel's DLRS +
Handwritten Digit Recognition with Intel's DLRS
+
Interactive handwritten digit recognition using PyTorch, running on an Intel Deep Learning Reference Stack (DLRS) backend. See clearlinux.org for more information.
+ + + +
+ +
+

+ +

+ +
+ +
+ +
+ + From 7103988a8f9d8b045683305fffccc089ffb8a8fd Mon Sep 17 00:00:00 2001 From: Daniela Plascencia Date: Tue, 14 Jan 2020 13:32:16 -0600 Subject: [PATCH 2/3] kubeflow/pipelines: Adds handwritten recog example Signed-off-by: Daniela Plascencia --- kubeflow/README.md | 77 +++++++++++++++ kubeflow/pipelines/pytorch-mnist/README.md | 90 ++++++++++++++++++ .../pipelines/pytorch-mnist/docker/Dockerfile | 49 ++++++++++ .../docker/manifests/model-server.yaml | 25 +++++ .../docker/manifests/website.yaml | 24 +++++ .../pytorch-mnist/docker/scripts/deploy.sh | 87 +++++++++++++++++ .../handwritten-digit-recog-pipeline.py | 71 ++++++++++++++ .../pipelines/pytorch-mnist/img/start-run.png | Bin 0 -> 41122 bytes .../pytorch-mnist/img/upload-pipeline.png | Bin 0 -> 25148 bytes .../pytorch-mnist/img/web-ui-url.png | Bin 0 -> 36648 bytes 10 files changed, 423 insertions(+) create mode 100644 kubeflow/README.md create mode 100644 kubeflow/pipelines/pytorch-mnist/README.md create mode 100644 kubeflow/pipelines/pytorch-mnist/docker/Dockerfile create mode 100644 kubeflow/pipelines/pytorch-mnist/docker/manifests/model-server.yaml create mode 100644 kubeflow/pipelines/pytorch-mnist/docker/manifests/website.yaml create mode 100644 kubeflow/pipelines/pytorch-mnist/docker/scripts/deploy.sh create mode 100644 kubeflow/pipelines/pytorch-mnist/handwritten-digit-recog-pipeline.py create mode 100644 kubeflow/pipelines/pytorch-mnist/img/start-run.png create mode 100644 kubeflow/pipelines/pytorch-mnist/img/upload-pipeline.png create mode 100644 kubeflow/pipelines/pytorch-mnist/img/web-ui-url.png diff --git a/kubeflow/README.md b/kubeflow/README.md new file mode 100644 index 0000000..61b0f40 --- /dev/null +++ b/kubeflow/README.md @@ -0,0 +1,77 @@ +# Kubeflow Specific Files + +This folder is home for kubeflow specific files to enable DLRS images with various workloads that exist as part of kubeflow. Long term plan would be to upstream some of these to kubeflow. + +# Getting started with Kubeflow + +>IMPORTANT: For troubleshooting, please refer to Kubeflow [documentation](https://www.kubeflow.org/docs/started/k8s/kfctl-k8s-istio/). + +#### Pre-requisites: + +* A running Kubernetes cluster + +Please refer to: [Run Kubernetes on Clear Linux OS](https://clearlinux.org/documentation/clear-linux/tutorials/kubernetes) + +## Deploying Kubeflow with kfctl/kustomize + +1. Get kfctl tarball, untar and add to your PATH if necessary + +```bash +KFCTL_PATH="path_desired_to_kfctl" +kfctl_ver=v0.7.0 +KFCTL_URL="https://github.com/kubeflow/kubeflow/releases/download/${kfctl_ver}/kfctl_${kfctl_ver}_linux.tar.gz" +wget -P ${KFCTL_PATH} ${KFCTL_URL} +tar -C ${KFCTL_PATH} -xvf ${KFCTL_PATH}/kfctl_v${kfctl_ver}_linux.tar.gz +export PATH=$PATH:${KFCTL_PATH} +``` + +2. Install Kubeflow resources +```bash +# Env variables needed for your deployment +export KF_NAME= +export BASE_DIR= +export KF_DIR=${BASE_DIR}/${KF_NAME} +export CONFIG_URI="https://raw.githubusercontent.com/kubeflow/manifests/v0.7-branch/kfdef/kfctl_k8s_istio.0.7.0.yaml" +``` + +3. Set up and deploy Kubeflow +```bash +mkdir -p ${KF_DIR} +cd ${KF_DIR} +kfctl apply -V -f ${CONFIG_URI} +``` + +Deployment takes around 10 minutes (or more depending on the hardware) to be ready to use. After that you can do +```bash +kubectl get pods -n kubeflow +``` +to list all the Kubeflow resources deployed and monitor their status. + + +## Deploying Kubeflow on Google Cloud Platform (GCP) + +Kubeflow has excellent documentation on how to deploy on GCP [here](https://www.kubeflow.org/docs/gke/deploy/deploy-cli/). However, the [Deep Learning Reference Stack](https://clearlinux.org/stacks/deep-learning) (DLRS) utilizes hardware advancments that are only on certain Intel chips (Skylake), and there is no single document explaining how to specify a minimum chip during kubeflow deployment. Those instructions are provided here. + +1. Choose a zone you want to deploy in that has Intel Skylake cpus. Zones are listed [here](https://cloud.google.com/compute/docs/regions-zones/). + +2. Deploy Kubeflow normally as specified [here](https://www.kubeflow.org/docs/gke/deploy/deploy-cli/) but stop at section ["Set up and deploy Kubeflow"](https://www.kubeflow.org/docs/gke/deploy/deploy-cli/#set-up-and-deploy-kubeflow). Instead, navigate to section ["Alternatively, set up your configuration for later deployment"](https://www.kubeflow.org/docs/gke/deploy/deploy-cli/#alternatively-set-up-your-configuration-for-later-deployment). Then follow step 1. + +3. In step 2, you are instructed to edit the configuration files. There are two changes required for a DLRS compatible GCP cluster, and they are detailed below. + +4. Navigate to the gcp_config directory and open the cluster.jinja file. Change the cluster property "minCpuPlatform" from "Intel Broadwell" to "Intel Skylake". Note: you may notice there are two minCpuPlatform properties in the file. On of them is for gpu node pools, and not all cpu/gpu combinations are combatible. Leave the gpu property untouched, and we will disable gpu node pools in the next step. + +5. Open the "cluster-kubeflow.yaml" file and change the "gpu-pool-max-nodes" property to 0. + +6. Follow steps 3-4 of ["Alternatively, set up your configuration for later deployment"](https://www.kubeflow.org/docs/gke/deploy/deploy-cli/#alternatively-set-up-your-configuration-for-later-deployment). + +That's it! you have a GCP cluster with Intel Skylake cpus. + + +# Kubeflow components + +There is a list of Kubeflow components you can interact with. In this repository you will find a set of components using the System Stacks for different workloads: +- TfJobs +- PytorchJobs +- Jupyter Notebooks +- Seldon Model Server +- Pipelines diff --git a/kubeflow/pipelines/pytorch-mnist/README.md b/kubeflow/pipelines/pytorch-mnist/README.md new file mode 100644 index 0000000..55c9766 --- /dev/null +++ b/kubeflow/pipelines/pytorch-mnist/README.md @@ -0,0 +1,90 @@ +# MNIST Kubeflow Pipeline on DLRS + +The following document describes how to run the Pytorch MNIST example on Kubeflow Pipelines on Google Cloud Platform (GCP). + +## Prerequisites + +* A [GCS bucket](https://cloud.google.com/storage/) to hold a Pytorch trained model. +* A Kubernetes deployment on GKE (v1.12.10-gke.20) +* A Kubeflow deployment on GKE (v0.6.1) +* Docker +* All images in the [Pytorch MNIST example](https://github.com/intel/stacks-usecase/tree/master/handwritten_digit_recog) already built and available in accessible registry + +## Host set up + +Kubeflow Pipelines must be compiled into a domain-specific language (DSL). Please follow these steps to set up the machine were you will be compiling all pipelines. + +The following commands will set up a virtual environment for Kubeflow Pipelines to work. + +```bash +# In case you don't have conda already + +wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh +bash Miniconda3-latest-Linux-x86_64.sh + +# Create and activate the mlpipeline virtual environment +conda create --name mlpipeline python=3.7 +conda activate mlpipeline + +# Install Kubeflow Pipelines SDK and other dependencies +wget https://raw.githubusercontent.com/kubeflow/examples/master/pipelines/mnist-pipelines/requirements.txt +pip install -r requirements.txt --upgrade +``` + +## Modify files + +All files in this repository have fields that you have to manually edit. Before running any `docker build` command make sure you have already modified the following: + +```bash +# Replace REGISTRY and TYPE where needed in handwritten-digit-recog-pipeline.py + image='REGISTRY/dlrs-train-TYPE' +# Replace REGISTRY and TYPE where needed in all yaml files inside manifests/ + image: REGISTRY/dlrs-serve-TYPE +``` + +## Compile the Handwritten Digit Recognition Pipeline + +Pipelines are written in Python, but they need to be compiled into a DSL, after activating the `mlpipeline` virtual environment, run the following command: + +```bash +python3 handwritten-digit-recog-pipeline.py +``` + +This will produce a compiled `handwritten-digit-recog-pipeline.py.tar.gz` file. + +## Running the pipeline + +### Upload the pipeline through Kubeflow UI + +Uploading the compiled pipeline using the UI is fairly easy. Hit the Upload pipeline button and follow the on screen instructions. + +![Upload Pipeline](./img/upload-pipeline.png "Upload Pipeline") + +### Run the Handwritten Digit Recognition Pipeline + +Start a new run and fill all the required fields. +This pipeline depends on two main user definitions: + +* `model-bucket`: The GCS Bucket you already have (see prerequisites) +* `gcloud-access-token`: This is gcloud auth token, you can get it by running `gcloud auth print-access-token` on the Cloud Shell + +![Start Run](./img/start-run.png "Start Run") + +This pipeline is comprised of three stages: + +#### Train + +The train stage will run `train.py`, which will train a Pytorch model using the MNIST dataset for handwritten digit recognition. The recently trained model will be then uploaded to the specified GCS Bucket. + + +#### Serve + +The serve stage will expose an API that receives POST requests and calls `classify.py` for testing random handwritten digits. + +#### Website + +The last stage creates a service hosting a simple Web UI that makes calls to the model server (see previous stage) for testing random handwritten digits. + +After all three stages of the pipeline finish, you can interact with the Web UI by going to the URL specified in the logs of the `web-ui` stage. + +![Web UI](./img/web-ui-url.png "Web UI") diff --git a/kubeflow/pipelines/pytorch-mnist/docker/Dockerfile b/kubeflow/pipelines/pytorch-mnist/docker/Dockerfile new file mode 100644 index 0000000..e701e29 --- /dev/null +++ b/kubeflow/pipelines/pytorch-mnist/docker/Dockerfile @@ -0,0 +1,49 @@ +# Copyright (c) 2019 Intel Corporation +# Copyright 2018 The Kubeflow Authors +# +# 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 debian + +RUN apt-get update -q && apt-get upgrade -y && \ + apt-get install -y -qq --no-install-recommends \ + apt-transport-https \ + ca-certificates \ + git \ + gnupg \ + lsb-release \ + unzip \ + wget && \ + wget --no-verbose -O /bin/kubectl \ + https://storage.googleapis.com/kubernetes-release/release/v1.11.2/bin/linux/amd64/kubectl && \ + chmod u+x /bin/kubectl && \ + wget --no-verbose -O /opt/kubernetes_v1.11.2 \ + https://github.com/kubernetes/kubernetes/archive/v1.11.2.tar.gz && \ + mkdir -p /src && \ + tar -C /src -xzf /opt/kubernetes_v1.11.2 && \ + rm -rf /opt/kubernetes_v1.11.2 && \ + wget --no-verbose -O /opt/google-apt-key.gpg \ + https://packages.cloud.google.com/apt/doc/apt-key.gpg && \ + apt-key add /opt/google-apt-key.gpg && \ + export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)" && \ + echo "deb https://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" >> \ + /etc/apt/sources.list.d/google-cloud-sdk.list && \ + apt-get update -q && \ + apt-get install -y -qq --no-install-recommends google-cloud-sdk && \ + gcloud config set component_manager/disable_update_check true + +COPY manifests/ /workdir/manifests/ +COPY scripts/deploy.sh /workdir/. +RUN chmod +x /workdir/deploy.sh + +ENTRYPOINT ["/workdir/deploy.sh"] diff --git a/kubeflow/pipelines/pytorch-mnist/docker/manifests/model-server.yaml b/kubeflow/pipelines/pytorch-mnist/docker/manifests/model-server.yaml new file mode 100644 index 0000000..4d8d88e --- /dev/null +++ b/kubeflow/pipelines/pytorch-mnist/docker/manifests/model-server.yaml @@ -0,0 +1,25 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dlrs-mnist-model-server + namespace: kubeflow + labels: + app: mnist-model-server +spec: + selector: + matchLabels: + app: mnist-model-server + tier: web + template: + metadata: + labels: + app: mnist-model-server + tier: web + spec: + containers: + - name: dlrs-mnist-model-server + image: REGISTRY/dlrs-serve-oss + command: ["/workdir/entrypoint.sh"] + args: ["-cb", "model-bucket", "-s", "serve", "-t", "gcloud_access_token"] + ports: + - containerPort: 5059 diff --git a/kubeflow/pipelines/pytorch-mnist/docker/manifests/website.yaml b/kubeflow/pipelines/pytorch-mnist/docker/manifests/website.yaml new file mode 100644 index 0000000..0f03afd --- /dev/null +++ b/kubeflow/pipelines/pytorch-mnist/docker/manifests/website.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dlrs-mnist-website + namespace: kubeflow + labels: + app: digit-classification +spec: + selector: + matchLabels: + app: digit-classification + tier: web + template: + metadata: + labels: + app: digit-classification + tier: web + spec: + containers: + - name: dlrs-mnist-website + image: REGISTRY/dlrs-website + args: ["--endpoint", "inference_API_endpoint", "--website_endpoint", "0.0.0.0"] + ports: + - containerPort: 5000 diff --git a/kubeflow/pipelines/pytorch-mnist/docker/scripts/deploy.sh b/kubeflow/pipelines/pytorch-mnist/docker/scripts/deploy.sh new file mode 100644 index 0000000..1ffbe33 --- /dev/null +++ b/kubeflow/pipelines/pytorch-mnist/docker/scripts/deploy.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash + +# Copyright (c) 2019 Intel Corporation +# Copyright 2018 The Kubeflow Authors +# +# 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. + + +function get_ip() { + EXTERNAL_IP=$(kubectl get service $1 -n kubeflow | awk '{print $4}' | tail -n 1) + while [[ ${EXTERNAL_IP} == "" ]]; do + EXTERNAL_IP=$(kubectl get service $1 -n kubeflow | awk '{print $4}' | tail -n 1) + done +} + +function cluster_connect() { + if [ -z "${CLUSTER_NAME}" ]; then + CLUSTER_NAME=$(wget -q -O- --header="Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/attributes/cluster-name) + fi + + # Ensure the server name is not more than 63 characters. + SERVER_NAME="${SERVER_NAME:0:63}" + # Trim any trailing hyphens from the server name. + while [[ "${SERVER_NAME:(-1)}" == "-" ]]; do SERVER_NAME="${SERVER_NAME::-1}"; done + + echo "Deploying ${SERVER_NAME} to the cluster ${CLUSTER_NAME}" + + # Connect kubectl to the local cluster + kubectl config set-cluster "${CLUSTER_NAME}" --server=https://kubernetes.default --certificate-authority=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt + kubectl config set-credentials pipeline --token "$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" + kubectl config set-context kubeflow --cluster "${CLUSTER_NAME}" --user pipeline + kubectl config use-context kubeflow +} + +function deploy() { + if [ "${stage}" == "serve" ]; then + echo "Deploying MODEL SERVER" + sed -i "s/model\-bucket/${bucket}/g" /workdir/manifests/model-server.yaml + sed -i "s/gcloud\_access\_token/${token}/g" /workdir/manifests/model-server.yaml + kubectl create -f /workdir/manifests/model-server.yaml + kubectl expose deployment -n kubeflow dlrs-mnist-model-server --type LoadBalancer --port 5059 --target-port 5059 + echo "Getting API's External IP" && get_ip "dlrs-mnist-model-server" + echo "Finish with API's External IP: ${EXTERNAL_IP}" + elif [ "${stage}" == "website" ]; then + echo "Deploying WEBSITE" + MODEL_EXTERNAL_IP=$(kubectl get service dlrs-mnist-model-server -n kubeflow | awk '{print $4}' | tail -n 1) + echo "API's External IP: ${MODEL_EXTERNAL_IP}" + sed -i "s/inference\_API\_endpoint/${MODEL_EXTERNAL_IP}/g" /workdir/manifests/website.yaml + kubectl create -f /workdir/manifests/website.yaml + kubectl expose deployment -n kubeflow dlrs-mnist-website --type LoadBalancer --port 8080 --target-port 5000 + echo "Getting Website's External IP" && get_ip "dlrs-mnist-website" + echo "Website URL : ${EXTERNAL_IP}:8080" + fi +} + +while getopts "b:s:t:" opt; do + case $opt in + b) + bucket=$OPTARG + ;; + s) + stage=$OPTARG + ;; + t) + token=$OPTARG + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + ;; + :) + echo "Option -$OPTARG requires an argument." >&2 + ;; + esac +done + +echo "Connecting kubectl to local cluster" && cluster_connect +echo "Deploying ${stage} stage" && deploy diff --git a/kubeflow/pipelines/pytorch-mnist/handwritten-digit-recog-pipeline.py b/kubeflow/pipelines/pytorch-mnist/handwritten-digit-recog-pipeline.py new file mode 100644 index 0000000..9a81da2 --- /dev/null +++ b/kubeflow/pipelines/pytorch-mnist/handwritten-digit-recog-pipeline.py @@ -0,0 +1,71 @@ +# Copyright 2019 Google LLC +# +# 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. +""" +Pytorch MNIST example running on Kubeflow Pipelines + +Run this script to compile pipeline +""" + + +import kfp.dsl as dsl +import kfp.gcp as gcp + +@dsl.pipeline( + name='dlrs-mnist-pipeline', + description='A pipeline to train and serve the Pytorch MNIST example.' +) +def mnist_pipeline(model_bucket='your-gs-bucket-name', gcloud_access_token='your-access-token'): + """ + Pipeline with three stages: + 1. Train a MNIST handwritten digit classifier + 2. Deploy a model server to the cluster + 3. Deploy a web-ui to interact with it + """ + train = dsl.ContainerOp( + name='train', + image='REGISTRY/dlrs-train-TYPE', + arguments=[ + "-cb", model_bucket, + "-s", "train", + "-t", gcloud_access_token + ] + ) + + serve = dsl.ContainerOp( + name='serve', + image='REGISTRY/dlrs-pipelines-deployer', + arguments=[ + "-cb", model_bucket, + "-s", "serve", + "-t", gcloud_access_token + ] + ) + serve.after(train) + + web_ui = dsl.ContainerOp( + name='web-ui', + image='REGISTRY/dlrs-pipelines-deployer' + arguments=[ + "-s", "website" + ] + ) + web_ui.after(serve) + + steps = [train, serve, web_ui] + for step in steps: + step.apply(gcp.use_gcp_secret('user-gcp-sa')) + +if __name__ == '__main__': + import kfp.compiler as compiler + compiler.Compiler().compile(mnist_pipeline, __file__ + '.tar.gz') diff --git a/kubeflow/pipelines/pytorch-mnist/img/start-run.png b/kubeflow/pipelines/pytorch-mnist/img/start-run.png new file mode 100644 index 0000000000000000000000000000000000000000..766bff2597243a99010a40d8cb10e02c384ca5f3 GIT binary patch literal 41122 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 G_D4CJ*;GQk)Jb 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 literal 0 HcmV?d00001 diff --git a/kubeflow/pipelines/pytorch-mnist/img/web-ui-url.png b/kubeflow/pipelines/pytorch-mnist/img/web-ui-url.png new file mode 100644 index 0000000000000000000000000000000000000000..dd1953f7092b1da3ea163f9469e8f70f3075f396 GIT binary patch literal 36648 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 Date: Wed, 15 Jan 2020 13:27:06 -0600 Subject: [PATCH 3/3] Adds LICENSE to train script Signed-off-by: Daniela Plascencia --- handwritten_digit_recog/python/train.py | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/handwritten_digit_recog/python/train.py b/handwritten_digit_recog/python/train.py index cfea271..7528865 100644 --- a/handwritten_digit_recog/python/train.py +++ b/handwritten_digit_recog/python/train.py @@ -1,3 +1,34 @@ +#BSD 3-Clause License +# +#Copyright (c) 2017, Intel Corporation +#Copyright (c) 2017, Pytorch contributors +#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 the copyright holder 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 AND CONTRIBUTORS "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 HOLDER 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. + from __future__ import print_function import argparse import torch