From 0c1a96b740bda71306c296851835f2264ed2bcc0 Mon Sep 17 00:00:00 2001 From: Guoxin Date: Wed, 2 Dec 2020 18:49:12 +0800 Subject: [PATCH] [cherry pick to pai-1.4.y] sync master change (#5144) * Visualized mnist500task (#5131) * update marketplace image version to 1.3.0 (#5137) Co-authored-by: AmberMsy <46340789+AmberMsy@users.noreply.github.com> --- examples/mnist_500_tasks/README.md | 34 +++++++++++++- .../mnist_500_tasks/images/final_status.JPG | Bin 0 -> 15425 bytes .../mnist_500_tasks/images/show_results.JPG | Bin 0 -> 36580 bytes .../images/show_results_file.JPG | Bin 0 -> 21354 bytes examples/mnist_500_tasks/src/get_results.py | 44 ++++++++++++++++++ examples/mnist_500_tasks/src/mnist_lr_500.py | 19 ++++++-- .../mnist_500_tasks/src/show_results.ipynb | 37 +++++++++++++++ .../yaml/CPU_500Task_MNIST.yaml | 38 ++++++++++++++- .../marketplace-restserver.k8s.dockerfile | 2 +- .../marketplace-webportal.k8s.dockerfile | 2 +- 10 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 examples/mnist_500_tasks/images/final_status.JPG create mode 100644 examples/mnist_500_tasks/images/show_results.JPG create mode 100644 examples/mnist_500_tasks/images/show_results_file.JPG create mode 100644 examples/mnist_500_tasks/src/get_results.py create mode 100644 examples/mnist_500_tasks/src/show_results.ipynb diff --git a/examples/mnist_500_tasks/README.md b/examples/mnist_500_tasks/README.md index b510663e73..6fedc89520 100644 --- a/examples/mnist_500_tasks/README.md +++ b/examples/mnist_500_tasks/README.md @@ -7,4 +7,36 @@ Here we provide a CPU-only job with 500 tasks on a taskrole. The example use Con | ConvNet | CPU | 6h30m10s (500*5 epoch) | [Details](metrics/ConvNet_CPU_500Task.JPG) | 95.15% (lr: 0.0101) 98.53% (lr: 0.1001) 98.95% (lr: 0.9981)| [CPU_500Task_MNIST.yaml](yaml/CPU_500Task_MNIST.yaml) | ## Usage -To quickly submit a training job to the OpenPAI cluster, users can directly submit the corresponding yaml file as mentioned above (in the yaml folder). \ No newline at end of file +Before running this example, you should first make sure that you have at least one permitted storage in OpenPAI. If you don’t know how to use storage, please refer to [our doc](https://openpai.readthedocs.io/). + +Before submitting yaml file as mentioned above (in the yaml folder), you need to update the following commands with your own storage path: + +`master` taskrole: +``` +python get_results.py --number=500 --data_path /mnt/confignfs/mnist500_result/ +--> +python get_results.py --number=500 --data_path /mnist500_result/ +``` + +`taskrole` taskerole: +``` +mount -t nfs4 10.151.40.235:/data data +--> +mount -t nfs4 data +``` + +Now you can submit the yaml file to try this example, and **don't forget** to select the storage you want to use in the `data` area on the right side of the page. + +## Visualization of results + +When all instances in `taskrole` run successfully, you can view the visualized results through the running `master`. The following figure shows the final status of the successful job. It should be noted that the visualized results can only be viewed when the `master` is running. This taskrole will keep running until the user manually stops it. + + + +You can access jupyter notebook by visiting `:8888` in the browser. Then, click on the file `show_results.ipynb`. + + + +Run it and get the following visualized result. + + \ No newline at end of file diff --git a/examples/mnist_500_tasks/images/final_status.JPG b/examples/mnist_500_tasks/images/final_status.JPG new file mode 100644 index 0000000000000000000000000000000000000000..2108707413de5e29657d143a9916f631174dec20 GIT binary patch literal 15425 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 literal 0 HcmV?d00001 diff --git a/examples/mnist_500_tasks/src/get_results.py b/examples/mnist_500_tasks/src/get_results.py new file mode 100644 index 0000000000..41ba81f85c --- /dev/null +++ b/examples/mnist_500_tasks/src/get_results.py @@ -0,0 +1,44 @@ + +import os +import csv +import time +import argparse +import shutil + +def summary(filepath, result_path): + with open(filepath, 'r') as f: + csv_read = csv.reader(f) + with open(result_path, 'a') as r: + csv_write = csv.writer(r) + for line in csv_read: + csv_write.writerow(line) + +def main(): + parser = argparse.ArgumentParser(description='Display Results') + parser.add_argument('--number', type=int, default=500, + help='The number of learning rates') + parser.add_argument('--data_path', default='./mnist500_result/', + help='The number of learning rates') + args = parser.parse_args() + + path = args.data_path + if not os.path.exists(path): + os.makedirs(path) + # Waiting for all results + while(len([lists for lists in os.listdir(path)]) < args.number): + for file in os.listdir('.'): + if file[-4:]=='.csv': + shutil.move(file, os.path.join(path, file)) + time.sleep(1) + for file in os.listdir('.'): + if file[-4:]=='.csv': + shutil.move(file, os.path.join(path, file)) + + for file in os.listdir(path): + filepath = os.path.join(path, file) + if os.path.isfile(filepath) and file[-4:]=='.csv': + summary(filepath, 'results.csv') + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/examples/mnist_500_tasks/src/mnist_lr_500.py b/examples/mnist_500_tasks/src/mnist_lr_500.py index 26c4ceb5c6..efd1eac0a9 100644 --- a/examples/mnist_500_tasks/src/mnist_lr_500.py +++ b/examples/mnist_500_tasks/src/mnist_lr_500.py @@ -6,7 +6,7 @@ import torch.optim as optim from torchvision import datasets, transforms from torch.optim.lr_scheduler import StepLR - +import csv class Net(nn.Module): def __init__(self): @@ -68,7 +68,14 @@ def test(model, device, test_loader): print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( test_loss, correct, len(test_loader.dataset), 100. * correct / len(test_loader.dataset))) + + return 100. * correct / len(test_loader.dataset) +def write_result(filepath, lr, acc): + with open(filepath, 'a') as f: + csv_write = csv.writer(f) + data = [lr, acc] + csv_write.writerow(data) def main(): # Training settings @@ -95,6 +102,8 @@ def main(): help='For Saving the current Model') parser.add_argument('--task_index', default=0, help='Multi-task Index') + parser.add_argument('--result_file', default='results.csv', + help='Accuracy of different learning rates') args = parser.parse_args() use_cuda = not args.no_cuda and torch.cuda.is_available() @@ -131,13 +140,13 @@ def main(): 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(model, device, test_loader) + acc = test(model, device, test_loader) scheduler.step() + write_result(args.result_file, lr, acc) if args.save_model: - torch.save(model.state_dict(), "mnist_cnn.pt") - + torch.save(model.state_dict(), "mnist_cnn.pt") if __name__ == '__main__': - main() + main() \ No newline at end of file diff --git a/examples/mnist_500_tasks/src/show_results.ipynb b/examples/mnist_500_tasks/src/show_results.ipynb new file mode 100644 index 0000000000..8733e6e640 --- /dev/null +++ b/examples/mnist_500_tasks/src/show_results.ipynb @@ -0,0 +1,37 @@ +{ + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": 3 + }, + "orig_nbformat": 2 + }, + "nbformat": 4, + "nbformat_minor": 2, + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "results = np.genfromtxt('./results.csv', delimiter=\",\", names=[\"LR\",\"ACC\"])\n", + "plt.plot(results[\"LR\"], results[\"ACC\"], 'o')\n", + "plt.xlabel('Learning Rate')\n", + "plt.ylabel('Accuracy')\n", + "plt.show()" + ] + } + ] +} \ No newline at end of file diff --git a/examples/mnist_500_tasks/yaml/CPU_500Task_MNIST.yaml b/examples/mnist_500_tasks/yaml/CPU_500Task_MNIST.yaml index c01c9d4ede..021be13199 100644 --- a/examples/mnist_500_tasks/yaml/CPU_500Task_MNIST.yaml +++ b/examples/mnist_500_tasks/yaml/CPU_500Task_MNIST.yaml @@ -7,22 +7,52 @@ prerequisites: uri: 'openpai/standard:python_3.6-pytorch_1.4.0-cpu' name: docker_image_0 taskRoles: + master: + instances: 1 + completion: + minFailedInstances: 1 + taskRetryCount: 0 + dockerImage: docker_image_0 + resourcePerInstance: + gpu: 0 + cpu: 1 + memoryMB: 50000 + commands: + - >- + wget + https://raw.githubusercontent.com/microsoft/pai/master/examples/mnist_500_tasks/src/get_results.py + - >- + python get_results.py --number=500 --data_path + /mnt/confignfs/mnist500_result/ + - >- + wget + https://raw.githubusercontent.com/microsoft/pai/master/examples/mnist_500_tasks/src/show_results.ipynb + - jupyter notebook taskrole: instances: 500 completion: minFailedInstances: 1 + minSucceededInstances: -1 taskRetryCount: 0 dockerImage: docker_image_0 resourcePerInstance: gpu: 0 cpu: 1 - memoryMB: 51200 + memoryMB: 50000 commands: - >- - wget https://raw.githubusercontent.com/microsoft/pai/master/examples/mnist_500_tasks/src/mnist_lr_500.py + wget + https://raw.githubusercontent.com/microsoft/pai/master/examples/mnist_500_tasks/src/mnist_lr_500.py - >- python mnist_lr_500.py --epoch 5 --task_index=$PAI_CURRENT_TASK_ROLE_CURRENT_TASK_INDEX + - apt-get update + - apt-get install --assume-yes nfs-common + - mkdir -p data/mnist500_result + - 'mount -t nfs4 10.151.40.235:/data data' + - >- + cp results.csv + data/mnist500_result/results_$PAI_CURRENT_TASK_ROLE_CURRENT_TASK_INDEX.csv defaults: virtualCluster: default extras: @@ -31,3 +61,7 @@ extras: - plugin: ssh parameters: jobssh: true + - plugin: teamwise_storage + parameters: + storageConfigNames: + - confignfs diff --git a/src/marketplace-restserver/build/marketplace-restserver.k8s.dockerfile b/src/marketplace-restserver/build/marketplace-restserver.k8s.dockerfile index 005c719740..51eab058c6 100644 --- a/src/marketplace-restserver/build/marketplace-restserver.k8s.dockerfile +++ b/src/marketplace-restserver/build/marketplace-restserver.k8s.dockerfile @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. -FROM docker.io/openpai/pai-marketplace-restserver:v1.2.0 +FROM docker.io/openpai/pai-marketplace-restserver:v1.3.0 diff --git a/src/marketplace-webportal/build/marketplace-webportal.k8s.dockerfile b/src/marketplace-webportal/build/marketplace-webportal.k8s.dockerfile index a2f12ff94a..71e47075f7 100644 --- a/src/marketplace-webportal/build/marketplace-webportal.k8s.dockerfile +++ b/src/marketplace-webportal/build/marketplace-webportal.k8s.dockerfile @@ -1,4 +1,4 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. -FROM docker.io/openpai/pai-marketplace-webportal:v1.2.0 +FROM docker.io/openpai/pai-marketplace-webportal:v1.3.0